Bug 570294, part h: Publish BasicCanvasLayer pixels to remote processes (slowly). sr=vlad
authorChris Jones <jones.chris.g@gmail.com>
Wed, 21 Jul 2010 16:17:33 -0500
changeset 48141 507ad177534a2027c077c2639c8707272b3af889
parent 48140 4515c729fe32b9aee03531341c9b80b029050b7b
child 48142 77ceebc9b2f33c8e866da48be5c2f8524dde5acf
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)
reviewersvlad
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 h: Publish BasicCanvasLayer pixels to remote processes (slowly). sr=vlad
gfx/layers/basic/BasicLayers.cpp
gfx/layers/ipc/ShadowLayers.cpp
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -32,18 +32,22 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifdef MOZ_IPC
+#  include "gfxSharedImageSurface.h"
+
 #  include "mozilla/layers/PLayerChild.h"
 #  include "mozilla/layers/PLayersChild.h"
+#  include "mozilla/layers/PLayersParent.h"
+#  include "ipc/ShadowLayerChild.h"
 #endif
 
 #include "BasicLayers.h"
 #include "ImageLayers.h"
 
 #include "nsTArray.h"
 #include "nsGUIEvent.h"
 #include "nsIRenderingContext.h"
@@ -785,16 +789,19 @@ BasicLayerManager::BasicLayerManager() :
   , mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE)
 {
   MOZ_COUNT_CTOR(BasicLayerManager);
 }
 
 BasicLayerManager::~BasicLayerManager()
 {
   NS_ASSERTION(!InTransaction(), "Died during transaction?");
+
+  mRoot = nsnull;
+
   MOZ_COUNT_DTOR(BasicLayerManager);
 }
 
 void
 BasicLayerManager::SetDefaultTarget(gfxContext* aContext,
                                     BufferMode aDoubleBuffering)
 {
   NS_ASSERTION(!InTransaction(),
@@ -1068,24 +1075,37 @@ public:
     MOZ_COUNT_DTOR(BasicShadowableLayer);
   }
 
   void SetShadow(PLayerChild* aShadow)
   {
     NS_ABORT_IF_FALSE(!mShadow, "can't have two shadows (yet)");
     mShadow = aShadow;
   }
+
+  virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer)
+  {
+    NS_RUNTIMEABORT("if this default impl is called, |aBuffer| leaks");
+  }
 };
 
 static ShadowableLayer*
 ToShadowable(Layer* aLayer)
 {
   return ToData(aLayer)->AsShadowableLayer();
 }
 
+template<class OpT>
+static BasicShadowableLayer*
+GetBasicShadowable(const OpT& op)
+{
+  return static_cast<BasicShadowableLayer*>(
+    static_cast<const ShadowLayerChild*>(op.layerChild())->layer());
+}
+
 class BasicShadowableContainerLayer : public BasicContainerLayer,
                                       public BasicShadowableLayer {
 public:
   BasicShadowableContainerLayer(BasicShadowLayerManager* aManager) :
     BasicContainerLayer(aManager)
   {
     MOZ_COUNT_CTOR(BasicShadowableContainerLayer);
   }
@@ -1203,28 +1223,89 @@ class BasicShadowableCanvasLayer : publi
 public:
   BasicShadowableCanvasLayer(BasicShadowLayerManager* aManager) :
     BasicCanvasLayer(aManager)
   {
     MOZ_COUNT_CTOR(BasicShadowableCanvasLayer);
   }
   virtual ~BasicShadowableCanvasLayer()
   {
+    if (mBackBuffer)
+      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer);
     MOZ_COUNT_DTOR(BasicShadowableCanvasLayer);
   }
 
+  virtual void Initialize(const Data& aData);
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData,
+                     float aOpacity);
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   {
     aAttrs = CanvasLayerAttributes(mFilter);
   }
 
   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);
+  }
+
+  nsRefPtr<gfxSharedImageSurface> mBackBuffer;
 };
 
