Commit 1ceb0793 authored by Dongseong Hwang's avatar Dongseong Hwang Committed by Commit Bot

Reland "viz: Turn off or crop primary plane when possible"

This is a reland of I7946d7acab334bffdf2bb49a1d9c424cf46fc610 and
the following bug fixes as follows;
"viz: Fix wrong uv_rect calculation" 4bf9d01d
"viz: add unittests for CL:1291590" f8dfbe74

Additional fix:
- Fix the flickering issue because of primary |uv_rect| cropping even though
an overlay attemption fails mainly due to limited pixel rate (e.g. 4k video).
- Fix wrong |uv_rect| calculation which causes atomic page flip failures with
"No space left on device (28)" error.

Original change's description:
> viz: Turn off or crop primary plane when possible
>
> For many fullscreen cases, the rest of the renderpass quads are solid
> black quads. In that case, we can turn off the primary plane, and not
> having to scan out an full screen of black pixels saves a good deal of
> power. In other cases, we can crop down the primary plane down to the
> content rectangle (youtube channel logo, for example) and save power.
>
> Averaging battery draw measurement over about a minute of play back
> for a fullscreen youtube video, power savings for soraka is around
> 500mW (6.5W to 6.0W) and 300mW for kevin (4.4W to 4.1W), when we
> turn off the primary plane.
>
> Change-Id: I7946d7acab334bffdf2bb49a1d9c424cf46fc610
> Reviewed-on: https://chromium-review.googlesource.com/c/1045256
> Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
> Reviewed-by: Dongseong Hwang <dongseong.hwang@intel.com>
> Commit-Queue: Kristian H. Kristensen <hoegsberg@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#600415}

TEST=SingleOverlayOnTopTest.AllowVideoNormalTransformWithOutputSurfaceOverlay

Bug: 896945, 900373
Change-Id: I88db118dbc3ca2fed8c8eaf1f9a4337cdae12990
Reviewed-on: https://chromium-review.googlesource.com/c/1346997
Commit-Queue: Dongseong Hwang <dongseong.hwang@intel.com>
Reviewed-by: default avatarDongseong Hwang <dongseong.hwang@intel.com>
Reviewed-by: default avatarKristian H. Kristensen <hoegsberg@chromium.org>
Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611484}
parent 8fa2c3d0
......@@ -4152,10 +4152,6 @@ TEST_F(GLRendererWithGpuFenceTest, GpuFenceIdIsUsedWithoutRootRenderPass) {
flipped, nearest_neighbor,
/*secure_output_only=*/false, ui::ProtectedVideoType::kClear);
EXPECT_CALL(overlay_scheduler,
Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, kSurfaceOverlayTextureId,
gfx::Rect(viewport_size), _, _, kGpuFenceId))
.Times(1);
EXPECT_CALL(overlay_scheduler,
Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _,
gfx::Rect(viewport_size), _, _, kGpuFenceId))
......
......@@ -9,6 +9,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.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/display_resource_provider.h"
#include "components/viz/service/display/output_surface.h"
......@@ -251,4 +252,61 @@ void OverlayProcessor::UpdateDamageRect(
damage_rect->Union(output_surface_overlay_damage_rect);
}
namespace {
bool DiscardableQuad(const DrawQuad* q) {
float opacity = q->shared_quad_state->opacity;
if (opacity < std::numeric_limits<float>::epsilon())
return true;
if (q->material == DrawQuad::SOLID_COLOR) {
if (SolidColorDrawQuad::MaterialCast(q)->color == SK_ColorBLACK ||
SolidColorDrawQuad::MaterialCast(q)->color == SK_ColorTRANSPARENT)
return true;
const SkColor color = SolidColorDrawQuad::MaterialCast(q)->color;
const float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
return q->ShouldDrawWithBlending() &&
alpha < std::numeric_limits<float>::epsilon();
}
return false;
}
} // namespace
// static
void OverlayProcessor::EliminateOrCropPrimary(
const QuadList& quad_list,
const QuadList::Iterator& candidate_iterator,
OverlayCandidate* primary,
OverlayCandidateList* candidate_list) {
gfx::RectF content_rect;
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
if (it == candidate_iterator)
continue;
if (!DiscardableQuad(*it)) {
auto& transform = it->shared_quad_state->quad_to_target_transform;
gfx::RectF display_rect = gfx::RectF(it->rect);
transform.TransformRect(&display_rect);
content_rect.Union(display_rect);
}
}
if (!content_rect.IsEmpty()) {
// Sometimes the content quads extend past primary->display_rect, so first
// clip the content_rect to that.
content_rect.Intersect(primary->display_rect);
DCHECK_NE(0, primary->display_rect.width());
DCHECK_NE(0, primary->display_rect.height());
primary->uv_rect = gfx::ScaleRect(
content_rect, 1. / primary->resource_size_in_pixels.width(),
1. / primary->resource_size_in_pixels.height());
primary->display_rect = content_rect;
candidate_list->push_back(*primary);
}
}
} // namespace viz
......@@ -79,6 +79,15 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
gfx::Rect* damage_rect,
std::vector<gfx::Rect>* content_bounds);
// Determine if we can eliminate (all remaining quads are black or
// transparent) or crop (non-black content is a small sub-rectangle) the
// primary framebuffer.
static void EliminateOrCropPrimary(
const QuadList& quad_list,
const QuadList::Iterator& candidate_iterator,
OverlayCandidate* primary,
OverlayCandidateList* candidate_list);
protected:
StrategyList strategies_;
OutputSurface* surface_;
......
......@@ -44,29 +44,25 @@ bool OverlayStrategySingleOnTop::Attempt(
if (best_quad_it == quad_list->end())
return false;
if (TryOverlay(quad_list, candidate_list, best_candidate, best_quad_it))
return true;
return false;
}
OverlayCandidateList new_candidate_list;
if (candidate_list->size() == 1) {
OverlayCandidate primary(candidate_list->back());
OverlayProcessor::EliminateOrCropPrimary(*quad_list, best_quad_it, &primary,
&new_candidate_list);
} else {
new_candidate_list = *candidate_list;
}
bool OverlayStrategySingleOnTop::TryOverlay(
QuadList* quad_list,
OverlayCandidateList* candidate_list,
const OverlayCandidate& candidate,
QuadList::Iterator candidate_iterator) {
// Add the overlay.
OverlayCandidateList new_candidate_list = *candidate_list;
new_candidate_list.push_back(candidate);
new_candidate_list.push_back(best_candidate);
new_candidate_list.back().plane_z_order = 1;
// Check for support.
capability_checker_->CheckOverlaySupport(&new_candidate_list);
const OverlayCandidate& overlay_candidate = new_candidate_list.back();
// If the candidate can be handled by an overlay, create a pass for it.
if (overlay_candidate.overlay_handled) {
quad_list->EraseAndInvalidateAllPointers(candidate_iterator);
if (new_candidate_list.back().overlay_handled) {
quad_list->EraseAndInvalidateAllPointers(best_quad_it);
candidate_list->swap(new_candidate_list);
return true;
}
......
......@@ -57,11 +57,19 @@ bool OverlayStrategyUnderlay::Attempt(
continue;
}
OverlayCandidateList new_candidate_list;
if (candidate_list->size() == 1) {
OverlayCandidate primary(candidate_list->back());
primary.is_opaque = false;
OverlayProcessor::EliminateOrCropPrimary(quad_list, it, &primary,
&new_candidate_list);
} else {
new_candidate_list = *candidate_list;
}
// Add the overlay.
OverlayCandidateList new_candidate_list = *candidate_list;
new_candidate_list.push_back(candidate);
new_candidate_list.back().plane_z_order = -1;
new_candidate_list.front().is_opaque = false;
// Check for support.
capability_checker_->CheckOverlaySupport(&new_candidate_list);
......
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