diff --git a/engine/src/flutter/flow/frame_timings.cc b/engine/src/flutter/flow/frame_timings.cc index d8e1589f5d..feb2df1a97 100644 --- a/engine/src/flutter/flow/frame_timings.cc +++ b/engine/src/flutter/flow/frame_timings.cc @@ -11,7 +11,10 @@ namespace flutter { -FrameTimingsRecorder::FrameTimingsRecorder() = default; +std::atomic_int FrameTimingsRecorder::frame_number_gen_ = {1}; + +FrameTimingsRecorder::FrameTimingsRecorder() + : frame_number_(frame_number_gen_++) {} FrameTimingsRecorder::~FrameTimingsRecorder() = default; @@ -132,4 +135,8 @@ std::unique_ptr FrameTimingsRecorder::CloneUntil( return recorder; } +uint64_t FrameTimingsRecorder::GetFrameNumber() const { + return frame_number_; +} + } // namespace flutter diff --git a/engine/src/flutter/flow/frame_timings.h b/engine/src/flutter/flow/frame_timings.h index 07e9f167f1..af8272ad4a 100644 --- a/engine/src/flutter/flow/frame_timings.h +++ b/engine/src/flutter/flow/frame_timings.h @@ -79,10 +79,19 @@ class FrameTimingsRecorder { /// the events. This summary is sent to the framework. FrameTiming RecordRasterEnd(fml::TimePoint raster_end); + /// Returns the frame number. Frame number is unique per frame and a frame + /// built earlier will have a frame number less than a frame that has been + /// built at a later point of time. + uint64_t GetFrameNumber() const; + private: + static std::atomic_int frame_number_gen_; + mutable std::mutex state_mutex_; State state_ = State::kUninitialized; + const uint64_t frame_number_; + fml::TimePoint vsync_start_; fml::TimePoint vsync_target_; fml::TimePoint build_start_; diff --git a/engine/src/flutter/flow/frame_timings_recorder_unittests.cc b/engine/src/flutter/flow/frame_timings_recorder_unittests.cc index 975af1cee1..9e714b3801 100644 --- a/engine/src/flutter/flow/frame_timings_recorder_unittests.cc +++ b/engine/src/flutter/flow/frame_timings_recorder_unittests.cc @@ -87,5 +87,22 @@ TEST(FrameTimingsRecorderTest, ThrowWhenRecordRasterBeforeBuildEnd) { #endif +TEST(FrameTimingsRecorderTest, RecordersHaveUniqueFrameNumbers) { + auto recorder1 = std::make_unique(); + auto recorder2 = std::make_unique(); + + ASSERT_TRUE(recorder2->GetFrameNumber() > recorder1->GetFrameNumber()); +} + +TEST(FrameTimingsRecorderTest, ClonedHasUniqueFrameNumber) { + auto recorder = std::make_unique(); + + const auto now = fml::TimePoint::Now(); + recorder->RecordVsync(now, now); + + auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kVsync); + ASSERT_NE(recorder->GetFrameNumber(), cloned->GetFrameNumber()); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/common/animator.cc b/engine/src/flutter/shell/common/animator.cc index 160ffbc454..2fbd6fa772 100644 --- a/engine/src/flutter/shell/common/animator.cc +++ b/engine/src/flutter/shell/common/animator.cc @@ -41,7 +41,6 @@ Animator::Animator(Delegate& delegate, : 2)), #endif // SHELL_ENABLE_METAL pending_frame_semaphore_(1), - frame_number_(1), paused_(false), regenerate_layer_tree_(false), frame_scheduled_(false), @@ -86,7 +85,11 @@ void Animator::EnqueueTraceFlowId(uint64_t trace_flow_id) { // This Parity is used by the timeline component to correctly align // GPU Workloads events with their respective Framework Workload. const char* Animator::FrameParity() { - return (frame_number_ % 2) ? "even" : "odd"; + if (!frame_timings_recorder_) { + return "even"; + } + uint64_t frame_number = frame_timings_recorder_->GetFrameNumber(); + return (frame_number % 2) ? "even" : "odd"; } static int64_t FxlToDartOrEarlier(fml::TimePoint time) { @@ -97,7 +100,8 @@ static int64_t FxlToDartOrEarlier(fml::TimePoint time) { void Animator::BeginFrame( std::unique_ptr frame_timings_recorder) { - TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++); + TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", + frame_timings_recorder->GetFrameNumber()); frame_timings_recorder_ = std::move(frame_timings_recorder); frame_timings_recorder_->RecordBuildStart(fml::TimePoint::Now()); @@ -239,8 +243,13 @@ void Animator::RequestFrame(bool regenerate_layer_tree) { // started an expensive operation right after posting this message however. // To support that, we need edge triggered wakes on VSync. + uint64_t frame_number = 0; + if (frame_timings_recorder_) { + frame_number = frame_timings_recorder_->GetFrameNumber(); + } + task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(), - frame_number = frame_number_]() { + frame_number = frame_number]() { if (!self) { return; } diff --git a/engine/src/flutter/shell/common/animator.h b/engine/src/flutter/shell/common/animator.h index c8efaffd04..058b1bdc32 100644 --- a/engine/src/flutter/shell/common/animator.h +++ b/engine/src/flutter/shell/common/animator.h @@ -108,7 +108,6 @@ class Animator final { fml::RefPtr layer_tree_pipeline_; fml::Semaphore pending_frame_semaphore_; LayerTreePipeline::ProducerContinuation producer_continuation_; - int64_t frame_number_; bool paused_; bool regenerate_layer_tree_; bool frame_scheduled_;