Commit 2808b7ec authored by Mark Yacoub's avatar Mark Yacoub Committed by Commit Bot

cros: Improve damage for underlays

Subtract damage caused by unchanged UI elements on top of HW underlay.
This optimization saves recomposting quads that haven't changed.
In a steady state when only the underlay contents are changing, we'll be
able to completely skip GPU compositing in many cases.

Bug: 795008
Test: Unit Test-> UnderlayTest.DamageSubtractedWhenElementsOnHwUnderlayNotChanged
Change-Id: I9ae1b9c50f63a7a8e50e3f9e16f6ad58adc5308c
Reviewed-on: https://chromium-review.googlesource.com/c/1461102Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarMaggie Chen <magchen@chromium.org>
Commit-Queue: Mark Yacoub <markyacoub@google.com>
Cr-Commit-Position: refs/heads/master@{#636213}
parent 920a8ec8
......@@ -9,6 +9,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/service/display/dc_layer_overlay.h"
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/output_surface.h"
......@@ -175,15 +176,16 @@ void OverlayProcessor::ProcessForOverlays(
// Only if that fails, attempt hardware overlay strategies.
Strategy* successful_strategy = nullptr;
for (const auto& strategy : strategies_) {
if (!strategy->Attempt(output_color_matrix, render_pass_backdrop_filters,
resource_provider, render_passes, candidates,
content_bounds)) {
continue;
if (strategy->Attempt(output_color_matrix, render_pass_backdrop_filters,
resource_provider, render_passes, candidates,
content_bounds)) {
successful_strategy = strategy.get();
UpdateDamageRect(candidates, previous_frame_underlay_rect,
previous_frame_underlay_was_unoccluded,
&render_pass->quad_list, damage_rect);
break;
}
successful_strategy = strategy.get();
UpdateDamageRect(candidates, previous_frame_underlay_rect,
previous_frame_underlay_was_unoccluded, damage_rect);
break;
}
if (!successful_strategy && !previous_frame_underlay_rect.IsEmpty())
......@@ -209,6 +211,7 @@ void OverlayProcessor::UpdateDamageRect(
OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect,
bool previous_frame_underlay_was_unoccluded,
const QuadList* quad_list,
gfx::Rect* damage_rect) {
gfx::Rect output_surface_overlay_damage_rect;
gfx::Rect this_frame_underlay_rect;
......@@ -224,24 +227,47 @@ void OverlayProcessor::UpdateDamageRect(
if (overlay.is_opaque)
damage_rect->Subtract(overlay_display_rect);
}
} else if (this_frame_underlay_rect.IsEmpty()) {
} else {
// Process underlay candidates:
// Track the underlay_rect from frame to frame. If it is the same
// and nothing is on top of it then that rect doesn't need to
// be damaged because the drawing is occurring on a different plane.
// If it is different then that indicates that a different underlay
// has been chosen and the previous underlay rect should be damaged
// because it has changed planes from the underlay plane to the
// main plane.
// Track the underlay_rect from frame to frame. If it is the same and
// nothing is on top of it then that rect doesn't need to be damaged
// because the drawing is occurring on a different plane. If it is
// different then that indicates that a different underlay has been chosen
// and the previous underlay rect should be damaged because it has changed
// planes from the underlay plane to the main plane.
// It then checks that this is not a transition from occluded to
// unoccluded.
//
// We also insist that the underlay is unoccluded for at leat one frame,
// else when content above the overlay transitions from not fully
// transparent to fully transparent, we still need to erase it from the
// framebuffer. Otherwise, the last non-transparent frame will remain.
// https://crbug.com/875879
// However, if the underlay is unoccluded, we check if the damage is due
// to a solid-opaque-transparent quad. If so, then we subtract this
// damage.
this_frame_underlay_rect = ToEnclosedRect(overlay.display_rect);
if ((this_frame_underlay_rect == previous_frame_underlay_rect) &&
overlay.is_unoccluded && previous_frame_underlay_was_unoccluded) {
bool same_underlay_rect =
this_frame_underlay_rect == previous_frame_underlay_rect;
bool transition_from_occluded_to_unoccluded =
overlay.is_unoccluded && !previous_frame_underlay_was_unoccluded;
bool always_unoccluded =
overlay.is_unoccluded && previous_frame_underlay_was_unoccluded;
bool has_damage = std::any_of(
quad_list->begin(), quad_list->end(), [](const auto& quad) {
bool solid_opaque_tranparent =
!quad->ShouldDrawWithBlending() &&
quad->material == DrawQuad::SOLID_COLOR &&
SolidColorDrawQuad::MaterialCast(quad)->color ==
SK_ColorTRANSPARENT;
return !solid_opaque_tranparent &&
quad->shared_quad_state->has_surface_damage;
});
if (same_underlay_rect && !transition_from_occluded_to_unoccluded &&
(always_unoccluded || !has_damage)) {
damage_rect->Subtract(this_frame_underlay_rect);
}
previous_frame_underlay_was_unoccluded_ = overlay.is_unoccluded;
......
......@@ -112,6 +112,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
void UpdateDamageRect(OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect,
bool previous_frame_underlay_was_unoccluded,
const QuadList* quad_list,
gfx::Rect* damage_rect);
DCLayerOverlayProcessor dc_processor_;
......
......@@ -1943,6 +1943,46 @@ TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
}
}
// Tests that no damage occurs due to unchanged elements on top of HW underlays
TEST_F(UnderlayTest, DamageSubtractedWhenElementsOnHwUnderlayNotChanged) {
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect rect(2, 3);
SharedQuadState* non_damaged_quad_state =
pass->shared_quad_state_list.AllocateAndCopyFrom(
pass->shared_quad_state_list.back());
// Element on top has not changed (no damage caused by this quad)
non_damaged_quad_state->has_surface_damage = false;
CreateSolidColorQuadAt(non_damaged_quad_state, SK_ColorBLACK, pass.get(),
rect);
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.front(),
pass.get());
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
// The damage rect should not be subtracted on the first frame
if (i == 0)
EXPECT_FALSE(damage_rect_.IsEmpty());
}
// As the UI on top of the underlay persists and does not change, damage
// should be subtracted.
EXPECT_TRUE(damage_rect_.IsEmpty());
}
TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment