From 57ad4ff01875e2ce260710919d22a1c91842452f Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:13:35 -0700 Subject: [PATCH] Added a devicelab test for vulkan validation layers (#134685) This makes sure validation layers are being used and that there are no validation errors fixes https://github.com/flutter/flutter/issues/134175 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 10 +++ TESTOWNERS | 1 + .../bin/tasks/hello_world_impeller.dart | 81 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 dev/devicelab/bin/tasks/hello_world_impeller.dart diff --git a/.ci.yaml b/.ci.yaml index e01d5b5ccd34..59ae1ab2bd1c 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1567,6 +1567,16 @@ targets: - bin/** - .ci.yaml + - name: Linux_android hello_world_impeller + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux"] + task_name: hello_world_impeller + - name: Linux_android android_defines_test recipe: devicelab/devicelab_drone presubmit: true diff --git a/TESTOWNERS b/TESTOWNERS index bdb7499e3cee..4f4096f01b11 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -135,6 +135,7 @@ /dev/devicelab/bin/tasks/fullscreen_textfield_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world__memory.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world_android__compile.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/hello_world_impeller.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/home_scroll_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart @eliasyishak @flutter/tool /dev/devicelab/bin/tasks/hybrid_android_views_integration_test.dart @stuartmorgan @flutter/plugin diff --git a/dev/devicelab/bin/tasks/hello_world_impeller.dart b/dev/devicelab/bin/tasks/hello_world_impeller.dart new file mode 100644 index 000000000000..e67a25b48e6d --- /dev/null +++ b/dev/devicelab/bin/tasks/hello_world_impeller.dart @@ -0,0 +1,81 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async' show Completer, StreamSubscription; +import 'dart:io' show Directory, Process; + +import 'package:flutter_devicelab/framework/devices.dart' + show Device, DeviceOperatingSystem, deviceOperatingSystem, devices; +import 'package:flutter_devicelab/framework/framework.dart' show task; +import 'package:flutter_devicelab/framework/task_result.dart' show TaskResult; +import 'package:flutter_devicelab/framework/utils.dart' + show dir, flutter, flutterDirectory, inDirectory, startFlutter; +import 'package:path/path.dart' as path; + +Future run() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + final Device device = await devices.workingDevice; + await device.unlock(); + final Directory appDir = + dir(path.join(flutterDirectory.path, 'examples/hello_world')); + + bool isUsingValidationLayers = false; + bool hasValidationErrors = false; + int impellerBackendCount = 0; + final Completer didReceiveBackendMessage = Completer(); + + await inDirectory(appDir, () async { + await flutter('packages', options: ['get']); + + final StreamSubscription adb = device.logcat.listen( + (String data) { + if (data.contains('Using the Impeller rendering backend')) { + // Sometimes more than one of these will be printed out if there is a + // fallback. + if (!didReceiveBackendMessage.isCompleted) { + didReceiveBackendMessage.complete(); + } + impellerBackendCount += 1; + } + if (data.contains( + 'Using the Impeller rendering backend (Vulkan with Validation Layers)')) { + isUsingValidationLayers = true; + } + // "ImpellerValidationBreak" comes from the engine: + // https://github.com/flutter/engine/blob/4160ebacdae2081d6f3160432f5f0dd87dbebec1/impeller/base/validation.cc#L40 + if (data.contains('ImpellerValidationBreak')) { + hasValidationErrors = true; + } + }, + ); + + final Process process = await startFlutter( + 'run', + options: [ + '--enable-impeller', + '-d', + device.deviceId, + ], + ); + + await didReceiveBackendMessage.future; + // Since we are waiting for the lack of errors, there is no determinate + // amount of time we can wait. + await Future.delayed(const Duration(seconds: 30)); + process.stdin.write('q'); + await adb.cancel(); + }); + + if (!isUsingValidationLayers || impellerBackendCount != 1) { + return TaskResult.failure('Not using Vulkan validation layers.'); + } + if (hasValidationErrors){ + return TaskResult.failure('Impeller validation errors detected.'); + } + return TaskResult.success(null); +} + +Future main() async { + await task(run); +}