Bug 1275694 - Use the local visible region to decide when to cull a layer in CalculateScissorRect(). r=kats, a=lizzard
authorMatt Woodrow <mwoodrow@mozilla.com>, Botond Ballo <botond@mozilla.com>
Thu, 09 Jun 2016 16:36:12 +1200
changeset 339962 a1269ccfe4c13e0b2ea9334ad42f292d910b90bf
parent 339961 65aee59b180854a503b0642e708bd7081785b31a
child 339963 4f2339c77cfcd694eed4d7261491d5791ac735b6
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, lizzard
bugs1275694
milestone49.0a2
Bug 1275694 - Use the local visible region to decide when to cull a layer in CalculateScissorRect(). r=kats, a=lizzard We still take care not to cull a layer if we need to draw a checkerboarding background for it. MozReview-Commit-ID: 3EuXEFB2wF9
gfx/layers/Layers.cpp
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -799,25 +799,23 @@ Layer::CalculateScissorRect(const Render
   } else {
     currentClip = aCurrentScissorRect;
   }
 
   if (!clipLayer->GetLocalClipRect()) {
     return currentClip;
   }
 
-  if (GetVisibleRegion().IsEmpty()) {
+  if (GetLocalVisibleRegion().IsEmpty() &&
+      !(AsLayerComposite() && AsLayerComposite()->NeedToDrawCheckerboarding())) {
     // When our visible region is empty, our parent may not have created the
     // intermediate surface that we would require for correct clipping; however,
     // this does not matter since we are invisible.
-    // Note that we do not use GetLocalVisibleRegion(), because that can be
-    // empty for a layer whose rendered contents have been async-scrolled
-    // completely offscreen, but for which we still need to draw a
-    // checkerboarding backround color, and calculating an empty scissor rect
-    // for such a layer would prevent that (see bug 1247452 comment 10).
+    // Make sure we still compute a clip rect if we want to draw checkboarding
+    // for this layer, since we want to do this even if the layer is invisible.
     return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
   }
 
   const RenderTargetIntRect clipRect =
     ViewAs<RenderTargetPixel>(*clipLayer->GetLocalClipRect(),
                               PixelCastJustification::RenderTargetIsParentLayerForRoot);
   if (clipRect.IsEmpty()) {
     // We might have a non-translation transform in the container so we can't
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -48,34 +48,16 @@
 #define XY(k)    (k).x, (k).y
 #define WH(k)    (k).width, (k).height
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
-static bool
-LayerHasCheckerboardingAPZC(Layer* aLayer, Color* aOutColor)
-{
-  for (LayerMetricsWrapper i(aLayer, LayerMetricsWrapper::StartAt::BOTTOM); i; i = i.GetParent()) {
-    if (!i.Metrics().IsScrollable()) {
-      continue;
-    }
-    if (i.GetApzc() && i.GetApzc()->IsCurrentlyCheckerboarding()) {
-      if (aOutColor) {
-        *aOutColor = i.Metadata().GetBackgroundColor();
-      }
-      return true;
-    }
-    break;
-  }
-  return false;
-}
-
 static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
                           LayerManagerComposite* aManager,
                           Layer* aLayer)
 {
 
   if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
     // XXX - should figure out a way to render this, but for now this
     // is hard to do, since it will often get superimposed over the first
@@ -352,25 +334,16 @@ ContainerRenderVR(ContainerT* aContainer
   // full rect, not just the visible one.  Luckily, right now, VR distortion is only
   // rendered when the element is fullscreen, so the visibleRect will be right anyway.
   aManager->GetCompositor()->DrawQuad(Rect(rect), clipRect, vrEffect, opacity,
                                       scaleTransform);
 
   DUMP("<<< ContainerRenderVR [%p]\n", aContainer);
 }
 
-static bool
-NeedToDrawCheckerboardingForLayer(Layer* aLayer, Color* aOutCheckerboardingColor)
-{
-  return (aLayer->Manager()->AsyncPanZoomEnabled() &&
-         aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
-         aLayer->IsOpaqueForVisibility() &&
-         LayerHasCheckerboardingAPZC(aLayer, aOutCheckerboardingColor);
-}
-
 /* all of the prepared data that we need in RenderLayer() */
 struct PreparedData
 {
   RefPtr<CompositingRenderTarget> mTmpTarget;
   AutoTArray<PreparedLayer, 12> mLayers;
   bool mNeedsSurfaceCopy;
 };
 
@@ -407,17 +380,17 @@ ContainerPrepare(ContainerT* aContainer,
     if (layerToRender->GetLayer()->IsBackfaceHidden()) {
       continue;
     }
 
     // We don't want to skip container layers because otherwise their mPrepared
     // may be null which is not allowed.
     if (!layerToRender->GetLayer()->AsContainerLayer()) {
       if (!layerToRender->GetLayer()->IsVisible() &&
-          !NeedToDrawCheckerboardingForLayer(layerToRender->GetLayer(), nullptr)) {
+          !layerToRender->NeedToDrawCheckerboarding(nullptr)) {
         CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
         continue;
       }
 
       if (clipRect.IsEmpty()) {
         CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
         continue;
       }
@@ -606,17 +579,17 @@ RenderLayers(ContainerT* aContainer,
     const RenderTargetIntRect& clipRect = preparedData.mClipRect;
     Layer* layer = layerToRender->GetLayer();
 
     if (layerToRender->HasStaleCompositor()) {
       continue;
     }
 
     Color color;
-    if (NeedToDrawCheckerboardingForLayer(layer, &color)) {
+    if (layerToRender->NeedToDrawCheckerboarding(&color)) {
       if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
         color = Color(255 / 255.f, 188 / 255.f, 217 / 255.f, 1.f); // "Cotton Candy"
       }
       // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
       // and only fill in that area. However the layer bounds takes into account the base translation
       // for the painted layer whereas the checkerboard region does not. One does not simply
       // intersect areas in different coordinate spaces. So we do this a little more permissively
       // and only fill in the background when we know there is checkerboard, which in theory
@@ -938,17 +911,16 @@ RefLayerComposite::RenderLayer(const gfx
 }
 
 void
 RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
 {
   ContainerPrepare(this, mCompositeManager, aClipRect);
 }
 
-
 void
 RefLayerComposite::CleanupResources()
 {
   mLastIntermediateSurface = nullptr;
   mVRRenderTargetSet = nullptr;
   mPrepared = nullptr;
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -17,16 +17,17 @@
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "LayerScope.h"                 // for LayerScope Tool
 #include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
 #include "PaintedLayerComposite.h"      // for PaintedLayerComposite
 #include "TiledContentHost.h"
 #include "Units.h"                      // for ScreenIntRect
 #include "UnitTransforms.h"             // for ViewAs
+#include "apz/src/AsyncPanZoomController.h"  // for AsyncPanZoomController
 #include "gfxPrefs.h"                   // for gfxPrefs
 #ifdef XP_MACOSX
 #include "gfxPlatformMac.h"
 #endif
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for frame color util
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
@@ -1585,16 +1586,45 @@ LayerComposite::GetShadowTransform() {
 }
 
 bool
 LayerComposite::HasStaleCompositor() const
 {
   return mCompositeManager->GetCompositor() != mCompositor;
 }
 
+static bool
+LayerHasCheckerboardingAPZC(Layer* aLayer, Color* aOutColor)
+{
+  bool answer = false;
+  for (LayerMetricsWrapper i(aLayer, LayerMetricsWrapper::StartAt::BOTTOM); i; i = i.GetParent()) {
+    if (!i.Metrics().IsScrollable()) {
+      continue;
+    }
+    if (i.GetApzc() && i.GetApzc()->IsCurrentlyCheckerboarding()) {
+      if (aOutColor) {
+        *aOutColor = i.Metadata().GetBackgroundColor();
+      }
+      answer = true;
+      break;
+    }
+    break;
+  }
+  return answer;
+}
+
+bool
+LayerComposite::NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor)
+{
+  return GetLayer()->Manager()->AsyncPanZoomEnabled() &&
+         (GetLayer()->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+         GetLayer()->IsOpaqueForVisibility() &&
+         LayerHasCheckerboardingAPZC(GetLayer(), aOutCheckerboardingColor);
+}
+
 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
 
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -532,16 +532,22 @@ public:
 
   /**
    * Return the part of the visible region that has been fully rendered.
    * While progressive drawing is in progress this region will be
    * a subset of the shadow visible region.
    */
   virtual nsIntRegion GetFullyRenderedRegion();
 
+  /**
+   * Return true if a checkerboarding background color needs to be drawn
+   * for this layer.
+   */
+  bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr);
+
 protected:
   gfx::Matrix4x4 mShadowTransform;
   LayerIntRegion mShadowVisibleRegion;
   Maybe<ParentLayerIntRect> mShadowClipRect;
   LayerManagerComposite* mCompositeManager;
   RefPtr<Compositor> mCompositor;
   float mShadowOpacity;
   bool mShadowTransformSetByAnimation;