Bug 747811 - Make the tiles backend safe across processes. r=nrc,BenWa
authorBenoit Girard <b56girard@gmail.com>, Chris Lord <chrislord.net@gmail.com>
Mon, 19 Aug 2013 14:59:22 +0100
changeset 156028 426f477baba5c239c79ff84e59185848a7395484
parent 156027 74454e112554d86a52973949257e6ca8ac4da692
child 156029 97d2a33c5455ee88788ea2bf4802a9edc4d63282
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnrc, BenWa
bugs747811
milestone26.0a1
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 747811 - Make the tiles backend safe across processes. r=nrc,BenWa The tiles backend passes raw pointers to transfer tiled buffers between the main thread and the compositor. This patch changes that to use shared memory and tile descriptors instead, as well as changing the memory management slightly to facilitate that.
gfx/layers/TiledLayerBuffer.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/composite/TiledContentHost.h
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/LayerTransaction.ipdlh
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/thebes/gfxBaseSharedMemorySurface.h
gfx/thebes/gfxReusableSurfaceWrapper.cpp
gfx/thebes/gfxReusableSurfaceWrapper.h
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -179,29 +179,33 @@ protected:
 private:
   const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
   Derived& AsDerived() { return *static_cast<Derived*>(this); }
 
   bool IsPlaceholder(Tile aTile) const { return aTile == AsDerived().GetPlaceholderTile(); }
 };
 
 class BasicTiledLayerBuffer;
+class SurfaceDescriptorTiles;
+class ISurfaceAllocator;
 
 // Shadow layers may implement this interface in order to be notified when a
 // tiled layer buffer is updated.
 class TiledLayerComposer
 {
 public:
   /**
    * Update the current retained layer with the updated layer data.
-   * The BasicTiledLayerBuffer is expected to be in the ReadLock state
-   * prior to this being called. aTiledBuffer is copy constructed and
-   * is retained until it has been uploaded/copyed and unlocked.
+   * It is expected that the tiles described by aTiledDescriptor are all in the
+   * ReadLock state, so that the locks can be adopted when recreating a
+   * BasicTiledLayerBuffer locally. This lock will be retained until the buffer
+   * has completed uploading.
    */
-  virtual void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* aTiledBuffer) = 0;
+  virtual void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                                       const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
 
   /**
    * If some part of the buffer is being rendered at a lower precision, this
    * returns that region. If it is not, an empty region will be returned.
    */
   virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
 };
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "GLContext.h"
 #include "BasicLayers.h" // for PaintContext
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "gfxReusableSurfaceWrapper.h"
+#include "gfxSharedImageSurface.h"
 #include "gfxPlatform.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "gfx2DGlue.h"
 
 #include <stdint.h>
 
 using namespace mozilla::gl;
 
@@ -457,32 +458,34 @@ DeprecatedTextureClientShmemYCbCr::Ensur
                                          gfxASurface::gfxContentType aType)
 {
   NS_RUNTIMEABORT("not enough arguments to do this (need both Y and CbCr sizes)");
   return false;
 }
 
 
 DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
-                                     const TextureInfo& aTextureInfo)
+                                                         const TextureInfo& aTextureInfo,
+                                                         gfxReusableSurfaceWrapper* aSurface)
   : DeprecatedTextureClient(aForwarder, aTextureInfo)
-  , mSurface(nullptr)
+  , mSurface(aSurface)
 {
   mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED;
 }
 
 bool
 DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType)
 {
   if (!mSurface ||
       mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) {
-    gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height),
-                                                   gfxPlatform::GetPlatform()->OptimalFormatForContent(aType),
-                                                   aType != gfxASurface::CONTENT_COLOR);
-    mSurface = new gfxReusableSurfaceWrapper(tmpTile);
+    nsRefPtr<gfxSharedImageSurface> sharedImage =
+      gfxSharedImageSurface::CreateUnsafe(mForwarder,
+                                          gfxIntSize(aSize.width, aSize.height),
+                                          gfxPlatform::GetPlatform()->OptimalFormatForContent(aType));
+    mSurface = new gfxReusableSurfaceWrapper(mForwarder, sharedImage);
     mContentType = aType;
   }
   return true;
 }
 
 gfxImageSurface*
 DeprecatedTextureClientTile::LockImageSurface()
 {
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -469,17 +469,18 @@ public:
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE { return gfxASurface::CONTENT_COLOR_ALPHA; }
 };
 
 class DeprecatedTextureClientTile : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther);
   DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
