summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/layers/draw_properties.h4
-rw-r--r--cc/layers/layer_impl.cc5
-rw-r--r--cc/layers/layer_impl.h5
-rw-r--r--cc/layers/picture_layer_impl.h4
-rw-r--r--cc/layers/render_surface_impl.h9
-rw-r--r--cc/trees/layer_tree_host_impl.cc75
-rw-r--r--cc/trees/layer_tree_host_unittest_occlusion.cc743
-rw-r--r--cc/trees/layer_tree_impl.cc148
-rw-r--r--cc/trees/layer_tree_impl.h4
-rw-r--r--cc/trees/occlusion.cc12
-rw-r--r--cc/trees/occlusion.h5
-rw-r--r--cc/trees/occlusion_tracker_unittest.cc59
12 files changed, 407 insertions, 666 deletions
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 5c78000..7cf89e7 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -6,6 +6,7 @@
#define CC_LAYERS_DRAW_PROPERTIES_H_
#include "base/memory/scoped_ptr.h"
+#include "cc/trees/occlusion.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
@@ -50,6 +51,9 @@ struct CC_EXPORT DrawProperties {
// Transforms objects from content space to screen space (viewport space).
gfx::Transform screen_space_transform;
+ // Known occlusion above the layer mapped to the content space of the layer.
+ Occlusion occlusion_in_content_space;
+
// DrawProperties::opacity may be different than LayerType::opacity,
// particularly in the case when a RenderSurface re-parents the layer's
// opacity, or when opacity is compounded by the hierarchy.
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 3795bb4..6e11644 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -378,11 +378,6 @@ RenderPassId LayerImpl::NextContributingRenderPassId(RenderPassId id) const {
return RenderPassId(0, 0);
}
-bool LayerImpl::UpdateTiles(const Occlusion& occlusion_in_layer_space,
- bool resourceless_software_draw) {
- return false;
-}
-
void LayerImpl::GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const {
NOTREACHED();
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index aa8dba2..3ba68e38 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -220,11 +220,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual RenderPassId FirstContributingRenderPassId() const;
virtual RenderPassId NextContributingRenderPassId(RenderPassId id) const;
- // Updates the layer's tiles. This should return true if meaningful work was
- // done. That is, if an early-out was hit and as a result the internal state
- // of tiles didn't change, this function should return false.
- virtual bool UpdateTiles(const Occlusion& occlusion_in_layer_space,
- bool resourceless_software_draw);
virtual void NotifyTileStateChanged(const Tile* tile) {}
virtual ScrollbarLayerImplBase* ToScrollbarLayer();
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index e2dfea1..dbc3804 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -57,8 +57,6 @@ class CC_EXPORT PictureLayerImpl
void AppendQuads(RenderPass* render_pass,
const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
- bool UpdateTiles(const Occlusion& occlusion_in_content_space,
- bool resourceless_software_draw) override;
void NotifyTileStateChanged(const Tile* tile) override;
void DidBeginTracing() override;
void ReleaseResources() override;
@@ -81,6 +79,8 @@ class CC_EXPORT PictureLayerImpl
void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
Region* new_invalidation,
const PictureLayerTilingSet* pending_set);
+ bool UpdateTiles(const Occlusion& occlusion_in_content_space,
+ bool resourceless_software_draw);
// Mask-related functions.
void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h
index 1cc2de8..2035e28 100644
--- a/cc/layers/render_surface_impl.h
+++ b/cc/layers/render_surface_impl.h
@@ -14,6 +14,7 @@
#include "cc/layers/layer_lists.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/shared_quad_state.h"
+#include "cc/trees/occlusion.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/transform.h"
@@ -125,6 +126,13 @@ class CC_EXPORT RenderSurfaceImpl {
void SetContentRect(const gfx::Rect& content_rect);
gfx::Rect content_rect() const { return content_rect_; }
+ const Occlusion& occlusion_in_content_space() const {
+ return occlusion_in_content_space_;
+ }
+ void set_occlusion_in_content_space(const Occlusion& occlusion) {
+ occlusion_in_content_space_ = occlusion;
+ }
+
LayerImplList& layer_list() { return layer_list_; }
void AddContributingDelegatedRenderPassLayer(LayerImpl* layer);
void ClearLayerLists();
@@ -174,6 +182,7 @@ class CC_EXPORT RenderSurfaceImpl {
LayerImplList layer_list_;
std::vector<DelegatedRendererLayerImpl*>
contributing_delegated_render_pass_layer_list_;
+ Occlusion occlusion_in_content_space_;
// The nearest ancestor target surface that will contain the contents of this
// surface, and that ignores outside occlusion. This can point to itself.
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 95e1ab1..047e068 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -68,7 +68,6 @@
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -592,25 +591,20 @@ DrawMode LayerTreeHostImpl::GetDrawMode() const {
static void AppendQuadsForLayer(
RenderPass* target_render_pass,
LayerImpl* layer,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
AppendQuadsData* append_quads_data) {
- layer->AppendQuads(
- target_render_pass,
- occlusion_tracker.GetCurrentOcclusionForLayer(layer->draw_transform()),
- append_quads_data);
+ layer->AppendQuads(target_render_pass,
+ layer->draw_properties().occlusion_in_content_space,
+ append_quads_data);
}
static void AppendQuadsForRenderSurfaceLayer(
RenderPass* target_render_pass,
LayerImpl* layer,
const RenderPass* contributing_render_pass,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
AppendQuadsData* append_quads_data) {
RenderSurfaceImpl* surface = layer->render_surface();
const gfx::Transform& draw_transform = surface->draw_transform();
- const Occlusion& occlusion =
- occlusion_tracker.GetCurrentOcclusionForContributingSurface(
- draw_transform);
+ const Occlusion& occlusion = surface->occlusion_in_content_space();
SkColor debug_border_color = surface->GetDebugBorderColor();
float debug_border_width = surface->GetDebugBorderWidth();
LayerImpl* mask_layer = layer->mask_layer();
@@ -623,9 +617,8 @@ static void AppendQuadsForRenderSurfaceLayer(
if (layer->has_replica()) {
const gfx::Transform& replica_draw_transform =
surface->replica_draw_transform();
- const Occlusion& replica_occlusion =
- occlusion_tracker.GetCurrentOcclusionForContributingSurface(
- replica_draw_transform);
+ Occlusion replica_occlusion = occlusion.GetOcclusionWithGivenDrawTransform(
+ surface->replica_draw_transform());
SkColor replica_debug_border_color = surface->GetReplicaDebugBorderColor();
float replica_debug_border_width = surface->GetReplicaDebugBorderWidth();
// TODO(danakj): By using the same RenderSurfaceImpl for both the
@@ -645,16 +638,13 @@ static void AppendQuadsForRenderSurfaceLayer(
}
}
-static void AppendQuadsToFillScreen(
- const gfx::Rect& root_scroll_layer_rect,
- RenderPass* target_render_pass,
- LayerImpl* root_layer,
- SkColor screen_background_color,
- const OcclusionTracker<LayerImpl>& occlusion_tracker) {
+static void AppendQuadsToFillScreen(const gfx::Rect& root_scroll_layer_rect,
+ RenderPass* target_render_pass,
+ LayerImpl* root_layer,
+ SkColor screen_background_color,
+ const Region& fill_region) {
if (!root_layer || !SkColorGetA(screen_background_color))
return;
-
- Region fill_region = occlusion_tracker.ComputeVisibleRegionInScreen();
if (fill_region.IsEmpty())
return;
@@ -758,14 +748,14 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
root_pass->damage_rect = root_pass->output_rect;
}
- OcclusionTracker<LayerImpl> occlusion_tracker(
- active_tree_->root_layer()->render_surface()->content_rect());
- occlusion_tracker.set_minimum_tracking_size(
- settings_.minimum_occlusion_tracking_size);
-
- // Add quads to the Render passes in front-to-back order to allow for testing
- // occlusion and performing culling during the tree walk.
- typedef LayerIterator<LayerImpl> LayerIteratorType;
+ // Grab this region here before iterating layers. Taking copy requests from
+ // the layers while constructing the render passes will dirty the render
+ // surface layer list and this unoccluded region, flipping the dirty bit to
+ // true, and making us able to query for it without doing
+ // UpdateDrawProperties again. The value inside the Region is not actually
+ // changed until UpdateDrawProperties happens, so a reference to it is safe.
+ const Region& unoccluded_screen_space_region =
+ active_tree_->UnoccludedScreenSpaceRegion();
// Typically when we are missing a texture and use a checkerboard quad, we
// still draw the frame. However when the layer being checkerboarded is moving
@@ -783,19 +773,15 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
int num_missing_tiles = 0;
int num_incomplete_tiles = 0;
- LayerIteratorType end =
- LayerIteratorType::End(frame->render_surface_layer_list);
- for (LayerIteratorType it =
- LayerIteratorType::Begin(frame->render_surface_layer_list);
- it != end;
- ++it) {
+ auto end = LayerIterator<LayerImpl>::End(frame->render_surface_layer_list);
+ for (auto it =
+ LayerIterator<LayerImpl>::Begin(frame->render_surface_layer_list);
+ it != end; ++it) {
RenderPassId target_render_pass_id =
it.target_render_surface_layer()->render_surface()->GetRenderPassId();
RenderPass* target_render_pass =
frame->render_passes_by_id[target_render_pass_id];
- occlusion_tracker.EnterLayer(it);
-
AppendQuadsData append_quads_data;
if (it.represents_target_render_surface()) {
@@ -813,13 +799,12 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
AppendQuadsForRenderSurfaceLayer(target_render_pass,
*it,
contributing_render_pass,
- occlusion_tracker,
&append_quads_data);
} else if (it.represents_itself() &&
!it->visible_content_rect().IsEmpty()) {
bool occluded =
- occlusion_tracker.GetCurrentOcclusionForLayer(it->draw_transform())
- .IsOccluded(it->visible_content_rect());
+ it->draw_properties().occlusion_in_content_space.IsOccluded(
+ it->visible_content_rect());
if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) {
DCHECK_EQ(active_tree_, it->layer_tree_impl());
@@ -835,7 +820,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
AppendQuadsForLayer(render_pass,
*it,
- occlusion_tracker,
&append_quads_data);
contributing_render_pass_id =
@@ -845,7 +829,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
AppendQuadsForLayer(target_render_pass,
*it,
- occlusion_tracker,
&append_quads_data);
// For layers that represent themselves, add composite frame timing
@@ -885,8 +868,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
if (RequiresHighResToDraw())
draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
}
-
- occlusion_tracker.LeaveLayer(it);
}
if (have_copy_request ||
@@ -907,10 +888,8 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
frame->render_passes.back()->has_transparent_background = false;
AppendQuadsToFillScreen(
active_tree_->RootScrollLayerDeviceViewportBounds(),
- frame->render_passes.back(),
- active_tree_->root_layer(),
- active_tree_->background_color(),
- occlusion_tracker);
+ frame->render_passes.back(), active_tree_->root_layer(),
+ active_tree_->background_color(), unoccluded_screen_space_region);
}
RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame);
diff --git a/cc/trees/layer_tree_host_unittest_occlusion.cc b/cc/trees/layer_tree_host_unittest_occlusion.cc
index fe87e44..9974ae4 100644
--- a/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -5,623 +5,266 @@
#include "cc/trees/layer_tree_host.h"
#include "cc/layers/layer.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
+#include "cc/layers/picture_layer.h"
+#include "cc/test/fake_content_layer_client.h"
#include "cc/test/layer_tree_test.h"
-#include "cc/test/test_occlusion_tracker.h"
+#include "cc/trees/layer_tree_impl.h"
namespace cc {
namespace {
-class TestLayer : public Layer {
- public:
- static scoped_refptr<TestLayer> Create() {
- return make_scoped_refptr(new TestLayer());
- }
-
- bool Update(ResourceUpdateQueue* update_queue,
- const OcclusionTracker<Layer>* occlusion) override {
- if (!occlusion)
- return false;
-
- const TestOcclusionTracker<Layer>* test_occlusion =
- static_cast<const TestOcclusionTracker<Layer>*>(occlusion);
- occlusion_ = UnionSimpleEnclosedRegions(
- test_occlusion->occlusion_from_inside_target(),
- test_occlusion->occlusion_from_outside_target());
- return false;
- }
-
- const SimpleEnclosedRegion& occlusion() const { return occlusion_; }
- const SimpleEnclosedRegion& expected_occlusion() const {
- return expected_occlusion_;
- }
- void set_expected_occlusion(const gfx::Rect& occlusion) {
- expected_occlusion_ = SimpleEnclosedRegion(occlusion);
- }
-
- private:
- TestLayer() : Layer() {
- SetIsDrawable(true);
- }
- ~TestLayer() override {}
-
- SimpleEnclosedRegion occlusion_;
- SimpleEnclosedRegion expected_occlusion_;
-};
+#define EXPECT_OCCLUSION_EQ(expected, actual) \
+ EXPECT_TRUE(expected.IsEqual(actual)) \
+ << " Expected: " << expected.ToString() << std::endl \
+ << " Actual: " << actual.ToString();
class LayerTreeHostOcclusionTest : public LayerTreeTest {
- public:
- LayerTreeHostOcclusionTest()
- : root_(TestLayer::Create()),
- child_(TestLayer::Create()),
- child2_(TestLayer::Create()),
- grand_child_(TestLayer::Create()),
- mask_(TestLayer::Create()) {
- }
-
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void DidCommit() override {
- TestLayer* root = static_cast<TestLayer*>(layer_tree_host()->root_layer());
- VerifyOcclusion(root);
-
- EndTest();
- }
-
- void AfterTest() override {}
-
- void VerifyOcclusion(TestLayer* layer) const {
- EXPECT_EQ(layer->expected_occlusion().ToString(),
- layer->occlusion().ToString());
-
- for (size_t i = 0; i < layer->children().size(); ++i) {
- TestLayer* child = static_cast<TestLayer*>(layer->children()[i].get());
- VerifyOcclusion(child);
- }
- }
-
- void SetLayerPropertiesForTesting(TestLayer* layer,
- TestLayer* parent,
- const gfx::Transform& transform,
- const gfx::PointF& position,
- const gfx::Size& bounds,
- bool opaque) const {
- layer->RemoveAllChildren();
- if (parent)
- parent->AddChild(layer);
- layer->SetTransform(transform);
- layer->SetPosition(position);
- layer->SetBounds(bounds);
- layer->SetContentsOpaque(opaque);
- }
-
protected:
void InitializeSettings(LayerTreeSettings* settings) override {
settings->minimum_occlusion_tracking_size = gfx::Size();
}
-
- scoped_refptr<TestLayer> root_;
- scoped_refptr<TestLayer> child_;
- scoped_refptr<TestLayer> child2_;
- scoped_refptr<TestLayer> grand_child_;
- scoped_refptr<TestLayer> mask_;
-
- gfx::Transform identity_matrix_;
};
-
-class LayerTreeHostOcclusionTestOcclusionSurfaceClipping
+// Verify occlusion is set on the layer draw properties.
+class LayerTreeHostOcclusionTestDrawPropertiesOnLayer
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // The child layer is a surface and the grand_child is opaque, but clipped
- // to the child and root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(50, 60));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetContentsOpaque(true);
+ child->SetIsDrawable(true);
+ root->AddChild(child);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionSurfaceClipping);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer is opaque, then it adds to the occlusion seen by the
- // root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(child->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion()),
+ child->draw_properties().occlusion_in_content_space);
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(root->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(10, 6, 50, 59))),
+ root->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque);
-
-class LayerTreeHostOcclusionTestOcclusionTwoChildren
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // Add a second child to the root layer and the regions should merge
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 20, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ void AfterTest() override {}
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionTwoChildren);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnLayer);
-class LayerTreeHostOcclusionTestOcclusionMask
+// Verify occlusion is set on the render surfaces.
+class LayerTreeHostOcclusionTestDrawPropertiesOnSurface
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // If the child layer has a mask on it, then it shouldn't contribute to
- // occlusion on stuff below it.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 20.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(500, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetMaskLayer(mask_.get());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 180, 180));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(1, 1));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ child->SetForceRenderSurface(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with a mask is below child2, then child2 should
- // contribute to occlusion on everything, and child shouldn't contribute
- // to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetMaskLayer(mask_.get());
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
-};
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion);
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
-class LayerTreeHostOcclusionTestOcclusionOpacity
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer has a non-opaque opacity, then it shouldn't
- // contribute to occlusion on stuff below it
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetOpacity(0.5f);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ surface->occlusion_in_content_space());
+ EndTest();
}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity);
-class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with non-opaque opacity is below child2, then
- // child2 should contribute to occlusion on everything, and child shouldn't
- // contribute to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetOpacity(0.5f);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ void AfterTest() override {}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion);
+ LayerTreeHostOcclusionTestDrawPropertiesOnSurface);
-class LayerTreeHostOcclusionTestOcclusionBlending
+// Verify occlusion is set on mask layers.
+class LayerTreeHostOcclusionTestDrawPropertiesOnMask
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // If the child layer has a blend mode, then it shouldn't
- // contribute to occlusion on stuff below it
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetBlendMode(SkXfermode::kMultiply_Mode);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(30, 40));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> make_surface_bigger = Layer::Create();
+ make_surface_bigger->SetBounds(gfx::Size(100, 100));
+ make_surface_bigger->SetPosition(gfx::PointF(-10.f, -15.f));
+ make_surface_bigger->SetIsDrawable(true);
+ child->AddChild(make_surface_bigger);
+
+ scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ mask->SetBounds(gfx::Size(30, 40));
+ mask->SetIsDrawable(true);
+ child->SetMaskLayer(mask.get());
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionBlending);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with a blend mode is below child2, then
- // child2 should contribute to occlusion on everything, and child shouldn't
- // contribute to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetBlendMode(SkXfermode::kMultiply_Mode);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
-};
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
+ LayerImpl* mask = child->mask_layer();
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion);
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
-class LayerTreeHostOcclusionTestOcclusionOpacityFilter
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- FilterOperations filters;
- filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
-
- // If the child layer has a filter that changes alpha values, and is below
- // child2, then child2 should contribute to occlusion on everything,
- // and child shouldn't contribute to the root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(child_.get(),
- root_.get(),
- identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(500, 500),
- true);
- SetLayerPropertiesForTesting(grand_child_.get(),
- child_.get(),
- identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(500, 500),
- true);
- SetLayerPropertiesForTesting(child2_.get(),
- root_.get(),
- identity_matrix_,
- gfx::PointF(10.f, 10.f),
- gfx::Size(30, 30),
- true);
-
- child_->SetMasksToBounds(true);
- child_->SetFilters(filters);
-
- // child2_ occludes grand_child_, showing it does occlude inside child_'s
- // subtree.
- grand_child_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
- // grand_child_ occludes child_, showing there is more occlusion in
- // child_'s subtree.
- child_->set_expected_occlusion(gfx::Rect(0, 0, 200, 200));
- // child2_'s occlusion reaches the root, but child_'s subtree does not.
- root_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ gfx::Transform transform = surface->draw_transform();
+ transform.PreconcatTransform(child->draw_transform());
+
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(transform, SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ mask->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionOpacityFilter);
+ void AfterTest() override {}
-class LayerTreeHostOcclusionTestOcclusionBlurFilter
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- gfx::Transform child_transform;
- child_transform.Translate(250.0, 250.0);
- child_transform.Rotate(90.0);
- child_transform.Translate(-250.0, -250.0);
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(10.f));
-
- // If the child layer has a filter that moves pixels/changes alpha, and is
- // below child2, then child should not inherit occlusion from outside its
- // subtree, and should not contribute to the root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), child_transform,
- gfx::PointF(30.f, 30.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 70.f), gfx::Size(500, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetFilters(filters);
-
- child_->set_expected_occlusion(gfx::Rect(10, 330, 160, 170));
- root_->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionBlurFilter);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnMask);
-class LayerTreeHostOcclusionTestOcclusionCopyRequest
+// Verify occlusion is set to empty inside the subtree of a replica. This is
+// done because the tile system does not know about replicas, and so would not
+// know that something is unoccluded on the replica even though it's occluded on
+// the original.
+class LayerTreeHostOcclusionTestDrawPropertiesInsideReplica
: public LayerTreeHostOcclusionTest {
public:
- static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
-
void SetupTree() override {
- // If the child layer has copy request, and is below child2,
- // then child should not inherit occlusion from outside its subtree.
- // The child layer will still receive occlusion from inside, and
- // the root layer will recive occlusion from child.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(), gfx::Size(100, 100), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 75), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 50), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
- child_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&CopyOutputCallback)));
- EXPECT_TRUE(child_->HasCopyRequest());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
- root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(1, 1));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ child->SetForceRenderSurface(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> replica = Layer::Create();
+ gfx::Transform translate;
+ translate.Translate(20.f, 4.f);
+ replica->SetTransform(translate);
+ child->SetReplicaLayer(replica.get());
+
+ scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ mask->SetBounds(gfx::Size(30, 40));
+ mask->SetIsDrawable(true);
+ child->SetMaskLayer(mask.get());
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionCopyRequest);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionReplica
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer has copy request, and is below child2,
- // then child should not inherit occlusion from outside its subtree.
- // The child layer will still receive occlusion from inside, and
- // the root layer will recive occlusion from child.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(), gfx::Size(100, 100), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 75), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 50), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
- scoped_refptr<Layer> replica_layer(Layer::Create());
- child_->SetReplicaLayer(replica_layer.get());
- EXPECT_TRUE(child_->has_replica());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
- root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
+ LayerImpl* mask = child->mask_layer();
+
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
+
+ // No occlusion from on child, which is part of the replica.
+ EXPECT_OCCLUSION_EQ(Occlusion(),
+ child->draw_properties().occlusion_in_content_space);
+ // Occlusion on the surface is okay.
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ surface->occlusion_in_content_space());
+ // No occlusion on the replica'd mask.
+ EXPECT_OCCLUSION_EQ(Occlusion(),
+ mask->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionReplica);
+ void AfterTest() override {}
-class LayerTreeHostOcclusionTestManySurfaces
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // We create enough RenderSurfaces that it will trigger Vector reallocation
- // while computing occlusion.
- std::vector<scoped_refptr<TestLayer>> layers;
- int num_surfaces = 200;
- int root_width = 400;
- int root_height = 400;
-
- for (int i = 0; i < num_surfaces; ++i) {
- layers.push_back(TestLayer::Create());
- if (i == 0) {
- SetLayerPropertiesForTesting(
- layers.back().get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(root_width, root_height), true);
- } else {
- SetLayerPropertiesForTesting(
- layers.back().get(), layers[layers.size() - 2].get(),
- identity_matrix_,
- gfx::PointF(1.f, 1.f),
- gfx::Size(root_width-i, root_height-i), true);
- layers.back()->SetForceRenderSurface(true);
- }
- }
-
- for (int i = 1; i < num_surfaces; ++i) {
- scoped_refptr<TestLayer> child = TestLayer::Create();
- SetLayerPropertiesForTesting(
- child.get(), layers[i].get(), identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(root_width, root_height), false);
- }
-
- for (int i = 0; i < num_surfaces-1; ++i) {
- gfx::Rect expected_occlusion(1, 1, root_width-i-1, root_height-i-1);
- layers[i]->set_expected_occlusion(expected_occlusion);
- }
-
- layer_tree_host()->SetRootLayer(layers[0]);
- LayerTreeTest::SetupTree();
- }
+ FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostOcclusionTestDrawPropertiesInsideReplica);
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 6806d9c..443308b 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -549,12 +549,9 @@ bool LayerTreeImpl::UpdateDrawProperties() {
render_surface_layer_list_.clear();
{
- TRACE_EVENT2("cc",
- "LayerTreeImpl::UpdateDrawProperties",
- "IsActive",
- IsActiveTree(),
- "SourceFrameNumber",
- source_frame_number_);
+ TRACE_EVENT2(
+ "cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
+ "IsActive", IsActiveTree(), "SourceFrameNumber", source_frame_number_);
LayerImpl* page_scale_layer =
page_scale_layer_ ? page_scale_layer_ : InnerViewportContainerLayer();
bool can_render_to_separate_surface =
@@ -577,66 +574,100 @@ bool LayerTreeImpl::UpdateDrawProperties() {
}
{
- TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateTilePriorities", "IsActive",
- IsActiveTree(), "SourceFrameNumber",
- source_frame_number_);
- scoped_ptr<OcclusionTracker<LayerImpl>> occlusion_tracker;
- if (settings().use_occlusion_for_tile_prioritization) {
- occlusion_tracker.reset(new OcclusionTracker<LayerImpl>(
- root_layer()->render_surface()->content_rect()));
- occlusion_tracker->set_minimum_tracking_size(
- settings().minimum_occlusion_tracking_size);
- }
-
- bool resourceless_software_draw = (layer_tree_host_impl_->GetDrawMode() ==
- DRAW_MODE_RESOURCELESS_SOFTWARE);
+ TRACE_EVENT2("cc", "LayerTreeImpl::UpdateDrawProperties::Occlusion",
+ "IsActive", IsActiveTree(), "SourceFrameNumber",
+ source_frame_number_);
+ OcclusionTracker<LayerImpl> occlusion_tracker(
+ root_layer()->render_surface()->content_rect());
+ occlusion_tracker.set_minimum_tracking_size(
+ settings().minimum_occlusion_tracking_size);
// LayerIterator is used here instead of CallFunctionForSubtree to only
// UpdateTilePriorities on layers that will be visible (and thus have valid
// draw properties) and not because any ordering is required.
- typedef LayerIterator<LayerImpl> LayerIteratorType;
- LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
- size_t layers_updated_count = 0;
- bool tile_priorities_updated = false;
- for (LayerIteratorType it =
- LayerIteratorType::Begin(&render_surface_layer_list_);
- it != end;
- ++it) {
- if (occlusion_tracker)
- occlusion_tracker->EnterLayer(it);
-
- LayerImpl* layer = *it;
- const Occlusion& occlusion_in_content_space =
- occlusion_tracker ? occlusion_tracker->GetCurrentOcclusionForLayer(
- layer->draw_transform())
- : Occlusion();
+ auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list_);
+ for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list_);
+ it != end; ++it) {
+ occlusion_tracker.EnterLayer(it);
+
+ // There are very few render targets so this should be cheap to do for
+ // each layer instead of something more complicated.
+ bool inside_replica = false;
+ LayerImpl* layer = it->render_target();
+ while (layer && !inside_replica) {
+ if (layer->render_target()->has_replica())
+ inside_replica = true;
+ layer = layer->render_target()->parent();
+ }
+
+ // Don't use occlusion if a layer will appear in a replica, since the
+ // tile raster code does not know how to look for the replica and would
+ // consider it occluded even though the replica is visible.
+ // Since occlusion is only used for browser compositor (i.e.
+ // use_occlusion_for_tile_prioritization) and it won't use replicas,
+ // this should matter not.
if (it.represents_itself()) {
- tile_priorities_updated |= layer->UpdateTiles(
- occlusion_in_content_space, resourceless_software_draw);
- ++layers_updated_count;
+ Occlusion occlusion =
+ inside_replica ? Occlusion()
+ : occlusion_tracker.GetCurrentOcclusionForLayer(
+ it->draw_transform());
+ it->draw_properties().occlusion_in_content_space = occlusion;
}
- if (!it.represents_contributing_render_surface()) {
- if (occlusion_tracker)
- occlusion_tracker->LeaveLayer(it);
- continue;
+ if (it.represents_contributing_render_surface()) {
+ // Surfaces aren't used by the tile raster code, so they can have
+ // occlusion regardless of replicas.
+ Occlusion occlusion =
+ occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+ it->render_surface()->draw_transform());
+ it->render_surface()->set_occlusion_in_content_space(occlusion);
+ // Masks are used to draw the contributing surface, so should have
+ // the same occlusion as the surface (nothing inside the surface
+ // occludes them).
+ if (LayerImpl* mask = it->mask_layer()) {
+ Occlusion mask_occlusion =
+ inside_replica
+ ? Occlusion()
+ : occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+ it->render_surface()->draw_transform() *
+ it->draw_transform());
+ mask->draw_properties().occlusion_in_content_space = mask_occlusion;
+ }
+ if (LayerImpl* replica = it->replica_layer()) {
+ if (LayerImpl* mask = replica->mask_layer())
+ mask->draw_properties().occlusion_in_content_space = Occlusion();
+ }
}
- if (layer->mask_layer()) {
- tile_priorities_updated |= layer->mask_layer()->UpdateTiles(
- occlusion_in_content_space, resourceless_software_draw);
- ++layers_updated_count;
- }
- if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
- tile_priorities_updated |=
- layer->replica_layer()->mask_layer()->UpdateTiles(
- occlusion_in_content_space, resourceless_software_draw);
- ++layers_updated_count;
- }
+ occlusion_tracker.LeaveLayer(it);
+ }
+
+ unoccluded_screen_space_region_ =
+ occlusion_tracker.ComputeVisibleRegionInScreen();
+ }
- if (occlusion_tracker)
- occlusion_tracker->LeaveLayer(it);
+ {
+ TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateDrawProperties::UpdateTiles",
+ "IsActive", IsActiveTree(), "SourceFrameNumber",
+ source_frame_number_);
+ const bool resourceless_software_draw =
+ (layer_tree_host_impl_->GetDrawMode() ==
+ DRAW_MODE_RESOURCELESS_SOFTWARE);
+ static const Occlusion kEmptyOcclusion;
+ size_t layers_updated_count = 0;
+ bool tile_priorities_updated = false;
+ for (PictureLayerImpl* layer : picture_layers_) {
+ // TODO(danakj): Remove this to fix crbug.com/446751
+ if (!layer->IsDrawnRenderSurfaceLayerListMember())
+ continue;
+ ++layers_updated_count;
+ const Occlusion& occlusion =
+ settings().use_occlusion_for_tile_prioritization
+ ? layer->draw_properties().occlusion_in_content_space
+ : kEmptyOcclusion;
+ tile_priorities_updated |=
+ layer->UpdateTiles(occlusion, resourceless_software_draw);
}
if (tile_priorities_updated)
@@ -657,6 +688,13 @@ const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
return render_surface_layer_list_;
}
+const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const {
+ // If this assert triggers, then the render_surface_layer_list_ is dirty, so
+ // the unoccluded_screen_space_region_ is not valid anymore.
+ DCHECK(!needs_update_draw_properties_);
+ return unoccluded_screen_space_region_;
+}
+
gfx::Size LayerTreeImpl::ScrollableSize() const {
LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
? OuterViewportScrollLayer()
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 6c37147..54c8660 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -220,6 +220,7 @@ class CC_EXPORT LayerTreeImpl {
void set_ui_resource_request_queue(const UIResourceRequestQueue& queue);
const LayerImplList& RenderSurfaceLayerList() const;
+ const Region& UnoccludedScreenSpaceRegion() const;
// These return the size of the root scrollable area and the size of
// the user-visible scrolling viewport, in CSS layout coordinates.
@@ -381,6 +382,9 @@ class CC_EXPORT LayerTreeImpl {
// List of visible layers for the most recently prepared frame.
LayerImplList render_surface_layer_list_;
+ // After drawing the |render_surface_layer_list_| the areas in this region
+ // would not be fully covered by opaque content.
+ Region unoccluded_screen_space_region_;
bool contents_textures_purged_;
bool viewport_size_invalid_;
diff --git a/cc/trees/occlusion.cc b/cc/trees/occlusion.cc
index 14168f9..6a71496 100644
--- a/cc/trees/occlusion.cc
+++ b/cc/trees/occlusion.cc
@@ -85,4 +85,16 @@ gfx::Rect Occlusion::GetUnoccludedRectInTargetSurface(
return unoccluded_rect_in_target_surface;
}
+bool Occlusion::IsEqual(const Occlusion& other) const {
+ return draw_transform_ == other.draw_transform_ &&
+ occlusion_from_inside_target_ == other.occlusion_from_inside_target_ &&
+ occlusion_from_outside_target_ == other.occlusion_from_outside_target_;
+}
+
+std::string Occlusion::ToString() const {
+ return draw_transform_.ToString() + "outside(" +
+ occlusion_from_outside_target_.ToString() + ") inside(" +
+ occlusion_from_inside_target_.ToString() + ")";
+}
+
} // namespace cc
diff --git a/cc/trees/occlusion.h b/cc/trees/occlusion.h
index 56f9962d..fec4915 100644
--- a/cc/trees/occlusion.h
+++ b/cc/trees/occlusion.h
@@ -5,6 +5,8 @@
#ifndef CC_TREES_OCCLUSION_H_
#define CC_TREES_OCCLUSION_H_
+#include <string>
+
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
#include "cc/base/simple_enclosed_region.h"
@@ -26,6 +28,9 @@ class CC_EXPORT Occlusion {
bool IsOccluded(const gfx::Rect& content_rect) const;
gfx::Rect GetUnoccludedContentRect(const gfx::Rect& content_rect) const;
+ bool IsEqual(const Occlusion& other) const;
+ std::string ToString() const;
+
private:
gfx::Rect GetUnoccludedRectInTargetSurface(
const gfx::Rect& content_rect) const;
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 847d60c..e3639ad 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -2672,6 +2672,53 @@ ALL_OCCLUSIONTRACKER_TEST(
OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded);
template <class Types>
+class OcclusionTrackerTestBlendModeDoesNotOcclude
+ : public OcclusionTrackerTest<Types> {
+ protected:
+ explicit OcclusionTrackerTestBlendModeDoesNotOcclude(bool opaque_layers)
+ : OcclusionTrackerTest<Types>(opaque_layers) {}
+ void RunMyTest() override {
+ typename Types::ContentLayerType* parent = this->CreateRoot(
+ this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
+ typename Types::LayerType* blend_mode_layer = this->CreateDrawingLayer(
+ parent, this->identity_matrix, gfx::PointF(0.f, 0.f),
+ gfx::Size(100, 100), true);
+ typename Types::LayerType* top_layer = this->CreateDrawingLayer(
+ parent, this->identity_matrix, gfx::PointF(10.f, 12.f),
+ gfx::Size(20, 22), true);
+
+ // Blend mode makes the layer own a surface.
+ Types::SetForceRenderSurface(blend_mode_layer, true);
+ blend_mode_layer->SetBlendMode(SkXfermode::kMultiply_Mode);
+
+ this->CalcDrawEtc(parent);
+
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
+ gfx::Rect(0, 0, 1000, 1000));
+
+ this->VisitLayer(top_layer, &occlusion);
+ // |top_layer| occludes.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+
+ this->VisitLayer(blend_mode_layer, &occlusion);
+ // |top_layer| occludes but not |blend_mode_layer|.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty());
+
+ this->VisitContributingSurface(blend_mode_layer, &occlusion);
+ // |top_layer| occludes but not |blend_mode_layer|.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+ }
+};
+
+ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestBlendModeDoesNotOcclude);
+
+template <class Types>
class OcclusionTrackerTestMinimumTrackingSize
: public OcclusionTrackerTest<Types> {
protected:
@@ -2817,12 +2864,22 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
gfx::PointF(),
gfx::Size(200, 400),
true);
+ typename Types::LayerType* top_layer =
+ this->CreateDrawingLayer(root, this->identity_matrix,
+ gfx::PointF(50, 0), gfx::Size(50, 400), true);
this->CalcDrawEtc(root);
TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
+ this->VisitLayer(top_layer, &occlusion);
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect(50, 0, 50, 400).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+
this->VisitLayer(copy_child, &occlusion);
+ // Layers outside the copy request do not occlude.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_EQ(gfx::Rect(200, 400).ToString(),
@@ -2834,7 +2891,7 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
// The occlusion from the copy should be kept.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
- EXPECT_EQ(gfx::Rect(100, 0, 200, 400).ToString(),
+ EXPECT_EQ(gfx::Rect(50, 0, 250, 400).ToString(),
occlusion.occlusion_from_inside_target().ToString());
}
};