+void
+BasicShadowableCanvasLayer::Initialize(const Data& aData)
+{
+  BasicCanvasLayer::Initialize(aData);
+  if (!HasShadow())
+      return;
+
+  nsRefPtr<gfxSharedImageSurface> tmpFrontBuffer;
+  // XXX error handling?
+  if (!BasicManager()->AllocDoubleBuffer(
+        gfxIntSize(aData.mSize.width, aData.mSize.height),
+        gfxASurface::ImageFormatARGB32,
+        getter_AddRefs(tmpFrontBuffer), getter_AddRefs(mBackBuffer)))
+    NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!");
+
+  BasicManager()->CreatedCanvasBuffer(BasicManager()->Hold(this),
+                                      aData.mSize,
+                                      tmpFrontBuffer);
+}
+
+void
+BasicShadowableCanvasLayer::Paint(gfxContext* aContext,
+                                  LayerManager::DrawThebesLayerCallback aCallback,
+                                  void* aCallbackData,
+                                  float aOpacity)
+{
+  BasicCanvasLayer::Paint(aContext, aCallback, aCallbackData, aOpacity);
+  if (!HasShadow())
+    return;
+
+  // XXX this is yucky and slow.  It'd be nice to draw directly into
+  // 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 BasicShadowThebesLayer : public ShadowThebesLayer, BasicImplData {
 public:
   BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowThebesLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicShadowThebesLayer);
   }
   virtual ~BasicShadowThebesLayer()
@@ -1281,38 +1362,87 @@ class BasicShadowCanvasLayer : public Sh
 public:
   BasicShadowCanvasLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowCanvasLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicShadowCanvasLayer);
   }
   virtual ~BasicShadowCanvasLayer()
   {
+    if (mFrontSurface)
+      BasicManager()->ShadowLayerManager::DestroySharedSurface(mFrontSurface);
     MOZ_COUNT_DTOR(BasicShadowCanvasLayer);
   }
 
-  virtual void Initialize(const Data& aData)
-  {}
+  virtual void Initialize(const Data& aData);
 
   virtual void Updated(const nsIntRect& aRect)
   {}
 
   virtual already_AddRefed<gfxSharedImageSurface>
-  Swap(gfxSharedImageSurface* newFront)
-  { return NULL; }
+  Swap(gfxSharedImageSurface* newFront);
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,
-                     float aOpacity)
-  {}
+                     float aOpacity);
 
   MOZ_LAYER_DECL_NAME("BasicShadowCanvasLayer", TYPE_SHADOW)
+
+private:
+  BasicShadowLayerManager* BasicManager()
+  {
+    return static_cast<BasicShadowLayerManager*>(mManager);
+  }
+
+  nsRefPtr<gfxSharedImageSurface> mFrontSurface;
+  nsIntRect mBounds;
 };
 
+void
+BasicShadowCanvasLayer::Initialize(const Data& aData)
+{
+  NS_ASSERTION(mFrontSurface == nsnull,
+               "BasicCanvasLayer::Initialize called twice!");
+  NS_ASSERTION(aData.mSurface && !aData.mGLContext, "no comprende OpenGL!");
+
+  mFrontSurface = static_cast<gfxSharedImageSurface*>(aData.mSurface);
+  mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
+}
+
+already_AddRefed<gfxSharedImageSurface>
+BasicShadowCanvasLayer::Swap(gfxSharedImageSurface* newFront)
+{
+  already_AddRefed<gfxSharedImageSurface> tmp = mFrontSurface.forget();
+  mFrontSurface = newFront;
+  return tmp;
+}
+
+void
+BasicShadowCanvasLayer::Paint(gfxContext* aContext,
+                              LayerManager::DrawThebesLayerCallback aCallback,
+                              void* aCallbackData,
+                              float aOpacity)
+{
+  MOZ_LAYERS_LOG(("[ShadowLayersChild] %s()", __FUNCTION__));
+
+  NS_ASSERTION(BasicManager()->InDrawing(),
+               "Can only draw in drawing phase");
+
+  nsRefPtr<gfxPattern> pat = new gfxPattern(mFrontSurface);
+
+  pat->SetFilter(mFilter);
+  pat->SetExtend(gfxPattern::EXTEND_PAD);
+
+  gfxRect r(0, 0, mBounds.width, mBounds.height);
+  aContext->NewPath();
+  aContext->PixelSnappedRectangleAndSetPattern(r, pat);
+  aContext->Fill();
+}
+
 // Create a shadow layer (PLayerChild) for aLayer, if we're forwarding
 // our layer tree to a parent process.  Record the new layer creation
 // in the current open transaction as a side effect.
 template<typename CreatedMethod>
 static void
 MaybeCreateShadowFor(BasicShadowableLayer* aLayer,
                      BasicShadowLayerManager* aMgr,
                      CreatedMethod aMethod)
