diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 86496d1fbbff9..b65e1c64a6a2a 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -174,6 +174,9 @@ void Animator::Render(std::unique_ptr layer_tree) { "Animator::Render"); frame_timings_recorder_->RecordBuildEnd(fml::TimePoint::Now()); + delegate_.OnAnimatorUpdateLatestFrameTargetTime( + frame_timings_recorder_->GetVsyncTargetTime()); + // Commit the pending continuation. PipelineProduceResult result = producer_continuation_.Complete(std::move(layer_tree)); diff --git a/shell/common/animator.h b/shell/common/animator.h index b63fd29b85903..ab6e2c253daba 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -36,6 +36,9 @@ class Animator final { virtual void OnAnimatorNotifyIdle(fml::TimePoint deadline) = 0; + virtual void OnAnimatorUpdateLatestFrameTargetTime( + fml::TimePoint frame_target_time) = 0; + virtual void OnAnimatorDraw( std::shared_ptr> pipeline, std::unique_ptr frame_timings_recorder) = 0; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 3e7fcb682416c..32ed28c61c94b 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -32,6 +32,9 @@ class FakeAnimatorDelegate : public Animator::Delegate { notify_idle_called_ = true; } + MOCK_METHOD1(OnAnimatorUpdateLatestFrameTargetTime, + void(fml::TimePoint frame_target_time)); + MOCK_METHOD2( OnAnimatorDraw, void(std::shared_ptr> pipeline, @@ -222,9 +225,12 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { [&](fml::TimePoint frame_target_time, uint64_t frame_number) { begin_frame_latch.Signal(); }); - - // It will only be called once even though we call the method Animator::Render - // twice. because it will only be called when the pipeline is empty. + // It must always be called when the method 'Animator::Render' is called, + // regardless of whether the pipeline is empty or not. + EXPECT_CALL(delegate, OnAnimatorUpdateLatestFrameTargetTime).Times(2); + // It will only be called once even though we call the method + // 'Animator::Render' twice. because it will only be called when the pipeline + // is empty. EXPECT_CALL(delegate, OnAnimatorDraw).Times(1); for (int i = 0; i < 2; i++) { diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 7ae9ff7a98d5f..536c968ebb7f6 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1106,23 +1106,26 @@ void Shell::OnAnimatorNotifyIdle(fml::TimePoint deadline) { } } -// |Animator::Delegate| -void Shell::OnAnimatorDraw( - std::shared_ptr> pipeline, - std::unique_ptr frame_timings_recorder) { +void Shell::OnAnimatorUpdateLatestFrameTargetTime( + fml::TimePoint frame_target_time) { FML_DCHECK(is_setup_); // record the target time for use by rasterizer. { std::scoped_lock time_recorder_lock(time_recorder_mutex_); - const fml::TimePoint frame_target_time = - frame_timings_recorder->GetVsyncTargetTime(); if (!latest_frame_target_time_) { latest_frame_target_time_ = frame_target_time; } else if (latest_frame_target_time_ < frame_target_time) { latest_frame_target_time_ = frame_target_time; } } +} + +// |Animator::Delegate| +void Shell::OnAnimatorDraw( + std::shared_ptr> pipeline, + std::unique_ptr frame_timings_recorder) { + FML_DCHECK(is_setup_); auto discard_callback = [this](flutter::LayerTree& tree) { std::scoped_lock lock(resize_mutex_); diff --git a/shell/common/shell.h b/shell/common/shell.h index 099743e6be978..46395048cae8b 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -579,6 +579,10 @@ class Shell final : public PlatformView::Delegate, // |Animator::Delegate| void OnAnimatorNotifyIdle(fml::TimePoint deadline) override; + // |Animator::Delegate| + void OnAnimatorUpdateLatestFrameTargetTime( + fml::TimePoint frame_target_time) override; + // |Animator::Delegate| void OnAnimatorDraw( std::shared_ptr> pipeline,