-                    const TextureInfo& aTextureInfo);
+                              const TextureInfo& aTextureInfo,
+                              gfxReusableSurfaceWrapper* aSurface = nullptr);
   ~DeprecatedTextureClientTile();
 
   virtual bool EnsureAllocated(gfx::IntSize aSize,
                                gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
 
   virtual gfxImageSurface* LockImageSurface() MOZ_OVERRIDE;
 
   gfxReusableSurfaceWrapper* GetReusableSurfaceWrapper()
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -68,27 +68,26 @@ TiledContentClient::TiledContentClient(C
   MOZ_COUNT_CTOR(TiledContentClient);
 
   mLowPrecisionTiledBuffer.SetResolution(gfxPlatform::GetLowPrecisionResolution());
 }
 
 void
 TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
 {
-  // Create a heap copy owned and released by the compositor. This is needed
-  // since we're sending this over an async message and content needs to be
-  // be able to modify the tiled buffer in the next transaction.
-  // TODO: Remove me once Bug 747811 lands.
   BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     ? &mLowPrecisionTiledBuffer
     : &mTiledBuffer;
 
-  BasicTiledLayerBuffer* heapCopy = new BasicTiledLayerBuffer(buffer->DeepCopy());
+  // Take an extra ReadLock on behalf of the TiledContentHost. This extra
+  // reference will be adopted when the descriptor is opened by
+  // gfxReusableSurfaceWrapper::Open.
   buffer->ReadLock();
-  mForwarder->PaintedTiledLayerBuffer(this, heapCopy);
+
+  mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
   buffer->ClearPaintedRegion();
 }
 
 BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
                                              ClientLayerManager* aManager)
   : mThebesLayer(aThebesLayer)
   , mManager(aManager)
   , mLastPaintOpaque(false)
@@ -108,16 +107,63 @@ BasicTiledLayerBuffer::GetContentType() 
   if (mThebesLayer->CanUseOpaqueSurface()) {
     return gfxASurface::CONTENT_COLOR;
   } else {
     return gfxASurface::CONTENT_COLOR_ALPHA;
   }
 }
 
 
+BasicTileDescriptor
+BasicTiledLayerTile::GetTileDescriptor()
+{
+  return BasicTileDescriptor(GetSurface()->GetShmem());
+}
+
+/* static */ BasicTiledLayerTile
+BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc)
+{
+  nsRefPtr<gfxReusableSurfaceWrapper> surface =
+    gfxReusableSurfaceWrapper::Open(aAllocator, aDesc.reusableSurface());
+  return BasicTiledLayerTile(
+    new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+}
+
+SurfaceDescriptorTiles
+BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
+{
+  InfallibleTArray<TileDescriptor> tiles;
+
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    TileDescriptor tileDesc;
+    if (mRetainedTiles.SafeElementAt(i, GetPlaceholderTile()) == GetPlaceholderTile()) {
+      tileDesc = PlaceholderTileDescriptor();
+    } else {
+      tileDesc = mRetainedTiles[i].GetTileDescriptor();
+    }
+    tiles.AppendElement(tileDesc);
+  }
+  return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
+                                tiles, mRetainedWidth, mRetainedHeight,
+                                mResolution);
+}
+
+/* static */ BasicTiledLayerBuffer
+BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator,
+                                      const SurfaceDescriptorTiles& aDescriptor)
+{
+  return BasicTiledLayerBuffer(aAllocator,
+                               aDescriptor.validRegion(),
+                               aDescriptor.paintedRegion(),
+                               aDescriptor.tiles(),
+                               aDescriptor.retainedWidth(),
+                               aDescriptor.retainedHeight(),
+                               aDescriptor.resolution());
+}
+
 void
 BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
                                    const nsIntRegion& aPaintRegion,
                                    LayerManager::DrawThebesLayerCallback aCallback,
                                    void* aCallbackData)
 {
   mCallback = aCallback;
   mCallbackData = aCallbackData;
@@ -458,25 +504,10 @@ BasicTiledLayerBuffer::ProgressiveUpdate
     aInvalidRegion.Sub(aInvalidRegion, regionToPaint);
   } while (repeat);
 
   // Return false if nothing has been drawn, or give what has been drawn
   // to the shadow layer to upload.
   return isBufferChanged;
 }
 
