Bug 640444: Self-copies end up changing all buffer content, so we need to read back the entire buffer after swapping. r=Bas a=b
authorChris Jones <jones.chris.g@gmail.com>
Fri, 11 Mar 2011 23:22:39 -0600
changeset 63397 d8fe8514d7e69344437c3f525d99bb862adcec4d
parent 63396 4173c1b88642d3577130394baa3c74640aa05683
child 63398 305256fdcb9abd36d44c7949726b17b5a88d05bf
child 63506 14fc52a00b6cf21735b64aa78783fe0f34dde300
push id19190
push usercjones@mozilla.com
push dateSat, 12 Mar 2011 05:23:08 +0000
treeherdermozilla-central@d8fe8514d7e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, b
bugs640444
milestone2.0b13pre
first release with
nightly linux32
d8fe8514d7e6 / 4.0b13pre / 20110312030414 / files
nightly linux64
d8fe8514d7e6 / 4.0b13pre / 20110312030414 / files
nightly mac
d8fe8514d7e6 / 4.0b13pre / 20110312030414 / files
nightly win32
d8fe8514d7e6 / 4.0b13pre / 20110312030414 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 640444: Self-copies end up changing all buffer content, so we need to read back the entire buffer after swapping. r=Bas a=b
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -217,16 +217,17 @@ WrapRotationAxis(PRInt32* aRotationPoint
 }
 
 ThebesLayerBuffer::PaintState
 ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
                               float aXResolution, float aYResolution,
                               PRUint32 aFlags)
 {
   PaintState result;
+  result.mDidSelfCopy = PR_FALSE;
   float curXRes = aLayer->GetXResolution();
   float curYRes = aLayer->GetYResolution();
 
   nsIntRegion validRegion = aLayer->GetValidRegion();
 
   ContentType contentType;
   nsIntRegion neededRegion;
   nsIntSize destBufferDims;
@@ -331,16 +332,17 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
           (newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
         // The stuff we need to redraw will wrap around an edge of the
         // buffer, so move the pixels we can keep into a position that
         // lets us redraw in just one quadrant.
         if (mBufferRotation == nsIntPoint(0,0)) {
           nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size());
           nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft();
           MovePixels(mBuffer, srcRect, dest, curXRes, curYRes);
+          result.mDidSelfCopy = PR_TRUE;
           // Don't set destBuffer; we special-case self-copies, and
           // just did the necessary work above.
           mBufferRect = destBufferRect;
         } else {
           // We can't do a real self-copy because the buffer is rotated.
           // So allocate a new buffer for the destination.
           destBufferRect = neededRegion.GetBounds();
           bufferDimsChanged = PR_TRUE;
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -105,22 +105,24 @@ public:
   }
 
   /**
    * 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
    * opaque to transparent or vice versa, since the details of rendering can
-   * depend on the buffer type.
+   * depend on the buffer type.  mDidSelfCopy is true if we kept our buffer
+   * but used MovePixels() to shift its content.
    */
   struct PaintState {
     nsRefPtr<gfxContext> mContext;
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
+    PRPackedBool mDidSelfCopy;
   };
 
   enum {
     PAINT_WILL_RESAMPLE = 0x01
   };
   /**
    * Start a drawing operation. This returns a PaintState describing what
    * needs to be drawn to bring the buffer up to date in the visible region.
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -423,16 +423,17 @@ protected:
     return static_cast<BasicLayerManager*>(mManager);
   }
 
   virtual void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
+              PRBool aDidSelfCopy,
               LayerManager::DrawThebesLayerCallback aCallback,
               void* aCallbackData)
   {
     if (!aCallback) {
       BasicManager()->SetTransactionIncomplete();
       return;
     }
     aCallback(this, aContext, aExtendedRegionToDraw, aRegionToInvalidate,
@@ -603,16 +604,17 @@ BasicThebesLayer::PaintThebes(gfxContext
       state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
       nsIntRegion extendedDrawRegion = state.mRegionToDraw;
       extendedDrawRegion.ExtendForScaling(paintXRes, paintYRes);
       mXResolution = paintXRes;
       mYResolution = paintYRes;
       SetAntialiasingFlags(this, state.mContext);
       PaintBuffer(state.mContext,
                   state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
+                  state.mDidSelfCopy,
                   aCallback, aCallbackData);
       Mutated();
     } else {
       // It's possible that state.mRegionToInvalidate is nonempty here,
       // if we are shrinking the valid region to nothing.
       NS_ASSERTION(state.mRegionToDraw.IsEmpty(),
                    "If we need to draw, we should have a context");
     }
@@ -1795,16 +1797,17 @@ private:
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   NS_OVERRIDE virtual void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
+              PRBool aDidSelfCopy,
               LayerManager::DrawThebesLayerCallback aCallback,
               void* aCallbackData);
 
   NS_OVERRIDE virtual already_AddRefed<gfxASurface>
   CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
 
   // This describes the gfxASurface we hand to mBuffer.  We keep a
   // copy of the descriptor here so that we can call
@@ -1855,31 +1858,37 @@ BasicShadowableThebesLayer::SetBackBuffe
   // back buffer (i.e. as they were for the old back buffer)
 }
 
 void
 BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
                                         const nsIntRegion& aRegionToDraw,
                                         const nsIntRegion& aExtendedRegionToDraw,
                                         const nsIntRegion& aRegionToInvalidate,
+                                        PRBool aDidSelfCopy,
                                         LayerManager::DrawThebesLayerCallback aCallback,
                                         void* aCallbackData)
 {
   Base::PaintBuffer(aContext,
                     aRegionToDraw, aExtendedRegionToDraw, aRegionToInvalidate,
+                    aDidSelfCopy,
                     aCallback, aCallbackData);
   if (!HasShadow()) {
     return;
   }
 
   nsIntRegion updatedRegion;
-  if (mIsNewBuffer) {
+  if (mIsNewBuffer || aDidSelfCopy) {
     // A buffer reallocation clears both buffers. The front buffer has all the
     // content by now, but the back buffer is still clear. Here, in effect, we
     // are saying to copy all of the pixels of the front buffer to the back.
+    // Also when we self-copied in the buffer, the buffer space
+    // changes and some changed buffer content isn't reflected in the
+    // draw or invalidate region (on purpose!).  When this happens, we
+    // need to read back the entire buffer too.
     updatedRegion = mVisibleRegion;
     mIsNewBuffer = false;
   } else {
     updatedRegion = aRegionToDraw;
   }
 
   NS_ASSERTION(mBuffer.BufferRect().Contains(aRegionToDraw.GetBounds()),
                "Update outside of buffer rect!");