Move buffer related decisions into their own function. (bug 1409871 part 11, r=nical) draft
authorRyan Hunt <rhunt@eqrion.net>
Thu, 12 Oct 2017 19:52:29 -0400
changeset 684133 6e66802c290c371d3752f4a241bca4f145c9cd98
parent 684132 6b4e3c69d0275b13bcf305b6a8636754772be5a4
child 684134 a83ce18da11a92c7d5892099a94aec059b392702
push id85567
push userbmo:rhunt@eqrion.net
push dateFri, 20 Oct 2017 22:13:22 +0000
reviewersnical
bugs1409871
milestone58.0a1
Move buffer related decisions into their own function. (bug 1409871 part 11, r=nical) This commit splits off the part of BeginPaint that makes the decision about whether to keep the buffer, its surface type, its content type, and the regions to invalidate or paint. MozReview-Commit-ID: JcPlv8GiRpA
gfx/layers/RotatedBuffer.cpp
gfx/layers/RotatedBuffer.h
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix
 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for ExtendMode::ExtendMode::CLAMP, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowableLayer
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
+#include "mozilla/Move.h"               // for Move
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "gfx2DGlue.h"
 #include "nsLayoutUtils.h"              // for invalidation debugging
 #include "PaintThread.h"
 
 namespace mozilla {
 
 using namespace gfx;
@@ -581,16 +582,116 @@ SourceRotatedBuffer::GetSourceSurface(Co
     MOZ_ASSERT(aSource == BUFFER_WHITE);
     surf = mSourceOnWhite;
   }
 
   MOZ_ASSERT(surf);
   return surf.forget();
 }
 
