Bug 570625, part 0: Don't throw out buffers when scrolling with a resolution applied. r=roc
authorChris Jones <jones.chris.g@gmail.com>
Tue, 14 Sep 2010 00:23:08 -0500
changeset 54100 324632361f18ce038234184757d878b5fe21f550
parent 54099 16b228558c58fd66ee3bfb95821f9fa92e204feb
child 54101 5004f6392fb29c0a3a3a54d4b2ffc7ac5bbec4bf
push id15768
push userdougt@mozilla.com
push dateThu, 16 Sep 2010 01:40:23 +0000
treeherdermozilla-central@cdb90b48f19f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs570625
milestone2.0b6pre
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 570625, part 0: Don't throw out buffers when scrolling with a resolution applied. r=roc
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -173,22 +173,23 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
     Clear();
   }
 
   if (result.mRegionToDraw.IsEmpty())
     return result;
   nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
 
   nsIntRect visibleBounds = aLayer->GetVisibleRegion().GetBounds();
-  nsIntSize scaledBufferSize = ScaledSize(visibleBounds.Size(),
-                                          aXResolution, aYResolution);
+  nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(),
+                                        aXResolution, aYResolution);
   nsRefPtr<gfxASurface> destBuffer;
   nsIntRect destBufferRect;
+  PRBool bufferDimsChanged = PR_FALSE;
 
-  if (BufferSizeOkFor(scaledBufferSize)) {
+  if (BufferSizeOkFor(destBufferDims)) {
     NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
                  "resolution changes must Clear()!");
 
     // The current buffer is big enough to hold the visible area.
     if (mBufferRect.Contains(visibleBounds)) {
       // We don't need to adjust mBufferRect.
       destBufferRect = mBufferRect;
     } else {
@@ -214,19 +215,20 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
         // The stuff we need to redraw will wrap around an edge of the
         // buffer, so we will need to do a self-copy
         if (mBufferRotation == nsIntPoint(0,0)) {
           destBuffer = mBuffer;
         } else {
           // We can't do a real self-copy because the buffer is rotated.
           // So allocate a new buffer for the destination.
           destBufferRect = visibleBounds;
-          destBuffer = CreateBuffer(aContentType,
-                                    ScaledSize(destBufferRect.Size(),
-                                               aXResolution, aYResolution));
+          destBufferDims = ScaledSize(destBufferRect.Size(),
+                                      aXResolution, aYResolution);
+          bufferDimsChanged = PR_TRUE;
+          destBuffer = CreateBuffer(aContentType, destBufferDims);
           if (!destBuffer)
             return result;
         }
       } else {
         mBufferRect = destBufferRect;
         mBufferRotation = newRotation;
       }
     } else {
@@ -234,19 +236,20 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
       // will be redrawn, so we don't need to copy anything, so we don't
       // set destBuffer.
       mBufferRect = destBufferRect;
       mBufferRotation = nsIntPoint(0,0);
     }
   } else {
     // The buffer's not big enough, so allocate a new one
     destBufferRect = visibleBounds;
-    destBuffer = CreateBuffer(aContentType,
-                              ScaledSize(destBufferRect.Size(),
-                                         aXResolution, aYResolution));
+    destBufferDims = ScaledSize(destBufferRect.Size(),
+                                aXResolution, aYResolution);
+    bufferDimsChanged = PR_TRUE;
+    destBuffer = CreateBuffer(aContentType, destBufferDims);
     if (!destBuffer)
       return result;
   }
 
   // If we have no buffered data already, then destBuffer will be a fresh buffer
   // and we do not need to clear it below.
   PRBool isClear = mBuffer == nsnull;
 
@@ -262,16 +265,19 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
                    "resolution changes must Clear()!");
       DrawBufferWithRotation(tmpCtx, 1.0, aXResolution, aYResolution);
     }
 
     mBuffer = destBuffer.forget();
     mBufferRect = destBufferRect;
     mBufferRotation = nsIntPoint(0,0);
   }
+  if (bufferDimsChanged) {
+    mBufferDims = destBufferDims;
+  }
 
   nsIntRegion invalidate;
   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
 
   result.mContext = new gfxContext(mBuffer);
 
   // Figure out which quadrant to draw in
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -77,33 +77,35 @@ public:
    *   fit visible bounds.  May be larger.
    */
   enum BufferSizePolicy {
     SizedToVisibleBounds,
     ContainsVisibleBounds
   };
 
   ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
-    : mBufferRotation(0,0)
+    : mBufferDims(0,0)
+    , mBufferRotation(0,0)
     , mBufferSizePolicy(aBufferSizePolicy)
   {
     MOZ_COUNT_CTOR(ThebesLayerBuffer);
   }
   virtual ~ThebesLayerBuffer()
   {
     MOZ_COUNT_DTOR(ThebesLayerBuffer);
   }
 
   /**
    * Wipe out all retained contents. Call this when the entire
    * buffer becomes invalid.
    */
   void Clear()
   {
     mBuffer = nsnull;
+    mBufferDims.SizeTo(0, 0);
     mBufferRect.Empty();
   }
 
   /**
    * This is returned by BeginPaint. The caller should draw into mContext.
    * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
    * by ThebesLayerBuffer and must be redrawn on the screen.
    * mRegionToInvalidate is set when the buffer has changed from
@@ -152,35 +154,42 @@ protected:
                           float aOpacity, float aXRes, float aYRes);
   void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
                               float aXRes, float aYRes);
 
   const nsIntRect& BufferRect() const { return mBufferRect; }
   const nsIntPoint& BufferRotation() const { return mBufferRotation; }
 
   already_AddRefed<gfxASurface>
-  SetBuffer(gfxASurface* aBuffer,
+  SetBuffer(gfxASurface* aBuffer, const nsIntSize& aBufferDims,
             const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
   {
     nsRefPtr<gfxASurface> tmp = mBuffer.forget();
     mBuffer = aBuffer;
+    mBufferDims = aBufferDims;
     mBufferRect = aBufferRect;
     mBufferRotation = aBufferRotation;
     return tmp.forget();
   }
 
 private:
   PRBool BufferSizeOkFor(const nsIntSize& aSize)
   {
-    return (aSize == mBufferRect.Size() ||
+    return (aSize == mBufferDims ||
             (SizedToVisibleBounds != mBufferSizePolicy &&
-             aSize < mBufferRect.Size()));
+             aSize < mBufferDims));
   }
 
   nsRefPtr<gfxASurface> mBuffer;
+  /**
+   * The actual dimensions of mBuffer.  For the ContainsVisibleBounds
+   * policy or with resolution-scaled drawing, mBufferDims might be
+   * different than mBufferRect.Size().
+   */
+  nsIntSize             mBufferDims;
   /** The area of the ThebesLayer that is covered by the buffer as a whole */
   nsIntRect             mBufferRect;
   /**
    * The x and y rotation of the buffer. Conceptually the buffer
    * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
    * is tiled to fill the plane, and the result is clipped to mBufferRect.
    * So the pixel at mBufferRotation within the buffer is what gets painted at
    * mBufferRect.TopLeft().
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1659,21 +1659,22 @@ public:
   }
 
   ~ShadowThebesLayerBuffer()
   {
     MOZ_COUNT_DTOR(ShadowThebesLayerBuffer);
   }
 
   already_AddRefed<gfxSharedImageSurface>
-  Swap(gfxSharedImageSurface* aNewFrontBuffer,
+  Swap(gfxSharedImageSurface* aNewFrontBuffer, const nsIntSize& aBufferDims,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation=nsIntPoint(0, 0))
   {
     nsRefPtr<gfxASurface> newBackBuffer = SetBuffer(aNewFrontBuffer,
+                                                    aBufferDims,
                                                     aBufferRect, aRotation);
     return static_cast<gfxSharedImageSurface*>(newBackBuffer.forget().get());
   }
 
 protected:
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(ContentType aType, const nsIntSize& aSize)
   {
@@ -1703,23 +1704,25 @@ public:
     ShadowThebesLayer::Disconnect();
   }
 
   virtual already_AddRefed<gfxSharedImageSurface>
   Swap(gfxSharedImageSurface* aNewFront,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation)
   {
-    return mFrontBuffer.Swap(aNewFront, aBufferRect, aRotation);
+    gfxIntSize size = aNewFront->GetSize();
+    return mFrontBuffer.Swap(aNewFront, nsIntSize(size.width, size.height),
+                             aBufferRect, aRotation);
   }
 
   virtual void DestroyFrontBuffer()
   {
     nsRefPtr<gfxSharedImageSurface> frontBuffer =
-      mFrontBuffer.Swap(0, nsIntRect());
+      mFrontBuffer.Swap(0, nsIntSize(), nsIntRect());
     if (frontBuffer) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer);
     }
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,