-BasicTiledLayerBuffer
-BasicTiledLayerBuffer::DeepCopy() const
-{
-  BasicTiledLayerBuffer result = *this;
-
-  for (size_t i = 0; i < result.mRetainedTiles.Length(); i++) {
-    if (result.mRetainedTiles[i].IsPlaceholderTile()) continue;
-
-    result.mRetainedTiles[i].mDeprecatedTextureClient =
-      new DeprecatedTextureClientTile(*result.mRetainedTiles[i].mDeprecatedTextureClient);
-  }
-
-  return result;
-}
-
 }
 }
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -4,20 +4,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_TILEDCONTENTCLIENT_H
 #define MOZILLA_GFX_TILEDCONTENTCLIENT_H
 
 #include "mozilla/layers/ContentClient.h"
 #include "TiledLayerBuffer.h"
 #include "gfxPlatform.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
 
 namespace mozilla {
 namespace layers {
 
+class BasicTileDescriptor;
+
 /**
  * Represent a single tile in tiled buffer. The buffer keeps tiles,
  * each tile keeps a reference to a texture client. The texture client
  * is backed by a gfxReusableSurfaceWrapper that implements a
  * copy-on-write mechanism while locked. The tile should be
  * locked before being sent to the compositor and unlocked
  * as soon as it is uploaded to prevent a copy.
  * Ideal place to store per tile debug information.
@@ -28,16 +31,20 @@ struct BasicTiledLayerTile {
   TimeStamp        mLastUpdate;
 #endif
 
   // Placeholder
   BasicTiledLayerTile()
     : mDeprecatedTextureClient(nullptr)
   {}
 
+  BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient)
+    : mDeprecatedTextureClient(aTextureClient)
+  {}
+
   BasicTiledLayerTile(const BasicTiledLayerTile& o) {
     mDeprecatedTextureClient = o.mDeprecatedTextureClient;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
     mLastUpdate = o.mLastUpdate;
 #endif
   }
   BasicTiledLayerTile& operator=(const BasicTiledLayerTile& o) {
     if (this == &o) return *this;
@@ -58,16 +65,19 @@ struct BasicTiledLayerTile {
 
   void ReadUnlock() {
     GetSurface()->ReadUnlock();
   }
   void ReadLock() {
     GetSurface()->ReadLock();
   }
 
+  BasicTileDescriptor GetTileDescriptor();
+  static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc);
+
   gfxReusableSurfaceWrapper* GetSurface() {
     return mDeprecatedTextureClient->GetReusableSurfaceWrapper();
   }
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it
  * doesn't need to be recalculated on every repeated transaction.
@@ -102,16 +112,40 @@ public:
   BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
                         ClientLayerManager* aManager);
   BasicTiledLayerBuffer()
     : mThebesLayer(nullptr)
     , mManager(nullptr)
     , mLastPaintOpaque(false)
   {}
 
+  BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                        const nsIntRegion& aValidRegion,
+                        const nsIntRegion& aPaintedRegion,
+                        const InfallibleTArray<TileDescriptor>& aTiles,
+                        int aRetainedWidth,
+                        int aRetainedHeight,
+                        float aResolution)
+  {
+    mValidRegion = aValidRegion;
+    mPaintedRegion = aPaintedRegion;
+    mRetainedWidth = aRetainedWidth;
+    mRetainedHeight = aRetainedHeight;
+    mResolution = aResolution;
+
+    for(size_t i = 0; i < aTiles.Length(); i++) {
+      if (aTiles[i].type() == TileDescriptor::TPlaceholderTileDescriptor) {
+        mRetainedTiles.AppendElement(GetPlaceholderTile());
+      } else {
+        const BasicTileDescriptor& basicTileDesc = aTiles[i].get_BasicTileDescriptor();
+        mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, basicTileDesc));
+      }
+    }
+  }
+
   void PaintThebes(const nsIntRegion& aNewValidRegion,
                    const nsIntRegion& aPaintRegion,
                    LayerManager::DrawThebesLayerCallback aCallback,
                    void* aCallbackData);
 
   void ReadUnlock() {
     for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
       if (mRetainedTiles[i].IsPlaceholderTile()) continue;
@@ -137,24 +171,20 @@ public:
    */
   bool ProgressiveUpdate(nsIntRegion& aValidRegion,
                          nsIntRegion& aInvalidRegion,
                          const nsIntRegion& aOldValidRegion,
                          BasicTiledLayerPaintData* aPaintData,
                          LayerManager::DrawThebesLayerCallback aCallback,
                          void* aCallbackData);
 
-  /**
-   * Copy this buffer duplicating the texture hosts under the tiles
-   * XXX This should go. It is a hack because we need to keep the
-   * surface wrappers alive whilst they are locked by the compositor.
-   * Once we properly implement the texture host/client architecture
-   * for tiled layers we shouldn't need this.
-   */
-  BasicTiledLayerBuffer DeepCopy() const;
+  SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
+
+  static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
+                                              const SurfaceDescriptorTiles& aDescriptor);
 
 protected:
   BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
                                    const nsIntPoint& aTileRect,
                                    const nsIntRegion& dirtyRect);
 
   // If this returns true, we perform the paint operation into a single large
   // buffer and copy it out to the tiles instead of calling PaintThebes() on
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -49,49 +49,39 @@ TiledLayerBufferComposite::ValidateTile(
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 1) {
     printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
   }
 #endif
   return aTile;
 }
 