+RotatedContentBuffer::BufferDecision
+RotatedContentBuffer::CalculateBufferForPaint(PaintedLayer* aLayer,
+                                              uint32_t aFlags)
+{
+  ContentType layerContentType =
+    aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
+                                    gfxContentType::COLOR_ALPHA;
+
+  SurfaceMode mode;
+  ContentType contentType;
+  IntRect destBufferRect;
+  nsIntRegion neededRegion;
+  nsIntRegion validRegion = aLayer->GetValidRegion();
+
+  bool canReuseBuffer = HaveBuffer();
+  bool canKeepBufferContents = true;
+
+  while (true) {
+    mode = aLayer->GetSurfaceMode();
+    neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
+    canReuseBuffer &= BufferSizeOkFor(neededRegion.GetBounds().Size());
+    contentType = layerContentType;
+
+    if (canReuseBuffer) {
+      if (mBufferRect.Contains(neededRegion.GetBounds())) {
+        // We don't need to adjust mBufferRect.
+        destBufferRect = mBufferRect;
+      } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) {
+        // The buffer's big enough but doesn't contain everything that's
+        // going to be visible. We'll move it.
+        destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
+      } else {
+        destBufferRect = neededRegion.GetBounds();
+      }
+    } else {
+      // We won't be reusing the buffer.  Compute a new rect.
+      destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+    }
+
+    if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
+      mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+#else
+      if (!aLayer->GetParent() ||
+          !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
+          !aLayer->AsShadowableLayer() ||
+          !aLayer->AsShadowableLayer()->HasShadow()) {
+        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+      } else {
+        contentType = gfxContentType::COLOR;
+      }
+#endif
+    }
+
+    if ((aFlags & PAINT_WILL_RESAMPLE) &&
+        (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
+         neededRegion.GetNumRects() > 1))
+    {
+      // The area we add to neededRegion might not be painted opaquely.
+      if (mode == SurfaceMode::SURFACE_OPAQUE) {
+        contentType = gfxContentType::COLOR_ALPHA;
+        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+      }
+
+      // We need to validate the entire buffer, to make sure that only valid
+      // pixels are sampled.
+      neededRegion = destBufferRect;
+    }
+
+    // If we have an existing buffer, but the content type has changed or we
+    // have transitioned into/out of component alpha, then we need to recreate it.
+    if (canReuseBuffer &&
+        (contentType != BufferContentType() ||
+        (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
+    {
+      // Restart the decision process; we won't re-enter since we guard on
+      // being able to re-use the buffer.
+      canReuseBuffer = false;
+      canKeepBufferContents = false;
+      validRegion.SetEmpty();
+      continue;
+    }
+
+    break;
+  }
+
+  NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
+               "Destination rect doesn't contain what we need to paint");
+
+  BufferDecision dest;
+  dest.mNeededRegion = Move(neededRegion);
+  dest.mValidRegion = Move(validRegion);
+  dest.mBufferRect = destBufferRect;
+  dest.mBufferMode = mode;
+  dest.mBufferContentType = contentType;
+  dest.mCanReuseBuffer = canReuseBuffer;
+  dest.mCanKeepBufferContents = canKeepBufferContents;
+  return dest;
+}
+
 gfxContentType
 RotatedContentBuffer::BufferContentType()
 {
   if (mBufferProvider || (mDTBuffer && mDTBuffer->IsValid())) {
     SurfaceFormat format = SurfaceFormat::B8G8R8A8;
 
     if (mBufferProvider) {
       format = mBufferProvider->GetFormat();
@@ -664,224 +765,154 @@ RotatedContentBuffer::FlushBuffers()
 }
 
 RotatedContentBuffer::PaintState
 RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
                                  uint32_t aFlags)
 {
   PaintState result;
 
-  nsIntRegion validRegion = aLayer->GetValidRegion();
-
-  bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
-  ContentType layerContentType =
-    canUseOpaqueSurface ? gfxContentType::COLOR :
-                          gfxContentType::COLOR_ALPHA;
-
-  SurfaceMode mode;
-  nsIntRegion neededRegion;
-  IntRect destBufferRect;
-
-  bool canReuseBuffer = HaveBuffer();
-
-  while (true) {
-    mode = aLayer->GetSurfaceMode();
-    neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
-    canReuseBuffer &= BufferSizeOkFor(neededRegion.GetBounds().Size());
-    result.mContentType = layerContentType;
-
-    if (canReuseBuffer) {
-      if (mBufferRect.Contains(neededRegion.GetBounds())) {
-        // We don't need to adjust mBufferRect.
-        destBufferRect = mBufferRect;
-      } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) {
-        // The buffer's big enough but doesn't contain everything that's
-        // going to be visible. We'll move it.
-        destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
-      } else {
-        destBufferRect = neededRegion.GetBounds();
-      }
-    } else {
-      // We won't be reusing the buffer.  Compute a new rect.
-      destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
-    }
+  BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
+  result.mContentType = dest.mBufferContentType;
 
-    if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
-      mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
-#else
-      if (!aLayer->GetParent() ||
-          !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
-          !aLayer->AsShadowableLayer() ||
-          !aLayer->AsShadowableLayer()->HasShadow()) {
-        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
-      } else {
-        result.mContentType = gfxContentType::COLOR;
-      }
-#endif
-    }
-
-    if ((aFlags & PAINT_WILL_RESAMPLE) &&
-        (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
-         neededRegion.GetNumRects() > 1))
-    {
-      // The area we add to neededRegion might not be painted opaquely.
-      if (mode == SurfaceMode::SURFACE_OPAQUE) {
-        result.mContentType = gfxContentType::COLOR_ALPHA;
-        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
-      }
-
-      // We need to validate the entire buffer, to make sure that only valid
-      // pixels are sampled.
-      neededRegion = destBufferRect;
-    }
-
-    // If we have an existing buffer, but the content type has changed or we
-    // have transitioned into/out of component alpha, then we need to recreate it.
-    if (canReuseBuffer &&
-        (result.mContentType != BufferContentType() ||
-        (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
-    {
-      // Restart the decision process; we won't re-enter since we guard on
-      // being able to re-use the buffer.
-      canReuseBuffer = false;
-      continue;
-    }
-
-    break;
-  }
-
-  if (HaveBuffer() &&
-      (result.mContentType != BufferContentType() ||
-      (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
-  {
+  if (!dest.mCanKeepBufferContents) {
     // We're effectively clearing the valid region, so we need to draw
     // the entire needed region now.
-    canReuseBuffer = false;
+    MOZ_ASSERT(!dest.mCanReuseBuffer);
+    MOZ_ASSERT(dest.mValidRegion.IsEmpty());
+
     result.mRegionToInvalidate = aLayer->GetValidRegion();
-    validRegion.SetEmpty();
     Clear();
 
 #if defined(MOZ_DUMP_PAINTING)
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       if (result.mContentType != BufferContentType()) {
         printf_stderr("Invalidating entire rotated buffer (layer %p): content type changed\n", aLayer);
-      } else if ((mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()) {
+      } else if ((dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()) {
         printf_stderr("Invalidating entire rotated buffer (layer %p): component alpha changed\n", aLayer);
       }
     }
 #endif
   }
 
-  NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
-               "Destination rect doesn't contain what we need to paint");
-
-  result.mRegionToDraw.Sub(neededRegion, validRegion);
+  result.mRegionToDraw.Sub(dest.mNeededRegion,
+                           dest.mValidRegion);
 
   if (result.mRegionToDraw.IsEmpty())
     return result;
 
   if (HaveBuffer()) {
     if (LockBuffers()) {
       // Do not modify result.mRegionToDraw or result.mContentType after this call.
       // Do not modify mBufferRect, mBufferRotation, or mDidSelfCopy,
       // or call CreateBuffer before this call.
       FinalizeFrame(result.mRegionToDraw);
     } else {
       // Abandon everything and redraw it all. Ideally we'd reallocate and copy
       // the old to the new and then call FinalizeFrame on the new buffer so that
       // we only need to draw the latest bits, but we need a big refactor to support
       // that ordering.
-      result.mRegionToDraw = neededRegion;
-      canReuseBuffer = false;
+      result.mRegionToDraw = dest.mNeededRegion;
+      dest.mCanReuseBuffer = false;
       Clear();
     }
   }
 
   // We need to disable rotation if we're going to be resampled when
   // drawing, because we might sample across the rotation boundary.
   // Also disable buffer rotation when using webrender.
   bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
                          !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
                          !(aLayer->Manager()->AsWebRenderLayerManager());
   bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
 
   IntRect drawBounds = result.mRegionToDraw.GetBounds();
   RefPtr<DrawTarget> destDTBuffer;
   RefPtr<DrawTarget> destDTBufferOnWhite;
   uint32_t bufferFlags = 0;
-  if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+  if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
     bufferFlags |= BUFFER_COMPONENT_ALPHA;
   }
-  if (canReuseBuffer) {
+  if (dest.mCanReuseBuffer) {
     if (!EnsureBuffer() ||
         (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
       return result;
     }
 
-    if (!AdjustTo(destBufferRect,
+    if (!AdjustTo(dest.mBufferRect,
                   drawBounds,
                   canHaveRotation,
                   canDrawRotated)) {
-      destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
-      CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
+      dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
+      CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags,
                    &destDTBuffer, &destDTBufferOnWhite);
 
       if (!destDTBuffer ||
           (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
-        if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
-          gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
+        if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+          gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get())
+                          << " dw=" << hexa(destDTBufferOnWhite.get())
+                          << " for " << dest.mBufferRect.x << ", "
+                          << dest.mBufferRect.y << ", "
+                          << dest.mBufferRect.Width() << ", "
+                          << dest.mBufferRect.Height();
         }
         return result;
       }
     }
   } else {
     // The buffer's not big enough, so allocate a new one
-    CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
+    CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags,
                  &destDTBuffer, &destDTBufferOnWhite);
     if (!destDTBuffer ||
         (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
-      if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
-        gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
+      if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+        gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get())
+                        << " dw=" << hexa(destDTBufferOnWhite.get())
+                        << " for " << dest.mBufferRect.x << ", "
+                        << dest.mBufferRect.y << ", "
+                        << dest.mBufferRect.Width() << ", "
+                        << dest.mBufferRect.Height();
       }
       return result;
     }
   }
 
-  NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
+  NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
                "If we're resampling, we need to validate the entire buffer");
 
   // If needed, copy the old buffer over to the new one
   if (destDTBuffer) {
     if ((HaveBuffer() && EnsureBuffer()) &&
-        (mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (HaveBufferOnWhite() && EnsureBufferOnWhite()))) {
+        (dest.mBufferMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (HaveBufferOnWhite() && EnsureBufferOnWhite()))) {
       DrawTargetRotatedBuffer oldBuffer = DrawTargetRotatedBuffer(mDTBuffer, mDTBufferOnWhite,
                                                                   mBufferRect, mBufferRotation);
 
       mDTBuffer = destDTBuffer.forget();
       mDTBufferOnWhite = destDTBufferOnWhite.forget();
-      mBufferRect = destBufferRect;
+      mBufferRect = dest.mBufferRect;
       mBufferRotation = IntPoint(0,0);
 
       UpdateDestinationFrom(oldBuffer, nsIntRegion(mBufferRect));
     } else {
       mDTBuffer = destDTBuffer.forget();
       mDTBufferOnWhite = destDTBufferOnWhite.forget();
-      mBufferRect = destBufferRect;
+      mBufferRect = dest.mBufferRect;
       mBufferRotation = IntPoint(0,0);
     }
   }
   NS_ASSERTION(canHaveRotation || mBufferRotation == IntPoint(0,0),
                "Rotation disabled, but we have nonzero rotation?");
 
   nsIntRegion invalidate;
-  invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
+  invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
+
   result.mClip = DrawRegionClip::DRAW;
-  result.mMode = mode;
+  result.mMode = dest.mBufferMode;
 
   return result;
 }
 
 RefPtr<CapturedPaintState>
 RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
                                                    DrawIterator* aIter,
                                                    bool aSetTransform)
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -466,16 +466,29 @@ protected:
 
     mBufferProviderOnWhite = aClient;
     if (!mBufferProviderOnWhite) {
       mDTBufferOnWhite = nullptr;
     }
   }
 
 protected:
+  struct BufferDecision {
+    nsIntRegion mNeededRegion;
+    nsIntRegion mValidRegion;
+    gfx::IntRect mBufferRect;
+    SurfaceMode mBufferMode;
+    ContentType mBufferContentType;
+    bool mCanReuseBuffer;
+    bool mCanKeepBufferContents;
+  };
+
+  BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer,
+                                         uint32_t aFlags);
+
   /**
    * Return the buffer's content type.  Requires a valid buffer or
    * buffer provider.
    */
   gfxContentType BufferContentType();
   bool BufferSizeOkFor(const gfx::IntSize& aSize);
   /**
    * If the buffer hasn't been mapped, map it.