Bug 570625, part 1: Only use back/front buffers for BasicThebesLayer and update back->front in the compositor process. r=roc sr=shaver
authorChris Jones <jones.chris.g@gmail.com>
Tue, 14 Sep 2010 00:23:08 -0500
changeset 54101 5004f6392fb29c0a3a3a54d4b2ffc7ac5bbec4bf
parent 54100 324632361f18ce038234184757d878b5fe21f550
child 54102 fdb0145ee11701331295c7e115a8e15b21bb6f8f
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, shaver
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 1: Only use back/front buffers for BasicThebesLayer and update back->front in the compositor process. r=roc sr=shaver
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -150,16 +150,28 @@ protected:
     TOP, BOTTOM
   };
   nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
   void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
                           float aOpacity, float aXRes, float aYRes);
   void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
                               float aXRes, float aYRes);
 
+  /**
+   * |BufferRect()| is the rect of device pixels that this
+   * ThebesLayerBuffer covers.  That is what DrawBufferWithRotation()
+   * will paint when it's called.
+   *
+   * |BufferDims()| is the actual dimensions of the underlying surface
+   * maintained by this, also in device pixels.  It is *not*
+   * necessarily true that |BufferRect().Size() == BufferDims()|.
+   * They may differ if a ThebesLayer is drawn at a non-1.0
+   * resolution.
+   */
+  const nsIntSize& BufferDims() const { return mBufferDims; }
   const nsIntRect& BufferRect() const { return mBufferRect; }
   const nsIntPoint& BufferRotation() const { return mBufferRotation; }
 
   already_AddRefed<gfxASurface>
   SetBuffer(gfxASurface* aBuffer, const nsIntSize& aBufferDims,
             const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
   {
     nsRefPtr<gfxASurface> tmp = mBuffer.forget();
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -256,16 +256,32 @@ public:
    * to aTarget.
    */
   void DrawTo(ThebesLayer* aLayer, PRBool aIsOpaqueContent,
               gfxContext* aTarget, float aOpacity);
 
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(ContentType aType, const nsIntSize& aSize);
 
+  /**
+   * Swap out the old backing buffer for |aBuffer|.
+   *
+   * CAVEAT EMPTOR: |aBuffer| must have the same dimensions and pixels
+   * as the previous buffer.  If not, rendering glitches will occur.
+   * This is a rather dangerous and low-level interface added in bug
+   * 570625 as an intermediate step to a better interface.
+   */
+  void SetBackingBuffer(gfxASurface* aBuffer)
+  {
+    gfxIntSize prevSize = gfxIntSize(BufferDims().width, BufferDims().height);
+    NS_ABORT_IF_FALSE(aBuffer->GetSize() == prevSize,
+                      "Swapped-in buffer size doesn't match old buffer's!");
+    SetBuffer(aBuffer, BufferDims(), BufferRect(), BufferRotation());
+  }
+
 private:
   BasicThebesLayer* mLayer;
 };
 
 class BasicThebesLayer : public ThebesLayer, BasicImplData {
 public:
   typedef BasicThebesLayerBuffer Buffer;
 
@@ -1338,16 +1354,17 @@ public:
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
 
   virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer)
   {
     mBackBuffer = aBuffer;
+    mBuffer.SetBackingBuffer(aBuffer);
   }
 
   virtual void Disconnect()
   {
     mBackBuffer = nsnull;
     BasicShadowableLayer::Disconnect();
   }
 
@@ -1362,16 +1379,18 @@ private:
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
               LayerManager::DrawThebesLayerCallback aCallback,
               void* aCallbackData);
 
   NS_OVERRIDE virtual already_AddRefed<gfxASurface>
   CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
 
+  // We give a ref to this buffer to our ThebesLayerBuffer, and keep
+  // this ref here that we can destroy its underlying shmem segment.
   nsRefPtr<gfxSharedImageSurface> mBackBuffer;
   nsIntSize mBufferSize;
 };
  
 void
 BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
                                         const nsIntRegion& aRegionToDraw,
                                         const nsIntRegion& aRegionToInvalidate,
