summaryrefslogtreecommitdiffstats
path: root/cc/output
diff options
context:
space:
mode:
authorwatk <watk@chromium.org>2015-12-04 14:07:29 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-04 22:09:09 +0000
commit9376c6a675cfa73d3eb99a92ee2fcabd171c04c9 (patch)
tree6076d4db4f03ba5d427ea95c80004507c21d5248 /cc/output
parentac85fc2969f2c11c78aad8c3911123c05d831197 (diff)
downloadchromium_src-9376c6a675cfa73d3eb99a92ee2fcabd171c04c9.zip
chromium_src-9376c6a675cfa73d3eb99a92ee2fcabd171c04c9.tar.gz
chromium_src-9376c6a675cfa73d3eb99a92ee2fcabd171c04c9.tar.bz2
OverlayProcessor subtracts damage by underlay planes if possible
Previously it wasn't possible for the OverlayProcessor to change the damage rect when it scheduled something as an underlay. Now it saves the visible rect each time an underlay is scheduled. If the next frame also has an underlay it checks whether: a) the underlay visible rect matches that of the previous frame, and b) there are no visible quads on top of it. When both are true, the framebuffer will have a hole in the right place, and doesn't need to be redrawn. It's important to note that this relies on the OverlayProcess knowing about each frame, so it can reason about the state of the framebuffer. For this, a new SkipProcessForOverlays() lets the Processor know that it should reset the saved visible rect. BUG=533630 TEST=cc_unittests CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel Review URL: https://codereview.chromium.org/1434913003 Cr-Commit-Position: refs/heads/master@{#363306}
Diffstat (limited to 'cc/output')
-rw-r--r--cc/output/direct_renderer.cc4
-rw-r--r--cc/output/overlay_candidate.cc18
-rw-r--r--cc/output/overlay_candidate.h11
-rw-r--r--cc/output/overlay_processor.cc55
-rw-r--r--cc/output/overlay_processor.h11
-rw-r--r--cc/output/overlay_strategy_single_on_top.cc12
-rw-r--r--cc/output/overlay_strategy_underlay.cc2
-rw-r--r--cc/output/overlay_unittest.cc121
8 files changed, 188 insertions, 46 deletions
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 600805a..a55564f 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -245,7 +245,9 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
break;
}
}
- if (!has_copy_requests) {
+ if (has_copy_requests) {
+ overlay_processor_->SkipProcessForOverlays();
+ } else {
overlay_processor_->ProcessForOverlays(
resource_provider_, render_passes_in_draw_order, &frame.overlay_list,
&frame.ca_layer_overlay_list, &frame.root_damage_rect);
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 658f153..367f316 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -175,6 +175,7 @@ OverlayCandidate::OverlayCandidate()
use_output_surface_for_resource(false),
resource_id(0),
plane_z_order(0),
+ is_unoccluded(false),
overlay_handled(false) {}
OverlayCandidate::~OverlayCandidate() {}
@@ -228,6 +229,23 @@ bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) {
}
// static
+bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end) {
+ // Check that no visible quad overlaps the candidate.
+ for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
+ ++overlap_iter) {
+ gfx::RectF overlap_rect = MathUtil::MapClippedRect(
+ overlap_iter->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(overlap_iter->rect));
+ if (candidate.display_rect.Intersects(overlap_rect) &&
+ !OverlayCandidate::IsInvisibleQuad(*overlap_iter))
+ return true;
+ }
+ return false;
+}
+
+// static
bool OverlayCandidate::FromTextureQuad(ResourceProvider* resource_provider,
const TextureDrawQuad* quad,
OverlayCandidate* candidate) {
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index aa42ba1..1a73561 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -8,6 +8,7 @@
#include <vector>
#include "cc/base/cc_export.h"
+#include "cc/quads/render_pass.h"
#include "cc/resources/resource_format.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -38,6 +39,12 @@ class CC_EXPORT OverlayCandidate {
// an overlay.
static bool IsInvisibleQuad(const DrawQuad* quad);
+ // Returns true if any any of the quads in the list given by |quad_list_begin|
+ // and |quad_list_end| are visible and on top of |candidate|.
+ static bool IsOccluded(const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end);
+
OverlayCandidate();
~OverlayCandidate();
@@ -66,6 +73,10 @@ class CC_EXPORT OverlayCandidate {
// Stacking order of the overlay plane relative to the main surface,
// which is 0. Signed to allow for "underlays".
int plane_z_order;
+ // True if the overlay does not have any visible quads on top of it. Set by
+ // the strategy so the OverlayProcessor can consider subtracting damage caused
+ // by underlay quads.
+ bool is_unoccluded;
// To be modified by the implementer if this candidate can go into
// an overlay.
diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc
index 40d6da6..74e68d2 100644
--- a/cc/output/overlay_processor.cc
+++ b/cc/output/overlay_processor.cc
@@ -76,23 +76,48 @@ void OverlayProcessor::ProcessForOverlays(ResourceProvider* resource_provider,
if (!strategy->Attempt(resource_provider, render_passes, candidates))
continue;
- // Subtract on-top overlays from the damage rect, unless the overlays use
- // the backbuffer as their content (in which case, add their combined rect
- // back to the damage at the end).
- gfx::Rect output_surface_overlay_damage_rect;
- for (const OverlayCandidate& overlay : *candidates) {
- if (overlay.plane_z_order > 0) {
- const gfx::Rect overlay_display_rect =
- ToEnclosedRect(overlay.display_rect);
- overlay_damage_rect_.Union(overlay_display_rect);
- damage_rect->Subtract(overlay_display_rect);
- if (overlay.use_output_surface_for_resource)
- output_surface_overlay_damage_rect.Union(overlay_display_rect);
- }
- }
- damage_rect->Union(output_surface_overlay_damage_rect);
+ UpdateDamageRect(candidates, damage_rect);
return;
}
}
+void OverlayProcessor::SkipProcessForOverlays() {
+ // If overlay processing was skipped for a frame there's no way to be sure
+ // of the state of the previous frame, so reset.
+ previous_frame_underlay_rect_ = gfx::Rect();
+}
+
+// Subtract on-top overlays from the damage rect, unless the overlays use
+// the backbuffer as their content (in which case, add their combined rect
+// back to the damage at the end).
+// Also subtract unoccluded underlays from the damage rect if we know that the
+// same underlay was scheduled on the previous frame. If the renderer decides
+// not to swap the framebuffer there will still be a transparent hole in the
+// previous frame. This only handles the common case of a single underlay quad
+// for fullscreen video.
+void OverlayProcessor::UpdateDamageRect(OverlayCandidateList* candidates,
+ gfx::Rect* damage_rect) {
+ gfx::Rect output_surface_overlay_damage_rect;
+ gfx::Rect this_frame_underlay_rect;
+ for (const OverlayCandidate& overlay : *candidates) {
+ if (overlay.plane_z_order > 0) {
+ const gfx::Rect overlay_display_rect =
+ ToEnclosedRect(overlay.display_rect);
+ overlay_damage_rect_.Union(overlay_display_rect);
+ damage_rect->Subtract(overlay_display_rect);
+ if (overlay.use_output_surface_for_resource)
+ output_surface_overlay_damage_rect.Union(overlay_display_rect);
+ } else if (overlay.plane_z_order < 0 && overlay.is_unoccluded &&
+ this_frame_underlay_rect.IsEmpty()) {
+ this_frame_underlay_rect = ToEnclosedRect(overlay.display_rect);
+ }
+ }
+
+ if (this_frame_underlay_rect == previous_frame_underlay_rect_)
+ damage_rect->Subtract(this_frame_underlay_rect);
+ previous_frame_underlay_rect_ = this_frame_underlay_rect;
+
+ damage_rect->Union(output_surface_overlay_damage_rect);
+}
+
} // namespace cc
diff --git a/cc/output/overlay_processor.h b/cc/output/overlay_processor.h
index f348fb8..8f3704c 100644
--- a/cc/output/overlay_processor.h
+++ b/cc/output/overlay_processor.h
@@ -24,9 +24,7 @@ class CC_EXPORT OverlayProcessor {
// Returns false if the strategy cannot be made to work with the
// current set of render passes. Returns true if the strategy was successful
// and adds any additional passes necessary to represent overlays to
- // |render_passes|. Strategy can also optimize |damage_rect| as it seems
- // fit to reduce GL composition, in case |damage_rect| is obscured by
- // overlays.
+ // |render_passes|.
virtual bool Attempt(ResourceProvider* resource_provider,
RenderPassList* render_passes,
OverlayCandidateList* candidates) = 0;
@@ -46,10 +44,14 @@ class CC_EXPORT OverlayProcessor {
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect);
+ // Notify the processor that ProcessForOverlays is being skipped this frame.
+ void SkipProcessForOverlays();
+
protected:
StrategyList strategies_;
OutputSurface* surface_;
gfx::Rect overlay_damage_rect_;
+ gfx::Rect previous_frame_underlay_rect_;
private:
bool ProcessForCALayers(ResourceProvider* resource_provider,
@@ -57,6 +59,9 @@ class CC_EXPORT OverlayProcessor {
OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect);
+ // Update |damage_rect| by removing damage casued by |candidates|.
+ void UpdateDamageRect(OverlayCandidateList* candidates,
+ gfx::Rect* damage_rect);
DISALLOW_COPY_AND_ASSIGN(OverlayProcessor);
};
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 78e5bf9..10ffcef 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -40,15 +40,9 @@ bool OverlayStrategySingleOnTop::TryOverlay(
const OverlayCandidate& candidate,
QuadList::Iterator candidate_iterator) {
// Check that no prior quads overlap it.
- for (auto overlap_iter = quad_list->cbegin();
- overlap_iter != candidate_iterator; ++overlap_iter) {
- gfx::RectF overlap_rect = MathUtil::MapClippedRect(
- overlap_iter->shared_quad_state->quad_to_target_transform,
- gfx::RectF(overlap_iter->rect));
- if (candidate.display_rect.Intersects(overlap_rect) &&
- !OverlayCandidate::IsInvisibleQuad(*overlap_iter))
- return false;
- }
+ if (OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(),
+ candidate_iterator))
+ return false;
// Add the overlay.
OverlayCandidateList new_candidate_list = *candidate_list;
diff --git a/cc/output/overlay_strategy_underlay.cc b/cc/output/overlay_strategy_underlay.cc
index 9a8a362..f9bb039 100644
--- a/cc/output/overlay_strategy_underlay.cc
+++ b/cc/output/overlay_strategy_underlay.cc
@@ -38,6 +38,8 @@ bool OverlayStrategyUnderlay::Attempt(ResourceProvider* resource_provider,
// If the candidate can be handled by an overlay, create a pass for it. We
// need to switch out the video quad with a black transparent one.
if (new_candidate_list.back().overlay_handled) {
+ new_candidate_list.back().is_unoccluded =
+ !OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it);
const SharedQuadState* shared_quad_state = it->shared_quad_state;
gfx::Rect rect = it->visible_rect;
SolidColorDrawQuad* replacement =
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 5d1b05f..7974297 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1360,7 +1360,8 @@ TEST_F(UnderlayTest, AllowOnTop) {
EXPECT_EQ(pass_list[0]->quad_list.front()->material, DrawQuad::SOLID_COLOR);
}
-TEST_F(UnderlayTest, DamageRect) {
+// The first time an underlay is scheduled its damage must not be subtracted.
+TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
@@ -1368,30 +1369,114 @@ TEST_F(UnderlayTest, DamageRect) {
damage_rect_ = kOverlayRect;
- // Add something behind it.
- CreateFullscreenOpaqueQuad(resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
- CreateFullscreenOpaqueQuad(resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
-
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
- // Check for potential candidates.
OverlayCandidateList candidate_list;
-
- // Primary plane.
- OverlayCandidate output_surface_plane;
- output_surface_plane.display_rect = gfx::RectF(kOverlayRect);
- output_surface_plane.quad_rect_in_target_space = kOverlayRect;
- output_surface_plane.use_output_surface_for_resource = true;
- output_surface_plane.overlay_handled = true;
- candidate_list.push_back(output_surface_plane);
-
overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
&candidate_list, nullptr,
&damage_rect_);
- DCHECK(!damage_rect_.IsEmpty());
+
+ EXPECT_EQ(kOverlayRect, damage_rect_);
+}
+
+// An identical underlay for two frames in a row means the damage can be
+// subtracted the second time.
+TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+
+ damage_rect_ = kOverlayRect;
+
+ // Add something behind it.
+ CreateFullscreenOpaqueQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+ &candidate_list, nullptr,
+ &damage_rect_);
+ }
+
+ // The second time the same overlay rect is scheduled it will be subtracted
+ // from the damage rect.
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+}
+
+// Underlay damage can only be subtracted if the previous frame's underlay
+// was the same rect.
+TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
+ gfx::Rect overlay_rects[] = {kOverlayBottomRightRect, kOverlayRect};
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ overlay_rects[i]);
+
+ damage_rect_ = overlay_rects[i];
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+ &candidate_list, nullptr,
+ &damage_rect_);
+
+ EXPECT_EQ(overlay_rects[i], damage_rect_);
+ }
+}
+
+TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ // Add an overlapping quad above the candidate.
+ CreateFullscreenOpaqueQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get());
+ CreateFullscreenCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+
+ damage_rect_ = kOverlayRect;
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+ &candidate_list, nullptr,
+ &damage_rect_);
+ }
+
+ EXPECT_EQ(kOverlayRect, damage_rect_);
+}
+
+TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ // Add a non-overlapping quad above the candidate.
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayTopLeftRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
+
+ damage_rect_ = kOverlayBottomRightRect;
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+ &candidate_list, nullptr,
+ &damage_rect_);
+ }
+
+ EXPECT_TRUE(damage_rect_.IsEmpty());
}
OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) {