From df604affa93b43e16a311b9ac7fc129f9c609a78 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 11 Nov 2021 10:28:20 -0800 Subject: [PATCH 1/9] ffr --- shell/common/animator.cc | 18 +++++- shell/common/animator.h | 12 +++- shell/common/engine.cc | 6 ++ shell/common/engine.h | 9 +++ shell/common/shell.cc | 6 ++ shell/common/vsync_waiter.cc | 56 +++++++++++++++++ shell/common/vsync_waiter.h | 61 +++++++++++++++++++ .../ios/framework/Source/vsync_waiter_ios.h | 4 ++ .../ios/framework/Source/vsync_waiter_ios.mm | 31 ++++++++++ 9 files changed, 201 insertions(+), 2 deletions(-) diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 32403f1c2e70a..ee302df4a073f 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -40,7 +40,11 @@ Animator::Animator(Delegate& delegate, : 2)), #endif // SHELL_ENABLE_METAL pending_frame_semaphore_(1), - weak_factory_(this) { + weak_factory_(this), + dynamic_frr_provider_(std::make_unique()), + current_frame_rate_range_(FrameRateRange()) { + // Set initial frame rate range. + waiter_->UpdateFrameRateRange(current_frame_rate_range_); } Animator::~Animator() = default; @@ -76,6 +80,12 @@ void Animator::EnqueueTraceFlowId(uint64_t trace_flow_id) { }); } +void Animator::RecordFrameDuration(const int64_t frame_duration) { + TRACE_EVENT0("flutter", "Engine::RecordFrameDuration"); + FML_DCHECK(frame_duration >= 0); + dynamic_frr_provider_->Record(frame_duration); +} + // This Parity is used by the timeline component to correctly align // GPU Workloads events with their respective Framework Workload. const char* Animator::FrameParity() { @@ -94,6 +104,12 @@ static fml::TimePoint FxlToDartOrEarlier(fml::TimePoint time) { void Animator::BeginFrame( std::unique_ptr frame_timings_recorder) { + FrameRateRange new_frame_rate_range = dynamic_frr_provider_->Provide(); + if (current_frame_rate_range_ != new_frame_rate_range) { + current_frame_rate_range_ = new_frame_rate_range; + waiter_->UpdateFrameRateRange(current_frame_rate_range_); + } + TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_request_number_); frame_request_number_++; diff --git a/shell/common/animator.h b/shell/common/animator.h index 85f940700dbc6..7ac8b9e8c1c9d 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -83,6 +83,15 @@ class Animator final { // active rendering. void EnqueueTraceFlowId(uint64_t trace_flow_id); + //---------------------------------------------------------------------------- + /// @brief Record the frame duration of the last frame. + /// + /// @param[in] frame_duration The delta between raster end time and build + /// start time, in milliseconds. This value must + /// be positive + /// + void RecordFrameDuration(const int64_t frame_duration); + private: using LayerTreePipeline = Pipeline; @@ -118,8 +127,9 @@ class Animator final { SkISize last_layer_tree_size_ = {0, 0}; std::deque trace_flow_ids_; bool has_rendered_ = false; - fml::WeakPtrFactory weak_factory_; + std::unique_ptr dynamic_frr_provider_; + FrameRateRange current_frame_rate_range_; friend class testing::ShellTest; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index a3d1862fbf43e..3b780362fbde5 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -246,6 +246,12 @@ void Engine::ReportTimings(std::vector timings) { runtime_controller_->ReportTimings(std::move(timings)); } +void Engine::RecordFrameDuration(const int64_t frame_duration) { + TRACE_EVENT0("flutter", "Engine::RecordFrameDuration"); + FML_DCHECK(frame_duration >= 0); + animator_->RecordFrameDuration(frame_duration); +} + void Engine::NotifyIdle(int64_t deadline) { auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros()); TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta", diff --git a/shell/common/engine.h b/shell/common/engine.h index 0b935ba703e3d..490cf6dd727f3 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -583,6 +583,15 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// void ReportTimings(std::vector timings); + //---------------------------------------------------------------------------- + /// @brief Record the frame duration of the last frame. + /// + /// @param[in] frame_duration The delta between raster end time and build + /// start time, in milliseconds. This value must + /// be positive + /// + void RecordFrameDuration(const int64_t frame_duration); + //---------------------------------------------------------------------------- /// @brief Gets the main port of the root isolate. Since the isolate is /// created immediately in the constructor of the engine, it is diff --git a/shell/common/shell.cc b/shell/common/shell.cc index df301e717fea9..3c552af4004bb 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1361,6 +1361,12 @@ void Shell::OnFrameRasterized(const FrameTiming& timing) { settings_.frame_rasterized_callback(timing); } + int64_t frame_duration_ms = (timing.Get(FrameTiming::Phase::kRasterFinish) - + timing.Get(FrameTiming::Phase::kBuildStart)) + .ToMilliseconds(); + + engine_->RecordFrameDuration(frame_duration_ms); + if (!needs_report_timings_) { return; } diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 1755755182e87..f37c70cc3055a 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -14,6 +14,10 @@ namespace flutter { +static constexpr const int64_t kFrameRateMin = 0; +static constexpr const int64_t kFrameRateMedium = 60; +static constexpr const int64_t kFrameRateHigh = 120; + static constexpr const char* kVsyncFlowName = "VsyncFlow"; #if defined(OS_FUCHSIA) @@ -170,4 +174,56 @@ void VsyncWaiter::ResumeDartMicroTasks(fml::TaskQueueId ui_task_queue_id) { task_queues->ResumeSecondarySource(ui_task_queue_id); } +// FrameRageRange + +FrameRateRange::FrameRateRange(const int64_t min, + const int64_t preferred, + const int64_t max) + : min_(min), preferred_(preferred), max_(max) {} + +FrameRateRange::FrameRateRange() + : min_(kFrameRateMin), preferred_(kFrameRateHigh), max_(kFrameRateHigh) {} + +int64_t FrameRateRange::GetMin() const { + return min_; +} + +int64_t FrameRateRange::GetPreferred() const { + return preferred_; +} + +int64_t FrameRateRange::GetMax() const { + return max_; +} + +// DynamicFrameRateRangeProvider + +DynamicFrameRateRangeProvider::DynamicFrameRateRangeProvider(size_t size) + : size_(size) {} + +void DynamicFrameRateRangeProvider::Record(int64_t frame_duration) { + FML_DCHECK(frame_durations_.size() <= size_); + if (frame_durations_.size() == size_) { + frame_durations_.erase(frame_durations_.begin()); + } + frame_durations_.push_back(frame_duration); +} + +FrameRateRange DynamicFrameRateRangeProvider::Provide() { + int64_t min = 0; + int64_t preferred = kFrameRateHigh; + if (frame_durations_.size() == size_) { + int64_t sum = 0; + for (auto& duration : frame_durations_) { + // TODO(cyanglaz): int overflow. + sum += duration; + } + int64_t average = sum / size_; + if (average > 8) { + preferred = kFrameRateMedium; + } + } + return FrameRateRange(min, preferred, preferred); +} + } // namespace flutter diff --git a/shell/common/vsync_waiter.h b/shell/common/vsync_waiter.h index b381f432a9bca..d6dc5b1207cf8 100644 --- a/shell/common/vsync_waiter.h +++ b/shell/common/vsync_waiter.h @@ -16,6 +16,64 @@ namespace flutter { +// Represents a dynamic frame rate range. +struct FrameRateRange { + public: + // Constructor with default values: + // min = kFrameRateMin, + // preferred = kFrameRateHigh, + // max = kFrameRateHigh + FrameRateRange(); + // Constructor with custom values. + FrameRateRange(const int64_t min, const int64_t preferred, const int64_t max); + + // Get the min frame rate. + int64_t GetMin() const; + + // Get the preferred frame rate. + int64_t GetPreferred() const; + + // Get the max frame rate. + int64_t GetMax() const; + + friend bool operator==(const FrameRateRange& lhs, const FrameRateRange& rhs) { + return lhs.min_ == rhs.min_ && lhs.preferred_ == rhs.preferred_ && + lhs.max_ == rhs.max_; + } + + friend bool operator!=(const FrameRateRange& lhs, const FrameRateRange& rhs) { + return lhs.min_ != rhs.min_ || lhs.preferred_ != rhs.preferred_ || + lhs.max_ != rhs.max_; + } + + private: + int64_t min_; + int64_t preferred_; + int64_t max_; +}; + +static const size_t kDefaultFRRProviderSize = 10; + +// This object can provide the preferred |FrameRateRange| to use +// based on the performance. +class DynamicFrameRateRangeProvider { + public: + // Constuctor. + // The `size` is used to determine how many frame durations are stored. + DynamicFrameRateRangeProvider(size_t size = kDefaultFRRProviderSize); + + // Record a frame_duration for the current frame. + // The `frame_duration` must be the current frame's duration. + void Record(int64_t frame_duration); + + // Provides a |FrameRateRange| based on the recorded frame_durations. + FrameRateRange Provide(); + + private: + std::vector frame_durations_; + size_t size_; +}; + /// Abstract Base Class that represents a platform specific mechanism for /// getting callbacks when a vsync event happens. class VsyncWaiter : public std::enable_shared_from_this { @@ -32,6 +90,9 @@ class VsyncWaiter : public std::enable_shared_from_this { /// |Animator::ScheduleMaybeClearTraceFlowIds|. void ScheduleSecondaryCallback(uintptr_t id, const fml::closure& callback); + // Tell vsync waiter to update the frame rate range. + virtual void UpdateFrameRateRange(const FrameRateRange& frame_rate_range){}; + protected: // On some backends, the |FireCallback| needs to be made from a static C // method. diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h index e4b0aedac2055..eeaa2d1bb19ae 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -34,6 +34,8 @@ - (void)invalidate; +- (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int64_t)preferred; + @end namespace flutter { @@ -44,6 +46,8 @@ class VsyncWaiterIOS final : public VsyncWaiter { ~VsyncWaiterIOS() override; + void UpdateFrameRateRange(const FrameRateRange& frame_rate_range) override; + private: fml::scoped_nsobject client_; diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index cb4858d0f8ba4..a3c4e8a01df42 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -39,11 +39,18 @@ [client_.get() await]; } +void VsyncWaiterIOS::UpdateFrameRateRange(const FrameRateRange& frame_rate_range) { + [client_.get() updateFrameRateRangeWithMin:frame_rate_range.GetMin() + max:frame_rate_range.GetMax() + preferred:frame_rate_range.GetPreferred()]; +} + } // namespace flutter @implementation VSyncClient { flutter::VsyncWaiter::Callback callback_; fml::scoped_nsobject display_link_; + double displayRefreshRate_; } - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner @@ -56,6 +63,7 @@ - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] }; display_link_.get().paused = YES; + displayRefreshRate_ = [DisplayLinkManager displayRefreshRate]; task_runner->PostTask([client = [self retain]]() { [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] @@ -97,6 +105,29 @@ - (void)invalidate { [display_link_.get() invalidate]; } +- (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int64_t)preferred { + float minRate = (float)min; + float preferredRate = fminf(preferred, displayRefreshRate_); + float maxRate = fminf(max, displayRefreshRate_); + if (@available(iOS 15, *)) { + // preferredFrameRateRange is only available in iOS 15 and above. + display_link_.get().preferredFrameRateRange = + CAFrameRateRangeMake(minRate, maxRate, preferredRate); + } else if (@available(iOS 10, *)) { + // preferredFramesPerSecond is only available in iOS 10 and above, and deprecated at iOS 15. + display_link_.get().preferredFramesPerSecond = preferredRate; + } + // No-op as setting the dynamic frame rate is not possible in lower iOS versions. + // TODO(cyanglaz) remove logs + FML_DLOG(ERROR) << "===================================================="; + FML_DLOG(ERROR) << ">>> engine preferred rate " << preferred; + FML_DLOG(ERROR) << ">>> engine max rate " << max; + FML_DLOG(ERROR) << ">>> system rate " << displayRefreshRate_; + FML_DLOG(ERROR) << ">>> min rate " << minRate; + FML_DLOG(ERROR) << ">>> final preferred rate " << preferredRate; + FML_DLOG(ERROR) << ">>> final max rate " << maxRate; +} + - (void)dealloc { [self invalidate]; From 0dd1aa8b1c391d0326274d71028e559e95409b00 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 12 Nov 2021 11:38:47 -0800 Subject: [PATCH 2/9] also prints frame duration --- shell/common/vsync_waiter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index f37c70cc3055a..780432c42e185 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -206,6 +206,7 @@ void DynamicFrameRateRangeProvider::Record(int64_t frame_duration) { if (frame_durations_.size() == size_) { frame_durations_.erase(frame_durations_.begin()); } + FML_DLOG(ERROR) << ">>> record frame duration " << frame_duration; frame_durations_.push_back(frame_duration); } From 8e89002adebc33d65460931ac1286f31cbab7b91 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 12 Nov 2021 11:58:03 -0800 Subject: [PATCH 3/9] dynamic system refresh rate --- .../darwin/ios/framework/Source/vsync_waiter_ios.mm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index a3c4e8a01df42..d52921ed3bbda 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -50,7 +50,6 @@ @implementation VSyncClient { flutter::VsyncWaiter::Callback callback_; fml::scoped_nsobject display_link_; - double displayRefreshRate_; } - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner @@ -62,8 +61,7 @@ - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner display_link_ = fml::scoped_nsobject { [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] }; - display_link_.get().paused = YES; - displayRefreshRate_ = [DisplayLinkManager displayRefreshRate]; + display_link_.get().paused = YES;; task_runner->PostTask([client = [self retain]]() { [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] @@ -107,8 +105,9 @@ - (void)invalidate { - (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int64_t)preferred { float minRate = (float)min; - float preferredRate = fminf(preferred, displayRefreshRate_); - float maxRate = fminf(max, displayRefreshRate_); + double displayRefreshRate = [DisplayLinkManager displayRefreshRate]; + float preferredRate = fminf(preferred, displayRefreshRate); + float maxRate = fminf(max, displayRefreshRate); if (@available(iOS 15, *)) { // preferredFrameRateRange is only available in iOS 15 and above. display_link_.get().preferredFrameRateRange = @@ -122,7 +121,7 @@ - (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int FML_DLOG(ERROR) << "===================================================="; FML_DLOG(ERROR) << ">>> engine preferred rate " << preferred; FML_DLOG(ERROR) << ">>> engine max rate " << max; - FML_DLOG(ERROR) << ">>> system rate " << displayRefreshRate_; + FML_DLOG(ERROR) << ">>> system rate " << displayRefreshRate; FML_DLOG(ERROR) << ">>> min rate " << minRate; FML_DLOG(ERROR) << ">>> final preferred rate " << preferredRate; FML_DLOG(ERROR) << ">>> final max rate " << maxRate; From 76a3d0d77a5cc8af0602e22478146386cc4b8080 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 12 Nov 2021 12:09:19 -0800 Subject: [PATCH 4/9] add real frame rate --- .../darwin/ios/framework/Source/vsync_waiter_ios.mm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index d52921ed3bbda..f763269a96d88 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -61,7 +61,8 @@ - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner display_link_ = fml::scoped_nsobject { [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] }; - display_link_.get().paused = YES;; + display_link_.get().paused = YES; + ; task_runner->PostTask([client = [self retain]]() { [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] @@ -121,7 +122,14 @@ - (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int FML_DLOG(ERROR) << "===================================================="; FML_DLOG(ERROR) << ">>> engine preferred rate " << preferred; FML_DLOG(ERROR) << ">>> engine max rate " << max; - FML_DLOG(ERROR) << ">>> system rate " << displayRefreshRate; + FML_DLOG(ERROR) << ">>> system preferred rate " << displayRefreshRate; + if (@available(iOS 10, *)) { + double systemFrameDuration = + display_link_.get().targetTimestamp - display_link_.get().timestamp; + FML_DLOG(ERROR) << ">>> system actual frame duration " << systemFrameDuration; + double systemFrameRate = 1 / systemFrameDuration; + FML_DLOG(ERROR) << ">>> system actual frame rate " << systemFrameRate; + } FML_DLOG(ERROR) << ">>> min rate " << minRate; FML_DLOG(ERROR) << ">>> final preferred rate " << preferredRate; FML_DLOG(ERROR) << ">>> final max rate " << maxRate; From ba57763a041292817adfdc35089bfa8a9a6a39e7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 12 Nov 2021 12:29:27 -0800 Subject: [PATCH 5/9] update to LOG for profile --- shell/common/vsync_waiter.cc | 2 +- .../ios/framework/Source/vsync_waiter_ios.mm | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 780432c42e185..b8a3c2f0ac923 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -206,7 +206,7 @@ void DynamicFrameRateRangeProvider::Record(int64_t frame_duration) { if (frame_durations_.size() == size_) { frame_durations_.erase(frame_durations_.begin()); } - FML_DLOG(ERROR) << ">>> record frame duration " << frame_duration; + FML_LOG(ERROR) << ">>> record frame duration " << frame_duration; frame_durations_.push_back(frame_duration); } diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index f763269a96d88..d8baa1abe0539 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -119,20 +119,20 @@ - (void)updateFrameRateRangeWithMin:(int64_t)min max:(int64_t)max preferred:(int } // No-op as setting the dynamic frame rate is not possible in lower iOS versions. // TODO(cyanglaz) remove logs - FML_DLOG(ERROR) << "===================================================="; - FML_DLOG(ERROR) << ">>> engine preferred rate " << preferred; - FML_DLOG(ERROR) << ">>> engine max rate " << max; - FML_DLOG(ERROR) << ">>> system preferred rate " << displayRefreshRate; + FML_LOG(ERROR) << "===================================================="; + FML_LOG(ERROR) << ">>> engine preferred rate " << preferred; + FML_LOG(ERROR) << ">>> engine max rate " << max; + FML_LOG(ERROR) << ">>> system preferred rate " << displayRefreshRate; if (@available(iOS 10, *)) { double systemFrameDuration = display_link_.get().targetTimestamp - display_link_.get().timestamp; - FML_DLOG(ERROR) << ">>> system actual frame duration " << systemFrameDuration; + FML_LOG(ERROR) << ">>> system actual frame duration " << systemFrameDuration; double systemFrameRate = 1 / systemFrameDuration; - FML_DLOG(ERROR) << ">>> system actual frame rate " << systemFrameRate; + FML_LOG(ERROR) << ">>> system actual frame rate " << systemFrameRate; } - FML_DLOG(ERROR) << ">>> min rate " << minRate; - FML_DLOG(ERROR) << ">>> final preferred rate " << preferredRate; - FML_DLOG(ERROR) << ">>> final max rate " << maxRate; + FML_LOG(ERROR) << ">>> min rate " << minRate; + FML_LOG(ERROR) << ">>> final preferred rate " << preferredRate; + FML_LOG(ERROR) << ">>> final max rate " << maxRate; } - (void)dealloc { From 2d57567a5b7f132b352c41cffc4b25fb0ae5d406 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 15 Nov 2021 10:15:06 -0800 Subject: [PATCH 6/9] min to be half of max --- shell/common/vsync_waiter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index b8a3c2f0ac923..0f2b2a602043d 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -14,7 +14,7 @@ namespace flutter { -static constexpr const int64_t kFrameRateMin = 0; +static constexpr const int64_t kFrameRateMin = 30; static constexpr const int64_t kFrameRateMedium = 60; static constexpr const int64_t kFrameRateHigh = 120; @@ -211,7 +211,6 @@ void DynamicFrameRateRangeProvider::Record(int64_t frame_duration) { } FrameRateRange DynamicFrameRateRangeProvider::Provide() { - int64_t min = 0; int64_t preferred = kFrameRateHigh; if (frame_durations_.size() == size_) { int64_t sum = 0; @@ -224,6 +223,7 @@ FrameRateRange DynamicFrameRateRangeProvider::Provide() { preferred = kFrameRateMedium; } } + int64_t min = preferred/2; return FrameRateRange(min, preferred, preferred); } From 20306af230f649d57b23238df842cd8c18487704 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 15 Nov 2021 11:15:35 -0800 Subject: [PATCH 7/9] min to be half of max --- shell/common/vsync_waiter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 0f2b2a602043d..152547e3ce27c 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -223,7 +223,7 @@ FrameRateRange DynamicFrameRateRangeProvider::Provide() { preferred = kFrameRateMedium; } } - int64_t min = preferred/2; + int64_t min = preferred / 2; return FrameRateRange(min, preferred, preferred); } From 68a97fe6ddad0cf07c2433843b82e375e555c8da Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 15 Nov 2021 16:01:13 -0800 Subject: [PATCH 8/9] reset when idle --- shell/common/animator.cc | 16 +++++++++++----- shell/common/animator.h | 2 ++ shell/common/vsync_waiter.cc | 12 +++++++++--- shell/common/vsync_waiter.h | 4 ++++ 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/shell/common/animator.cc b/shell/common/animator.cc index ee302df4a073f..0d9a5b3c3781d 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -104,11 +104,7 @@ static fml::TimePoint FxlToDartOrEarlier(fml::TimePoint time) { void Animator::BeginFrame( std::unique_ptr frame_timings_recorder) { - FrameRateRange new_frame_rate_range = dynamic_frr_provider_->Provide(); - if (current_frame_rate_range_ != new_frame_rate_range) { - current_frame_rate_range_ = new_frame_rate_range; - waiter_->UpdateFrameRateRange(current_frame_rate_range_); - } + UpdateFrameRateRangeIfChanged(); TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_request_number_); @@ -164,6 +160,8 @@ void Animator::BeginFrame( } if (!frame_scheduled_ && has_rendered_) { + dynamic_frr_provider_->Reset(); + UpdateFrameRateRangeIfChanged(); // 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 @@ -314,4 +312,12 @@ void Animator::ScheduleMaybeClearTraceFlowIds() { }); } +void Animator::UpdateFrameRateRangeIfChanged() { + FrameRateRange new_frame_rate_range = dynamic_frr_provider_->Provide(); + if (current_frame_rate_range_ != new_frame_rate_range) { + current_frame_rate_range_ = new_frame_rate_range; + waiter_->UpdateFrameRateRange(current_frame_rate_range_); + } +} + } // namespace flutter diff --git a/shell/common/animator.h b/shell/common/animator.h index 7ac8b9e8c1c9d..9d2a67f70aefd 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -109,6 +109,8 @@ class Animator final { // Clear |trace_flow_ids_| if |frame_scheduled_| is false. void ScheduleMaybeClearTraceFlowIds(); + void UpdateFrameRateRangeIfChanged(); + Delegate& delegate_; TaskRunners task_runners_; std::shared_ptr waiter_; diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 152547e3ce27c..91336a8de335b 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -211,7 +211,7 @@ void DynamicFrameRateRangeProvider::Record(int64_t frame_duration) { } FrameRateRange DynamicFrameRateRangeProvider::Provide() { - int64_t preferred = kFrameRateHigh; + int64_t preferred = kFrameRateMedium; if (frame_durations_.size() == size_) { int64_t sum = 0; for (auto& duration : frame_durations_) { @@ -219,12 +219,18 @@ FrameRateRange DynamicFrameRateRangeProvider::Provide() { sum += duration; } int64_t average = sum / size_; - if (average > 8) { - preferred = kFrameRateMedium; + if (average > 16) { + preferred = kFrameRateMin; + } else if (average < 8) { + preferred = kFrameRateHigh; } } int64_t min = preferred / 2; return FrameRateRange(min, preferred, preferred); } +void DynamicFrameRateRangeProvider::Reset() { + frame_durations_.clear(); +} + } // namespace flutter diff --git a/shell/common/vsync_waiter.h b/shell/common/vsync_waiter.h index d6dc5b1207cf8..09f0fc6c31f29 100644 --- a/shell/common/vsync_waiter.h +++ b/shell/common/vsync_waiter.h @@ -69,6 +69,10 @@ class DynamicFrameRateRangeProvider { // Provides a |FrameRateRange| based on the recorded frame_durations. FrameRateRange Provide(); + // Lose all memory about the recent frame performances, resets to inital + // state. + void Reset(); + private: std::vector frame_durations_; size_t size_; From 3ec9df08df03f421f40116d8fef64d450411e3f2 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 16 Nov 2021 09:52:19 -0800 Subject: [PATCH 9/9] default set to 60 --- shell/common/vsync_waiter.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 91336a8de335b..3a6f9d1ad8785 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -182,7 +182,9 @@ FrameRateRange::FrameRateRange(const int64_t min, : min_(min), preferred_(preferred), max_(max) {} FrameRateRange::FrameRateRange() - : min_(kFrameRateMin), preferred_(kFrameRateHigh), max_(kFrameRateHigh) {} + : min_(kFrameRateMin), + preferred_(kFrameRateMedium), + max_(kFrameRateMedium) {} int64_t FrameRateRange::GetMin() const { return min_;