cc: Apply occlusion before creating quads in RenderSurfaceImpl.

This makes the AppendQuads method query occlusion directly and subtract
it from the quads it would create before they are created, skipping
quads that are completely occluded and avoiding a malloc/free for them.

Depends on: https://codereview.chromium.org/205443002/
Depends on: https://codereview.chromium.org/203463015/

R=enne
BUG=344962

Review URL: https://codereview.chromium.org/205503002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@258633 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 0c7bb62..14696e7 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -41,6 +41,7 @@
       'layers/picture_layer_impl_unittest.cc',
       'layers/picture_layer_unittest.cc',
       'layers/render_surface_unittest.cc',
+      'layers/render_surface_impl_unittest.cc',
       'layers/scrollbar_layer_unittest.cc',
       'layers/solid_color_layer_impl_unittest.cc',
       'layers/solid_color_scrollbar_layer_impl_unittest.cc',
diff --git a/cc/layers/quad_sink.h b/cc/layers/quad_sink.h
index 1b82470..add4e99 100644
--- a/cc/layers/quad_sink.h
+++ b/cc/layers/quad_sink.h
@@ -16,6 +16,7 @@
 namespace cc {
 
 class DrawQuad;
+class LayerImpl;
 class SharedQuadState;
 
 class CC_EXPORT QuadSink {
@@ -32,6 +33,10 @@
       const gfx::Rect& content_rect,
       const gfx::Transform& draw_transform) = 0;
 
+  virtual gfx::Rect UnoccludedContributingSurfaceContentRect(
+      const gfx::Rect& content_rect,
+      const gfx::Transform& draw_transform) = 0;
+
   // Returns true if the quad is added to the list, and false if the quad is
   // entirely culled.
   virtual bool MaybeAppend(scoped_ptr<DrawQuad> draw_quad) = 0;
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 9a1edbf..ddb7158 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -143,6 +143,12 @@
 
   const gfx::Transform& draw_transform =
       for_replica ? replica_draw_transform_ : draw_transform_;
+  gfx::Rect visible_content_rect =
+      quad_sink->UnoccludedContributingSurfaceContentRect(content_rect_,
+                                                          draw_transform);
+  if (visible_content_rect.IsEmpty())
+    return;
+
   SharedQuadState* shared_quad_state =
       quad_sink->UseSharedQuadState(SharedQuadState::Create());
   shared_quad_state->SetAll(draw_transform,
@@ -154,8 +160,6 @@
                             owning_layer_->blend_mode());
 
   if (owning_layer_->ShowDebugBorders()) {
-    gfx::Rect quad_rect = content_rect_;
-    gfx::Rect visible_quad_rect = quad_rect;
     SkColor color = for_replica ?
                     DebugColors::SurfaceReplicaBorderColor() :
                     DebugColors::SurfaceBorderColor();
@@ -167,8 +171,8 @@
     scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
         DebugBorderDrawQuad::Create();
     debug_border_quad->SetNew(
-        shared_quad_state, quad_rect, visible_quad_rect, color, width);
-    quad_sink->MaybeAppend(debug_border_quad.PassAs<DrawQuad>());
+        shared_quad_state, content_rect_, visible_content_rect, color, width);
+    quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
   }
 
   // TODO(shawnsingh): By using the same RenderSurfaceImpl for both the content
@@ -212,7 +216,6 @@
         uv_scale_y);
   }
 
-  gfx::Rect visible_content_rect(content_rect_);
   ResourceProvider::ResourceId mask_resource_id =
       mask_layer ? mask_layer->ContentsResourceId() : 0;
   gfx::Rect contents_changed_since_last_frame =
@@ -229,7 +232,7 @@
                mask_uv_rect,
                owning_layer_->filters(),
                owning_layer_->background_filters());
-  quad_sink->MaybeAppend(quad.PassAs<DrawQuad>());
+  quad_sink->Append(quad.PassAs<DrawQuad>());
 }
 
 }  // namespace cc
diff --git a/cc/layers/render_surface_impl_unittest.cc b/cc/layers/render_surface_impl_unittest.cc
new file mode 100644
index 0000000..20c2afb
--- /dev/null
+++ b/cc/layers/render_surface_impl_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/render_surface_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(RenderSurfaceLayerImplTest, Occlusion) {
+  gfx::Size layer_size(1000, 1000);
+  gfx::Size viewport_size(1000, 1000);
+
+  LayerTestCommon::LayerImplTest impl;
+
+  LayerImpl* owning_layer_impl = impl.AddChildToRoot<LayerImpl>();
+  owning_layer_impl->SetAnchorPoint(gfx::PointF());
+  owning_layer_impl->SetBounds(layer_size);
+  owning_layer_impl->SetContentBounds(layer_size);
+  owning_layer_impl->SetDrawsContent(true);
+  owning_layer_impl->SetForceRenderSurface(true);
+
+  impl.CalcDrawProps(viewport_size);
+
+  RenderSurfaceImpl* render_surface_impl = owning_layer_impl->render_surface();
+  ASSERT_TRUE(render_surface_impl);
+
+  {
+    SCOPED_TRACE("No occlusion");
+    gfx::Rect occluded;
+    impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+    LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+                                                 gfx::Rect(layer_size));
+    EXPECT_EQ(1u, impl.quad_list().size());
+  }
+
+  {
+    SCOPED_TRACE("Full occlusion");
+    gfx::Rect occluded(owning_layer_impl->visible_content_rect());
+    impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+    LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+    EXPECT_EQ(impl.quad_list().size(), 0u);
+  }
+
+  {
+    SCOPED_TRACE("Partial occlusion");
+    gfx::Rect occluded(200, 0, 800, 1000);
+    impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+    size_t partially_occluded_count = 0;
+    LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+        impl.quad_list(),
+        gfx::Rect(layer_size),
+        occluded,
+        &partially_occluded_count);
+    // The layer outputs one quad, which is partially occluded.
+    EXPECT_EQ(1u, impl.quad_list().size());
+    EXPECT_EQ(1u, partially_occluded_count);
+  }
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 31a16e1f..beffb20 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -120,4 +120,16 @@
   layer_impl->DidDraw(resource_provider());
 }
 
+void LayerTestCommon::LayerImplTest::AppendSurfaceQuadsWithOcclusion(
+    RenderSurfaceImpl* surface_impl,
+    const gfx::Rect& occluded) {
+  AppendQuadsData data;
+
+  quad_culler_.clear_lists();
+  quad_culler_.set_occluded_content_rect_for_contributing_surface(occluded);
+  bool for_replica = false;
+  RenderPass::Id id(1, 1);
+  surface_impl->AppendQuads(&quad_culler_, &data, for_replica, id);
+}
+
 }  // namespace cc
diff --git a/cc/test/layer_test_common.h b/cc/test/layer_test_common.h
index cb564175..06521832 100644
--- a/cc/test/layer_test_common.h
+++ b/cc/test/layer_test_common.h
@@ -28,8 +28,10 @@
 namespace gfx { class Rect; }
 
 namespace cc {
+class LayerImpl;
 class OutputSurface;
 class QuadList;
+class RenderSurfaceImpl;
 class ResourceProvider;
 
 class LayerTestCommon {
@@ -78,6 +80,8 @@
     void CalcDrawProps(const gfx::Size& viewport_size);
     void AppendQuadsWithOcclusion(LayerImpl* layer_impl,
                                   const gfx::Rect& occluded);
+    void AppendSurfaceQuadsWithOcclusion(RenderSurfaceImpl* surface_impl,
+                                         const gfx::Rect& occluded);
 
     OutputSurface* output_surface() const {
       return host_->host_impl()->output_surface();
diff --git a/cc/test/mock_quad_culler.cc b/cc/test/mock_quad_culler.cc
index d15f126..54d631c 100644
--- a/cc/test/mock_quad_culler.cc
+++ b/cc/test/mock_quad_culler.cc
@@ -30,11 +30,22 @@
 gfx::Rect MockQuadCuller::UnoccludedContentRect(
     const gfx::Rect& content_rect,
     const gfx::Transform& draw_transform) {
+  DCHECK(draw_transform.IsIdentity() || occluded_content_rect_.IsEmpty());
   gfx::Rect result = content_rect;
   result.Subtract(occluded_content_rect_);
   return result;
 }
 
+gfx::Rect MockQuadCuller::UnoccludedContributingSurfaceContentRect(
+    const gfx::Rect& content_rect,
+    const gfx::Transform& draw_transform) {
+  DCHECK(draw_transform.IsIdentity() ||
+         occluded_content_rect_for_contributing_surface_.IsEmpty());
+  gfx::Rect result = content_rect;
+  result.Subtract(occluded_content_rect_for_contributing_surface_);
+  return result;
+}
+
 bool MockQuadCuller::MaybeAppend(scoped_ptr<DrawQuad> draw_quad) {
   if (!draw_quad->rect.IsEmpty()) {
     active_quad_list_->push_back(draw_quad.Pass());
diff --git a/cc/test/mock_quad_culler.h b/cc/test/mock_quad_culler.h
index 543b8ec1..2d9486b 100644
--- a/cc/test/mock_quad_culler.h
+++ b/cc/test/mock_quad_culler.h
@@ -26,6 +26,9 @@
   virtual gfx::Rect UnoccludedContentRect(const gfx::Rect& content_rect,
                                           const gfx::Transform& draw_transform)
       OVERRIDE;
+  virtual gfx::Rect UnoccludedContributingSurfaceContentRect(
+      const gfx::Rect& content_rect,
+      const gfx::Transform& draw_transform) OVERRIDE;
   virtual bool MaybeAppend(scoped_ptr<DrawQuad> draw_quad) OVERRIDE;
   virtual void Append(scoped_ptr<DrawQuad> draw_quad) OVERRIDE;
 
@@ -38,6 +41,11 @@
     occluded_content_rect_ = occluded;
   }
 
+  void set_occluded_content_rect_for_contributing_surface(
+      const gfx::Rect& occluded) {
+    occluded_content_rect_for_contributing_surface_ = occluded;
+  }
+
   void clear_lists() {
     active_quad_list_->clear();
     active_shared_quad_state_list_->clear();
@@ -49,6 +57,7 @@
   SharedQuadStateList* active_shared_quad_state_list_;
   SharedQuadStateList shared_quad_state_storage_;
   gfx::Rect occluded_content_rect_;
+  gfx::Rect occluded_content_rect_for_contributing_surface_;
 };
 
 }  // namespace cc
diff --git a/cc/trees/quad_culler.cc b/cc/trees/quad_culler.cc
index f161f64..68ef157f 100644
--- a/cc/trees/quad_culler.cc
+++ b/cc/trees/quad_culler.cc
@@ -44,6 +44,13 @@
       layer_->render_target(), content_rect, draw_transform);
 }
 
+gfx::Rect QuadCuller::UnoccludedContributingSurfaceContentRect(
+    const gfx::Rect& content_rect,
+    const gfx::Transform& draw_transform) {
+  return occlusion_tracker_.UnoccludedContributingSurfaceContentRect(
+      layer_, content_rect, draw_transform);
+}
+
 static inline bool AppendQuadInternal(
     scoped_ptr<DrawQuad> draw_quad,
     const gfx::Rect& culled_rect,
diff --git a/cc/trees/quad_culler.h b/cc/trees/quad_culler.h
index 74aae6d..de2aa3e 100644
--- a/cc/trees/quad_culler.h
+++ b/cc/trees/quad_culler.h
@@ -30,6 +30,9 @@
   virtual gfx::Rect UnoccludedContentRect(const gfx::Rect& content_rect,
                                           const gfx::Transform& draw_transform)
       OVERRIDE;
+  virtual gfx::Rect UnoccludedContributingSurfaceContentRect(
+      const gfx::Rect& content_rect,
+      const gfx::Transform& draw_transform) OVERRIDE;
   virtual bool MaybeAppend(scoped_ptr<DrawQuad> draw_quad) OVERRIDE;
   virtual void Append(scoped_ptr<DrawQuad> draw_quad) OVERRIDE;