-TiledContentHost::~TiledContentHost()
-{
-  mMainMemoryTiledBuffer.ReadUnlock();
-  mLowPrecisionMainMemoryTiledBuffer.ReadUnlock();
-}
-
 void
 TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor)
 {
   CompositableHost::Attach(aLayer, aCompositor);
   static_cast<ThebesLayerComposite*>(aLayer)->EnsureTiled();
 }
 
 void
-TiledContentHost::PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer)
+TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                                          const SurfaceDescriptorTiles& aTiledDescriptor)
 {
-  if (mTiledBuffer->IsLowPrecision()) {
-    mLowPrecisionMainMemoryTiledBuffer.ReadUnlock();
-    mLowPrecisionMainMemoryTiledBuffer = *mTiledBuffer;
+  if (aTiledDescriptor.resolution() < 1) {
+    mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
     mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload,
                                    mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion());
     mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion();
     mPendingLowPrecisionUpload = true;
   } else {
-    mMainMemoryTiledBuffer.ReadUnlock();
-    mMainMemoryTiledBuffer = *mTiledBuffer;
+    mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
     mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
     mMainMemoryTiledBuffer.ClearPaintedRegion();
     mPendingUpload = true;
   }
-
-  // TODO: Remove me once Bug 747811 lands.
-  delete mTiledBuffer;
 }
 
 void
 TiledContentHost::ProcessLowPrecisionUploadQueue()
 {
   if (!mPendingLowPrecisionUpload) {
     return;
   }
@@ -104,18 +94,16 @@ TiledContentHost::ProcessLowPrecisionUpl
   // frame resolution. As it's always updated first when zooming, this
   // should always be true.
   mLowPrecisionVideoMemoryTiledBuffer.Upload(&mLowPrecisionMainMemoryTiledBuffer,
                                  mLowPrecisionMainMemoryTiledBuffer.GetValidRegion(),
                                  mLowPrecisionRegionToUpload,
                                  mVideoMemoryTiledBuffer.GetFrameResolution());
   nsIntRegion validRegion = mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
 
-  mLowPrecisionMainMemoryTiledBuffer.ReadUnlock();
-
   mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer();
   mLowPrecisionRegionToUpload = nsIntRegion();
   mPendingLowPrecisionUpload = false;
 }
 
 void
 TiledContentHost::ProcessUploadQueue(nsIntRegion* aNewValidRegion,
                                      TiledLayerProperties* aLayerProperties)
@@ -128,22 +116,18 @@ TiledContentHost::ProcessUploadQueue(nsI
   mRegionToUpload.And(mRegionToUpload, mMainMemoryTiledBuffer.GetValidRegion());
 
   mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
                                  mMainMemoryTiledBuffer.GetValidRegion(),
                                  mRegionToUpload, aLayerProperties->mEffectiveResolution);
 
   *aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
 
-  mMainMemoryTiledBuffer.ReadUnlock();
   // Release all the tiles by replacing the tile buffer with an empty
