Bug 570294, part j: Publish BasicThebesLayer pixels to remote processes (slowly). r=roc
authorChris Jones <jones.chris.g@gmail.com>
Wed, 21 Jul 2010 16:17:33 -0500
changeset 48143 595b4c395ba21affefb53c3db40846241ea92571
parent 48142 77ceebc9b2f33c8e866da48be5c2f8524dde5acf
child 48144 eaa79dbf259c99d28c5ea424ad1f9780d93171c9
push id14589
push usercjones@mozilla.com
push dateFri, 23 Jul 2010 17:12:29 +0000
treeherdermozilla-central@49185ce20807 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs570294
milestone2.0b3pre
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 570294, part j: Publish BasicThebesLayer pixels to remote processes (slowly). r=roc
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -151,16 +151,27 @@ protected:
   };
   nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
   void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide, float aOpacity);
   void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity);
 
   const nsIntRect& BufferRect() const { return mBufferRect; }
   const nsIntPoint& BufferRotation() const { return mBufferRotation; }
 
+  already_AddRefed<gfxASurface>
+  SetBuffer(gfxASurface* aBuffer,
+            const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
+  {
+    gfxASurface* tmp = mBuffer;
+    mBuffer = aBuffer;
+    mBufferRect = aBufferRect;
+    mBufferRotation = aBufferRotation;
+    return tmp;
+  }
+
 private:
   PRBool BufferSizeOkFor(const nsIntSize& aSize)
   {
     return (aSize == mBufferRect.Size() ||
             (SizedToVisibleBounds != mBufferSizePolicy &&
              aSize < mBufferRect.Size()));
   }
 
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -222,18 +222,51 @@ BasicContainerLayer::RemoveChildInternal
 
   aChild->SetNextSibling(nsnull);
   aChild->SetPrevSibling(nsnull);
   aChild->SetParent(nsnull);
 
   NS_RELEASE(aChild);
 }
 
+class BasicThebesLayer;
+class BasicThebesLayerBuffer : public ThebesLayerBuffer {
+  typedef ThebesLayerBuffer Base;
+
+public:
+  BasicThebesLayerBuffer(BasicThebesLayer* aLayer)
+    : Base(ContainsVisibleBounds)
+    , mLayer(aLayer)
+  {}
+
+  virtual ~BasicThebesLayerBuffer()
+  {}
+
+  using Base::BufferRect;
+  using Base::BufferRotation;
+
+  /**
+   * Complete the drawing operation. The region to draw must have been
+   * drawn before this is called. The contents of the buffer are drawn
+   * to aTarget.
+   */
+  void DrawTo(ThebesLayer* aLayer, PRBool aIsOpaqueContent,
+              gfxContext* aTarget, float aOpacity);
+
+  virtual already_AddRefed<gfxASurface>
+  CreateBuffer(ContentType aType, const nsIntSize& aSize);
+
+private:
+  BasicThebesLayer* mLayer;
+};
+
 class BasicThebesLayer : public ThebesLayer, BasicImplData {
 public:
+  typedef BasicThebesLayerBuffer Buffer;
+
   BasicThebesLayer(BasicLayerManager* aLayerManager) :
     ThebesLayer(aLayerManager, static_cast<BasicImplData*>(this)),
     mBuffer(this)
   {
     MOZ_COUNT_CTOR(BasicThebesLayer);
   }
   virtual ~BasicThebesLayer()
   {
@@ -252,46 +285,16 @@ public:
                  "Can only set properties in construction phase");
     mValidRegion.Sub(mValidRegion, aRegion);
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,
                      float aOpacity);
-
-protected:
-  BasicLayerManager* BasicManager()
-  {
-    return static_cast<BasicLayerManager*>(mManager);
-  }
-
-  class Buffer : public ThebesLayerBuffer {
-  public:
-    Buffer(BasicThebesLayer* aLayer)
-      : ThebesLayerBuffer(ContainsVisibleBounds)
-      , mLayer(aLayer)
-    {}
-
-    /**
-     * Complete the drawing operation. The region to draw must have been
-     * drawn before this is called. The contents of the buffer are drawn
-     * to aTarget.
-     */
-    void DrawTo(PRBool aIsOpaqueContent, gfxContext* aTarget, float aOpacity);
-
-    virtual already_AddRefed<gfxASurface>
-    CreateBuffer(ContentType aType, const nsIntSize& aSize)
-    {
-      return mLayer->CreateBuffer(aType, aSize);
-    }
-
-  private:
-    BasicThebesLayer* mLayer;
-  };
   
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize)
   {
     nsRefPtr<gfxASurface> referenceSurface = mBuffer.GetBuffer();
     if (!referenceSurface) {
       gfxContext* defaultTarget = BasicManager()->GetDefaultTarget();
       if (defaultTarget) {
@@ -304,16 +307,34 @@ protected:
           referenceSurface = BasicManager()->GetTarget()->CurrentSurface();
         }
       }
     }
     return referenceSurface->CreateSimilarSurface(
       aType, gfxIntSize(aSize.width, aSize.height));
   }
 
+protected:
+  BasicLayerManager* BasicManager()
+  {
+    return static_cast<BasicLayerManager*>(mManager);
+  }
+
+  virtual void
+  PaintBuffer(gfxContext* aContext,
+              const nsIntRegion& aRegionToDraw,
+              const nsIntRegion& aRegionToInvalidate,
+              LayerManager::DrawThebesLayerCallback aCallback,
+              void* aCallbackData)
+  {
+    aCallback(this, aContext, aRegionToDraw, aRegionToInvalidate,
+              aCallbackData);
+    mValidRegion.Or(mValidRegion, aRegionToDraw);
+  }
+
   Buffer mBuffer;
 };
 
 static void
 ClipToContain(gfxContext* aContext, const nsIntRect& aRect)
 {
   gfxRect deviceRect =
     aContext->UserToDevice(gfxRect(aRect.x, aRect.y, aRect.width, aRect.height));
@@ -368,44 +389,52 @@ BasicThebesLayer::Paint(gfxContext* aCon
     mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
 
     if (state.mContext) {
       // The area that became invalid and is visible needs to be repainted
       // (this could be the whole visible area if our buffer switched
       // from RGB to RGBA, because we might need to repaint with
       // subpixel AA)
       state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
-      aCallback(this, state.mContext, state.mRegionToDraw,
-                state.mRegionToInvalidate, aCallbackData);
-      mValidRegion.Or(mValidRegion, state.mRegionToDraw);
+      PaintBuffer(state.mContext,
+                  state.mRegionToDraw, state.mRegionToInvalidate,
+                  aCallback, aCallbackData);
     } 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");
     }
   }
 
-  mBuffer.DrawTo(isOpaqueContent, target, aOpacity);
+  mBuffer.DrawTo(this, isOpaqueContent, target, aOpacity);
 }
 
 void
-BasicThebesLayer::Buffer::DrawTo(PRBool aIsOpaqueContent,
-                                 gfxContext* aTarget,
-                                 float aOpacity)
+BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
+                               PRBool aIsOpaqueContent,
+                               gfxContext* aTarget,
+                               float aOpacity)
 {
   aTarget->Save();
-  ClipToRegion(aTarget, mLayer->GetVisibleRegion());
+  ClipToRegion(aTarget, aLayer->GetVisibleRegion());
   if (aIsOpaqueContent) {
     aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
   }
   DrawBufferWithRotation(aTarget, aOpacity);
   aTarget->Restore();
 }
 
+already_AddRefed<gfxASurface>
+BasicThebesLayerBuffer::CreateBuffer(ContentType aType, 
+                                     const nsIntSize& aSize)
+{
+  return mLayer->CreateBuffer(aType, aSize);
+}
+
 class BasicImageLayer : public ImageLayer, BasicImplData {
 public:
   BasicImageLayer(BasicLayerManager* aLayerManager) :
     ImageLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicImageLayer);
   }
   virtual ~BasicImageLayer()
@@ -1173,35 +1202,109 @@ BasicShadowableContainerLayer::RemoveChi
                                  ShadowManager()->Hold(aChild));
   }
   BasicContainerLayer::RemoveChild(aChild);
 }
 
 class BasicShadowableThebesLayer : public BasicThebesLayer,
                                    public BasicShadowableLayer
 {
+  typedef BasicThebesLayer Base;
+
 public:
   BasicShadowableThebesLayer(BasicShadowLayerManager* aManager) :
     BasicThebesLayer(aManager)
   {
     MOZ_COUNT_CTOR(BasicShadowableThebesLayer);
   }
   virtual ~BasicShadowableThebesLayer()
   {
+    if (mBackBuffer)
+      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer);
     MOZ_COUNT_DTOR(BasicShadowableThebesLayer);
   }
 
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   {
     aAttrs = ThebesLayerAttributes(GetValidRegion());
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
+
+  virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer)
+  {
+    mBackBuffer = aBuffer;
+  }
+
+private:
+  BasicShadowLayerManager* BasicManager()
+  {
+    return static_cast<BasicShadowLayerManager*>(mManager);
+  }
+
+  NS_OVERRIDE virtual void
+  PaintBuffer(gfxContext* aContext,
+              const nsIntRegion& aRegionToDraw,
+              const nsIntRegion& aRegionToInvalidate,
+              LayerManager::DrawThebesLayerCallback aCallback,
+              void* aCallbackData);
+
+  NS_OVERRIDE virtual already_AddRefed<gfxASurface>
+  CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
+
+  nsRefPtr<gfxSharedImageSurface> mBackBuffer;
+  nsIntSize mBufferSize;
 };
+ 
+void
+BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
+                                        const nsIntRegion& aRegionToDraw,
+                                        const nsIntRegion& aRegionToInvalidate,
+                                        LayerManager::DrawThebesLayerCallback aCallback,
+                                        void* aCallbackData)
+{
+  NS_ABORT_IF_FALSE(!!mBackBuffer, "should have a back buffer by now");
+
+  Base::PaintBuffer(aContext, aRegionToDraw, aRegionToInvalidate,
+                    aCallback, aCallbackData);
+
+  nsRefPtr<gfxContext> tmpCtx = new gfxContext(mBackBuffer);
+  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)
+{
+  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;
+
+  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);
+}
+
 
 class BasicShadowableImageLayer : public BasicImageLayer,
                                   public BasicShadowableLayer
 {
 public:
   BasicShadowableImageLayer(BasicShadowLayerManager* aManager) :
     BasicImageLayer(aManager)
   {
@@ -1378,44 +1481,119 @@ BasicShadowableCanvasLayer::Paint(gfxCon
   // the shmem back buffer
   nsRefPtr<gfxContext> tmpCtx = new gfxContext(mBackBuffer);
   tmpCtx->DrawSurface(mSurface, gfxSize(mBounds.width, mBounds.height));
 
   BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
                                 mBackBuffer);
 }
 
+class ShadowThebesLayerBuffer : public BasicThebesLayerBuffer
+{
+  typedef BasicThebesLayerBuffer Base;
+
+public:
+  ShadowThebesLayerBuffer()
+    : Base(NULL)
+  {
+    MOZ_COUNT_CTOR(ShadowThebesLayerBuffer);
+  }
+
+  ~ShadowThebesLayerBuffer()
+  {
+    MOZ_COUNT_DTOR(ShadowThebesLayerBuffer);
+  }
+
+  already_AddRefed<gfxSharedImageSurface>
+  Swap(gfxSharedImageSurface* aNewFrontBuffer,
+       const nsIntRect& aBufferRect,
+       const nsIntPoint& aRotation=nsIntPoint(0, 0))
+  {
+    nsRefPtr<gfxASurface> newBackBuffer = SetBuffer(aNewFrontBuffer,
+                                                    aBufferRect, aRotation);
+    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");
+    return nsnull;
+  }
+};
 
 class BasicShadowThebesLayer : public ShadowThebesLayer, BasicImplData {
 public:
   BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowThebesLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicShadowThebesLayer);
   }
-  virtual ~BasicShadowThebesLayer()
-  {
-    MOZ_COUNT_DTOR(BasicShadowThebesLayer);
-  }
+  virtual ~BasicShadowThebesLayer();
 
   virtual already_AddRefed<gfxSharedImageSurface>
   Swap(gfxSharedImageSurface* aNewFront,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation)
-  { return nsnull; }
+  {
+    return mFrontBuffer.Swap(aNewFront, aBufferRect, aRotation);
+  }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,
-                     float aOpacity)
-  {}
+                     float aOpacity);
 
   MOZ_LAYER_DECL_NAME("BasicShadowThebesLayer", TYPE_SHADOW)
+
+private:
+  BasicShadowLayerManager* BasicManager()
+  {
+    return static_cast<BasicShadowLayerManager*>(mManager);
+  }
+
+  ShadowThebesLayerBuffer mFrontBuffer;
 };
 
+BasicShadowThebesLayer::~BasicShadowThebesLayer()
+{
+  nsRefPtr<gfxSharedImageSurface> frontBuffer =
+    mFrontBuffer.Swap(0, nsIntRect());
+  if (frontBuffer) {
+    BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer);
+  }
+
+  MOZ_COUNT_DTOR(BasicShadowThebesLayer);
+}
+
+void
+BasicShadowThebesLayer::Paint(gfxContext* aContext,
+                              LayerManager::DrawThebesLayerCallback aCallback,
+                              void* aCallbackData,
+                              float aOpacity)
+{
+  NS_ASSERTION(BasicManager()->InDrawing(),
+               "Can only draw in drawing phase");
+  NS_ASSERTION(BasicManager()->IsRetained(),
+               "ShadowThebesLayer makes no sense without retained mode");
+
+  gfxContext* target = BasicManager()->GetTarget();
+  NS_ASSERTION(target, "We shouldn't be called if there's no target");
+
+  nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
+  PRBool isOpaqueContent =
+    (targetSurface->AreSimilarSurfacesSensitiveToContentType() &&
+     aOpacity == 1.0 &&
+     CanUseOpaqueSurface());
+
+  mFrontBuffer.DrawTo(this, isOpaqueContent, target, aOpacity);
+}
+
+
 class BasicShadowImageLayer : public ShadowImageLayer, BasicImplData {
 public:
   BasicShadowImageLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowImageLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicShadowImageLayer);
   }
   virtual ~BasicShadowImageLayer()