@@ -1379,57 +1398,56 @@ BasicShadowableThebesLayer::PaintBuffer(
                                         void* aCallbackData)
 {
   Base::PaintBuffer(aContext, aRegionToDraw, aRegionToInvalidate,
                     aCallback, aCallbackData);
 
   if (HasShadow()) {
     NS_ABORT_IF_FALSE(!!mBackBuffer, "should have a back buffer by now");
 
-    nsRefPtr<gfxContext> tmpCtx = new gfxContext(mBackBuffer);
-    tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    tmpCtx->DrawSurface(aContext->OriginalSurface(),
-                        gfxIntSize(mBufferSize.width, mBufferSize.height));
-
     BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
                                         mBuffer.BufferRect(),
                                         mBuffer.BufferRotation(),
                                         mBackBuffer);
   }
 }
 
 already_AddRefed<gfxASurface>
 BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType,
                                          const nsIntSize& aSize)
 {
-  if (HasShadow()) {
-    if (mBackBuffer) {
-      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer);
-      mBackBuffer = nsnull;
+  if (!HasShadow()) {
+    return BasicThebesLayer::CreateBuffer(aType, aSize);
+  }
 
-      BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this));
-    }
+  if (mBackBuffer) {
+    BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this),
+                                          mBackBuffer);
+    mBackBuffer = nsnull;
+  }
 
-    nsRefPtr<gfxSharedImageSurface> tmpFront;
-    // XXX error handling
-    if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height),
-                                           gfxASurface::ImageFormatARGB32,
-                                           getter_AddRefs(tmpFront),
-                                           getter_AddRefs(mBackBuffer)))
-      NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!");
-    mBufferSize = aSize;
+  gfxASurface::gfxImageFormat format = (aType == gfxASurface::CONTENT_COLOR) ?
+                                       gfxASurface::ImageFormatRGB24 : 
+                                       gfxASurface::ImageFormatARGB32;
+  nsRefPtr<gfxSharedImageSurface> tmpFront;
+  // XXX error handling
+  if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height),
+                                         format,
+                                         getter_AddRefs(tmpFront),
+                                         getter_AddRefs(mBackBuffer)))
+    NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!");
+  mBufferSize = aSize;
 
-    BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
-                                        // only |aSize| really matters
-                                        // here, since Painted() soon
-                                        // follows
-                                        nsIntRect(nsIntPoint(0, 0), aSize),
-                                        tmpFront);
-  }
-  return Base::CreateBuffer(aType, aSize);
+  BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
+                                      // only |aSize| really matters
+                                      // here, since Painted() soon
+                                      // follows
+                                      nsIntRect(nsIntPoint(0, 0), aSize),
+                                      tmpFront);
+  return nsRefPtr<gfxASurface>(mBackBuffer).forget();
 }
 
 
 class BasicShadowableImageLayer : public BasicImageLayer,
                                   public BasicShadowableLayer
 {
 public:
   BasicShadowableImageLayer(BasicShadowLayerManager* aManager) :
@@ -1666,16 +1684,25 @@ public:
   already_AddRefed<gfxSharedImageSurface>
   Swap(gfxSharedImageSurface* aNewFrontBuffer, const nsIntSize& aBufferDims,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation=nsIntPoint(0, 0))
   {
     nsRefPtr<gfxASurface> newBackBuffer = SetBuffer(aNewFrontBuffer,
                                                     aBufferDims,
                                                     aBufferRect, aRotation);
+    if (newBackBuffer && aNewFrontBuffer) {
+      // Copy the new pixels in the new front buffer to our previous
+      // front buffer.  This is intended to be optimized!  Many
+      // factors are involved.
+      nsRefPtr<gfxContext> tmpCtx = new gfxContext(newBackBuffer);
+      tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
+      tmpCtx->DrawSurface(aNewFrontBuffer,
+                          gfxIntSize(aBufferDims.width, aBufferDims.height));
+    }
     return static_cast<gfxSharedImageSurface*>(newBackBuffer.forget().get());
   }
 
 protected:
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(ContentType aType, const nsIntSize& aSize)
   {
     NS_RUNTIMEABORT("ShadowThebesLayer can't paint content");
@@ -1712,17 +1739,17 @@ public:
     gfxIntSize size = aNewFront->GetSize();
     return mFrontBuffer.Swap(aNewFront, nsIntSize(size.width, size.height),
                              aBufferRect, aRotation);
   }
 
   virtual void DestroyFrontBuffer()
   {
     nsRefPtr<gfxSharedImageSurface> frontBuffer =
-      mFrontBuffer.Swap(0, nsIntSize(), nsIntRect());
+      mFrontBuffer.Swap(nsnull, nsIntSize(), nsIntRect());
     if (frontBuffer) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer);
     }
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -47,16 +47,17 @@
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layers/PLayersParent.h"
 #include "ShadowLayers.h"
 #include "ShadowLayerChild.h"
 
 namespace mozilla {
 namespace layers {
 
+typedef nsTArray<nsRefPtr<gfxSharedImageSurface> > BufferArray; 
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
 
 class Transaction
 {
 public:
   Transaction() : mOpen(PR_FALSE) {}
 
@@ -67,28 +68,35 @@ public:
     NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
     mCset.push_back(aEdit);
   }
   void AddMutant(ShadowableLayer* aLayer)
   {
     NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
     mMutants.insert(aLayer);
   }
+  void AddBufferToDestroy(gfxSharedImageSurface* aBuffer)
+  {
+    NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
+    mDyingBuffers.AppendElement(aBuffer);
+  }
 
   void End()
   {
     mCset.clear();
+    mDyingBuffers.Clear();
     mMutants.clear();
     mOpen = PR_FALSE;
   }
 
   PRBool Empty() const { return mCset.empty() && mMutants.empty(); }
   PRBool Finished() const { return !mOpen && Empty(); }
 
   EditVector mCset;
+  BufferArray mDyingBuffers;
   ShadowableLayerSet mMutants;
 
 private:
   PRBool mOpen;
 
   // disabled
   Transaction(const Transaction&);
   Transaction& operator=(const Transaction&);
@@ -183,19 +191,21 @@ ShadowLayerForwarder::CreatedCanvasBuffe
                                           gfxSharedImageSurface* aTempFrontSurface)
 {
   mTxn->AddEdit(OpCreateCanvasBuffer(NULL, Shadow(aCanvas),
                                      aSize,
                                      aTempFrontSurface->GetShmem()));
 }
 
 void
-ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes)
+ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes,
+                                            gfxSharedImageSurface* aBackBufferToDestroy)
 {
   mTxn->AddEdit(OpDestroyThebesFrontBuffer(NULL, Shadow(aThebes)));
+  mTxn->AddBufferToDestroy(aBackBufferToDestroy);
 }
 
 void
 ShadowLayerForwarder::DestroyedImageBuffer(ShadowableLayer* aImage)
 {
   mTxn->AddEdit(OpDestroyImageFrontBuffer(NULL, Shadow(aImage)));
 }
 
