From 8b9840b32f350455dbfe59542e4fc2c3a88f5351 Mon Sep 17 00:00:00 2001 From: v00863305 Date: Wed, 10 Jan 2024 14:00:33 +0300 Subject: [PATCH 1/2] Customize unlocked frame culling Fine-granted reduction of GPU texture memory consumption by browser application with multiple offscreen frames (tabs), could be achieved by using of custom frame eviction limits (periodic delay, explicit count limit) which provides possibility to release tile GPU backing resources (shared images) from evicted Viz surfaces (compositor frames). - periodic delay (5 mins) - enabled by default - explicit count limit (10 frames) - disabled by default To configure custom frame eviction please use the following features: --enabled-features=AggressiveFrameCulling:delay/5m, ExplicitFrameCullingLimit:max-count/10 Signed-off-by: Volykhin Andrei Change-Id: I6505f81b335d13edc146a26505805b04524658d5 --- components/viz/client/frame_eviction_manager.cc | 11 +++++++++-- components/viz/common/features.cc | 11 +++++++++++ components/viz/common/features.h | 8 ++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/components/viz/client/frame_eviction_manager.cc b/components/viz/client/frame_eviction_manager.cc index bc70b77c66..8a722b997b 100644 --- a/components/viz/client/frame_eviction_manager.cc +++ b/components/viz/client/frame_eviction_manager.cc @@ -105,7 +105,7 @@ void FrameEvictionManager::RegisterUnlockedFrame( // Unretained: `idle_frames_culling_timer_` is a member of `this`, doesn't // outlive it, and cancels the task in its destructor. idle_frames_culling_timer_.Start( - FROM_HERE, kPeriodicCullingDelay, + FROM_HERE, features::kAggressiveFrameCullingDelay.Get(), base::BindRepeating(&FrameEvictionManager::CullOldUnlockedFrames, base::Unretained(this))); } @@ -161,7 +161,13 @@ FrameEvictionManager::FrameEvictionManager() switches::kMaxNumberOfSavedFrames)) { max_number_of_saved_frames_ = kMaxNumberOfSavedFrames; } +#endif +#if BUILDFLAG(IS_OHOS) + if (base::FeatureList::IsEnabled(features::kExplicitFrameCullingLimit)) { + max_number_of_saved_frames_ = + std::max(1, features::kExplicitFrameCullingLimitMaxCount.Get()); + } #endif } @@ -193,7 +199,8 @@ void FrameEvictionManager::CullOldUnlockedFrames() { auto now = clock_->NowTicks(); while (!unlocked_frames_.empty() && - now - unlocked_frames_.back().second >= kPeriodicCullingDelay) { + now - unlocked_frames_.back().second >= + features::kAggressiveFrameCullingDelay.Get()) { size_t old_size = unlocked_frames_.size(); auto* frame = unlocked_frames_.back().first; frame->EvictCurrentFrame(); diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index ebc18015f2..93fdfe7c76 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc @@ -197,6 +197,8 @@ BASE_FEATURE(kAllowUndamagedNonrootRenderPassToSkip, BASE_FEATURE(kAggressiveFrameCulling, "AggressiveFrameCulling", base::FEATURE_ENABLED_BY_DEFAULT); +const base::FeatureParam kAggressiveFrameCullingDelay{ + &kAggressiveFrameCulling, "delay", base::Minutes(5)}; // If enabled, do not rely on surface garbage collection to happen // periodically, but trigger it eagerly, to avoid missing calls. @@ -259,6 +261,15 @@ BASE_FEATURE(kOnBeginFrameAllowLateAcks, "OnBeginFrameAllowLateAcks", base::FEATURE_DISABLED_BY_DEFAULT); +#if BUILDFLAG(IS_OHOS) +// If enabled, define explicit culling limit for *all* frames. +BASE_FEATURE(kExplicitFrameCullingLimit, + "ExplicitFrameCullingLimit", + base::FEATURE_DISABLED_BY_DEFAULT); +const base::FeatureParam kExplicitFrameCullingLimitMaxCount{ + &kExplicitFrameCullingLimit, "max-count", 10}; +#endif + bool IsDelegatedCompositingEnabled() { return base::FeatureList::IsEnabled(kDelegatedCompositing); } diff --git a/components/viz/common/features.h b/components/viz/common/features.h index 2fc330a441..0fb69a339d 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h @@ -59,6 +59,8 @@ VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kDrawPredictedInkPoint); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kAllowBypassRenderPassQuads); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kAllowUndamagedNonrootRenderPassToSkip); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kAggressiveFrameCulling); +VIZ_COMMON_EXPORT extern const base::FeatureParam + kAggressiveFrameCullingDelay; VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kEagerSurfaceGarbageCollection); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOverrideThrottledFrameRateParams); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kRendererAllocatesImages); @@ -67,6 +69,12 @@ VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kEvictSubtree); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOnBeginFrameAcks); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOnBeginFrameAllowLateAcks); +#if BUILDFLAG(IS_OHOS) +VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kExplicitFrameCullingLimit); +VIZ_COMMON_EXPORT extern const base::FeatureParam + kExplicitFrameCullingLimitMaxCount; +#endif + VIZ_COMMON_EXPORT extern const char kDraw1Point12Ms[]; VIZ_COMMON_EXPORT extern const char kDraw2Points6Ms[]; VIZ_COMMON_EXPORT extern const char kDraw1Point6Ms[]; -- Gitee From e4af894d407f5df91841da7553233113659767f1 Mon Sep 17 00:00:00 2001 From: v00863305 Date: Fri, 2 Feb 2024 09:50:31 +0300 Subject: [PATCH 2/2] First frame activation deadline Allow to use the specified deadline policy on the first frame drawing (show with visibility) to synchronize web content with browser UI. Having HarmonyOS display a placeholder (optional) for a longer period of time is preferable to drawing nothing, and the first frame can take a while on low-end systems. --enable-features=FirstFrameActivationDeadline OHOS external begin frame source should adjust MISSED begin frame arguments to the current time otherwise surface activation deadline will be resolved incorrectly. VSync (MISSED) -> ....do nothing ... -> NeedsBeginFrame -> BeginFrame (with old MISSED begin frame args) -> ... -> CommitFrame (deadline resolved against old MISSED begin frame args) Signed-off-by: Volykhin Andrei Change-Id: I1cad430d838cff67ed735e2af2e901b68a4f2725 --- components/viz/common/features.cc | 8 +++++++ components/viz/common/features.h | 3 +++ .../common/frame_sinks/begin_frame_source.cc | 7 +++--- .../external_begin_frame_source_ohos.cc | 24 +++++++++++++++++++ .../external_begin_frame_source_ohos.h | 3 +++ components/viz/service/surfaces/surface.cc | 4 ++++ .../renderer_host/delegated_frame_host.cc | 21 ++++++++++++++++ 7 files changed, 66 insertions(+), 4 deletions(-) diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index 93fdfe7c76..8b1908aab7 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc @@ -268,6 +268,14 @@ BASE_FEATURE(kExplicitFrameCullingLimit, base::FEATURE_DISABLED_BY_DEFAULT); const base::FeatureParam kExplicitFrameCullingLimitMaxCount{ &kExplicitFrameCullingLimit, "max-count", 10}; + +// If enabled, wait to activate a surface with dependencies on the first frame +// drawing with specified deadline. +BASE_FEATURE(kFirstFrameActivationDeadline, + "FirstFrameActivationDeadline", + base::FEATURE_ENABLED_BY_DEFAULT); +const base::FeatureParam kFirstFrameActivationDeadlineTimeout{ + &kFirstFrameActivationDeadline, "timeout", base::Seconds(5)}; #endif bool IsDelegatedCompositingEnabled() { diff --git a/components/viz/common/features.h b/components/viz/common/features.h index 0fb69a339d..15b6f52c1a 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h @@ -73,6 +73,9 @@ VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOnBeginFrameAllowLateAcks); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kExplicitFrameCullingLimit); VIZ_COMMON_EXPORT extern const base::FeatureParam kExplicitFrameCullingLimitMaxCount; +VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kFirstFrameActivationDeadline); +VIZ_COMMON_EXPORT extern const base::FeatureParam + kFirstFrameActivationDeadlineTimeout; #endif VIZ_COMMON_EXPORT extern const char kDraw1Point12Ms[]; diff --git a/components/viz/common/frame_sinks/begin_frame_source.cc b/components/viz/common/frame_sinks/begin_frame_source.cc index 2a33b47794..ac92c8bbcc 100644 --- a/components/viz/common/frame_sinks/begin_frame_source.cc +++ b/components/viz/common/frame_sinks/begin_frame_source.cc @@ -491,10 +491,9 @@ void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) { return; } - TRACE_EVENT2( - "viz", "ExternalBeginFrameSource::OnBeginFrame", "frame_time", - last_begin_frame_args_.frame_time.since_origin().InMicroseconds(), - "interval", last_begin_frame_args_.interval.InMicroseconds()); + TRACE_EVENT2("viz", "ExternalBeginFrameSource::OnBeginFrame", "frame_time", + args.frame_time.since_origin().InMicroseconds(), "interval", + args.interval.InMicroseconds()); last_begin_frame_args_ = args; base::flat_set observers(observers_); diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_ohos.cc b/components/viz/service/frame_sinks/external_begin_frame_source_ohos.cc index d37717a485..3ce2f59504 100644 --- a/components/viz/service/frame_sinks/external_begin_frame_source_ohos.cc +++ b/components/viz/service/frame_sinks/external_begin_frame_source_ohos.cc @@ -229,6 +229,30 @@ ReportLossFrame::GetInstance()->SetVsyncPeriod(vsync_period_); } } +BeginFrameArgs ExternalBeginFrameSourceOHOS::GetMissedBeginFrameArgs( + BeginFrameObserver* obs) { + auto frame_time = last_begin_frame_args_.frame_time; + auto interval = last_begin_frame_args_.interval; + auto now = base::TimeTicks::Now(); + + if (last_begin_frame_args_.IsValid()) { + frame_time = now.SnappedToNextTick(frame_time, interval) - interval; + } else { + // Create BeginFrameArgs for now so that we don't have to wait until vsync. + frame_time = now; + interval = BeginFrameArgs::DefaultInterval(); + } + + // Don't create new args unless we've actually moved past the previous frame. + if (!last_begin_frame_args_.IsValid() || + frame_time > last_begin_frame_args_.frame_time) { + last_begin_frame_args_ = begin_frame_args_generator_.GenerateBeginFrameArgs( + source_id(), frame_time, frame_time + interval, interval); + } + + return ExternalBeginFrameSource::GetMissedBeginFrameArgs(obs); +} + void ExternalBeginFrameSourceOHOS::OnNeedsBeginFrames(bool needs_begin_frames) { SetEnabled(needs_begin_frames); } diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_ohos.h b/components/viz/service/frame_sinks/external_begin_frame_source_ohos.h index e56bf67ed6..7cb1304634 100644 --- a/components/viz/service/frame_sinks/external_begin_frame_source_ohos.h +++ b/components/viz/service/frame_sinks/external_begin_frame_source_ohos.h @@ -63,6 +63,9 @@ class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceOHOS void ResetVSyncFrequency() override; private: + // ExternalBeginFrameSource overrides. + BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs) override; + // ExternalBeginFrameSourceClient implementation. void OnNeedsBeginFrames(bool needs_begin_frames) override; diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc index 499c903155..e7282a7b0e 100644 --- a/components/viz/service/surfaces/surface.cc +++ b/components/viz/service/surfaces/surface.cc @@ -354,6 +354,10 @@ void Surface::OnActivationDependencyResolved( blocking_allocation_groups_.erase(group); if (!activation_dependencies_.empty()) return; + + TRACE_EVENT_NESTABLE_ASYNC_END0("viz", "SurfaceQueuedPending", + TRACE_ID_LOCAL(this)); + // All blockers have been cleared. The surface can be activated now. ActivatePendingFrame(); } diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc index 65766e9570..7b5062a283 100644 --- a/content/browser/renderer_host/delegated_frame_host.cc +++ b/content/browser/renderer_host/delegated_frame_host.cc @@ -39,6 +39,21 @@ namespace { // factor. constexpr float kFrameContentCaptureQuality = 0.4f; +#if BUILDFLAG(IS_OHOS) +cc::DeadlinePolicy FirstFrameDeadlinePolicy() { + if (base::FeatureList::IsEnabled( + features::kFirstFrameActivationDeadline)) { + // Wait up to deadline timeout for the first frame to be produced. + int64_t deadline_in_frames = base::ClampRound( + features::kFirstFrameActivationDeadlineTimeout.Get() / + viz::BeginFrameArgs::DefaultInterval()); + return cc::DeadlinePolicy::UseSpecifiedDeadline(deadline_in_frames); + } + + return cc::DeadlinePolicy::UseDefaultDeadline(); +} +#endif + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -96,10 +111,16 @@ void DelegatedFrameHost::WasShown( std::move(record_tab_switch_time_request))); } +#if BUILDFLAG(IS_OHOS) + // Use the specified deadline to synchronize web content with browser UI. + EmbedSurface( + new_local_surface_id, new_dip_size, FirstFrameDeadlinePolicy()); +#else // Use the default deadline to synchronize web content with browser UI. // TODO(fsamuel): Investigate if there is a better deadline to use here. EmbedSurface(new_local_surface_id, new_dip_size, cc::DeadlinePolicy::UseDefaultDeadline()); +#endif // Remove stale content that might be displayed. if (stale_content_layer_->has_external_content()) { -- Gitee