0

Apply throttling to occluded frame sinks.

cc::OcclusionTracker calculates and marks the occlusion states for each
layer and this occlusion information is used to skip appending quads if
a layer will not be drawn. These occluded layers will not make into the
CompositorFrame, however, there's no action taken to the surfaces that
are occluded so the frame sinks continue to submit CompositorFrames at
full rate.

This CL takes advantage of the occlusion information and uses it to
mark the frame sinks that will not draw as qualified for throttling.
ChromeOS ash then throttle the frame sinks accordingly.

This CL is an effort to improve ChromeOS login/lock screen performance.
There might be other scenarios that could benefit from this CL.

This CL will throttle all active browser windows behind the lock screen
if EnableCompositingBasedThrottling feature is enabled. Usually an
occluded window is detected by aura::WindowOcclusionTracker, however
aura::WindowOcclusionTracker only tracks aura::Window, the lock screen
uses a solid color layer through WallpaperView for the purpose of
occlusion and this occlusion is not detectable by
aura::WindowOcclusionTracker, but is caught in cc.

The performance comparison between with and with out this CL, locally
tested on Nami is:
- Two windows running webgl aquarium measures at 30% cpu usage when
logged in. The cpu usage drops to 20% without throttling and 15%
with throttling when locked.
- One maximized window running webgl aquarium measures at 15% cpu usage
when logged in. The cpu usage doesn't drop without throttling and drops
to 11% with throttling applied.

Bug: 1193824
Change-Id: I8bfc987663446bceb13ce248c4d52782cbdc47d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2919945
Commit-Queue: Jun Liu <yjliu@chromium.org>
Reviewed-by: kylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#889509}
This commit is contained in:
yjliu
2021-06-04 23:16:27 +00:00
committed by Chromium LUCI CQ
parent 75b7a631e7
commit 7ef1353fea
5 changed files with 57 additions and 0 deletions

@ -1290,6 +1290,9 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
layer->transform_tree_index(),
target_render_pass);
}
} else {
if (settings_.enable_compositing_based_throttling)
throttle_decider_.ProcessLayerNotToDraw(layer);
}
rendering_stats_instrumentation_->AddVisibleContentArea(

@ -865,6 +865,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
return pending_raster_queries_.get();
}
base::flat_set<viz::FrameSinkId> GetFrameSinksToThrottleForTesting() const {
return throttle_decider_.ids();
}
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,

@ -891,6 +891,16 @@ class CommitToPendingTreeLayerTreeHostImplTest : public LayerTreeHostImplTest {
}
};
class OccludedSurfaceThrottlingLayerTreeHostImplTest
: public LayerTreeHostImplTest {
public:
void SetUp() override {
LayerTreeSettings settings = DefaultSettings();
settings.enable_compositing_based_throttling = true;
CreateHostImpl(settings, CreateLayerTreeFrameSink());
}
};
// A test fixture for new animation timelines tests.
class LayerTreeHostImplTimelinesTest : public LayerTreeHostImplTest {
public:
@ -18083,6 +18093,33 @@ TEST_F(UnifiedScrollingTest, CompositedWithSquashedLayerMutatesTransform) {
ScrollEnd();
}
// Verifies that when a surface layer is occluded, its frame sink id will be
// marked as qualified for throttling.
TEST_F(OccludedSurfaceThrottlingLayerTreeHostImplTest,
ThrottleOccludedSurface) {
LayerTreeImpl* tree = host_impl_->active_tree();
gfx::Rect viewport_rect(0, 0, 800, 600);
auto* root = SetupRootLayer<LayerImpl>(tree, viewport_rect.size());
auto* occluded = AddLayer<SurfaceLayerImpl>(tree);
occluded->SetBounds(gfx::Size(400, 300));
occluded->SetDrawsContent(true);
viz::SurfaceId start = MakeSurfaceId(viz::FrameSinkId(1, 2), 1);
viz::SurfaceId end = MakeSurfaceId(viz::FrameSinkId(3, 4), 1);
occluded->SetRange(viz::SurfaceRange(start, end), 2u);
CopyProperties(root, occluded);
auto* occluder = AddLayer<SolidColorLayerImpl>(tree);
occluder->SetBounds(gfx::Size(400, 400));
occluder->SetDrawsContent(true);
occluder->SetContentsOpaque(true);
CopyProperties(root, occluder);
DrawFrame();
EXPECT_EQ(host_impl_->GetFrameSinksToThrottleForTesting(),
base::flat_set<viz::FrameSinkId>{end.frame_sink_id()});
}
TEST_F(LayerTreeHostImplTest, FrameElementIdHitTestSimple) {
SetupDefaultRootLayer(gfx::Size(100, 100));

@ -6,6 +6,7 @@
#include <vector>
#include "cc/layers/surface_layer_impl.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/surfaces/surface_range.h"
@ -86,6 +87,14 @@ void ThrottleDecider::ProcessRenderPass(
id_to_pass_map_.emplace(render_pass.id, &render_pass);
}
void ThrottleDecider::ProcessLayerNotToDraw(const LayerImpl* layer) {
if (layer->is_surface_layer()) {
const auto* surface_layer = static_cast<const SurfaceLayerImpl*>(layer);
if (surface_layer->range().IsValid())
ids_.insert(surface_layer->range().end().frame_sink_id());
}
}
bool ThrottleDecider::HasThrottlingChanged() const {
return ids_ != last_ids_;
}

@ -12,6 +12,7 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
namespace cc {
class LayerImpl;
// This class is used to decide if any frame sinks in a render pass list
// satisfies the compositing-based criteria to be throttled.
@ -30,6 +31,9 @@ class CC_EXPORT ThrottleDecider {
// intersection calculation of surface/quad rects are confined to the render
// pass's constituent quads.
void ProcessRenderPass(const viz::CompositorRenderPass& render_pass);
// Process a layer that will not draw. This is only relevant for surface
// layers and checks if the embedded frame sink is qualified for throttling.
void ProcessLayerNotToDraw(const LayerImpl* layer);
bool HasThrottlingChanged() const;
const base::flat_set<viz::FrameSinkId>& ids() const { return ids_; }