Closes https://github.com/flutter/flutter/issues/155769.
This is a variant of the approach in https://github.com/flutter/engine/pull/52241, based on feedback from @jakemac53 and @jonahwilliams (who originally sped up `dart test` significantly by using `frontend_server` under the scenes: https://github.com/dart-lang/test/pull/1399), in short:
```gn
# tools/engine_tool/BUILD.gn
import("//flutter/build/dart/internal/gen_dartcli_call.gni")
gen_dartcli_call("tests") {
args = [ "test" ]
cwd = "//flutter/tools/engine_tool"
}
```
This stanza, when built (`ninja -C ../out/host_debug flutter/tools/engine_tool:tests`) generates the following file:
```sh
# ../out/host_debug/gen/flutter/tools/engine_tool/tests
set -e
# Needed because if it is set, cd may print the path it changed to.
unset CDPATH
# Store the current working directory.
prev_cwd=$(pwd)
# Set a trap to restore the working directory.
trap 'cd "$prev_cwd"' EXIT
CD_PATH="/Users/matanl/Developer/engine/src/flutter/tools/engine_tool"
if [ -n "$CD_PATH" ]; then
cd "$CD_PATH"
fi
/Users/matanl/Developer/engine/src/flutter/prebuilts/macos-arm64/dart-sdk/bin/dart "test"
```
In turn, when executed (`../out/host_debug/gen/flutter/tools/engine_tool/tests`) it just runs `dart test`:
```sh
flutter % ../out/host_debug/gen/flutter/tools/engine_tool/tests
Building package executable...
Built test:test.
00:00 +0: test/test_command_test.dart: test command executes test
00:00 +3: test/run_command_test.dart: run command invokes flutter run
...
00:00 +117: All tests passed!
```
There is no actual compilation performed by the tool (that is handled implicitly by `dart test`), and as a result neither a `depfile` is needed, nor generating a pre-compiled artifact like a snapshot or AOT elf/assembly.
---
This work is incomplete, that is, we'd want to properly tag the executable so `et` can find it, and create a wrapper template (i.e. `dart_test`) that tightens things up a bit, but I wanted to show the work at this intermediate step to get feedback before moving forward.
/cc @jonahwilliams, @jtmcdole as well.
This turns on Metal validation for launching impeller_unittests from the tests panel. This matches the default behavior of launching tests from XCode. Without these assertions errors in Metal are completely silent. In my case I just got a black screen until I tried running the tests through xcode.
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This issue was found with memory sanitizer.
Commit 988c4ffb83398bf8511122d73f0f85010e0edeea introduced a change that leads to use-after-free condition.
In function MessageLoopTaskQueues::GetNextTaskToRun:
1) Call is made to PeekNextTaskUnlocked(queue_id);. Returned value contains a reference to to an object of const DelayedTask& taken from an std::queue container as returned by primary_task_queue_.top().
2) Variable TaskSource::TopTask top now contains a reference to this object.
3) Function queue_entries_.at(top.task_queue_id)->task_source->PopTask(...) which in turn calls pop() method on std::queue.
4) Object of type DelayedTask on top of the queue gets deleted.
5) top.task.GetTaskSourceGrade() is called later with top.task refering to an already deleted object.
*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.*
*List which issues are fixed by this PR. You must list at least one issue.*
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This is an attempt to reland the overlay optimization for skwasm and fixing the golden diffs from the framework tests.
Original PR description:
This PR refactors the scene builder's logic in order to more aggressively merge flutter content and platform view content together. This essentially covers the case discussed in this flutter issue: https://github.com/flutter/flutter/issues/149863
This optimization ensures that each picture or platform view is applied to the lowest possible slice in the scene, which avoids the proliferation of redundant slices and overlays in the scene.
Most iOS embedder developers rely on two simulator builds:
* ios_debug_sim_unopt (for simulators on x64 hosts)
* ios_debug_sim_unopt_arm64 (for simulators on arm64 hosts)
We specify these two builds, for example, in our iOS unit test Xcode project `testing/ios/IosUnitTests/Tests/FlutterEngineConfig.xcconfig`.
Currently `local_engine.json` specifies two simulator builds:
* ios_debug_sim_unopt (for simulators on x64 hosts)
* ios_debug_sim_arm64 (for simulators on arm64 hosts)
While the x64 build specifies the `--unoptimized` flag, the arm64 build does not, which is problematic for those wanting to use both `et` and run the iOS unit tests.
This adds the `--unoptimized` flag for consistency with prevailing practice among iOS embedder developers.
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Reverts: flutter/engine#55092
Initiated by: jonahwilliams
Reason for reverting: framework golden failures.
Original PR Author: jonahwilliams
Reviewed By: {chinmaygarde, jtmcdole}
This change reverts the following previous change:
Follow up to https://github.com/flutter/engine/pull/55060
Currently we have multiple stages of hashing while font rendering, which is relatively expensive for the actualy required workload. First, we hash the contents of all text frames to compute the unique set of glyphs per frame. Then we diff this hash set against the hashmap of glyphs within the atlas. Finally we hash and lookup the final rendered bounds for each glyph.
We can simplify this to 2. hash lookups for glyphs not yet in the atlas and 1. hash lookup for glyphs that are in the atlas. This is done by combing the step where we uniquely compute glyphs per frame with the diff against the current atlas. When this lookup is performed, we also store the glyph position (if found) in the text_frame itself - which allows text contents to skip the last hash, as long as the glyph has already been rendered.
### Before

