Commit 643c3e9a authored by Maggie Chen's avatar Maggie Chen Committed by Commit Bot

Optimize damage rect added from the previous overlay damage

This optimization reduces the damage rect size when the current damage rect
doesn't cover the video quad. For example, the video is paused or no video
change in this frame.

Because the overlay image is missing in gl composition, there might be
corruption if the old overlay needs to be redrawn in gl composition but the
damage rect doesn't cover it. Although sometimes it's needed to add the
overlay damage rect from the previous frame. It might increase the damage rect
than necessary when overlay is the same.

The unioned overlay quad size of the previous frame was always added to the
damage rect of the next frame before calling the overlay processor. This CL
optimizes the damage rect by handling the overlay damage rect in
DCLayerOverlayProcessor().

The other change of this CL is to move overlay and underlay validation code into
one function. This makes it easier to read and makes sure there is no validation
failures after the damage rect has changed.

BUG=868561

Change-Id: Ia66b950d5f010cb4b65288276cb9486e0d3d7709
Reviewed-on: https://chromium-review.googlesource.com/c/1472190
Commit-Queue: Maggie Chen <magchen@chromium.org>
Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#634952}
parent 63406aee
...@@ -40,6 +40,7 @@ enum DCLayerResult { ...@@ -40,6 +40,7 @@ enum DCLayerResult {
DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad, DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad,
const gfx::Transform& transform_to_root_target, const gfx::Transform& transform_to_root_target,
bool has_hw_overlay_support, bool has_hw_overlay_support,
int current_frame_processed_overlay_count,
DisplayResourceProvider* resource_provider, DisplayResourceProvider* resource_provider,
DCLayerOverlay* dc_layer) { DCLayerOverlay* dc_layer) {
// Check that resources are overlay compatible first so that subsequent // Check that resources are overlay compatible first so that subsequent
...@@ -61,6 +62,22 @@ DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad, ...@@ -61,6 +62,22 @@ DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad,
ui::ProtectedVideoType::kSoftwareProtected) { ui::ProtectedVideoType::kSoftwareProtected) {
return DC_LAYER_FAILED_NO_HW_OVERLAY_SUPPORT; return DC_LAYER_FAILED_NO_HW_OVERLAY_SUPPORT;
} }
if (!quad->shared_quad_state->quad_to_target_transform
.Preserves2dAxisAlignment() &&
quad->protected_video_type !=
ui::ProtectedVideoType::kHardwareProtected &&
!base::FeatureList::IsEnabled(
features::kDirectCompositionComplexOverlays)) {
return DC_LAYER_FAILED_COMPLEX_TRANSFORM;
}
if (current_frame_processed_overlay_count > 0 &&
quad->protected_video_type !=
ui::ProtectedVideoType::kHardwareProtected) {
return DC_LAYER_FAILED_TOO_MANY_OVERLAYS;
}
// Direct composition path only supports single NV12 buffer, or two buffers // Direct composition path only supports single NV12 buffer, or two buffers
// one each for Y and UV planes. // one each for Y and UV planes.
DCHECK(quad->y_plane_resource_id() && quad->u_plane_resource_id()); DCHECK(quad->y_plane_resource_id() && quad->u_plane_resource_id());
...@@ -95,6 +112,24 @@ DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad, ...@@ -95,6 +112,24 @@ DCLayerResult FromYUVQuad(const YUVVideoDrawQuad* quad,
return DC_LAYER_SUCCESS; return DC_LAYER_SUCCESS;
} }
DCLayerResult IsUnderlayAllowed(const QuadList::Iterator& it,
bool is_root,
const DCLayerOverlay& dc_layer) {
if (!dc_layer.RequiresOverlay()) {
if (!base::FeatureList::IsEnabled(features::kDirectCompositionUnderlays)) {
return DC_LAYER_FAILED_OCCLUDED;
}
if (!is_root && !base::FeatureList::IsEnabled(
features::kDirectCompositionNonrootOverlays)) {
return DC_LAYER_FAILED_NON_ROOT;
}
if (it->shared_quad_state->opacity < 1.0f) {
return DC_LAYER_FAILED_TRANSPARENT;
}
}
return DC_LAYER_SUCCESS;
}
// This returns the smallest rectangle in target space that contains the quad. // This returns the smallest rectangle in target space that contains the quad.
gfx::RectF ClippedQuadRectangle(const DrawQuad* quad) { gfx::RectF ClippedQuadRectangle(const DrawQuad* quad) {
gfx::RectF quad_rect = cc::MathUtil::MapClippedRect( gfx::RectF quad_rect = cc::MathUtil::MapClippedRect(
...@@ -182,20 +217,24 @@ void DCLayerOverlayProcessor::Process( ...@@ -182,20 +217,24 @@ void DCLayerOverlayProcessor::Process(
DisplayResourceProvider* resource_provider, DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect, const gfx::RectF& display_rect,
RenderPassList* render_passes, RenderPassList* render_passes,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
DCLayerOverlayList* dc_layer_overlays) { DCLayerOverlayList* dc_layer_overlays) {
processed_overlay_in_frame_ = false;
pass_punch_through_rects_.clear(); pass_punch_through_rects_.clear();
for (auto& pass : *render_passes) { for (auto& pass : *render_passes) {
bool is_root = (pass == render_passes->back()); bool is_root = (pass == render_passes->back());
ProcessRenderPass(resource_provider, display_rect, pass.get(), is_root, ProcessRenderPass(resource_provider, display_rect, pass.get(), is_root,
overlay_damage_rect,
is_root ? damage_rect : &pass->damage_rect, is_root ? damage_rect : &pass->damage_rect,
dc_layer_overlays); dc_layer_overlays);
} }
} }
void DCLayerOverlayProcessor::ClearOverlayState() {
previous_frame_underlay_rect_ = gfx::Rect();
previous_frame_underlay_occlusion_ = gfx::Rect();
previous_frame_overlay_rect_union_ = gfx::Rect();
previous_frame_processed_overlay_count_ = 0;
}
QuadList::Iterator DCLayerOverlayProcessor::ProcessRenderPassDrawQuad( QuadList::Iterator DCLayerOverlayProcessor::ProcessRenderPassDrawQuad(
RenderPass* render_pass, RenderPass* render_pass,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
...@@ -294,7 +333,6 @@ void DCLayerOverlayProcessor::ProcessRenderPass( ...@@ -294,7 +333,6 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
const gfx::RectF& display_rect, const gfx::RectF& display_rect,
RenderPass* render_pass, RenderPass* render_pass,
bool is_root, bool is_root,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
DCLayerOverlayList* dc_layer_overlays) { DCLayerOverlayList* dc_layer_overlays) {
gfx::Rect this_frame_underlay_rect; gfx::Rect this_frame_underlay_rect;
...@@ -318,10 +356,11 @@ void DCLayerOverlayProcessor::ProcessRenderPass( ...@@ -318,10 +356,11 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
auto uma_protected_video_type = ui::ProtectedVideoType::kClear; auto uma_protected_video_type = ui::ProtectedVideoType::kClear;
switch (it->material) { switch (it->material) {
case DrawQuad::YUV_VIDEO_CONTENT: case DrawQuad::YUV_VIDEO_CONTENT:
result = result = FromYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
FromYUVQuad(YUVVideoDrawQuad::MaterialCast(*it), render_pass->transform_to_root_target,
render_pass->transform_to_root_target, has_hw_overlay_support_,
has_hw_overlay_support_, resource_provider, &dc_layer); current_frame_processed_overlay_count_,
resource_provider, &dc_layer);
uma_protected_video_type = uma_protected_video_type =
YUVVideoDrawQuad::MaterialCast(*it)->protected_video_type; YUVVideoDrawQuad::MaterialCast(*it)->protected_video_type;
break; break;
...@@ -334,24 +373,40 @@ void DCLayerOverlayProcessor::ProcessRenderPass( ...@@ -334,24 +373,40 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
continue; continue;
} }
if (!it->shared_quad_state->quad_to_target_transform gfx::Rect quad_rectangle_in_target_space =
.Preserves2dAxisAlignment() && gfx::ToEnclosingRect(ClippedQuadRectangle(*it));
!dc_layer.RequiresOverlay() &&
!base::FeatureList::IsEnabled(
features::kDirectCompositionComplexOverlays)) {
RecordDCLayerResult(DC_LAYER_FAILED_COMPLEX_TRANSFORM,
dc_layer.protected_video_type);
continue;
}
// These rects are in quad target space.
gfx::Rect quad_rectangle = gfx::ToEnclosingRect(ClippedQuadRectangle(*it));
bool has_occluding_surface_damage = false; bool has_occluding_surface_damage = false;
gfx::RectF occlusion_bounding_box = gfx::RectF occlusion_bounding_box = GetOcclusionBounds(
GetOcclusionBounds(gfx::RectF(quad_rectangle), quad_list->begin(), it, gfx::RectF(quad_rectangle_in_target_space), quad_list->begin(), it,
&has_occluding_surface_damage); &has_occluding_surface_damage);
// Non-root video is always treated as underlay.
bool is_overlay = occlusion_bounding_box.IsEmpty() && is_root;
// Skip quad if it's an underlay and underlays are not allowed
if (!is_overlay) {
result = IsUnderlayAllowed(it, is_root, dc_layer);
if (result != DC_LAYER_SUCCESS) {
RecordDCLayerResult(result, uma_protected_video_type);
continue;
}
}
bool processed_overlay = false; // Quad is always promoted to either an underlay or an overlay after this
// point. It should not fail.
// If the current overlay has changed in size/position from the
// previous frame, we have to add the overlay quads from the previous frame
// to the damage rect for GL compositor. It's hard to optimize the case with
// multiple overlays. So always add the overlay rects back in this case.
// This is only done once at the first overlay/underlay.
if (current_frame_processed_overlay_count_ == 0 && is_root &&
!previous_frame_overlay_rect_union_.IsEmpty()) {
if (quad_rectangle_in_target_space !=
previous_frame_overlay_rect_union_ ||
previous_frame_processed_overlay_count_ > 1)
damage_rect->Union(previous_frame_overlay_rect_union_);
previous_frame_overlay_rect_union_ = gfx::Rect();
}
// Underlays are less efficient, so attempt regular overlays first. Only // Underlays are less efficient, so attempt regular overlays first. Only
// check root render pass because we can only check for occlusion within a // check root render pass because we can only check for occlusion within a
...@@ -361,37 +416,48 @@ void DCLayerOverlayProcessor::ProcessRenderPass( ...@@ -361,37 +416,48 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
// overlays for protected video, but don't calculate damage differently. // overlays for protected video, but don't calculate damage differently.
// TODO(magchen): Collect all overlay candidates, and filter the list at the // TODO(magchen): Collect all overlay candidates, and filter the list at the
// end to find the best candidates (largest size?). // end to find the best candidates (largest size?).
if (is_root && if (is_overlay) {
(!processed_overlay_in_frame_ || dc_layer.RequiresOverlay()) && ProcessForOverlay(display_rect, quad_list, quad_rectangle_in_target_space,
ProcessForOverlay(display_rect, quad_list, quad_rectangle, &it, damage_rect);
occlusion_bounding_box, &it, damage_rect)) {
// ProcessForOverlay makes the iterator point to the next value on // ProcessForOverlay makes the iterator point to the next value on
// success. // success.
next_it = it; next_it = it;
processed_overlay = true; } else {
} else if (ProcessForUnderlay(display_rect, render_pass, quad_rectangle, ProcessForUnderlay(display_rect, render_pass,
occlusion_bounding_box, it, is_root, quad_rectangle_in_target_space, occlusion_bounding_box,
has_occluding_surface_damage, damage_rect, it, is_root, has_occluding_surface_damage, damage_rect,
&this_frame_underlay_rect, &this_frame_underlay_rect,
&this_frame_underlay_occlusion, &dc_layer)) { &this_frame_underlay_occlusion, &dc_layer);
processed_overlay = true;
} }
if (processed_overlay) { gfx::Rect rect_in_root = cc::MathUtil::MapEnclosingClippedRect(
gfx::Rect rect_in_root = cc::MathUtil::MapEnclosingClippedRect( render_pass->transform_to_root_target, quad_rectangle_in_target_space);
render_pass->transform_to_root_target, quad_rectangle); current_frame_overlay_rect_union_.Union(rect_in_root);
overlay_damage_rect->Union(rect_in_root);
RecordDCLayerResult(DC_LAYER_SUCCESS, dc_layer.protected_video_type); RecordDCLayerResult(DC_LAYER_SUCCESS, dc_layer.protected_video_type);
dc_layer_overlays->push_back(dc_layer); dc_layer_overlays->push_back(dc_layer);
// Only allow one overlay unless non-root overlays are enabled. // Only allow one overlay unless it's hardware protected video.
// TODO(magchen): We want to produce all overlay candidates, and then // TODO(magchen): We want to produce all overlay candidates, and then
// choose the best one. // choose the best one.
processed_overlay_in_frame_ = true; current_frame_processed_overlay_count_++;
}
} }
// Update previous frame state after processing root pass
if (is_root) { if (is_root) {
// If there is no overlay in this frame, previous_frame_overlay_rect_union_
// will be added to the damage_rect here for GL composition because the
// overlay image from the previous frame is missing in the GL composition
// path. If any overlay is found in this frame, the previous overlay rects
// would have been handled above and previous_frame_overlay_rect_union_
// becomes empty.
damage_rect->Union(previous_frame_overlay_rect_union_);
previous_frame_overlay_rect_union_ = current_frame_overlay_rect_union_;
current_frame_overlay_rect_union_ = gfx::Rect();
previous_frame_processed_overlay_count_ =
current_frame_processed_overlay_count_;
current_frame_processed_overlay_count_ = 0;
damage_rect->Intersect(gfx::ToEnclosingRect(display_rect)); damage_rect->Intersect(gfx::ToEnclosingRect(display_rect));
previous_display_rect_ = display_rect; previous_display_rect_ = display_rect;
previous_frame_underlay_rect_ = this_frame_underlay_rect; previous_frame_underlay_rect_ = this_frame_underlay_rect;
...@@ -399,15 +465,11 @@ void DCLayerOverlayProcessor::ProcessRenderPass( ...@@ -399,15 +465,11 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
} }
} }
bool DCLayerOverlayProcessor::ProcessForOverlay( void DCLayerOverlayProcessor::ProcessForOverlay(const gfx::RectF& display_rect,
const gfx::RectF& display_rect, QuadList* quad_list,
QuadList* quad_list, const gfx::Rect& quad_rectangle,
const gfx::Rect& quad_rectangle, QuadList::Iterator* it,
const gfx::RectF& occlusion_bounding_box, gfx::Rect* damage_rect) {
QuadList::Iterator* it,
gfx::Rect* damage_rect) {
if (!occlusion_bounding_box.IsEmpty())
return false;
// The quad is on top, so promote it to an overlay and remove all damage // The quad is on top, so promote it to an overlay and remove all damage
// underneath it. // underneath it.
bool display_rect_changed = (display_rect != previous_display_rect_); bool display_rect_changed = (display_rect != previous_display_rect_);
...@@ -418,10 +480,9 @@ bool DCLayerOverlayProcessor::ProcessForOverlay( ...@@ -418,10 +480,9 @@ bool DCLayerOverlayProcessor::ProcessForOverlay(
damage_rect->Subtract(quad_rectangle); damage_rect->Subtract(quad_rectangle);
} }
*it = quad_list->EraseAndInvalidateAllPointers(*it); *it = quad_list->EraseAndInvalidateAllPointers(*it);
return true;
} }
bool DCLayerOverlayProcessor::ProcessForUnderlay( void DCLayerOverlayProcessor::ProcessForUnderlay(
const gfx::RectF& display_rect, const gfx::RectF& display_rect,
RenderPass* render_pass, RenderPass* render_pass,
const gfx::Rect& quad_rectangle, const gfx::Rect& quad_rectangle,
...@@ -433,31 +494,6 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay( ...@@ -433,31 +494,6 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay(
gfx::Rect* this_frame_underlay_rect, gfx::Rect* this_frame_underlay_rect,
gfx::Rect* this_frame_underlay_occlusion, gfx::Rect* this_frame_underlay_occlusion,
DCLayerOverlay* dc_layer) { DCLayerOverlay* dc_layer) {
if (!dc_layer->RequiresOverlay()) {
if (!base::FeatureList::IsEnabled(features::kDirectCompositionUnderlays)) {
RecordDCLayerResult(DC_LAYER_FAILED_OCCLUDED,
dc_layer->protected_video_type);
return false;
}
if (!is_root && !base::FeatureList::IsEnabled(
features::kDirectCompositionNonrootOverlays)) {
RecordDCLayerResult(DC_LAYER_FAILED_NON_ROOT,
dc_layer->protected_video_type);
return false;
}
if (it->shared_quad_state->opacity < 1.0f) {
RecordDCLayerResult(DC_LAYER_FAILED_TRANSPARENT,
dc_layer->protected_video_type);
return false;
}
// Record this UMA only after we're absolutely sure this quad could be an
// underlay.
if (processed_overlay_in_frame_) {
RecordDCLayerResult(DC_LAYER_FAILED_TOO_MANY_OVERLAYS,
dc_layer->protected_video_type);
return false;
}
}
// TODO(magchen): Assign decreasing z-order so that underlays processed // TODO(magchen): Assign decreasing z-order so that underlays processed
// earlier, and hence which are above the subsequent underlays, are placed // earlier, and hence which are above the subsequent underlays, are placed
// above in the direct composition visual tree. // above in the direct composition visual tree.
...@@ -505,8 +541,9 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay( ...@@ -505,8 +541,9 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay(
bool is_axis_aligned = bool is_axis_aligned =
shared_quad_state->quad_to_target_transform.Preserves2dAxisAlignment(); shared_quad_state->quad_to_target_transform.Preserves2dAxisAlignment();
if (is_root && !processed_overlay_in_frame_ && is_axis_aligned && is_opaque && if (is_root && current_frame_processed_overlay_count_ == 0 &&
!underlay_rect_changed && !display_rect_changed) { is_axis_aligned && is_opaque && !underlay_rect_changed &&
!display_rect_changed) {
// If this underlay rect is the same as for last frame, subtract its area // If this underlay rect is the same as for last frame, subtract its area
// from the damage of the main surface, as the cleared area was already // from the damage of the main surface, as the cleared area was already
// cleared last frame. Add back the damage from the occluded area for this // cleared last frame. Add back the damage from the occluded area for this
...@@ -533,13 +570,16 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay( ...@@ -533,13 +570,16 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay(
// Entire replacement quad must be redrawn. // Entire replacement quad must be redrawn.
// TODO(sunnyps): We should avoid this extra damage if we knew that the // TODO(sunnyps): We should avoid this extra damage if we knew that the
// video was the only thing damaging this render surface. // video was the only thing damaging this render surface.
// TODO(magchen): non-root quad_rectangle should be transformed to root
// target space
damage_rect->Union(quad_rectangle); damage_rect->Union(quad_rectangle);
} }
// We only compare current frame's first root pass underlay with the previous // We only compare current frame's first root pass underlay with the previous
// frame's first root pass underlay. Non-opaque regions can have different // frame's first root pass underlay. Non-opaque regions can have different
// alpha from one frame to another so this optimization doesn't work. // alpha from one frame to another so this optimization doesn't work.
if (is_root && !processed_overlay_in_frame_ && is_axis_aligned && is_opaque) { if (is_root && current_frame_processed_overlay_count_ == 0 &&
is_axis_aligned && is_opaque) {
*this_frame_underlay_rect = quad_rectangle; *this_frame_underlay_rect = quad_rectangle;
*this_frame_underlay_occlusion = *this_frame_underlay_occlusion =
gfx::ToEnclosingRect(occlusion_bounding_box); gfx::ToEnclosingRect(occlusion_bounding_box);
...@@ -550,8 +590,6 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay( ...@@ -550,8 +590,6 @@ bool DCLayerOverlayProcessor::ProcessForUnderlay(
// RPDQ target (parent render pass) in ProcessRenderPassDrawQuad(). // RPDQ target (parent render pass) in ProcessRenderPassDrawQuad().
pass_punch_through_rects_[render_pass->id].push_back( pass_punch_through_rects_[render_pass->id].push_back(
gfx::ToEnclosingRect(ClippedQuadRectangle(*it))); gfx::ToEnclosingRect(ClippedQuadRectangle(*it)));
return true;
} }
} // namespace viz } // namespace viz
...@@ -75,14 +75,15 @@ class DCLayerOverlayProcessor { ...@@ -75,14 +75,15 @@ class DCLayerOverlayProcessor {
void Process(DisplayResourceProvider* resource_provider, void Process(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect, const gfx::RectF& display_rect,
RenderPassList* render_passes, RenderPassList* render_passes,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
DCLayerOverlayList* dc_layer_overlays); DCLayerOverlayList* dc_layer_overlays);
void ClearOverlayState() { void ClearOverlayState();
previous_frame_underlay_rect_ = gfx::Rect();
previous_frame_underlay_occlusion_ = gfx::Rect();
}
void SetHasHwOverlaySupport() { has_hw_overlay_support_ = true; } void SetHasHwOverlaySupport() { has_hw_overlay_support_ = true; }
// This is the damage contribution due to previous frame's overlays which can
// be empty.
gfx::Rect previous_frame_overlay_damage_contribution() {
return previous_frame_overlay_rect_union_;
}
private: private:
// Returns an iterator to the element after |it|. // Returns an iterator to the element after |it|.
...@@ -94,16 +95,14 @@ class DCLayerOverlayProcessor { ...@@ -94,16 +95,14 @@ class DCLayerOverlayProcessor {
const gfx::RectF& display_rect, const gfx::RectF& display_rect,
RenderPass* render_pass, RenderPass* render_pass,
bool is_root, bool is_root,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
DCLayerOverlayList* dc_layer_overlays); DCLayerOverlayList* dc_layer_overlays);
bool ProcessForOverlay(const gfx::RectF& display_rect, void ProcessForOverlay(const gfx::RectF& display_rect,
QuadList* quad_list, QuadList* quad_list,
const gfx::Rect& quad_rectangle, const gfx::Rect& quad_rectangle,
const gfx::RectF& occlusion_bounding_box,
QuadList::Iterator* it, QuadList::Iterator* it,
gfx::Rect* damage_rect); gfx::Rect* damage_rect);
bool ProcessForUnderlay(const gfx::RectF& display_rect, void ProcessForUnderlay(const gfx::RectF& display_rect,
RenderPass* render_pass, RenderPass* render_pass,
const gfx::Rect& quad_rectangle, const gfx::Rect& quad_rectangle,
const gfx::RectF& occlusion_bounding_box, const gfx::RectF& occlusion_bounding_box,
...@@ -118,7 +117,11 @@ class DCLayerOverlayProcessor { ...@@ -118,7 +117,11 @@ class DCLayerOverlayProcessor {
gfx::Rect previous_frame_underlay_rect_; gfx::Rect previous_frame_underlay_rect_;
gfx::Rect previous_frame_underlay_occlusion_; gfx::Rect previous_frame_underlay_occlusion_;
gfx::RectF previous_display_rect_; gfx::RectF previous_display_rect_;
bool processed_overlay_in_frame_ = false; // previous and current overlay_rect_union_ include both overlay and underlay
gfx::Rect previous_frame_overlay_rect_union_;
gfx::Rect current_frame_overlay_rect_union_;
int previous_frame_processed_overlay_count_ = 0;
int current_frame_processed_overlay_count_ = 0;
bool has_hw_overlay_support_ = true; bool has_hw_overlay_support_ = true;
// Store information about clipped punch-through rects in target space for // Store information about clipped punch-through rects in target space for
......
...@@ -109,9 +109,9 @@ bool OverlayProcessor::ProcessForDCLayers( ...@@ -109,9 +109,9 @@ bool OverlayProcessor::ProcessForDCLayers(
if (!overlay_validator || !overlay_validator->AllowDCLayerOverlays()) if (!overlay_validator || !overlay_validator->AllowDCLayerOverlays())
return false; return false;
dc_processor_.Process( dc_processor_.Process(resource_provider,
resource_provider, gfx::RectF(render_passes->back()->output_rect), gfx::RectF(render_passes->back()->output_rect),
render_passes, &overlay_damage_rect_, damage_rect, dc_layer_overlays); render_passes, damage_rect, dc_layer_overlays);
DCHECK(overlay_candidates->empty()); DCHECK(overlay_candidates->empty());
return true; return true;
...@@ -150,7 +150,12 @@ void OverlayProcessor::ProcessForOverlays( ...@@ -150,7 +150,12 @@ void OverlayProcessor::ProcessForOverlays(
// CALayers because the framebuffer would be missing the removed quads' // CALayers because the framebuffer would be missing the removed quads'
// contents. // contents.
if (!render_pass->copy_requests.empty()) { if (!render_pass->copy_requests.empty()) {
damage_rect->Union(
dc_processor_.previous_frame_overlay_damage_contribution());
// Update damage rect before calling ClearOverlayState, otherwise
// previous_frame_overlay_rect_union will be empty.
dc_processor_.ClearOverlayState(); dc_processor_.ClearOverlayState();
return; return;
} }
......
...@@ -2455,7 +2455,89 @@ TEST_F(DCLayerOverlayTest, Occluded) { ...@@ -2455,7 +2455,89 @@ TEST_F(DCLayerOverlayTest, Occluded) {
// The underlay rectangle is the same, so the damage for first video quad is // The underlay rectangle is the same, so the damage for first video quad is
// contained within the combined occluding rects for this and the last // contained within the combined occluding rects for this and the last
// frame. Second video quad also adds its damage. // frame. Second video quad also adds its damage.
EXPECT_EQ(gfx::Rect(1, 2, 255, 254), damage_rect_);
// This is calculated by carving out the underlay rect size from the
// damage_rect, adding back the quads on top and then the overlay/underlay
// rects from the previous frame. The damage rect carried over from the
// revious frame with multiple overlays cannot be skipped.
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
// Non-occluding quad fully outside video rect
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
// Underlay video quad
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 210, 20, 20);
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, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// All rects must be redrawn at the first frame.
EXPECT_EQ(gfx::Rect(0, 0, 230, 230), damage_rect_);
}
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
// Non-occluding quad fully outside video rect
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
// Underlay video quad
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 210, 20, 20);
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, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Only the non-overlay damaged rect need to be drawn by the gl compositor
EXPECT_EQ(gfx::Rect(210, 210, 20, 20), damage_rect_);
} }
} }
...@@ -2584,8 +2666,10 @@ TEST_F(DCLayerOverlayTest, MultiplePassDamageRect) { ...@@ -2584,8 +2666,10 @@ TEST_F(DCLayerOverlayTest, MultiplePassDamageRect) {
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), pass_list[0]->damage_rect); EXPECT_EQ(gfx::Rect(0, 0, 256, 256), pass_list[0]->damage_rect);
EXPECT_EQ(gfx::Rect(), pass_list[1]->damage_rect); EXPECT_EQ(gfx::Rect(), pass_list[1]->damage_rect);
EXPECT_EQ(gfx::Rect(0, 100, 256, 156), root_damage_rect); EXPECT_EQ(gfx::Rect(0, 100, 256, 156), root_damage_rect);
// Overlay damage handling is done entirely within DCOverlayProcessor so this
// is expected to return an empty rect
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage(); gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(gfx::Rect(0, 100, 256, 256), overlay_damage); EXPECT_EQ(gfx::Rect(0, 0, 0, 0), overlay_damage);
EXPECT_EQ(1u, pass_list[0]->quad_list.size()); EXPECT_EQ(1u, pass_list[0]->quad_list.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, EXPECT_EQ(DrawQuad::SOLID_COLOR,
......
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