Pause dart microtasks while UI thread is processing frame workloads (flutter/engine#25789)
This commit is contained in:
@@ -325,7 +325,7 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
|
||||
std::make_unique<ShellTestVsyncWaiter>(task_runners, vsync_clock));
|
||||
} else {
|
||||
return static_cast<std::unique_ptr<VsyncWaiter>>(
|
||||
std::make_unique<VsyncWaiterFallback>(task_runners));
|
||||
std::make_unique<VsyncWaiterFallback>(task_runners, true));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1335,6 +1335,7 @@ TEST_F(ShellTest, ReportTimingsIsCalledImmediatelyAfterTheFirstFrame) {
|
||||
};
|
||||
AddNativeCallback("NativeReportTimingsCallback",
|
||||
CREATE_NATIVE_ENTRY(nativeTimingCallback));
|
||||
ASSERT_TRUE(configuration.IsValid());
|
||||
RunEngine(shell.get(), std::move(configuration));
|
||||
|
||||
for (int i = 0; i < 10; i += 1) {
|
||||
|
||||
@@ -91,7 +91,8 @@ void VsyncWaiter::ScheduleSecondaryCallback(uintptr_t id,
|
||||
}
|
||||
|
||||
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
|
||||
fml::TimePoint frame_target_time) {
|
||||
fml::TimePoint frame_target_time,
|
||||
bool pause_secondary_tasks) {
|
||||
Callback callback;
|
||||
std::vector<fml::closure> secondary_callbacks;
|
||||
|
||||
@@ -114,6 +115,9 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
|
||||
|
||||
if (callback) {
|
||||
auto flow_identifier = fml::tracing::TraceNonce();
|
||||
if (pause_secondary_tasks) {
|
||||
PauseDartMicroTasks();
|
||||
}
|
||||
|
||||
// The base trace ensures that flows have a root to begin from if one does
|
||||
// not exist. The trace viewer will ignore traces that have no base event
|
||||
@@ -124,11 +128,15 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
|
||||
TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier);
|
||||
|
||||
task_runners_.GetUITaskRunner()->PostTaskForTime(
|
||||
[callback, flow_identifier, frame_start_time, frame_target_time]() {
|
||||
[this, callback, flow_identifier, frame_start_time, frame_target_time,
|
||||
pause_secondary_tasks]() {
|
||||
FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime",
|
||||
frame_start_time, "TargetTime", frame_target_time);
|
||||
callback(frame_start_time, frame_target_time);
|
||||
TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier);
|
||||
if (pause_secondary_tasks) {
|
||||
ResumeDartMicroTasks();
|
||||
}
|
||||
},
|
||||
frame_start_time);
|
||||
}
|
||||
@@ -139,4 +147,16 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
|
||||
}
|
||||
}
|
||||
|
||||
void VsyncWaiter::PauseDartMicroTasks() {
|
||||
auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
|
||||
auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
|
||||
task_queues->PauseSecondarySource(ui_task_queue_id);
|
||||
}
|
||||
|
||||
void VsyncWaiter::ResumeDartMicroTasks() {
|
||||
auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
|
||||
auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
|
||||
task_queues->ResumeSecondarySource(ui_task_queue_id);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -49,13 +49,17 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
|
||||
virtual void AwaitVSync() = 0;
|
||||
|
||||
void FireCallback(fml::TimePoint frame_start_time,
|
||||
fml::TimePoint frame_target_time);
|
||||
fml::TimePoint frame_target_time,
|
||||
bool pause_secondary_tasks = true);
|
||||
|
||||
private:
|
||||
std::mutex callback_mutex_;
|
||||
Callback callback_;
|
||||
std::unordered_map<uintptr_t, fml::closure> secondary_callbacks_;
|
||||
|
||||
void PauseDartMicroTasks();
|
||||
void ResumeDartMicroTasks();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter);
|
||||
};
|
||||
|
||||
|
||||
@@ -21,8 +21,11 @@ static fml::TimePoint SnapToNextTick(fml::TimePoint value,
|
||||
|
||||
} // namespace
|
||||
|
||||
VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners)
|
||||
: VsyncWaiter(std::move(task_runners)), phase_(fml::TimePoint::Now()) {}
|
||||
VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners,
|
||||
bool for_testing)
|
||||
: VsyncWaiter(std::move(task_runners)),
|
||||
phase_(fml::TimePoint::Now()),
|
||||
for_testing_(for_testing) {}
|
||||
|
||||
VsyncWaiterFallback::~VsyncWaiterFallback() = default;
|
||||
|
||||
@@ -36,7 +39,7 @@ void VsyncWaiterFallback::AwaitVSync() {
|
||||
auto next =
|
||||
SnapToNextTick(fml::TimePoint::Now(), phase_, kSingleFrameInterval);
|
||||
|
||||
FireCallback(next, next + kSingleFrameInterval);
|
||||
FireCallback(next, next + kSingleFrameInterval, !for_testing_);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -15,12 +15,14 @@ namespace flutter {
|
||||
/// A |VsyncWaiter| that will fire at 60 fps irrespective of the vsync.
|
||||
class VsyncWaiterFallback final : public VsyncWaiter {
|
||||
public:
|
||||
VsyncWaiterFallback(TaskRunners task_runners);
|
||||
explicit VsyncWaiterFallback(TaskRunners task_runners,
|
||||
bool for_testing = false);
|
||||
|
||||
~VsyncWaiterFallback() override;
|
||||
|
||||
private:
|
||||
fml::TimePoint phase_;
|
||||
const bool for_testing_;
|
||||
|
||||
// |VsyncWaiter|
|
||||
void AwaitVSync() override;
|
||||
|
||||
@@ -23,7 +23,8 @@ VsyncWaiterIOS::VsyncWaiterIOS(flutter::TaskRunners task_runners)
|
||||
callback:std::bind(&VsyncWaiterIOS::FireCallback,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)]) {}
|
||||
std::placeholders::_2,
|
||||
true)]) {}
|
||||
|
||||
VsyncWaiterIOS::~VsyncWaiterIOS() {
|
||||
// This way, we will get no more callbacks from the display link that holds a weak (non-nilling)
|
||||
|
||||
@@ -197,7 +197,7 @@ void VsyncWaiter::FireCallbackNow() {
|
||||
}
|
||||
fml::TimePoint previous_vsync = next_vsync - vsync_info.presentation_interval;
|
||||
|
||||
FireCallback(previous_vsync, next_vsync);
|
||||
FireCallback(previous_vsync, next_vsync, false);
|
||||
}
|
||||
|
||||
} // namespace flutter_runner
|
||||
|
||||
Reference in New Issue
Block a user