mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
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.
This commit is contained in:
parent
01963ea21a
commit
be2544ab59
|
@ -1025,28 +1025,29 @@ 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,
|
||||||
// the very next frame pretends to have occurred immediately after this
|
// the very next frame pretends to have occurred immediately after this
|
||||||
// warm-up frame. The warm-up frame's timestamp will typically be far in
|
// warm-up frame. The warm-up frame's timestamp will typically be far in
|
||||||
// the past (the time of the last real frame), so if we didn't reset the
|
// the past (the time of the last real frame), so if we didn't reset the
|
||||||
// epoch we would see a sudden jump from the old time in the warm-up frame
|
// epoch we would see a sudden jump from the old time in the warm-up frame
|
||||||
// to the new time in the "real" frame. The biggest problem with this is
|
// to the new time in the "real" frame. The biggest problem with this is
|
||||||
// that implicit animations end up being triggered at the old time and
|
// that implicit animations end up being triggered at the old time and
|
||||||
// then skipping every frame and finishing in the new time.
|
// then skipping every frame and finishing in the new time.
|
||||||
resetEpoch();
|
resetEpoch();
|
||||||
_warmUpFrame = false;
|
_warmUpFrame = false;
|
||||||
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';
|
||||||
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() {
|
||||||
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() {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue