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 @@ ...@@ -9,6 +9,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.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/dc_layer_overlay.h"
#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface.h"
...@@ -175,16 +176,17 @@ void OverlayProcessor::ProcessForOverlays( ...@@ -175,16 +176,17 @@ void OverlayProcessor::ProcessForOverlays(
// Only if that fails, attempt hardware overlay strategies. // Only if that fails, attempt hardware overlay strategies.
Strategy* successful_strategy = nullptr; Strategy* successful_strategy = nullptr;
for (const auto& strategy : strategies_) { for (const auto& strategy : strategies_) {
if (!strategy->Attempt(output_color_matrix, render_pass_backdrop_filters, if (strategy->Attempt(output_color_matrix, render_pass_backdrop_filters,
resource_provider, render_passes, candidates, resource_provider, render_passes, candidates,
content_bounds)) { content_bounds)) {
continue;
}
successful_strategy = strategy.get(); successful_strategy = strategy.get();
UpdateDamageRect(candidates, previous_frame_underlay_rect, UpdateDamageRect(candidates, previous_frame_underlay_rect,
previous_frame_underlay_was_unoccluded, damage_rect); previous_frame_underlay_was_unoccluded,
&render_pass->quad_list, damage_rect);
break; break;
} }
}
if (!successful_strategy && !previous_frame_underlay_rect.IsEmpty()) if (!successful_strategy && !previous_frame_underlay_rect.IsEmpty())
damage_rect->Union(previous_frame_underlay_rect); damage_rect->Union(previous_frame_underlay_rect);
...@@ -209,6 +211,7 @@ void OverlayProcessor::UpdateDamageRect( ...@@ -209,6 +211,7 @@ void OverlayProcessor::UpdateDamageRect(
OverlayCandidateList* candidates, OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect, const gfx::Rect& previous_frame_underlay_rect,
bool previous_frame_underlay_was_unoccluded, bool previous_frame_underlay_was_unoccluded,
const QuadList* quad_list,
gfx::Rect* damage_rect) { gfx::Rect* damage_rect) {
gfx::Rect output_surface_overlay_damage_rect; gfx::Rect output_surface_overlay_damage_rect;
gfx::Rect this_frame_underlay_rect; gfx::Rect this_frame_underlay_rect;
...@@ -224,24 +227,47 @@ void OverlayProcessor::UpdateDamageRect( ...@@ -224,24 +227,47 @@ void OverlayProcessor::UpdateDamageRect(
if (overlay.is_opaque) if (overlay.is_opaque)
damage_rect->Subtract(overlay_display_rect); damage_rect->Subtract(overlay_display_rect);
} }
} else if (this_frame_underlay_rect.IsEmpty()) { } else {
// Process underlay candidates: // Process underlay candidates:
// Track the underlay_rect from frame to frame. If it is the same // Track the underlay_rect from frame to frame. If it is the same and
// and nothing is on top of it then that rect doesn't need to // nothing is on top of it then that rect doesn't need to be damaged
// be damaged because the drawing is occurring on a different plane. // because the drawing is occurring on a different plane. If it is
// If it is different then that indicates that a different underlay // different then that indicates that a different underlay has been chosen
// has been chosen and the previous underlay rect should be damaged // and the previous underlay rect should be damaged because it has changed
// because it has changed planes from the underlay plane to the // planes from the underlay plane to the main plane.
// 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, // We also insist that the underlay is unoccluded for at leat one frame,
// else when content above the overlay transitions from not fully // else when content above the overlay transitions from not fully
// transparent to fully transparent, we still need to erase it from the // transparent to fully transparent, we still need to erase it from the
// framebuffer. Otherwise, the last non-transparent frame will remain. // framebuffer. Otherwise, the last non-transparent frame will remain.
// https://crbug.com/875879 // 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); 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); damage_rect->Subtract(this_frame_underlay_rect);
} }
previous_frame_underlay_was_unoccluded_ = overlay.is_unoccluded; previous_frame_underlay_was_unoccluded_ = overlay.is_unoccluded;
......
...@@ -112,6 +112,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessor { ...@@ -112,6 +112,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
void UpdateDamageRect(OverlayCandidateList* candidates, void UpdateDamageRect(OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect, const gfx::Rect& previous_frame_underlay_rect,
bool previous_frame_underlay_was_unoccluded, bool previous_frame_underlay_was_unoccluded,
const QuadList* quad_list,
gfx::Rect* damage_rect); gfx::Rect* damage_rect);
DCLayerOverlayProcessor dc_processor_; DCLayerOverlayProcessor dc_processor_;
......
...@@ -1943,6 +1943,46 @@ TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) { ...@@ -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) { TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass(); 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