Bug 992486 - Part 5: Fix copying the front buffer to back buffer. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 10 Apr 2014 20:42:29 +1200
changeset 177949 276c8f37dd5db2155e611a394e7be33651be6198
parent 177948 6656fd9ae6424e195e891795e0f7db1759131e61
child 177950 70af90b7e08b11591ef4bc457186a5561aeb6ec4
push id26569
push userryanvm@gmail.com
push dateFri, 11 Apr 2014 04:11:36 +0000
treeherdermozilla-central@783c5013dbec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs992486
milestone31.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 992486 - Part 5: Fix copying the front buffer to back buffer. r=roc
gfx/layers/RotatedBuffer.cpp
gfx/layers/RotatedBuffer.h
gfx/layers/client/ContentClient.cpp
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -223,18 +223,42 @@ RotatedContentBuffer::DrawTo(ThebesLayer
   DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aOp, aMask, aMaskTransform);
   if (clipped) {
     aTarget->PopClip();
   }
 }
 
 DrawTarget*
 RotatedContentBuffer::BorrowDrawTargetForQuadrantUpdate(const nsIntRect& aBounds,
-                                                        ContextSource aSource)
+                                                        ContextSource aSource,
+                                                        DrawIterator* aIter)
 {
+  nsIntRect bounds = aBounds;
+  if (aIter) {
+    // If an iterator was provided, then BeginPaint must have been run with
+    // PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
+    // Iterate over each of them, and return an appropriate buffer each time we find
+    // one that intersects the draw region. The iterator mCount value tracks which
+    // quadrants we have considered across multiple calls to this function.
+    aIter->mDrawRegion.SetEmpty();
+    while (aIter->mCount < 4) {
+      nsIntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
+        (aIter->mCount & 2) ? TOP : BOTTOM);
+      aIter->mDrawRegion.And(aBounds, quadrant);
+      aIter->mCount++;
+      if (!aIter->mDrawRegion.IsEmpty()) {
+        break;
+      }
+    }
+    if (aIter->mDrawRegion.IsEmpty()) {
+      return nullptr;
+    }
+    bounds = aIter->mDrawRegion.GetBounds();
+  }
+
   if (!EnsureBuffer()) {
     return nullptr;
   }
 
   MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
   if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
     if (!EnsureBufferOnWhite()) {
       return nullptr;
@@ -249,20 +273,20 @@ RotatedContentBuffer::BorrowDrawTargetFo
   } else {
     // BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
     mLoanedDrawTarget = mDTBuffer;
   }
 
   // Figure out which quadrant to draw in
   int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
   int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
-  XSide sideX = aBounds.XMost() <= xBoundary ? RIGHT : LEFT;
-  YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP;
+  XSide sideX = bounds.XMost() <= xBoundary ? RIGHT : LEFT;
+  YSide sideY = bounds.YMost() <= yBoundary ? BOTTOM : TOP;
   nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
-  NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants");
+  NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
 
   mLoanedTransform = mLoanedDrawTarget->GetTransform();
   mLoanedTransform.Translate(-quadrantRect.x, -quadrantRect.y);
   mLoanedDrawTarget->SetTransform(mLoanedTransform);
   mLoanedTransform.Translate(quadrantRect.x, quadrantRect.y);
 
   return mLoanedDrawTarget;
 }
@@ -668,44 +692,29 @@ RotatedContentBuffer::BeginPaint(ThebesL
 DrawTarget*
 RotatedContentBuffer::BorrowDrawTargetForPainting(const PaintState& aPaintState,
                                                   DrawIterator* aIter /* = nullptr */)
 {
   if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
     return nullptr;
   }
 
-  const nsIntRegion* drawPtr;
+  DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
+                                                         BUFFER_BOTH, aIter);
+  if (!result) {
+    return nullptr;
+  }
+  const nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
   if (aIter) {
-    // If an iterator was provided, then BeginPaint must have been run with
-    // PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
-    // Iterate over each of them, and return an appropriate buffer each time we find
-    // one that intersects the draw region. The iterator mCount value tracks which
-    // quadrants we have considered across multiple calls to this function.
-    aIter->mDrawRegion.SetEmpty();
-    while (aIter->mCount < 4) {
-      nsIntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
-                                                (aIter->mCount & 2) ? TOP : BOTTOM);
-      aIter->mDrawRegion.And(aPaintState.mRegionToDraw, quadrant);
-      aIter->mCount++;
-      if (!aIter->mDrawRegion.IsEmpty()) {
-        break;
-      }
-    }
-    if (aIter->mDrawRegion.IsEmpty()) {
-      return nullptr;
-    }
+    // The iterators draw region currently only contains the bounds of the region,
+    // this makes it the precise region.
+    aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
     drawPtr = &aIter->mDrawRegion;
-  } else {
-    drawPtr = &aPaintState.mRegionToDraw;
   }
 
-  DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(drawPtr->GetBounds(),
-                                                         BUFFER_BOTH);
-
   if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
     MOZ_ASSERT(mDTBuffer && mDTBufferOnWhite);
     nsIntRegionRectIterator iter(*drawPtr);
     const nsIntRect *iterRect;
     while ((iterRect = iter.Next())) {
       mDTBuffer->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height),
                           ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
       mDTBufferOnWhite->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height),
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -353,17 +353,18 @@ protected:
    * first calling ReturnDrawTarget.
    *
    * ReturnDrawTarget will restore the transform on the draw target. But it is
    * the callers responsibility to restore the clip. The caller should flush the
    * draw target, if necessary.
    */
   gfx::DrawTarget*
   BorrowDrawTargetForQuadrantUpdate(const nsIntRect& aBounds,
-                                    ContextSource aSource);
+                                    ContextSource aSource,
+                                    DrawIterator* aIter);
 
   static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
 
 protected:
   /**
    * Return the buffer's content type.  Requires a valid buffer or
    * buffer provider.
    */
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -494,56 +494,52 @@ ContentClientDoubleBuffered::FinalizeFra
     mFrontClientOnWhite->Unlock();
   }
 }
 
 void
 ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
                                                    const nsIntRegion& aUpdateRegion)
 {
-  DrawTarget* destDT =
-    BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK);
-  if (!destDT) {
-    return;
-  }
-
-  bool isClippingCheap = IsClippingCheap(destDT, aUpdateRegion);
-  if (isClippingCheap) {
-    gfxUtils::ClipToRegion(destDT, aUpdateRegion);
-  }
-
-  aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
-  if (isClippingCheap) {
-    destDT->PopClip();
-  }
-  // Flush the destination before the sources become inaccessible (Unlock).
-  destDT->Flush();
-  ReturnDrawTargetToBuffer(destDT);
-
-  if (aSource.HaveBufferOnWhite()) {
-    MOZ_ASSERT(HaveBufferOnWhite());
-    DrawTarget* destDT =
-      BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
-    if (!destDT) {
-      return;
+  DrawIterator iter;
+  while (DrawTarget* destDT =
+    BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
+    bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
+    if (isClippingCheap) {
+      gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
     }
 
-    bool isClippingCheap = IsClippingCheap(destDT, aUpdateRegion);
-    if (isClippingCheap) {
-      gfxUtils::ClipToRegion(destDT, aUpdateRegion);
-    }
-
-    aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
+    aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
     if (isClippingCheap) {
       destDT->PopClip();
     }
     // Flush the destination before the sources become inaccessible (Unlock).
     destDT->Flush();
     ReturnDrawTargetToBuffer(destDT);
   }
+
+  if (aSource.HaveBufferOnWhite()) {
+    MOZ_ASSERT(HaveBufferOnWhite());
+    DrawIterator whiteIter;
+    while (DrawTarget* destDT =
+      BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
+      bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
+      if (isClippingCheap) {
+        gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
+      }
+
+      aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
+      if (isClippingCheap) {
+        destDT->PopClip();
+      }
+      // Flush the destination before the sources become inaccessible (Unlock).
+      destDT->Flush();
+      ReturnDrawTargetToBuffer(destDT);
+    }
+  }
 }
 
 void
 ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
 {
   if (mTextureClient) {
     DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
     MOZ_ASSERT(locked);