Commit ee70c342 authored by David Stevens's avatar David Stevens Committed by Commit Bot

Expand occluding damage underlay optimization

This change adds a |no_damage| flag to SharedQuadState that viz
clients can use to indicate that the quad doesn't contribute damage
to the render pass. Exo is updated to use this flag. The new flag is
then used in SurfaceAggregator to expand the occluding damage
optimization to apply to any quad which is explicitly marked as the
only damaged quad in its render pass.

Bug: 1082082
Change-Id: I75b01ad724c6f0227cc1076185f301237310bc44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2275283Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarMaggie Chen <magchen@chromium.org>
Commit-Queue: David Stevens <stevensd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#793057}
parent 5c9a9a25
...@@ -1069,6 +1069,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin, ...@@ -1069,6 +1069,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
gfx::RRectF() /*rounded_corner_bounds=*/, gfx::Rect() /*clip_rect=*/, gfx::RRectF() /*rounded_corner_bounds=*/, gfx::Rect() /*clip_rect=*/,
false /*is_clipped=*/, are_contents_opaque, state_.alpha /*opacity=*/, false /*is_clipped=*/, are_contents_opaque, state_.alpha /*opacity=*/,
SkBlendMode::kSrcOver /*blend_mode=*/, 0 /*sorting_context_id=*/); SkBlendMode::kSrcOver /*blend_mode=*/, 0 /*sorting_context_id=*/);
quad_state->no_damage = damage_rect.IsEmpty();
if (current_resource_.id) { if (current_resource_.id) {
gfx::RectF uv_crop(gfx::SizeF(1, 1)); gfx::RectF uv_crop(gfx::SizeF(1, 1));
......
...@@ -78,6 +78,11 @@ class VIZ_COMMON_EXPORT SharedQuadState { ...@@ -78,6 +78,11 @@ class VIZ_COMMON_EXPORT SharedQuadState {
// The amount to skew quads in this layer. For experimental de-jelly effect. // The amount to skew quads in this layer. For experimental de-jelly effect.
float de_jelly_delta_y = 0.0f; float de_jelly_delta_y = 0.0f;
// If true, indicates that the quads do not contribute damage to their
// render pass's damage; if false, whether or not the quads contribute
// damage is unknown. Only meaningful in root render passes.
bool no_damage = false;
}; };
} // namespace viz } // namespace viz
......
...@@ -297,29 +297,53 @@ void SurfaceAggregator::UnionSurfaceDamageRectsOnTop( ...@@ -297,29 +297,53 @@ void SurfaceAggregator::UnionSurfaceDamageRectsOnTop(
// shared_quad_state->occluding_damage_rect and used by the overlay // shared_quad_state->occluding_damage_rect and used by the overlay
// processor for damage rect optimization. This function is called once // processor for damage rect optimization. This function is called once
// for each surface. It adds the damage rects of all surfaces to // for each surface. It adds the damage rects of all surfaces to
// damage_rects_union_of_surfaces_on_top_. The occluding damage rect // damage_rects_union_of_surfaces_on_top_. If there is a DrawQuad in the
// is then calculated based on this rect. // surface to which the optimization can be applied, this function returns
bool SurfaceAggregator::ProcessSurfaceOccludingDamage( // that quad and sets the occluding_damage_rect out parameter to the
// appropriate rectangle.
DrawQuad* SurfaceAggregator::ProcessSurfaceOccludingDamage(
const Surface* surface, const Surface* surface,
const RenderPassList& render_pass_list, const RenderPassList& render_pass_list,
const gfx::Transform& parent_target_transform, const gfx::Transform& parent_target_transform,
const RenderPass* dest_pass, const RenderPass* dest_pass,
gfx::Rect* occluding_damage_rect) { gfx::Rect* occluding_damage_rect) {
if (!needs_surface_occluding_damage_rect_) if (!needs_surface_occluding_damage_rect_)
return false; return nullptr;
bool occluding_damage_rect_valid = false;
RenderPass* last_render_pass = render_pass_list.back().get(); RenderPass* last_render_pass = render_pass_list.back().get();
gfx::Transform quad_to_root_target_transform = gfx::Transform( gfx::Transform quad_to_root_target_transform = gfx::Transform(
dest_pass->transform_to_root_target, parent_target_transform); dest_pass->transform_to_root_target, parent_target_transform);
// This occluding damage detection only works when there is only one quad // The occluding damage optimization currently relies on two things - there
// in the current surface. // can't be any damage above the quad within the surface, and the quad needs
if (render_pass_list.size() == 1 && last_render_pass->quad_list.size() == 1) { // its own SQS for the occluding_damage_rect metadata.
auto* quad = last_render_pass->quad_list.back(); DrawQuad* target_quad = nullptr;
if (last_render_pass->quad_list.size() == 1) {
// If there's only one quad in the root render pass, then the conditions
// are clearly satisfied.
target_quad = last_render_pass->quad_list.back();
} else {
// If there are multiple quads in the surface, if exactly one quad is
// marked as having damage, then we know that quad doesn't have damage
// above it, and we know that it has its own SQS (because its
// sqs->no_damage is unique).
for (auto* quad : last_render_pass->quad_list) {
if (quad->shared_quad_state->no_damage) {
continue;
}
if (target_quad == nullptr) {
target_quad = quad;
} else {
target_quad = nullptr;
break;
}
}
}
if (target_quad) {
*occluding_damage_rect = CalculateOccludingSurfaceDamageRect( *occluding_damage_rect = CalculateOccludingSurfaceDamageRect(
quad, quad_to_root_target_transform); target_quad, quad_to_root_target_transform);
occluding_damage_rect_valid = true;
} }
gfx::Rect surface_damage_rect; gfx::Rect surface_damage_rect;
...@@ -337,7 +361,7 @@ bool SurfaceAggregator::ProcessSurfaceOccludingDamage( ...@@ -337,7 +361,7 @@ bool SurfaceAggregator::ProcessSurfaceOccludingDamage(
UnionSurfaceDamageRectsOnTop( UnionSurfaceDamageRectsOnTop(
surface_damage_rect, quad_to_root_target_transform, last_render_pass); surface_damage_rect, quad_to_root_target_transform, last_render_pass);
} }
return occluding_damage_rect_valid; return target_quad;
} }
bool SurfaceAggregator::RenderPassNeedsFullDamage( bool SurfaceAggregator::RenderPassNeedsFullDamage(
...@@ -529,7 +553,7 @@ void SurfaceAggregator::EmitSurfaceContent( ...@@ -529,7 +553,7 @@ void SurfaceAggregator::EmitSurfaceContent(
} }
gfx::Rect occluding_damage_rect; gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage( DrawQuad* quad_with_occluding_damage_rect = ProcessSurfaceOccludingDamage(
surface, render_pass_list, combined_transform, dest_pass, surface, render_pass_list, combined_transform, dest_pass,
&occluding_damage_rect); &occluding_damage_rect);
...@@ -576,7 +600,7 @@ void SurfaceAggregator::EmitSurfaceContent( ...@@ -576,7 +600,7 @@ void SurfaceAggregator::EmitSurfaceContent(
surface->GetActiveFrame().device_scale_factor(), surface->GetActiveFrame().device_scale_factor(),
child_to_parent_map, gfx::Transform(), {}, copy_pass.get(), child_to_parent_map, gfx::Transform(), {}, copy_pass.get(),
surface_id, RoundedCornerInfo(), occluding_damage_rect, surface_id, RoundedCornerInfo(), occluding_damage_rect,
occluding_damage_rect_valid); quad_with_occluding_damage_rect);
// If the render pass has copy requests, or should be cached, or has // If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the // moving-pixel filters, or in a moving-pixel surface, we should damage the
...@@ -629,7 +653,7 @@ void SurfaceAggregator::EmitSurfaceContent( ...@@ -629,7 +653,7 @@ void SurfaceAggregator::EmitSurfaceContent(
surface->GetActiveFrame().device_scale_factor(), surface->GetActiveFrame().device_scale_factor(),
child_to_parent_map, surface_transform, quads_clip, child_to_parent_map, surface_transform, quads_clip,
dest_pass, surface_id, rounded_corner_info, dest_pass, surface_id, rounded_corner_info,
occluding_damage_rect, occluding_damage_rect_valid); occluding_damage_rect, quad_with_occluding_damage_rect);
} else { } else {
auto* shared_quad_state = CopyAndScaleSharedQuadState( auto* shared_quad_state = CopyAndScaleSharedQuadState(
source_sqs, scaled_quad_to_target_transform, target_transform, source_sqs, scaled_quad_to_target_transform, target_transform,
...@@ -640,7 +664,7 @@ void SurfaceAggregator::EmitSurfaceContent( ...@@ -640,7 +664,7 @@ void SurfaceAggregator::EmitSurfaceContent(
inverse_extra_content_scale_x, inverse_extra_content_scale_x,
inverse_extra_content_scale_y), inverse_extra_content_scale_y),
clip_rect, dest_pass, rounded_corner_info, occluding_damage_rect, clip_rect, dest_pass, rounded_corner_info, occluding_damage_rect,
occluding_damage_rect_valid); /* occluding_damage_rect_valid */ false);
// At this point, we need to calculate three values in order to construct // At this point, we need to calculate three values in order to construct
// the RenderPassDrawQuad: // the RenderPassDrawQuad:
...@@ -964,7 +988,7 @@ void SurfaceAggregator::CopyQuadsToPass( ...@@ -964,7 +988,7 @@ void SurfaceAggregator::CopyQuadsToPass(
const SurfaceId& surface_id, const SurfaceId& surface_id,
const RoundedCornerInfo& parent_rounded_corner_info, const RoundedCornerInfo& parent_rounded_corner_info,
const gfx::Rect& occluding_damage_rect, const gfx::Rect& occluding_damage_rect,
bool occluding_damage_rect_valid) { DrawQuad* quad_with_occluding_damage_rect) {
const SharedQuadState* last_copied_source_shared_quad_state = nullptr; const SharedQuadState* last_copied_source_shared_quad_state = nullptr;
// If the current frame has copy requests or cached render passes, then // If the current frame has copy requests or cached render passes, then
// aggregate the entire thing, as otherwise parts of the copy requests may be // aggregate the entire thing, as otherwise parts of the copy requests may be
...@@ -1032,7 +1056,7 @@ void SurfaceAggregator::CopyQuadsToPass( ...@@ -1032,7 +1056,7 @@ void SurfaceAggregator::CopyQuadsToPass(
SharedQuadState* dest_shared_quad_state = CopySharedQuadState( SharedQuadState* dest_shared_quad_state = CopySharedQuadState(
quad->shared_quad_state, target_transform, clip_rect, dest_pass, quad->shared_quad_state, target_transform, clip_rect, dest_pass,
new_rounded_corner_info, occluding_damage_rect, new_rounded_corner_info, occluding_damage_rect,
occluding_damage_rect_valid); quad == quad_with_occluding_damage_rect);
if (de_jelly_enabled_) { if (de_jelly_enabled_) {
// If a surface is being drawn for a second time, clear our // If a surface is being drawn for a second time, clear our
...@@ -1133,7 +1157,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame, ...@@ -1133,7 +1157,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
} }
gfx::Rect occluding_damage_rect; gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage( DrawQuad* quad_with_occluding_damage_rect = ProcessSurfaceOccludingDamage(
surface, source_pass_list, surface_transform, surface, source_pass_list, surface_transform,
source_pass_list.back().get(), &occluding_damage_rect); source_pass_list.back().get(), &occluding_damage_rect);
...@@ -1189,7 +1213,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame, ...@@ -1189,7 +1213,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
: gfx::Transform(), : gfx::Transform(),
{}, copy_pass.get(), surface->surface_id(), {}, copy_pass.get(), surface->surface_id(),
RoundedCornerInfo(), occluding_damage_rect, RoundedCornerInfo(), occluding_damage_rect,
occluding_damage_rect_valid); quad_with_occluding_damage_rect);
// If the render pass has copy requests, or should be cached, or has // If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the // moving-pixel filters, or in a moving-pixel surface, we should damage the
......
...@@ -181,7 +181,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator { ...@@ -181,7 +181,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const SurfaceId& surface_id, const SurfaceId& surface_id,
const RoundedCornerInfo& rounded_corner_info, const RoundedCornerInfo& rounded_corner_info,
const gfx::Rect& occluding_damage_rect, const gfx::Rect& occluding_damage_rect,
bool occluding_damage_rect_valid); DrawQuad* quad_with_occluding_damage_rect);
// Recursively walks through the render pass and updates the // Recursively walks through the render pass and updates the
// |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ). // |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
...@@ -257,11 +257,12 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator { ...@@ -257,11 +257,12 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void UnionSurfaceDamageRectsOnTop(const gfx::Rect& surface_rect, void UnionSurfaceDamageRectsOnTop(const gfx::Rect& surface_rect,
const gfx::Transform& target_transform, const gfx::Transform& target_transform,
const RenderPass* pass); const RenderPass* pass);
bool ProcessSurfaceOccludingDamage(const Surface* surface, DrawQuad* ProcessSurfaceOccludingDamage(
const RenderPassList& render_pass_list, const Surface* surface,
const gfx::Transform& target_transform, const RenderPassList& render_pass_list,
const RenderPass* dest_pass, const gfx::Transform& target_transform,
gfx::Rect* occluding_damage_rect); const RenderPass* dest_pass,
gfx::Rect* occluding_damage_rect);
bool RenderPassNeedsFullDamage(const RenderPass* pass) const; bool RenderPassNeedsFullDamage(const RenderPass* pass) const;
bool IsRootSurface(const Surface* surface) const; bool IsRootSurface(const Surface* surface) const;
......
...@@ -6787,6 +6787,61 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) { ...@@ -6787,6 +6787,61 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
EXPECT_EQ(gfx::Rect(60, 0, 14, 40), EXPECT_EQ(gfx::Rect(60, 0, 14, 40),
video_sqs->occluding_damage_rect.value()); video_sqs->occluding_damage_rect.value());
} }
// Add a quad on top of video quad
child_surface_quads = std::vector<Quad>(
{Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(0, 0, 50, 50)),
Quad::YUVVideoQuad(gfx::Rect(0, 0, 100, 100))});
child_surface_passes =
std::vector<Pass>({Pass(child_surface_quads, /*size*/ gfx::Size(100, 100),
/*damage_rect*/ gfx::Rect(0, 0, 100, 100))});
// Frame #5 - Child surface contains a quad other than the video
{
CompositorFrame child_surface_frame = MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, child_surface_passes,
&child_surface_frame.metadata.referenced_surfaces);
child_sink_->SubmitCompositorFrame(child_local_surface_id,
std::move(child_surface_frame));
// No change in root frame
auto aggregated_frame = AggregateFrame(root_surface_id);
auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
// Only the video quad (10, 0, 80, 80) is damaged
EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect);
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
// The underlay optimization doesn't apply with multiple
// possibly damaged quads
EXPECT_FALSE(video_sqs->occluding_damage_rect.has_value());
}
// Frame #6 - Child surface contains an undamaged quad other than the video
{
CompositorFrame child_surface_frame = MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, child_surface_passes,
&child_surface_frame.metadata.referenced_surfaces);
auto* render_pass = child_surface_frame.render_pass_list[0].get();
auto* surface_quad_sqs = render_pass->shared_quad_state_list.front();
surface_quad_sqs->no_damage = true;
child_sink_->SubmitCompositorFrame(child_local_surface_id,
std::move(child_surface_frame));
// No change in root frame
auto aggregated_frame = AggregateFrame(root_surface_id);
auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
// Only the video quad (10, 0, 80, 80) is damaged
EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect);
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
// No occluding damage
EXPECT_EQ(gfx::Rect(), video_sqs->occluding_damage_rect.value());
}
} }
// Tests that quads outside the damage rect are not ignored for cached render // Tests that quads outside the damage rect are not ignored for cached render
......
...@@ -71,6 +71,10 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, OptSharedQuadState> { ...@@ -71,6 +71,10 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, OptSharedQuadState> {
static float de_jelly_delta_y(const OptSharedQuadState& input) { static float de_jelly_delta_y(const OptSharedQuadState& input) {
return input.sqs->de_jelly_delta_y; return input.sqs->de_jelly_delta_y;
} }
static bool no_damage(const OptSharedQuadState& input) {
return input.sqs->no_damage;
}
}; };
template <> template <>
...@@ -124,6 +128,10 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> { ...@@ -124,6 +128,10 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> {
return sqs.de_jelly_delta_y; return sqs.de_jelly_delta_y;
} }
static bool no_damage(const viz::SharedQuadState& sqs) {
return sqs.no_damage;
}
static bool Read(viz::mojom::SharedQuadStateDataView data, static bool Read(viz::mojom::SharedQuadStateDataView data,
viz::SharedQuadState* out) { viz::SharedQuadState* out) {
if (!data.ReadQuadToTargetTransform(&out->quad_to_target_transform) || if (!data.ReadQuadToTargetTransform(&out->quad_to_target_transform) ||
...@@ -143,6 +151,7 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> { ...@@ -143,6 +151,7 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> {
out->sorting_context_id = data.sorting_context_id(); out->sorting_context_id = data.sorting_context_id();
out->is_fast_rounded_corner = data.is_fast_rounded_corner(); out->is_fast_rounded_corner = data.is_fast_rounded_corner();
out->de_jelly_delta_y = data.de_jelly_delta_y(); out->de_jelly_delta_y = data.de_jelly_delta_y();
out->no_damage = data.no_damage();
return true; return true;
} }
}; };
......
...@@ -43,4 +43,9 @@ struct SharedQuadState { ...@@ -43,4 +43,9 @@ struct SharedQuadState {
// The y offset by which to skew quads in this layer. For experimental // The y offset by which to skew quads in this layer. For experimental
// de-jelly effect. // de-jelly effect.
float de_jelly_delta_y; float de_jelly_delta_y;
// If true, indicates that the quads do not contribute damage to their
// render pass's damage; if false, whether or not the quads contribute
// damage is unknown.
bool no_damage;
}; };
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