Commit bc366664 authored by Peter McNeeley's avatar Peter McNeeley Committed by Chromium LUCI CQ

Minor improvement to overlay damage for opaque overlays

Due to existing limitations in damage calculations some overlay
candidate quads will still lack a valid |surface_damage_index|. This
means that separating out the damage of a promoted overlay quad from the
damage on the primary plan is now virtually impossible. However, a
simple optimization is still possible if the overlay candidate is opaque
and sits above the primary plane (pure overlay not underlay). So in this
case the |display_rect| of the promoted overlay can be subtracted from
the primary plane damage.

The motivation for these changes is primarily improved Lacros power
performance. The special case mentioned above is far more common in
existing lacros due to the entire lacros window being contained in one
compositor frame.

Finally, it should be noted that with this change some pages now move
closer to power equivalence between Lacros and ash chrome. Specifically
the Google Keeps drawing application has now only ~6% greater power
usage on Lacros than ash chrome.



Change-Id: I83af491adb3dd2832f599d34e5849fd518ffdfa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2634926Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Commit-Queue: Peter McNeeley <petermcneeley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845294}
parent a2a1e431
...@@ -154,9 +154,9 @@ bool OverlayCandidate::FromDrawQuad( ...@@ -154,9 +154,9 @@ bool OverlayCandidate::FromDrawQuad(
} }
candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad); candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
candidate->overlay_damage_index = candidate->overlay_damage_index =
sqs->overlay_damage_index.value_or(kInvalidDamageIndex); sqs->overlay_damage_index.value_or(kInvalidDamageIndex);
candidate->assume_damaged = !sqs->no_damage;
switch (quad->material) { switch (quad->material) {
case DrawQuad::Material::kTextureContent: case DrawQuad::Material::kTextureContent:
......
...@@ -133,6 +133,11 @@ class VIZ_SERVICE_EXPORT OverlayCandidate { ...@@ -133,6 +133,11 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Is true if an HW overlay is required for the quad content. // Is true if an HW overlay is required for the quad content.
bool requires_overlay = false; bool requires_overlay = false;
// Is true when quad is part of a |shared_quad_state| that has damage.
// This is a fallback case for when |overlay_damage_index| is unavailable and
// will be absent from the |SurfaceDamageRectList|.
bool assume_damaged = false;
private: private:
static bool FromDrawQuadResource( static bool FromDrawQuadResource(
DisplayResourceProvider* resource_provider, DisplayResourceProvider* resource_provider,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "components/viz/service/display/overlay_candidate.h" #include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h" #include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h" #include "components/viz/service/display/overlay_strategy_underlay.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h" #include "ui/gfx/transform.h"
...@@ -171,10 +172,17 @@ gfx::Rect ComputeDamageExcludingIndex( ...@@ -171,10 +172,17 @@ gfx::Rect ComputeDamageExcludingIndex(
uint32_t overlay_damage_index, uint32_t overlay_damage_index,
SurfaceDamageRectList* surface_damage_rect_list, SurfaceDamageRectList* surface_damage_rect_list,
const gfx::Rect& existing_damage, const gfx::Rect& existing_damage,
const gfx::Rect& display_rect) { const gfx::Rect& display_rect,
bool is_opaque_pure_overlay) {
gfx::Rect root_damage_rect; gfx::Rect root_damage_rect;
if (overlay_damage_index == OverlayCandidate::kInvalidDamageIndex) { if (overlay_damage_index == OverlayCandidate::kInvalidDamageIndex) {
// An opaque overlay that is on top will hide any damage underneath.
// TODO(petermcneeley): This is a special case optimization which could be
// removed if we had more reliable damage.
if (is_opaque_pure_overlay) {
return gfx::SubtractRects(existing_damage, display_rect);
}
return existing_damage; return existing_damage;
} }
...@@ -244,7 +252,7 @@ void OverlayProcessorUsingStrategy::UpdateDamageRect( ...@@ -244,7 +252,7 @@ void OverlayProcessorUsingStrategy::UpdateDamageRect(
// Removes all damage from this overlay and occluded surface damages. // Removes all damage from this overlay and occluded surface damages.
*damage_rect = ComputeDamageExcludingIndex( *damage_rect = ComputeDamageExcludingIndex(
exclude_overlay_index, surface_damage_rect_list, *damage_rect, exclude_overlay_index, surface_damage_rect_list, *damage_rect,
this_frame_overlay_rect); this_frame_overlay_rect, is_opaque_overlay && !is_underlay);
// Track the overlay_rect from frame to frame. If it is the same and nothing // Track the overlay_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 // is on top of it then that rect doesn't need to be damaged because the
...@@ -334,7 +342,8 @@ void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized( ...@@ -334,7 +342,8 @@ void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized(
static_cast<float>(it->candidate.damage_area_estimate) / display_area, static_cast<float>(it->candidate.damage_area_estimate) / display_area,
it->candidate.resource_id, tracker_config_, it->candidate.resource_id, tracker_config_,
it->candidate.overlay_damage_index != it->candidate.overlay_damage_index !=
OverlayCandidate::kInvalidDamageIndex); OverlayCandidate::kInvalidDamageIndex ||
it->candidate.assume_damaged);
// Here a series of criteria are considered for wholesale rejection of a // Here a series of criteria are considered for wholesale rejection of a
// candidate. The rational for rejection is usually power improvements but // candidate. The rational for rejection is usually power improvements but
...@@ -345,7 +354,7 @@ void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized( ...@@ -345,7 +354,7 @@ void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized(
tracker_config_) || tracker_config_) ||
!prioritization_config_.changing_threshold) && !prioritization_config_.changing_threshold) &&
(track_data.GetModeledPowerGain(frame_sequence_number_, (track_data.GetModeledPowerGain(frame_sequence_number_,
tracker_config_, display_area) > 0 || tracker_config_, display_area) >= 0 ||
!prioritization_config_.damage_rate_threshold)); !prioritization_config_.damage_rate_threshold));
if (it->candidate.requires_overlay || passes_min_threshold) { if (it->candidate.requires_overlay || passes_min_threshold) {
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/stl_util.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_output_surface_client.h"
...@@ -934,6 +935,59 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) { ...@@ -934,6 +935,59 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
EXPECT_EQ(resource_big, candidate_list.front().resource_id); EXPECT_EQ(resource_big, candidate_list.front().resource_id);
} }
TEST_F(SingleOverlayOnTopTest, OpaqueOverlayDamageSubtract) {
// This tests a specific damage optimization where an opaque pure overlay can
// subtract damage from the primary plane even if the overlay does not have a
// |shared_quad_state| surface damage index.
constexpr int kCandidateSmall = 64;
const gfx::Rect kOverlayDisplayRect = {10, 10, kCandidateSmall,
kCandidateSmall};
const gfx::Rect kDamageRect[] = {
gfx::Rect(10, 10, kCandidateSmall, kCandidateSmall),
gfx::Rect(0, 10, kCandidateSmall, kCandidateSmall),
gfx::Rect(6, 6, kCandidateSmall, kCandidateSmall)};
const gfx::Rect kExpectedDamage[] = {
gfx::Rect(), gfx::Rect(0, 10, 10, kCandidateSmall),
gfx::Rect(6, 6, kCandidateSmall, kCandidateSmall)};
AddExpectedRectToOverlayProcessor(gfx::RectF(kOverlayDisplayRect));
for (size_t i = 0; i < base::size(kDamageRect); ++i) {
auto pass = CreateRenderPass();
SharedQuadState* damaged_shared_quad_state =
pass->shared_quad_state_list.AllocateAndCopyFrom(
pass->shared_quad_state_list.back());
damaged_shared_quad_state->no_damage = false;
auto* quad = CreateCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), damaged_shared_quad_state, pass.get(),
kOverlayDisplayRect);
quad->needs_blending = false;
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
SurfaceDamageRectList surface_damage_rect_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
damage_rect_ = kDamageRect[i];
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &candidate_list,
&damage_rect_, &content_bounds_);
EXPECT_RECT_EQ(damage_rect_, kExpectedDamage[i]);
}
}
TEST_F(SingleOverlayOnTopTest, DamageRect) { TEST_F(SingleOverlayOnTopTest, DamageRect) {
auto pass = CreateRenderPass(); auto pass = CreateRenderPass();
CreateFullscreenCandidateQuad( CreateFullscreenCandidateQuad(
...@@ -1783,9 +1837,11 @@ TEST_F(ChangeSingleOnTopTest, DoNotPromoteIfContentsDontChange) { ...@@ -1783,9 +1837,11 @@ TEST_F(ChangeSingleOnTopTest, DoNotPromoteIfContentsDontChange) {
child_provider_.get(), pass->output_rect.size(), child_provider_.get(), pass->output_rect.size(),
true /*is_overlay_candidate*/); true /*is_overlay_candidate*/);
previous_resource_id = resource_id; previous_resource_id = resource_id;
pass->shared_quad_state_list.back()->no_damage = false;
} else { } else {
// Starting the 3rd frame, they should have the same resource ID. // Starting the 3rd frame, they should have the same resource ID.
resource_id = previous_resource_id; resource_id = previous_resource_id;
pass->shared_quad_state_list.back()->no_damage = true;
} }
// Create a quad with the resource ID selected above. // Create a quad with the resource ID selected above.
......
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