-  // tiled buffer. This will prevent us from doing a double unlock when
-  // calling  ~TiledThebesLayerComposite.
-  // XXX: This wont be needed when we do progressive upload and lock
-  // tile by tile.
+  // tiled buffer.
   mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
   mRegionToUpload = nsIntRegion();
   mPendingUpload = false;
 }
 
 void
 TiledContentHost::Composite(EffectChain& aEffectChain,
                             float aOpacity,
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_TILEDCONTENTHOST_H
 #define GFX_TILEDCONTENTHOST_H
 
 #include "ContentHost.h"
 #include "ClientTiledThebesLayer.h" // for BasicTiledLayerBuffer
+#include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/TextureHost.h"
 
 namespace mozilla {
 namespace layers {
 
 class ThebesBuffer;
 class OptionalThebesBuffer;
 struct TexturedEffect;
@@ -132,18 +133,24 @@ class TiledThebesLayerComposite;
 class TiledContentHost : public ContentHost,
                          public TiledLayerComposer
 {
 public:
   TiledContentHost(const TextureInfo& aTextureInfo)
     : ContentHost(aTextureInfo)
     , mPendingUpload(false)
     , mPendingLowPrecisionUpload(false)
-  {}
-  ~TiledContentHost();
+  {
+    MOZ_COUNT_CTOR(TiledContentHost);
+  }
+
+  ~TiledContentHost()
+  {
+    MOZ_COUNT_DTOR(TiledContentHost);
+  }
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE
   {
     return LayerRenderState();
   }
 
 
   virtual void UpdateThebes(const ThebesBufferData& aData,
@@ -154,17 +161,18 @@ public:
     MOZ_ASSERT(false, "N/A for tiled layers");
   }
 
   const nsIntRegion& GetValidLowPrecisionRegion() const
   {
     return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
   }
 
-  void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer);
+  void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                               const SurfaceDescriptorTiles& aTiledDescriptor);
 
   // Renders a single given tile.
   void RenderTile(const TiledTexture& aTile,
                   EffectChain& aEffectChain,
                   float aOpacity,
                   const gfx::Matrix4x4& aTransform,
                   const gfx::Point& aOffset,
                   const gfx::Filter& aFilter,
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -13,16 +13,17 @@
 #include "mozilla/layers/ISurfaceAllocator.h"
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class TextureFactoryIdentifier;
 class SurfaceDescriptor;
+class SurfaceDescriptorTiles;
 class ThebesBufferData;
 class DeprecatedTextureClient;
 class TextureClient;
 class BasicTiledLayerBuffer;
 
 /**
  * A transaction is a set of changes that happenned on the content side, that
  * should be sent to the compositor side.
@@ -80,17 +81,17 @@ public:
 
   /**
    * Tell the compositor that a Compositable is killing its buffer(s),
    * that is TextureClient/Hosts.
    */
   virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0;
 
   virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                       BasicTiledLayerBuffer* aTiledLayerBuffer) = 0;
+                                       const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
 
   /**
    * Communicate to the compositor that the texture identified by aCompositable
    * and aTextureId has been updated to aImage.
    */
   virtual void UpdateTexture(CompositableClient* aCompositable,
                              TextureIdentifier aTextureId,
                              SurfaceDescriptor* aDescriptor) = 0;
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -191,18 +191,18 @@ CompositableParentManager::ReceiveCompos
       const OpPaintTiledLayerBuffer& op = aEdit.get_OpPaintTiledLayerBuffer();
       CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
       CompositableHost* compositable =
         compositableParent->GetCompositableHost();
 
       TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer();
       NS_ASSERTION(tileComposer, "compositable is not a tile composer");
 
-      BasicTiledLayerBuffer* p = reinterpret_cast<BasicTiledLayerBuffer*>(op.tiledLayerBuffer());
-      tileComposer->PaintedTiledLayerBuffer(p);
+      const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
+      tileComposer->PaintedTiledLayerBuffer(this, tileDesc);
       break;
     }
     case CompositableOperation::TOpUseTexture: {
       const OpUseTexture& op = aEdit.get_OpUseTexture();
       if (op.textureID() == 0) {
         NS_WARNING("Invalid texture ID");
         break;
       }
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -254,17 +254,17 @@ public:
 
   /**
    * See CompositableForwarder::UseTexture
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) MOZ_OVERRIDE;
 
   virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                       BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE
+                                       const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
   {
     NS_RUNTIMEABORT("should not be called");
   }
 
   /**
    * Communicate to the compositor that the texture identified by aCompositable
    * and aTextureId has been updated to aDescriptor.
    */
--- a/gfx/layers/ipc/LayerTransaction.ipdlh
+++ b/gfx/layers/ipc/LayerTransaction.ipdlh
@@ -240,19 +240,17 @@ struct OpRemoveChild      { PLayer conta
 struct OpRepositionChild  { PLayer container; PLayer childLayer; PLayer after; };
 struct OpRaiseToTopChild  { PLayer container; PLayer childLayer; };
 
 struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
 
 // Paint (buffer update)
 struct OpPaintTiledLayerBuffer {
   PCompositable compositable;
-  // Bug 747811
-  // FIXME: We need to support sharing tile across process.
-  uintptr_t tiledLayerBuffer;
+  SurfaceDescriptorTiles tileLayerDescriptor;
 };
 
 struct OpCreatedTexture {
   PCompositable compositable;
   uint32_t textureId;
   SurfaceDescriptor descriptor;
   TextureInfo textureInfo;
 };
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -48,16 +48,37 @@ struct SurfaceDescriptorD3D10 {
 
 struct SharedTextureDescriptor {
   SharedTextureShareType shareType;
   SharedTextureHandle handle;
   nsIntSize size;
   bool inverted;
 };
 
+struct BasicTileDescriptor {
+  Shmem reusableSurface;
+};
+
+struct PlaceholderTileDescriptor {
+};
+
+union TileDescriptor {
+  BasicTileDescriptor;
+  PlaceholderTileDescriptor;
+};
+
+struct SurfaceDescriptorTiles {
+  nsIntRegion validRegion;
+  nsIntRegion paintedRegion;
+  TileDescriptor[] tiles;
+  int         retainedWidth;
+  int         retainedHeight;
+  float       resolution;
+};
+
 // XXX - soon to be removed
 struct SurfaceDescriptorGralloc {
   PGrallocBuffer buffer;
   /**
    * android::GraphicBuffer has a size information. But there are cases
    * that GraphicBuffer's size and actual video's size are different.
    * Extra size member is necessary. See Bug 850566.
    */
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -290,22 +290,20 @@ ShadowLayerForwarder::RepositionChild(Sh
                    aContainer->AsLayer(), aChild->AsLayer()));
     mTxn->AddEdit(OpRaiseToTopChild(nullptr, Shadow(aContainer),
                                     nullptr, Shadow(aChild)));
   }
 }
 
 void
 ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                              BasicTiledLayerBuffer* aTiledLayerBuffer)
+                                              const SurfaceDescriptorTiles& aTileLayerDescriptor)
 {
-  if (XRE_GetProcessType() != GeckoProcessType_Default)
-    NS_RUNTIMEABORT("PaintedTiledLayerBuffer must be made IPC safe (not share pointers)");
   mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
-                                               uintptr_t(aTiledLayerBuffer)));
+                                               aTileLayerDescriptor));
 }
 
 void
 ShadowLayerForwarder::UpdateTexture(CompositableClient* aCompositable,
                                     TextureIdentifier aTextureId,
                                     SurfaceDescriptor* aDescriptor)
 {
   if (aDescriptor->type() != SurfaceDescriptor::T__None &&
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -41,20 +41,20 @@ class PLayerTransactionParent;
 class ShadowableLayer;
 class ThebesLayerComposite;
 class ContainerLayerComposite;
 class ImageLayerComposite;
 class ColorLayerComposite;
 class CanvasLayerComposite;
 class RefLayerComposite;
 class SurfaceDescriptor;
+class SurfaceDescriptorTiles;
 class ThebesBuffer;
 class TiledLayerComposer;
 class Transaction;
-class SurfaceDescriptor;
 class CanvasSurface;
 class DeprecatedTextureClientShmem;
 class ShmemTextureClient;
 class ContentClientRemote;
 class CompositableChild;
 class ImageClient;
 class CanvasClient;
 class ContentClient;
@@ -257,17 +257,17 @@ public:
   /**
    * Notify the compositor that a tiled layer buffer has changed
    * that needs to be synced to the shadow retained copy. The tiled
    * layer buffer will operate directly on the shadow retained buffer
    * and is free to choose it's own internal representation (double buffering,
    * copy on write, tiling).
    */
   virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                       BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE;
+                                       const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
 
   /**
    * Notify the compositor that a compositable will be updated asynchronously
    * through ImageBridge, using an ID to connect the protocols on the
    * compositor side.
    */
   void AttachAsyncCompositable(PLayerTransactionChild* aLayer, uint64_t aID);
 
--- a/gfx/thebes/gfxBaseSharedMemorySurface.h
+++ b/gfx/thebes/gfxBaseSharedMemorySurface.h
@@ -8,36 +8,39 @@
 #define GFX_SHARED_MEMORYSURFACE_H
 
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/SharedMemory.h"
 
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "cairo.h"
+#include "pratom.h"
 
 struct SharedImageInfo {
     int32_t width;
     int32_t height;
     int32_t format;
+    int32_t readCount;
 };
 
 inline SharedImageInfo*
 GetShmInfoPtr(const mozilla::ipc::Shmem& aShmem)
 {
     return reinterpret_cast<SharedImageInfo*>
         (aShmem.get<char>() + aShmem.Size<char>() - sizeof(SharedImageInfo));
 }
 
 extern const cairo_user_data_key_t SHM_KEY;
 
 template <typename Base, typename Sub>
 class gfxBaseSharedMemorySurface : public Base {
     typedef mozilla::ipc::SharedMemory SharedMemory;
     typedef mozilla::ipc::Shmem Shmem;
+    friend class gfxReusableSurfaceWrapper;
 
 public:
     virtual ~gfxBaseSharedMemorySurface()
     {
         MOZ_COUNT_DTOR(gfxBaseSharedMemorySurface);
     }
 
     /**
@@ -118,16 +121,38 @@ protected:
 
 private:
     void WriteShmemInfo()
     {
         SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
         shmInfo->width = this->mSize.width;
         shmInfo->height = this->mSize.height;
         shmInfo->format = this->mFormat;
+        shmInfo->readCount = 0;
+    }
+
+    int32_t
+    ReadLock()
+    {
+        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
+        return PR_ATOMIC_INCREMENT(&shmInfo->readCount);
+    }
+
+    int32_t
+    ReadUnlock()
+    {
+        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
+        return PR_ATOMIC_DECREMENT(&shmInfo->readCount);
+    }
+
+    int32_t
+    GetReadCount()
+    {
+        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
+        return shmInfo->readCount;
     }
 
     static size_t GetAlignedSize(const gfxIntSize& aSize, long aStride)
     {
         #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
         return MOZ_ALIGN_WORD(sizeof(SharedImageInfo) + aSize.height * aStride);
     }
 
--- a/gfx/thebes/gfxReusableSurfaceWrapper.cpp
+++ b/gfx/thebes/gfxReusableSurfaceWrapper.cpp
@@ -1,73 +1,97 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxReusableSurfaceWrapper.h"
-#include "gfxImageSurface.h"
+#include "gfxSharedImageSurface.h"
+
+using mozilla::ipc::Shmem;
+using mozilla::layers::ISurfaceAllocator;
 
-gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(gfxImageSurface* aSurface)
-  : mSurface(aSurface)
-  , mFormat(aSurface->Format())
-  , mSurfaceData(aSurface->Data())
-  , mReadCount(0)
+gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(ISurfaceAllocator* aAllocator,
+                                                     gfxSharedImageSurface* aSurface)
+  : mAllocator(aAllocator)
+  , mSurface(aSurface)
 {
   MOZ_COUNT_CTOR(gfxReusableSurfaceWrapper);
+  ReadLock();
 }
 
-class DeleteImageOnMainThread : public nsRunnable {
-public:
-  DeleteImageOnMainThread(gfxImageSurface *aImage)
-  : mImage(aImage)
-  {}
-
-  NS_IMETHOD Run()
-  {
-    return NS_OK;
-  }
-private:
-  nsRefPtr<gfxImageSurface> mImage;
-};
-
 gfxReusableSurfaceWrapper::~gfxReusableSurfaceWrapper()
 {
-  NS_ABORT_IF_FALSE(mReadCount == 0, "Should not be locked when released");
   MOZ_COUNT_DTOR(gfxReusableSurfaceWrapper);
-  if (!NS_IsMainThread()) {
-    NS_DispatchToMainThread(new DeleteImageOnMainThread(mSurface));
-  }
+  ReadUnlock();
 }
 
 void
 gfxReusableSurfaceWrapper::ReadLock()
 {
-  NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadOnlyLock");
-  mReadCount++;
+  NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadLock");
+  mSurface->ReadLock();
 }
 
 void
 gfxReusableSurfaceWrapper::ReadUnlock()
 {
-  mReadCount--;
-  NS_ABORT_IF_FALSE(mReadCount >= 0, "Should not be negative");
+  int32_t readCount = mSurface->ReadUnlock();
+  NS_ABORT_IF_FALSE(readCount >= 0, "Read count should not be negative");
+
+  if (readCount == 0) {
+    mAllocator->DeallocShmem(mSurface->GetShmem());
+  }
 }
 
 gfxReusableSurfaceWrapper*
 gfxReusableSurfaceWrapper::GetWritable(gfxImageSurface** aSurface)
 {
   NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call GetWritable");
 
-  if (mReadCount == 0) {
+  int32_t readCount = mSurface->GetReadCount();
+  NS_ABORT_IF_FALSE(readCount > 0, "A ReadLock must be held when calling GetWritable");
+  if (readCount == 1) {
     *aSurface = mSurface;
     return this;
   }
 
   // Something else is reading the surface, copy it
-  gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format(), false);
+  nsRefPtr<gfxSharedImageSurface> copySurface =
+    gfxSharedImageSurface::CreateUnsafe(mAllocator, mSurface->GetSize(), mSurface->Format());
   copySurface->CopyFrom(mSurface);
   *aSurface = copySurface;
 
-  // We need to create a new wrapper since this wrapper has a read only lock.
-  gfxReusableSurfaceWrapper* wrapper = new gfxReusableSurfaceWrapper(copySurface);
+  // We need to create a new wrapper since this wrapper has an external ReadLock
+  gfxReusableSurfaceWrapper* wrapper = new gfxReusableSurfaceWrapper(mAllocator, copySurface);
+
+  // No need to release the ReadLock on the surface, this will happen when
+  // the wrapper is destroyed.
+
   return wrapper;
 }
 
+const unsigned char*
+gfxReusableSurfaceWrapper::GetReadOnlyData() const
+{
+  NS_ABORT_IF_FALSE(mSurface->GetReadCount() > 0, "Should have read lock");
+  return mSurface->Data();
+}
+
+gfxASurface::gfxImageFormat
+gfxReusableSurfaceWrapper::Format()
+{
+  return mSurface->Format();
+}
+
+Shmem&
+gfxReusableSurfaceWrapper::GetShmem()
+{
+  return mSurface->GetShmem();
+}
+
+/* static */ already_AddRefed<gfxReusableSurfaceWrapper>
+gfxReusableSurfaceWrapper::Open(ISurfaceAllocator* aAllocator, const Shmem& aShmem)
+{
+  nsRefPtr<gfxSharedImageSurface> sharedImage = gfxSharedImageSurface::Open(aShmem);
+  nsRefPtr<gfxReusableSurfaceWrapper> wrapper = new gfxReusableSurfaceWrapper(aAllocator, sharedImage);
+  wrapper->ReadUnlock();
+  return wrapper.forget();
+}
--- a/gfx/thebes/gfxReusableSurfaceWrapper.h
+++ b/gfx/thebes/gfxReusableSurfaceWrapper.h
@@ -4,21 +4,22 @@
 
 #ifndef GFXCOWSURFACEWRAPPER
 #define GFXCOWSURFACEWRAPPER
 
 #include "gfxASurface.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
 
-class gfxImageSurface;
+class gfxSharedImageSurface;
 
 /**
- * Provides a cross thread wrapper for a gfxImageSurface
+ * Provides a cross thread wrapper for a gfxSharedImageSurface
  * that has copy-on-write schemantics.
  *
  * Only the owner thread can write to the surface and aquire
  * read locks.
  *
  * OMTC Usage:
  * 1) Content creates a writable copy of this surface
  *    wrapper which be optimized to the same wrapper if there
@@ -27,47 +28,56 @@ class gfxImageSurface;
  *    or potentially many time, each increasing a read lock.
  * 3) When the compositor has processed the surface and uploaded
  *    the content it then releases the read lock.
  */
 class gfxReusableSurfaceWrapper {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper)
 public:
   /**
-   * Pass the gfxASurface to the wrapper.
-   * The wrapper should hold the only strong reference
-   * to the surface and its memebers.
+   * Pass the gfxSharedImageSurface to the wrapper. The wrapper will ReadLock
+   * on creation and ReadUnlock on destruction.
    */
-  gfxReusableSurfaceWrapper(gfxImageSurface* aSurface);
+  gfxReusableSurfaceWrapper(mozilla::layers::ISurfaceAllocator* aAllocator, gfxSharedImageSurface* aSurface);
 
   ~gfxReusableSurfaceWrapper();
 
-  const unsigned char* GetReadOnlyData() const {
-    NS_ABORT_IF_FALSE(mReadCount > 0, "Should have read lock");
-    return mSurfaceData;
-  }
+  const unsigned char* GetReadOnlyData() const;
+
+  mozilla::ipc::Shmem& GetShmem();
 
-  const gfxASurface::gfxImageFormat& Format() { return mFormat; }
+  /**
+   * Create a gfxReusableSurfaceWrapper from the shared memory segment of a
+   * gfxSharedImageSurface. A ReadLock must be held, which will be adopted by
+   * the returned gfxReusableSurfaceWrapper.
+   */
+  static already_AddRefed<gfxReusableSurfaceWrapper>
+  Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem);
+
+  gfxASurface::gfxImageFormat Format();
 
   /**
    * Get a writable copy of the image.
    * If necessary this will copy the wrapper. If there are no contention
-   * the same wrapper will be returned.
+   * the same wrapper will be returned. A ReadLock must be held when
+   * calling this function, and calling it will give up this lock.
    */
   gfxReusableSurfaceWrapper* GetWritable(gfxImageSurface** aSurface);
 
   /**
    * A read only lock count is recorded, any attempts to
-   * call GetWritable() while this count is positive will
+   * call GetWritable() while this count is greater than one will
    * create a new surface/wrapper pair.
+   *
+   * When a surface's read count falls to zero, its memory will be
+   * deallocated. It is the responsibility of the user to make sure
+   * that all locks are matched with an equal number of unlocks.
    */
   void ReadLock();
   void ReadUnlock();
 
 private:
   NS_DECL_OWNINGTHREAD
-  nsRefPtr<gfxImageSurface>         mSurface;
-  const gfxASurface::gfxImageFormat mFormat;
-  const unsigned char*              mSurfaceData;
-  mozilla::Atomic<int32_t>                           mReadCount;
+  mozilla::layers::ISurfaceAllocator*     mAllocator;
+  nsRefPtr<gfxSharedImageSurface>         mSurface;
 };
 
 #endif // GFXCOWSURFACEWRAPPER