@@ -272,16 +282,22 @@ ShadowLayerForwarder::EndTransaction(nsT
 
   AutoTxnEnd _(mTxn);
 
   if (mTxn->Empty()) {
     MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?), skipping Update()"));
     return PR_TRUE;
   }
 
+  MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
+
+  for (PRUint32 i = 0; i < mTxn->mDyingBuffers.Length(); ++i) {
+    DestroySharedSurface(mTxn->mDyingBuffers[i]);
+  }
+
   MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
 
   for (ShadowableLayerSet::const_iterator it = mTxn->mMutants.begin();
        it != mTxn->mMutants.end(); ++it) {
     ShadowableLayer* shadow = *it;
     Layer* mutant = shadow->AsLayer();
     NS_ABORT_IF_FALSE(!!mutant, "unshadowable layer?");
 
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -156,21 +156,25 @@ public:
   void CreatedImageBuffer(ShadowableLayer* aImage,
                           nsIntSize aSize,
                           gfxSharedImageSurface* aInitialFrontSurface);
   void CreatedCanvasBuffer(ShadowableLayer* aCanvas,
                            nsIntSize aSize,
                            gfxSharedImageSurface* aInitialFrontSurface);
 
   /**
-   * The specified layer should destroy its front buffer.  This can
-   * happen when a new front/back buffer pair have been created
-   * because of a layer resize, e.g.
+   * The specified layer is destroying its buffers.
+   * |aBackBufferToDestroy| is deallocated when this transaction is
+   * posted to the parent.  During the parent-side transaction, the
+   * shadow is told to destroy its front buffer.  This can happen when
+   * a new front/back buffer pair have been created because of a layer
+   * resize, e.g.
    */
-  void DestroyedThebesBuffer(ShadowableLayer* aThebes);
+  void DestroyedThebesBuffer(ShadowableLayer* aThebes,
+                             gfxSharedImageSurface* aBackBufferToDestroy);
   void DestroyedImageBuffer(ShadowableLayer* aImage);
   void DestroyedCanvasBuffer(ShadowableLayer* aCanvas);
 
 
   /**
    * At least one attribute of |aMutant| has changed, and |aMutant|
    * needs to sync to its shadow layer.  This initial implementation
    * forwards all attributes when any is mutated.