### After

Using this handy dandy test app:
```dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Platform View'),
),
body: SafeArea(child: Stack(children: [
SizedBox(
width: 380,
height: 380,
child: LinearProgressIndicator(),
),
Stack(
children: List<Widget>.generate(1000, (index) {
// The problem already happens with a small amount of widgets.
// Using an excessive amount of widgets is just to make the problem more evident.
return Text("Lots of Texts represent a Widget with complex components.");
}),
),
Align(
alignment: Alignment.bottomCenter,
child:
TextButton(
child: Text("Button"),
onPressed: () {
print("Tap ${DateTime.now()}");
},
),
),
],
),
),
),
);
}
}
```
Follow up to https://github.com/flutter/engine/pull/55060
Currently we have multiple stages of hashing while font rendering, which is relatively expensive for the actualy required workload. First, we hash the contents of all text frames to compute the unique set of glyphs per frame. Then we diff this hash set against the hashmap of glyphs within the atlas. Finally we hash and lookup the final rendered bounds for each glyph.
We can simplify this to 2. hash lookups for glyphs not yet in the atlas and 1. hash lookup for glyphs that are in the atlas. This is done by combing the step where we uniquely compute glyphs per frame with the diff against the current atlas. When this lookup is performed, we also store the glyph position (if found) in the text_frame itself - which allows text contents to skip the last hash, as long as the glyph has already been rendered.
### Before

### After

Using this handy dandy test app:
```dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Platform View'),
),
body: SafeArea(child: Stack(children: [
SizedBox(
width: 380,
height: 380,
child: LinearProgressIndicator(),
),
Stack(
children: List<Widget>.generate(1000, (index) {
// The problem already happens with a small amount of widgets.
// Using an excessive amount of widgets is just to make the problem more evident.
return Text("Lots of Texts represent a Widget with complex components.");
}),
),
Align(
alignment: Alignment.bottomCenter,
child:
TextButton(
child: Text("Button"),
onPressed: () {
print("Tap ${DateTime.now()}");
},
),
),
],
),
),
),
);
}
}
```
When making a drawAtlas call with no colors, use the faster shader that does not apply blending.
Now that we're switched to experimental canvas, we can remove the copying of the display list data. The draw can directly refer to pointers from the display list structure, as the draw is processed during DL dispatching.
This enhances the overlay optimization by delaying combining pictures to get tighter bounds for the pictures that make up the scene, enabling more sophisticated optimization since we can determine if they intersect with platform views on a per-picture basis.
Fixes https://github.com/flutter/flutter/issues/149863
On a Macbook in Chrome in an example app with an infinite scrolling grid of platform views, this brings the ratio of dropped frames from 93% to 55% (roughly 4 fps to 30 fps).
This is a reland of https://github.com/flutter/engine/pull/54878 with a fix for scenes with pictures and shader masks that are eventually entirely clipped out.
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Reverts: flutter/engine#55450
Initiated by: matanlurey
Reason for reverting: Fixed forward in https://github.com/flutter/packages/pull/7712.
Original PR Author: auto-submit[bot]
Reviewed By: {fluttergithubbot}
This change reverts the following previous change:
Reverts: flutter/engine#55418
Initiated by: bdero
Reason for reverting: [Engine->Framework roll breakage](https://github.com/flutter/flutter/issues/155727#issuecomment-2375489803)
Original PR Author: matanlurey
Reviewed By: {jonahwilliams}
This change reverts the following previous change:
Closes https://github.com/flutter/flutter/issues/155131.
Not only did I rename the method, but I also changed the contract slightly - now `onSurfaceAvailable` is _only_ invoked _after_ `onSurfaceDestroyed` has been called. The cost is a single `boolean`, and it honestly makes the API make a lot more sense than someone having to track this themselves.
/cc @johnmccutchan (OOO), and @flutter/android-reviewers.
Reverts: flutter/engine#55402
Initiated by: chingjun
Reason for reverting: caused internal tests to fail.
See b/369740500 for more details.
Original PR Author: harryterkelsen
Reviewed By: {yjbanov}
This change reverts the following previous change:
This enhances the overlay optimization by delaying combining pictures to get tighter bounds for the pictures that make up the scene, enabling more sophisticated optimization since we can determine if they intersect with platform views on a per-picture basis.
Fixes https://github.com/flutter/flutter/issues/149863
On a Macbook in Chrome in an example app with an infinite scrolling grid of platform views, this brings the ratio of dropped frames from 93% to 55% (roughly 4 fps to 30 fps).
This is a reland of https://github.com/flutter/engine/pull/54878 with a fix for scenes with pictures that are eventually entirely clipped out.
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Fixes https://github.com/flutter/flutter/issues/125640
This doesn't actually do anything, instead it forces opaque to false. If developers want opaque to be false, they can just set it directly.