Commit a2bc3fd7 authored by Maggie Chen's avatar Maggie Chen Committed by Commit Bot

Skip overlay if there are more than one videos in a frame.

For Windows 10 only.
We only promote one YUV overlay even if there are more than one YUV
quads in a frame. We might not save power if the rest of YUV quads are
drawn in the Renderer by 3D hardware.
The previous overlay strategy that promotes the quad with the biggest
pixel size is removed.

Bug: 1117240
Change-Id: Id729e5d8af842682528c2dcb9d0e70e4f49fea66
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2362084
Commit-Queue: Maggie Chen <magchen@chromium.org>
Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799958}
parent 7f2e75d0
...@@ -217,8 +217,10 @@ void FromTextureQuad(const TextureDrawQuad* quad, ...@@ -217,8 +217,10 @@ void FromTextureQuad(const TextureDrawQuad* quad,
// all configurations, RequiresOverlay() will be true for all protected video. // all configurations, RequiresOverlay() will be true for all protected video.
bool RequiresOverlay(const QuadList::Iterator& it) { bool RequiresOverlay(const QuadList::Iterator& it) {
if (it->material == DrawQuad::Material::kYuvVideoContent && if (it->material == DrawQuad::Material::kYuvVideoContent &&
YUVVideoDrawQuad::MaterialCast(*it)->protected_video_type == (YUVVideoDrawQuad::MaterialCast(*it)->protected_video_type ==
gfx::ProtectedVideoType::kHardwareProtected) { gfx::ProtectedVideoType::kHardwareProtected ||
YUVVideoDrawQuad::MaterialCast(*it)->protected_video_type ==
gfx::ProtectedVideoType::kSoftwareProtected)) {
return true; return true;
} else if (it->material == DrawQuad::Material::kTextureContent) { } else if (it->material == DrawQuad::Material::kTextureContent) {
return true; return true;
...@@ -401,11 +403,6 @@ void DCLayerOverlayProcessor::Process( ...@@ -401,11 +403,6 @@ void DCLayerOverlayProcessor::Process(
gfx::Rect this_frame_overlay_rect; gfx::Rect this_frame_overlay_rect;
gfx::Rect this_frame_underlay_rect; gfx::Rect this_frame_underlay_rect;
int candidate_rect_area = 0;
gfx::Rect candidate_quad_rectangle_in_target_space;
gfx::Rect candidate_occluding_damage_rect;
bool candidate_is_overlay = false;
// Which render passes have backdrop filters. // Which render passes have backdrop filters.
base::flat_set<RenderPassId> render_pass_has_backdrop_filters; base::flat_set<RenderPassId> render_pass_has_backdrop_filters;
for (const auto& render_pass : *render_pass_list) { for (const auto& render_pass : *render_pass_list) {
...@@ -423,15 +420,21 @@ void DCLayerOverlayProcessor::Process( ...@@ -423,15 +420,21 @@ void DCLayerOverlayProcessor::Process(
DCHECK_GT(render_pass_list->size(), 1u); DCHECK_GT(render_pass_list->size(), 1u);
root_render_pass = (*render_pass_list)[render_pass_list->size() - 2].get(); root_render_pass = (*render_pass_list)[render_pass_list->size() - 2].get();
} }
// Used for generating the candidate index list.
QuadList* quad_list = &root_render_pass->quad_list; QuadList* quad_list = &root_render_pass->quad_list;
auto candidate_it = quad_list->begin(); std::vector<size_t> candidate_index_list;
auto next_it = quad_list->begin(); size_t index = 0;
for (auto it = quad_list->begin(); it != quad_list->end(); it = next_it) {
// next_it may be modified inside the loop if methods modify the quad list // Used for looping through candidate_index_list to UpdateDCLayerOverlays()
// and invalidate iterators to it. size_t prev_index = 0;
next_it = it; auto prev_it = quad_list->begin();
++next_it;
// Used for whether overlay should be skipped
int yuv_quads_in_quad_list = 0;
bool has_required_overlays = false;
for (auto it = quad_list->begin(); it != quad_list->end(); ++it, ++index) {
if (it->material == DrawQuad::Material::kRenderPass) { if (it->material == DrawQuad::Material::kRenderPass) {
const RenderPassDrawQuad* rpdq = RenderPassDrawQuad::MaterialCast(*it); const RenderPassDrawQuad* rpdq = RenderPassDrawQuad::MaterialCast(*it);
if (render_pass_has_backdrop_filters.count(rpdq->render_pass_id)) { if (render_pass_has_backdrop_filters.count(rpdq->render_pass_id)) {
...@@ -444,10 +447,11 @@ void DCLayerOverlayProcessor::Process( ...@@ -444,10 +447,11 @@ void DCLayerOverlayProcessor::Process(
DCLayerResult result; DCLayerResult result;
switch (it->material) { switch (it->material) {
case DrawQuad::Material::kYuvVideoContent: case DrawQuad::Material::kYuvVideoContent:
result = ValidateYUVQuad(YUVVideoDrawQuad::MaterialCast(*it), result =
backdrop_filter_rects, has_overlay_support_, ValidateYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
current_frame_processed_overlay_count_, backdrop_filter_rects, has_overlay_support_,
resource_provider); candidate_index_list.size(), resource_provider);
yuv_quads_in_quad_list++;
break; break;
case DrawQuad::Material::kTextureContent: case DrawQuad::Material::kTextureContent:
result = ValidateTextureQuad(TextureDrawQuad::MaterialCast(*it), result = ValidateTextureQuad(TextureDrawQuad::MaterialCast(*it),
...@@ -461,6 +465,33 @@ void DCLayerOverlayProcessor::Process( ...@@ -461,6 +465,33 @@ void DCLayerOverlayProcessor::Process(
RecordDCLayerResult(result, it); RecordDCLayerResult(result, it);
continue; continue;
} }
const bool requires_overlay = RequiresOverlay(it);
if (requires_overlay)
has_required_overlays = true;
if (candidate_index_list.size() == 0) {
prev_index = index;
prev_it = it;
}
candidate_index_list.push_back(index);
}
// We might not save power if there are more than one videos and only
// one is promoted to overlay. Skip overlay for this frame.
if (candidate_index_list.size() > 0 && yuv_quads_in_quad_list > 1 &&
!has_required_overlays) {
candidate_index_list.clear();
// In this case, there is only one candidate in the list.
RecordDCLayerResult(DC_LAYER_FAILED_TOO_MANY_OVERLAYS, prev_it);
}
// Copy the overlay quad info to dc_layer_overlays and replace/delete overlay
// quads in quad_list.
for (auto index : candidate_index_list) {
auto it = std::next(prev_it, index - prev_index);
prev_it = it;
prev_index = index;
gfx::Rect quad_rectangle_in_target_space = gfx::Rect quad_rectangle_in_target_space =
gfx::ToEnclosingRect(ClippedQuadRectangle(*it)); gfx::ToEnclosingRect(ClippedQuadRectangle(*it));
...@@ -477,59 +508,20 @@ void DCLayerOverlayProcessor::Process( ...@@ -477,59 +508,20 @@ void DCLayerOverlayProcessor::Process(
const bool requires_overlay = RequiresOverlay(it); const bool requires_overlay = RequiresOverlay(it);
// Skip quad if it's an underlay and underlays are not allowed. // Skip quad if it's an underlay and underlays are not allowed.
if (!is_overlay && !requires_overlay) if (!is_overlay && !requires_overlay) {
result = IsUnderlayAllowed(it); DCLayerResult result = IsUnderlayAllowed(it);
if (result != DC_LAYER_SUCCESS) {
RecordDCLayerResult(result, it);
continue;
}
if (requires_overlay) {
// Record the DCLayer result for the previous candidate. We won't consider
// any more candidates for overlays other than required ones.
if (candidate_rect_area > 0) {
RecordDCLayerResult(DC_LAYER_FAILED_TOO_MANY_OVERLAYS, candidate_it);
candidate_rect_area = 0;
}
UpdateDCLayerOverlays( if (result != DC_LAYER_SUCCESS) {
display_rect, root_render_pass, it, quad_rectangle_in_target_space, RecordDCLayerResult(result, it);
occluding_damage_rect, is_overlay, &next_it, &this_frame_overlay_rect, continue;
&this_frame_underlay_rect, damage_rect, dc_layer_overlays);
} else {
// Defer UpdateDCLayerOverlays(). Only one overlay is allowed.
// The quad with the largest size will be sellected.
int rect_area = quad_rectangle_in_target_space.size().GetArea();
if (rect_area > candidate_rect_area) {
// Record the DCLayer result for the previous candidate.
if (candidate_rect_area)
RecordDCLayerResult(DC_LAYER_FAILED_TOO_MANY_OVERLAYS, candidate_it);
candidate_it = it;
candidate_rect_area = rect_area;
candidate_quad_rectangle_in_target_space =
quad_rectangle_in_target_space;
candidate_occluding_damage_rect = occluding_damage_rect;
candidate_is_overlay = is_overlay;
} }
} }
}
// Now update |dc_layer_overlays| after all quads in the current render pass UpdateDCLayerOverlays(display_rect, root_render_pass, it,
// have been validated. No need to promote it to overlay if there is already quad_rectangle_in_target_space, occluding_damage_rect,
// one. is_overlay, &prev_it, &prev_index,
if (candidate_rect_area && current_frame_processed_overlay_count_ == 0) { &this_frame_overlay_rect, &this_frame_underlay_rect,
// Be very careful. candidate_it is valid here only if damage_rect, dc_layer_overlays);
// |current_frame_processed_overlay_count_| == 0. If it's not 0,
// UpdateDCLayerOverlays() has been called and the old iterators might be
// invalid.
UpdateDCLayerOverlays(display_rect, root_render_pass, candidate_it,
candidate_quad_rectangle_in_target_space,
candidate_occluding_damage_rect, candidate_is_overlay,
&next_it, &this_frame_overlay_rect,
&this_frame_underlay_rect, damage_rect,
dc_layer_overlays);
} }
// Update previous frame state after processing root pass. If there is no // Update previous frame state after processing root pass. If there is no
...@@ -564,7 +556,8 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays( ...@@ -564,7 +556,8 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays(
const gfx::Rect& quad_rectangle_in_target_space, const gfx::Rect& quad_rectangle_in_target_space,
const gfx::Rect& occluding_damage_rect, const gfx::Rect& occluding_damage_rect,
bool is_overlay, bool is_overlay,
QuadList::Iterator* next_it, QuadList::Iterator* new_it,
size_t* new_index,
gfx::Rect* this_frame_overlay_rect, gfx::Rect* this_frame_overlay_rect,
gfx::Rect* this_frame_underlay_rect, gfx::Rect* this_frame_underlay_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
...@@ -607,9 +600,10 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays( ...@@ -607,9 +600,10 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays(
// TODO(sunnyps): Is the above comment correct? We seem to allow multiple // TODO(sunnyps): Is the above comment correct? We seem to allow multiple
// overlays for protected video, but don't calculate damage differently. // overlays for protected video, but don't calculate damage differently.
if (is_overlay) { if (is_overlay) {
*next_it = *new_it =
ProcessForOverlay(display_rect, render_pass, ProcessForOverlay(display_rect, render_pass,
quad_rectangle_in_target_space, it, damage_rect); quad_rectangle_in_target_space, it, damage_rect);
(*new_index)++;
*this_frame_overlay_rect = quad_rectangle_in_target_space; *this_frame_overlay_rect = quad_rectangle_in_target_space;
} else { } else {
ProcessForUnderlay(display_rect, render_pass, ProcessForUnderlay(display_rect, render_pass,
......
...@@ -108,7 +108,8 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor ...@@ -108,7 +108,8 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
const gfx::Rect& quad_rectangle_in_target_space, const gfx::Rect& quad_rectangle_in_target_space,
const gfx::Rect& occluding_damage_rect, const gfx::Rect& occluding_damage_rect,
bool is_overlay, bool is_overlay,
QuadList::Iterator* next_it, QuadList::Iterator* new_it,
size_t* new_index,
gfx::Rect* this_frame_overlay_rect, gfx::Rect* this_frame_overlay_rect,
gfx::Rect* this_frame_underlay_rect, gfx::Rect* this_frame_underlay_rect,
gfx::Rect* damage_rect, gfx::Rect* damage_rect,
......
...@@ -591,9 +591,9 @@ TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) { ...@@ -591,9 +591,9 @@ TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) {
} }
} }
// If there are multiple overlay quad candidates, the one with the largest // If there are multiple yuv overlay quad candidates, no overlay will be
// size should be promoted to overlay. // promoted to save power.
TEST_F(DCLayerOverlayTest, DifferentOverlaySizes) { TEST_F(DCLayerOverlayTest, MultipleYUVOverlay) {
base::test::ScopedFeatureList feature_list; base::test::ScopedFeatureList feature_list;
{ {
std::unique_ptr<RenderPass> pass = CreateRenderPass(); std::unique_ptr<RenderPass> pass = CreateRenderPass();
...@@ -628,13 +628,16 @@ TEST_F(DCLayerOverlayTest, DifferentOverlaySizes) { ...@@ -628,13 +628,16 @@ TEST_F(DCLayerOverlayTest, DifferentOverlaySizes) {
render_pass_filters, render_pass_backdrop_filters, nullptr, render_pass_filters, render_pass_backdrop_filters, nullptr,
&dc_layer_list, &damage_rect_, &content_bounds_); &dc_layer_list, &damage_rect_, &content_bounds_);
// Only one overlay is allowed. // Skip overlays.
EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(gfx::Rect(0, 0, 220, 220), damage_rect_); EXPECT_EQ(gfx::Rect(0, 0, 220, 220), damage_rect_);
// The second video with a larger size should be prmoted to overlay. // Check whether all 3 quads including two YUV quads are still in the render
EXPECT_EQ(second_rect, dc_layer_list.front().quad_rect); // pass
RenderPass* root_pass = pass_list.back().get();
int quad_count = root_pass->quad_list.size();
EXPECT_EQ(3, quad_count);
} }
} }
......
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