Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions shell/common/animator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

namespace shell {

namespace {

// Wait 51 milliseconds (which is 1 more milliseconds than 3 frames at 60hz)
// before notifying the engine that we are idle. See comments in |BeginFrame|
// for further discussion on why this is necessary.
constexpr fml::TimeDelta kNotifyIdleTaskWaitTime =
fml::TimeDelta::FromMilliseconds(51);

} // namespace

Animator::Animator(Delegate& delegate,
blink::TaskRunners task_runners,
std::unique_ptr<VsyncWaiter> waiter)
Expand All @@ -23,6 +33,7 @@ Animator::Animator(Delegate& delegate,
paused_(false),
regenerate_layer_tree_(false),
frame_scheduled_(false),
notify_idle_task_id_(0),
dimension_change_pending_(false),
weak_factory_(this) {}

Expand Down Expand Up @@ -64,6 +75,7 @@ void Animator::BeginFrame(fml::TimePoint frame_start_time,
TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++);

frame_scheduled_ = false;
notify_idle_task_id_++;
regenerate_layer_tree_ = false;
pending_frame_semaphore_.Signal();

Expand Down Expand Up @@ -95,9 +107,28 @@ void Animator::BeginFrame(fml::TimePoint frame_start_time,
}

if (!frame_scheduled_) {
// We don't have another frame pending, so we're waiting on user input
// or I/O. Allow the Dart VM 100 ms.
delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_ + 100000);
// Under certain workloads (such as our parent view resizing us, which is
// communicated to us by repeat viewport metrics events), we won't
// actually have a frame scheduled yet, despite the fact that we *will* be
// producing a frame next vsync (it will be scheduled once we receive the
// viewport event). Because of this, we hold off on calling
// |OnAnimatorNotifyIdle| for a little bit, as that could cause garbage
// collection to trigger at a highly undesirable time.
task_runners_.GetUITaskRunner()->PostDelayedTask(
[self = weak_factory_.GetWeakPtr(),
notify_idle_task_id = notify_idle_task_id_]() {
if (!self.get()) {
return;
}
// If our (this task's) task id is the same as the current one, then
// no further frames were produced, and it is safe (w.r.t. jank) to
// notify the engine we are idle.
if (notify_idle_task_id == self->notify_idle_task_id_) {
self->delegate_.OnAnimatorNotifyIdle(
*self.get(), Dart_TimelineGetMicros() + 100000);
}
},
kNotifyIdleTaskWaitTime);
}
}

Expand Down
1 change: 1 addition & 0 deletions shell/common/animator.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class Animator final {
bool paused_;
bool regenerate_layer_tree_;
bool frame_scheduled_;
int notify_idle_task_id_;
bool dimension_change_pending_;
SkISize last_layer_tree_size_;

Expand Down