Fix a coordinate space bug in the cached invalid region of container layers. (bug 1381666 part 3, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Mon, 31 Jul 2017 12:28:54 -0700
changeset 420849 2736371868ec427366574b77098440ed41cc0e39
parent 420848 368331e8a462cd0fe6e6ea81afb5f4a817e2e5e3
child 420850 c3e6fac14d49d391d4232c7a4bcd248d09b52346
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1381666
milestone56.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
Fix a coordinate space bug in the cached invalid region of container layers. (bug 1381666 part 3, r=mattwoodrow)
gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
gfx/layers/mlgpu/ContainerLayerMLGPU.h
gfx/layers/mlgpu/FrameBuilder.cpp
--- a/gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
+++ b/gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
@@ -14,32 +14,36 @@
 #include "UtilityMLGPU.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
 ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
-  : ContainerLayer(aManager, nullptr)
-  , LayerMLGPU(aManager)
+ : ContainerLayer(aManager, nullptr),
+   LayerMLGPU(aManager),
+   mInvalidateEntireSurface(false)
 {
 }
 
 ContainerLayerMLGPU::~ContainerLayerMLGPU()
 {
   while (mFirstChild) {
     RemoveChild(mFirstChild);
   }
 }
 
 bool
 ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
 {
   if (!UseIntermediateSurface()) {
+    // Set this so we invalidate the entire cached render target (if any)
+    // if our container uses an intermediate surface again later.
+    mInvalidateEntireSurface = true;
     return true;
   }
 
   if ((!mRenderTarget || mChildrenChanged) &&
       gfxPrefs::AdvancedLayersEnableContainerResizing())
   {
     // Try to compute a more accurate visible region.
     AL_LOG("Computing new surface size for container %p:\n", GetLayer());
@@ -59,23 +63,29 @@ ContainerLayerMLGPU::OnPrepareToRender(F
   mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
   mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize();
 
   if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) {
     mRenderTarget = nullptr;
   }
 
   gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
-  if (!mRenderTarget || !gfxPrefs::AdvancedLayersUseInvalidation()) {
+  if (!mRenderTarget ||
+      !gfxPrefs::AdvancedLayersUseInvalidation() ||
+      mInvalidateEntireSurface)
+  {
     // Fine-grained invalidation is disabled, invalidate everything.
     mInvalidRect = viewport;
   } else {
     // Clamp the invalid rect to the viewport.
+    mInvalidRect -= mTargetOffset;
     mInvalidRect = mInvalidRect.Intersect(viewport);
   }
+
+  mInvalidateEntireSurface = false;
   return true;
 }
 
 static IntRect
 GetTransformedBounds(Layer* aLayer)
 {
   IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
   if (bounds.IsEmpty()) {
@@ -178,26 +188,26 @@ ContainerLayerMLGPU::UpdateRenderTarget(
 
   return mRenderTarget;
 }
 
 void
 ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect& aRect)
 {
   // For simplicity we only track the bounds of the invalid area, since regions
-  // are expensive. We can adjust this in the future if needed.
-  gfx::IntRect bounds = aRect;
-  bounds.MoveBy(-GetTargetOffset());
-
+  // are expensive.
+  //
   // Note we add the bounds to the invalid rect from the last frame, since we
-  // only clear the area that we actually paint.
-  if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(bounds)) {
+  // only clear the area that we actually paint. If this overflows we use the
+  // last render target size, since if that changes we'll invalidate everything
+  // anyway.
+  if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(aRect)) {
     mInvalidRect = result.value();
   } else {
-    mInvalidRect = gfx::IntRect(gfx::IntPoint(0, 0), GetTargetSize());
+    mInvalidateEntireSurface = true;
   }
 }
 
 void
 ContainerLayerMLGPU::ClearCachedResources()
 {
   mRenderTarget = nullptr;
 }
--- a/gfx/layers/mlgpu/ContainerLayerMLGPU.h
+++ b/gfx/layers/mlgpu/ContainerLayerMLGPU.h
@@ -62,16 +62,18 @@ protected:
 private:
   RefPtr<MLGRenderTarget> mRenderTarget;
 
   // We cache these since occlusion culling can change the visible region.
   gfx::IntPoint mTargetOffset;
   gfx::IntSize mTargetSize;
 
   // The region of the container that needs to be recomposited if visible. We
-  // store this as a rectangle instead of an nsIntRegion for efficiency.
+  // store this as a rectangle instead of an nsIntRegion for efficiency. This
+  // is in layer coordinates.
   gfx::IntRect mInvalidRect;
+  bool mInvalidateEntireSurface;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h
--- a/gfx/layers/mlgpu/FrameBuilder.cpp
+++ b/gfx/layers/mlgpu/FrameBuilder.cpp
@@ -157,16 +157,17 @@ FrameBuilder::ProcessContainerLayer(Cont
 
   // If the container is not part of the invalid region, we don't draw it
   // or traverse it. Note that we do not pass the geometry here. Otherwise
   // we could decide the particular split is not visible, and because of the
   // check above, never bother traversing the container again.
   gfx::IntRect boundingBox = layer->GetClippedBoundingBox(aView, Nothing());
   const gfx::IntRect& invalidRect = aView->GetInvalidRect();
   if (boundingBox.IsEmpty() || !invalidRect.Intersects(boundingBox)) {
+    AL_LOG("Culling ContainerLayer %p that does not need painting\n", aContainer);
     return false;
   }
 
   if (!aContainer->UseIntermediateSurface()) {
     // In case the layer previously required an intermediate surface, we
     // clear any intermediate render targets here.
     layer->ClearCachedResources();