@@ -1457,22 +1587,40 @@ BasicShadowLayerManager::EndTransaction(
 {
   BasicLayerManager::EndTransaction(aCallback, aCallbackData);
 #ifdef DEBUG
   mPhase = PHASE_FORWARD;
 #endif
 
   // forward this transaction's changeset to our ShadowLayerManager
   nsAutoTArray<EditReply, 10> replies;
-  if (HasShadowManager() && !ShadowLayerForwarder::EndTransaction(&replies)) {
+  if (HasShadowManager() && ShadowLayerForwarder::EndTransaction(&replies)) {
+    for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
+      const EditReply& reply = replies[i];
+
+      switch (reply.type()) {
+      case EditReply::TOpBufferSwap: {
+        MOZ_LAYERS_LOG(("[LayersForwarder] BufferSwap"));
+
+        const OpBufferSwap& obs = reply.get_OpBufferSwap();
+        GetBasicShadowable(obs)->SetBackBuffer(
+          new gfxSharedImageSurface(obs.newBackBuffer()));
+        break;
+      }
+
+      default:
+        NS_RUNTIMEABORT("not reached");
+      }
+    }
+  } else if (HasShadowManager()) {
     NS_WARNING("failed to forward Layers transaction");
   }
 
   // this may result in Layers being deleted, which results in
-  // PLayer::Send__delete__()
+  // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 
 #ifdef DEBUG
   mPhase = PHASE_NONE;
 #endif
 }
 
 ShadowableLayer*
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -40,16 +40,17 @@
 
 #include <set>
 #include <vector>
 
 #include "gfxSharedImageSurface.h"
 
 #include "mozilla/layers/PLayerChild.h"
 #include "mozilla/layers/PLayersChild.h"
+#include "mozilla/layers/PLayersParent.h"
 #include "ShadowLayers.h"
 #include "ShadowLayerChild.h"
 
 namespace mozilla {
 namespace layers {
 
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
@@ -289,17 +290,49 @@ ShadowLayerForwarder::EndTransaction(nsT
     MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
     return PR_FALSE;
   }
 
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return PR_TRUE;
 }
 
+PRBool
+ShadowLayerForwarder::AllocDoubleBuffer(const gfxIntSize& aSize,
+                                        gfxASurface::gfxImageFormat aFormat,
+                                        gfxSharedImageSurface** aFrontBuffer,
+                                        gfxSharedImageSurface** aBackBuffer)
+{
+  NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
+
+  nsRefPtr<gfxSharedImageSurface> front = new gfxSharedImageSurface();
+  nsRefPtr<gfxSharedImageSurface> back = new gfxSharedImageSurface();
+  if (!front->Init(mShadowManager, aSize, aFormat) ||
+      !back->Init(mShadowManager, aSize, aFormat))
+    return PR_FALSE;
+
+  *aFrontBuffer = NULL;       *aBackBuffer = NULL;
+  front.swap(*aFrontBuffer);  back.swap(*aBackBuffer);
+  return PR_TRUE;
+}
+
+void
+ShadowLayerForwarder::DestroySharedSurface(gfxSharedImageSurface* aSurface)
+{
+  mShadowManager->DeallocShmem(aSurface->GetShmem());
+}
+
 PLayerChild*
 ShadowLayerForwarder::ConstructShadowFor(ShadowableLayer* aLayer)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   return mShadowManager->SendPLayerConstructor(new ShadowLayerChild(aLayer));
 }
 
+
+void
+ShadowLayerManager::DestroySharedSurface(gfxSharedImageSurface* aSurface)
+{
+  mForwarder->DeallocShmem(aSurface->GetShmem());
+}
+
 } // namespace layers
 } // namespace mozilla