Unverified Commit be2544ab authored by Tong Mu's avatar Tong Mu Committed by GitHub

Render the warm up frame in a proper rendering process (#143290)

_This PR requires https://github.com/flutter/engine/pull/50570._

This PR uses the new `PlatformDispatcher.scheduleWarmUpFrame` API to render warm up frames.

For why the warm up frame must involve the engine to render, see https://github.com/flutter/flutter/issues/142851.
parent 01963ea2
...@@ -1025,12 +1025,12 @@ mixin SchedulerBinding on BindingBase { ...@@ -1025,12 +1025,12 @@ mixin SchedulerBinding on BindingBase {
debugTimelineTask = TimelineTask()..start('Warm-up frame'); debugTimelineTask = TimelineTask()..start('Warm-up frame');
} }
final bool hadScheduledFrame = _hasScheduledFrame; final bool hadScheduledFrame = _hasScheduledFrame;
// We use timers here to ensure that microtasks flush in between. PlatformDispatcher.instance.scheduleWarmUpFrame(
Timer.run(() { beginFrame: () {
assert(_warmUpFrame); assert(_warmUpFrame);
handleBeginFrame(null); handleBeginFrame(null);
}); },
Timer.run(() { drawFrame: () {
assert(_warmUpFrame); assert(_warmUpFrame);
handleDrawFrame(); handleDrawFrame();
// We call resetEpoch after this frame so that, in the hot reload case, // We call resetEpoch after this frame so that, in the hot reload case,
...@@ -1046,7 +1046,8 @@ mixin SchedulerBinding on BindingBase { ...@@ -1046,7 +1046,8 @@ mixin SchedulerBinding on BindingBase {
if (hadScheduledFrame) { if (hadScheduledFrame) {
scheduleFrame(); scheduleFrame();
} }
}); },
);
// Lock events so touch events etc don't insert themselves until the // Lock events so touch events etc don't insert themselves until the
// scheduled frame has finished. // scheduled frame has finished.
......
...@@ -14,6 +14,21 @@ import 'scheduler_tester.dart'; ...@@ -14,6 +14,21 @@ import 'scheduler_tester.dart';
class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding { class TestSchedulerBinding extends BindingBase with SchedulerBinding, ServicesBinding {
final Map<String, List<Map<String, dynamic>>> eventsDispatched = <String, List<Map<String, dynamic>>>{}; final Map<String, List<Map<String, dynamic>>> eventsDispatched = <String, List<Map<String, dynamic>>>{};
VoidCallback? additionalHandleBeginFrame;
VoidCallback? additionalHandleDrawFrame;
@override
void handleBeginFrame(Duration? rawTimeStamp) {
additionalHandleBeginFrame?.call();
super.handleBeginFrame(rawTimeStamp);
}
@override
void handleDrawFrame() {
additionalHandleDrawFrame?.call();
super.handleDrawFrame();
}
@override @override
void postEvent(String eventKind, Map<String, dynamic> eventData) { void postEvent(String eventKind, Map<String, dynamic> eventData) {
getEventsDispatched(eventKind).add(eventData); getEventsDispatched(eventKind).add(eventData);
...@@ -39,6 +54,11 @@ void main() { ...@@ -39,6 +54,11 @@ void main() {
scheduler = TestSchedulerBinding(); scheduler = TestSchedulerBinding();
}); });
tearDown(() {
scheduler.additionalHandleBeginFrame = null;
scheduler.additionalHandleDrawFrame = null;
});
test('Tasks are executed in the right order', () { test('Tasks are executed in the right order', () {
final TestStrategy strategy = TestStrategy(); final TestStrategy strategy = TestStrategy();
scheduler.schedulingStrategy = strategy.shouldRunTaskWithPriority; scheduler.schedulingStrategy = strategy.shouldRunTaskWithPriority;
...@@ -111,6 +131,25 @@ void main() { ...@@ -111,6 +131,25 @@ void main() {
expect(executedTasks[0], equals(0)); expect(executedTasks[0], equals(0));
}); });
test('scheduleWarmUpFrame should flush microtasks between callbacks', () async {
addTearDown(() => scheduler.handleEventLoopCallback());
bool microtaskDone = false;
final Completer<void> drawFrameDone = Completer<void>();
scheduler.additionalHandleBeginFrame = () {
expect(microtaskDone, false);
scheduleMicrotask(() {
microtaskDone = true;
});
};
scheduler.additionalHandleDrawFrame = () {
expect(microtaskDone, true);
drawFrameDone.complete();
};
scheduler.scheduleWarmUpFrame();
await drawFrameDone.future;
});
test('2 calls to scheduleWarmUpFrame just schedules it once', () { test('2 calls to scheduleWarmUpFrame just schedules it once', () {
final List<VoidCallback> timerQueueTasks = <VoidCallback>[]; final List<VoidCallback> timerQueueTasks = <VoidCallback>[];
bool taskExecuted = false; bool taskExecuted = false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment