mirror of
https://github.com/flutter/flutter
synced 2024-10-01 05:54:08 +00:00
Reverts "Refactor external_ui
→ external_textures
" (#142173)
Reverts flutter/flutter#142062 Initiated by: eliasyishak This change reverts the following previous change: Original Description: This PR makes no _behavioral_ changes to executed code, and instead focuses on organization and naming: 1. Almost[^1] anything named `external_ui` is renamed `external_textures` 1. Extended the README to explain the intent of the test, as well as how to run it 1. Renamed `main.dart` and `main_test.dart` to `frame_rate_main.dart` and `frame_rate_test.dart` (we'll add more) 1. Did some refactoring of the test to make it more obvious what is being asserted (i.e. `widgetBuilds` and friends) Given how complex (and in-flux) this directory is, I'm also requesting either John, Jonah or I review any changes. [^1]: Except the name of the `.ci.yaml` task, i.e. `name: Linux_pixel_7pro external_ui_integration_test` because I'm apparently not able to change that without creating a new task as `bringup: true` and playing a bit of a dance. Maybe that's worth doing though (in future PRs)?
This commit is contained in:
parent
2e2042ff8e
commit
54e9f2dbe6
4
.ci.yaml
4
.ci.yaml
|
@ -2175,7 +2175,7 @@ targets:
|
||||||
properties:
|
properties:
|
||||||
tags: >
|
tags: >
|
||||||
["devicelab", "android", "linux", "pixel", "7pro"]
|
["devicelab", "android", "linux", "pixel", "7pro"]
|
||||||
task_name: external_textures_integration_test
|
task_name: external_ui_integration_test
|
||||||
|
|
||||||
# linux motog4 benchmark
|
# linux motog4 benchmark
|
||||||
- name: Linux_android fading_child_animation_perf__timeline_summary
|
- name: Linux_android fading_child_animation_perf__timeline_summary
|
||||||
|
@ -4281,7 +4281,7 @@ targets:
|
||||||
properties:
|
properties:
|
||||||
tags: >
|
tags: >
|
||||||
["devicelab", "ios", "mac"]
|
["devicelab", "ios", "mac"]
|
||||||
task_name: external_textures_integration_test_ios
|
task_name: external_ui_integration_test_ios
|
||||||
ignore_flakiness: "true"
|
ignore_flakiness: "true"
|
||||||
|
|
||||||
- name: Mac_ios route_test_ios
|
- name: Mac_ios route_test_ios
|
||||||
|
|
|
@ -9,4 +9,3 @@
|
||||||
/packages/flutter_tools/pubspec.yaml @christopherfujino
|
/packages/flutter_tools/pubspec.yaml @christopherfujino
|
||||||
/packages/flutter_tools/templates/module/ios/ @jmagman
|
/packages/flutter_tools/templates/module/ios/ @jmagman
|
||||||
/packages/flutter_tools/templates/**/Podfile* @jmagman
|
/packages/flutter_tools/templates/**/Podfile* @jmagman
|
||||||
/dev/integration_tests/external_textures/** @matanlurey @johnmccutchan @jonahwilliams
|
|
||||||
|
|
|
@ -129,7 +129,7 @@
|
||||||
/dev/devicelab/bin/tasks/cull_opacity_perf__timeline_summary.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/cull_opacity_perf__timeline_summary.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/drive_perf_debug_warning.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/drive_perf_debug_warning.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/embedded_android_views_integration_test.dart @stuartmorgan @flutter/plugin
|
/dev/devicelab/bin/tasks/embedded_android_views_integration_test.dart @stuartmorgan @flutter/plugin
|
||||||
/dev/devicelab/bin/tasks/external_textures_integration_test.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/external_ui_integration_test.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/fading_child_animation_perf__timeline_summary.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/fading_child_animation_perf__timeline_summary.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/fast_scroll_large_images__memory.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/fast_scroll_large_images__memory.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/flavors_test.dart @zanderso @flutter/tool
|
/dev/devicelab/bin/tasks/flavors_test.dart @zanderso @flutter/tool
|
||||||
|
@ -174,7 +174,7 @@
|
||||||
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart @jonahwilliams @flutter/engine
|
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart @jonahwilliams @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart @vashworth @flutter/engine
|
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart @vashworth @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/external_textures_integration_test_ios.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/external_ui_integration_test_ios.dart @zanderso @flutter/engine
|
||||||
/dev/devicelab/bin/tasks/flavors_test_ios.dart @vashworth @flutter/tool
|
/dev/devicelab/bin/tasks/flavors_test_ios.dart @vashworth @flutter/tool
|
||||||
/dev/devicelab/bin/tasks/flavors_test_ios_xcode_debug.dart @vashworth @flutter/tool
|
/dev/devicelab/bin/tasks/flavors_test_ios_xcode_debug.dart @vashworth @flutter/tool
|
||||||
/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_ios.dart @zanderso @flutter/engine
|
/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_ios.dart @zanderso @flutter/engine
|
||||||
|
|
|
@ -8,5 +8,5 @@ import 'package:flutter_devicelab/tasks/integration_tests.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||||
await task(createExternalTexturesIntegrationTest());
|
await task(createExternalUiIntegrationTest());
|
||||||
}
|
}
|
|
@ -8,5 +8,5 @@ import 'package:flutter_devicelab/tasks/integration_tests.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
deviceOperatingSystem = DeviceOperatingSystem.ios;
|
deviceOperatingSystem = DeviceOperatingSystem.ios;
|
||||||
await task(createExternalTexturesIntegrationTest());
|
await task(createExternalUiIntegrationTest());
|
||||||
}
|
}
|
|
@ -40,9 +40,9 @@ TaskFunction createIntegrationTestFlavorsTest({Map<String, String>? environment}
|
||||||
).call;
|
).call;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskFunction createExternalTexturesIntegrationTest() {
|
TaskFunction createExternalUiIntegrationTest() {
|
||||||
return DriverTest(
|
return DriverTest(
|
||||||
'${flutterDirectory.path}/dev/integration_tests/external_textures',
|
'${flutterDirectory.path}/dev/integration_tests/external_ui',
|
||||||
'lib/main.dart',
|
'lib/main.dart',
|
||||||
).call;
|
).call;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
# external_textures
|
|
||||||
|
|
||||||
Tests external texture rendering between a native[^1] platform and Flutter.
|
|
||||||
|
|
||||||
Part of Flutter's API for [plugins](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin) includes passing _external textures_, or textures
|
|
||||||
created outside of Flutter, to Flutter, typically using the [`Texture`][texture]
|
|
||||||
widget. This is useful for plugins that render video, or for plugins that
|
|
||||||
interact with the camera.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
- [`packages/camera`][camera]
|
|
||||||
- [`packages/video_player`][video_player]
|
|
||||||
|
|
||||||
[texture]: https://api.flutter.dev/flutter/widgets/Texture-class.html
|
|
||||||
[camera]: https://github.com/flutter/packages/tree/8255fbed74465425a1ec06a1804225e705e29f52/packages/camera
|
|
||||||
[video_player]: https://github.com/flutter/packages/tree/8255fbed74465425a1ec06a1804225e705e29f52/packages/video_player
|
|
||||||
|
|
||||||
Because external textures are created outside of Flutter, there is often subtle
|
|
||||||
translation that needs to happen between the native platform and Flutter, which
|
|
||||||
is hard to observe. These integration tests are designed to help catch these
|
|
||||||
subtle translation issues.
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
- Each `lib/*_main.dart` file is a Flutter app instrumenting a test case.
|
|
||||||
- There is a cooresponding `test_driver/*_test.dart` that runs assertions.
|
|
||||||
|
|
||||||
To run the test cases locally, use `flutter drive`[^2]:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
flutter drive lib/frame_rate_main.dart --driver test_driver/frame_rate_test.dart
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> On CI, the test cases are run within our [device lab](../../devicelab/README.md).
|
|
||||||
>
|
|
||||||
> See [`devicelab/lib/tasks/integration_tests.dart`](../../devicelab/lib/tasks/integration_tests.dart)
|
|
||||||
> and search for `createExternalTexturesIntegrationTest`.
|
|
||||||
>
|
|
||||||
> The actual tests are run by task runners:
|
|
||||||
>
|
|
||||||
> - [Android](../../devicelab/bin/tasks/external_textures_integration_test.dart)
|
|
||||||
> - [iOS](../../devicelab/bin/tasks/external_textures_integration_test_ios.dart)
|
|
||||||
|
|
||||||
[^1]: Only iOS and Android.
|
|
||||||
[^2]: Unfortunately documentation is quite limited. See [#142021](https://github.com/flutter/flutter/issues/142021).
|
|
|
@ -1,73 +0,0 @@
|
||||||
// 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';
|
|
||||||
|
|
||||||
import 'package:flutter_driver/flutter_driver.dart';
|
|
||||||
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
|
||||||
|
|
||||||
final RegExp _calibrationRegExp = RegExp('Flutter frame rate is (.*)fps');
|
|
||||||
final RegExp _statsRegExp = RegExp('Produced: (.*)fps\nConsumed: (.*)fps\nWidget builds: (.*)');
|
|
||||||
const Duration _samplingTime = Duration(seconds: 8);
|
|
||||||
|
|
||||||
Future<void> main() async {
|
|
||||||
late final FlutterDriver driver;
|
|
||||||
|
|
||||||
setUpAll(() async {
|
|
||||||
driver = await FlutterDriver.connect();
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await driver.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies we consume texture frames at a rate close to the minimum of the
|
|
||||||
// rate at which they are produced and Flutter's frame rate. In addition,
|
|
||||||
// it verifies that widget builds are not triggered by external texture
|
|
||||||
// frames.
|
|
||||||
test('renders frames from the device at a rate similar to the frames produced', () async {
|
|
||||||
final SerializableFinder fab = find.byValueKey('fab');
|
|
||||||
final SerializableFinder summary = find.byValueKey('summary');
|
|
||||||
|
|
||||||
// Wait for calibration to complete and fab to appear.
|
|
||||||
await driver.waitFor(fab);
|
|
||||||
|
|
||||||
final String calibrationResult = await driver.getText(summary);
|
|
||||||
final Match? matchCalibration = _calibrationRegExp.matchAsPrefix(calibrationResult);
|
|
||||||
expect(matchCalibration, isNotNull);
|
|
||||||
final double flutterFrameRate = double.parse(matchCalibration?.group(1) ?? '0');
|
|
||||||
|
|
||||||
// Texture frame stats at 0.5x Flutter frame rate
|
|
||||||
await driver.tap(fab);
|
|
||||||
await Future<void>.delayed(_samplingTime);
|
|
||||||
await driver.tap(fab);
|
|
||||||
|
|
||||||
final String statsSlow = await driver.getText(summary);
|
|
||||||
final Match matchSlow = _statsRegExp.matchAsPrefix(statsSlow)!;
|
|
||||||
expect(matchSlow, isNotNull);
|
|
||||||
|
|
||||||
double framesProduced = double.parse(matchSlow.group(1)!);
|
|
||||||
expect(framesProduced, closeTo(flutterFrameRate / 2.0, 5.0));
|
|
||||||
double framesConsumed = double.parse(matchSlow.group(2)!);
|
|
||||||
expect(framesConsumed, closeTo(flutterFrameRate / 2.0, 5.0));
|
|
||||||
int widgetBuilds = int.parse(matchSlow.group(3)!);
|
|
||||||
expect(widgetBuilds, 1);
|
|
||||||
|
|
||||||
// Texture frame stats at 2.0x Flutter frame rate
|
|
||||||
await driver.tap(fab);
|
|
||||||
await Future<void>.delayed(_samplingTime);
|
|
||||||
await driver.tap(fab);
|
|
||||||
|
|
||||||
final String statsFast = await driver.getText(summary);
|
|
||||||
final Match matchFast = _statsRegExp.matchAsPrefix(statsFast)!;
|
|
||||||
expect(matchFast, isNotNull);
|
|
||||||
|
|
||||||
framesProduced = double.parse(matchFast.group(1)!);
|
|
||||||
expect(framesProduced, closeTo(flutterFrameRate * 2.0, 5.0));
|
|
||||||
framesConsumed = double.parse(matchFast.group(2)!);
|
|
||||||
expect(framesConsumed, closeTo(flutterFrameRate, 10.0));
|
|
||||||
widgetBuilds = int.parse(matchSlow.group(3)!);
|
|
||||||
expect(widgetBuilds, 1);
|
|
||||||
}, timeout: Timeout.none);
|
|
||||||
}
|
|
3
dev/integration_tests/external_ui/README.md
Normal file
3
dev/integration_tests/external_ui/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# external_ui
|
||||||
|
|
||||||
|
A Flutter project for testing external texture rendering.
|
|
@ -9,7 +9,7 @@ found in the LICENSE file. -->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:label="external_textures">
|
android:label="external_ui">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
|
@ -11,7 +11,7 @@
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>external_textures</string>
|
<string>external_ui</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
|
@ -1,4 +1,4 @@
|
||||||
name: external_textures
|
name: external_ui
|
||||||
description: A test of Flutter integrating external UIs.
|
description: A test of Flutter integrating external UIs.
|
||||||
|
|
||||||
environment:
|
environment:
|
68
dev/integration_tests/external_ui/test_driver/main_test.dart
Normal file
68
dev/integration_tests/external_ui/test_driver/main_test.dart
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// 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';
|
||||||
|
|
||||||
|
import 'package:flutter_driver/flutter_driver.dart';
|
||||||
|
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
||||||
|
|
||||||
|
final RegExp calibrationRegExp = RegExp('Flutter frame rate is (.*)fps');
|
||||||
|
final RegExp statsRegExp = RegExp('Produced: (.*)fps\nConsumed: (.*)fps\nWidget builds: (.*)');
|
||||||
|
const Duration samplingTime = Duration(seconds: 8);
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
group('texture suite', () {
|
||||||
|
late FlutterDriver driver;
|
||||||
|
|
||||||
|
setUpAll(() async {
|
||||||
|
driver = await FlutterDriver.connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
// This test verifies that we can consume texture frames at a rate
|
||||||
|
// close to the minimum of the rate at which they are produced
|
||||||
|
// and Flutter's frame rate. It also verifies that we do not rebuild the
|
||||||
|
// Widget tree during texture consumption. The test starts by measuring
|
||||||
|
// Flutter's frame rate.
|
||||||
|
test('texture rendering', () async {
|
||||||
|
final SerializableFinder fab = find.byValueKey('fab');
|
||||||
|
final SerializableFinder summary = find.byValueKey('summary');
|
||||||
|
|
||||||
|
// Wait for calibration to complete and fab to appear.
|
||||||
|
await driver.waitFor(fab);
|
||||||
|
|
||||||
|
final String calibrationResult = await driver.getText(summary);
|
||||||
|
final Match? matchCalibration = calibrationRegExp.matchAsPrefix(calibrationResult);
|
||||||
|
expect(matchCalibration, isNotNull);
|
||||||
|
final double flutterFrameRate = double.parse(matchCalibration?.group(1) ?? '0');
|
||||||
|
|
||||||
|
// Texture frame stats at 0.5x Flutter frame rate
|
||||||
|
await driver.tap(fab);
|
||||||
|
await Future<void>.delayed(samplingTime);
|
||||||
|
await driver.tap(fab);
|
||||||
|
|
||||||
|
final String statsSlow = await driver.getText(summary);
|
||||||
|
final Match matchSlow = statsRegExp.matchAsPrefix(statsSlow)!;
|
||||||
|
expect(matchSlow, isNotNull);
|
||||||
|
expect(double.parse(matchSlow.group(1)!), closeTo(flutterFrameRate / 2.0, 5.0));
|
||||||
|
expect(double.parse(matchSlow.group(2)!), closeTo(flutterFrameRate / 2.0, 5.0));
|
||||||
|
expect(int.parse(matchSlow.group(3)!), 1);
|
||||||
|
|
||||||
|
// Texture frame stats at 2.0x Flutter frame rate
|
||||||
|
await driver.tap(fab);
|
||||||
|
await Future<void>.delayed(samplingTime);
|
||||||
|
await driver.tap(fab);
|
||||||
|
|
||||||
|
final String statsFast = await driver.getText(summary);
|
||||||
|
final Match matchFast = statsRegExp.matchAsPrefix(statsFast)!;
|
||||||
|
expect(matchFast, isNotNull);
|
||||||
|
expect(double.parse(matchFast.group(1)!), closeTo(flutterFrameRate * 2.0, 5.0));
|
||||||
|
expect(double.parse(matchFast.group(2)!), closeTo(flutterFrameRate, 10.0));
|
||||||
|
expect(int.parse(matchFast.group(3)!), 1);
|
||||||
|
}, timeout: Timeout.none);
|
||||||
|
|
||||||
|
tearDownAll(() async {
|
||||||
|
driver.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue