Bug 1208829 - Recompute visible regions during composition. r=mstange
authorBotond Ballo <botond@mozilla.com>
Mon, 23 Nov 2015 14:45:53 -0500
changeset 308675 ace5242c0852582f9f4649b220ce12928645fa94
parent 308674 8ab97eef69965d91500ab6689718df76b69035d2
child 308676 023df5fce87e6ef5b2588cf06a62334ea51de537
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1208829
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1208829 - Recompute visible regions during composition. r=mstange
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -200,47 +200,75 @@ LayerManagerComposite::BeginTransactionW
 
   mIsCompositorReady = true;
   mCompositor->SetTargetContext(aTarget, aRect);
   mTarget = aTarget;
   mTargetBounds = aRect;
 }
 
 void
-LayerManagerComposite::PostProcessLayers(Layer* aLayer, nsIntRegion& aOpaqueRegion)
+LayerManagerComposite::PostProcessLayers(Layer* aLayer,
+                                         nsIntRegion& aOpaqueRegion,
+                                         LayerIntRegion& aVisibleRegion)
 {
   nsIntRegion localOpaque;
   Matrix transform2d;
   Maybe<nsIntPoint> integerTranslation;
   // If aLayer has a simple transform (only an integer translation) then we
   // can easily convert aOpaqueRegion into pre-transform coordinates and include
   // that region.
   if (aLayer->GetLocalTransform().Is2D(&transform2d)) {
     if (transform2d.IsIntegerTranslation()) {
       integerTranslation = Some(TruncatedToInt(transform2d.GetTranslation()));
       localOpaque = aOpaqueRegion;
       localOpaque.MoveBy(-*integerTranslation);
     }
   }
 
-  // Subtract any areas that we know to be opaque from our
-  // visible region.
-  LayerComposite* composite = aLayer->AsLayerComposite();
-  if (!localOpaque.IsEmpty()) {
-    nsIntRegion visible = composite->GetShadowVisibleRegion();
-    visible.SubOut(localOpaque);
-    composite->SetShadowVisibleRegion(visible);
+  // Save the value of localOpaque, which currently stores the region obscured
+  // by siblings (and uncles and such), before our descendants contribute to it.
+  nsIntRegion obscured = localOpaque;
+
+  // Recurse on our descendants, in front-to-back order. In this process:
+  //  - Occlusions are computed for them, and they contribute to localOpaque.
+  //  - They recalculate their visible regions, and accumulate them into
+  //    descendantsVisibleRegion.
+  LayerIntRegion descendantsVisibleRegion;
+  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
+    PostProcessLayers(child, localOpaque, descendantsVisibleRegion);
   }
 
-  // Compute occlusions for our descendants (in front-to-back order) and allow them to
-  // contribute to localOpaque.
-  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
-    PostProcessLayers(child, localOpaque);
+  // Recalculate our visible region.
+  LayerComposite* composite = aLayer->AsLayerComposite();
+  LayerIntRegion visible = LayerIntRegion::FromUnknownRegion(composite->GetShadowVisibleRegion());
+
+  // If we have descendants, throw away the visible region stored on this
+  // layer, and use the region accumulated by our descendants instead.
+  if (aLayer->GetFirstChild()) {
+    visible = descendantsVisibleRegion;
+  }
+
+  // Subtract any areas that we know to be opaque.
+  if (!obscured.IsEmpty()) {
+    visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured));
   }
 
+  composite->SetShadowVisibleRegion(visible.ToUnknownRegion());
+
+  // Transform the newly calculated visible region into our parent's space,
+  // apply our clip to it (if any), and accumulate it into |aVisibleRegion|
+  // for the caller to use.
+  ParentLayerIntRegion visibleParentSpace = TransformTo<ParentLayerPixel>(
+      aLayer->GetLocalTransform(), visible);
+  if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) {
+    visibleParentSpace.AndWith(*clipRect);
+  }
+  aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
+      PixelCastJustification::MovingDownToChildren));
+
   // If we have a simple transform, then we can add our opaque area into
   // aOpaqueRegion.
   if (integerTranslation &&
       !aLayer->HasMaskLayers() &&
       aLayer->IsOpaqueForVisibility()) {
     if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
       localOpaque.OrWith(composite->GetFullyRenderedRegion());
     }
@@ -356,17 +384,18 @@ LayerManagerComposite::UpdateAndRender()
 
   if (!didEffectiveTransforms) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
   }
 
   nsIntRegion opaque;
-  PostProcessLayers(mRoot, opaque);
+  LayerIntRegion visible;
+  PostProcessLayers(mRoot, opaque, visible);
 
   Render(invalid);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   RenderToPresentationSurface();
 #endif
   mGeometryChanged = false;
   mWindowOverlayChanged = false;
 }
@@ -1015,17 +1044,18 @@ LayerManagerComposite::RenderToPresentat
                                                   rotation);
   viewMatrix.Invert(); // unrotate
   viewMatrix.PostScale(scale, scale);
   viewMatrix.PostTranslate(offset.x, offset.y);
   Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix);
 
   mRoot->ComputeEffectiveTransforms(matrix);
   nsIntRegion opaque;
-  PostProcessLayers(mRoot, opaque);
+  LayerIntRegion visible;
+  PostProcessLayers(mRoot, opaque, visible);
 
   nsIntRegion invalid;
   Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
   Rect rect, actualBounds;
 
   mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
 
   // The Java side of Fennec sets a scissor rect that accounts for
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -170,18 +170,24 @@ public:
 
   /**
    * Post-processes layers before composition. This performs the following:
    *
    *   - Applies occlusion culling. This restricts the shadow visible region
    *     of layers that are covered with opaque content.
    *     |aOpaqueRegion| is the region already known to be covered with opaque
    *     content, in the post-transform coordinate space of aLayer.
+   *
+   *   - Recomputes visible regions to account for async transforms.
+   *     Each layer accumulates into |aVisibleRegion| its post-transform
+   *     (including async transforms) visible region.
    */
-  void PostProcessLayers(Layer* aLayer, nsIntRegion& aOpaqueRegion);
+  void PostProcessLayers(Layer* aLayer,
+                         nsIntRegion& aOpaqueRegion,
+                         LayerIntRegion& aVisibleRegion);
 
   /**
    * RAII helper class to add a mask effect with the compositable from aMaskLayer
    * to the EffectChain aEffect and notify the compositable when we are done.
    */
   class AutoAddMaskEffect
   {
   public: