Bug 963073 - Merge tiling branch. r=Bas,jrmuizel,BenWa
authorBas Schouten <bschouten@mozilla.com>
Fri, 07 Mar 2014 22:34:04 +0100
changeset 189810 8394fed3332ede1b9745dd1b065cf60e13cef5b4
parent 189809 c8355055899c922cee30f77a371ec3183f293b94
child 189811 40b2ac4137724746ad22bca1a3a5c4d58cde7b06
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, jrmuizel, BenWa
bugs963073
milestone30.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 963073 - Merge tiling branch. r=Bas,jrmuizel,BenWa http://hg.mozilla.org/users/bschouten_mozilla.com/tiling/summary This work is mainly porting tiled layers to new textures, implementing double-buffered tiles and implementing a texture client pool, to be used by tiled content clients. Any questions regarding this patch should go to: Bas Schouten <bschouten@mozilla.com> Chris Lord <clord@mozilla.com> Nicolas Silva <nsilva@mozilla.com> In their absence questions can be directed to: Jeff Muizelaar <jmuizelaar@mozilla.com> Benoit Girard <bgirard@mozilla.com>
browser/devtools/profiler/cleopatra/js/parserWorker.js
gfx/layers/Compositor.h
gfx/layers/TiledLayerBuffer.h
gfx/layers/basic/TextureClientX11.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/CanvasClient.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/client/ClientThebesLayer.cpp
gfx/layers/client/ClientTiledThebesLayer.cpp
gfx/layers/client/ClientTiledThebesLayer.h
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/ImageClient.cpp
gfx/layers/client/ImageClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TextureClientPool.cpp
gfx/layers/client/TextureClientPool.h
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/composite/TiledContentHost.h
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/d3d9/TextureD3D9.h
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/ISurfaceAllocator.h
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayerTransactionParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/moz.build
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/GrallocTextureClient.cpp
gfx/layers/opengl/GrallocTextureClient.h
gfx/layers/opengl/GrallocTextureHost.cpp
gfx/layers/opengl/GrallocTextureHost.h
gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
gfx/layers/opengl/TextureClientOGL.h
gfx/thebes/gfxPrefs.h
--- a/browser/devtools/profiler/cleopatra/js/parserWorker.js
+++ b/browser/devtools/profiler/cleopatra/js/parserWorker.js
@@ -1221,17 +1221,17 @@ var diagnosticList = [
 
   {
     image: "js.png",
     title: "Bug 772916 - Gradients are slow on mobile",
     bugNumber: "772916",
     check: function(frames, symbols, meta) {
 
       return stepContains('PaintGradient', frames, symbols)
-          && stepContains('BasicTiledLayerBuffer::PaintThebesSingleBufferDraw', frames, symbols)
+          && stepContains('ClientTiledLayerBuffer::PaintThebesSingleBufferDraw', frames, symbols)
           ;
     },
   },
   {
     image: "cache.png",
     title: "Bug 717761 - Main thread can be blocked by IO on the cache thread",
     bugNumber: "717761",
     check: function(frames, symbols, meta) {
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -128,16 +128,33 @@ class LayerManagerComposite;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
 /**
+ * A base class for a platform-dependent helper for use by TextureHost.
+ */
+class CompositorBackendSpecificData : public RefCounted<CompositorBackendSpecificData>
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositorBackendSpecificData)
+  CompositorBackendSpecificData()
+  {
+    MOZ_COUNT_CTOR(CompositorBackendSpecificData);
+  }
+  virtual ~CompositorBackendSpecificData()
+  {
+    MOZ_COUNT_DTOR(CompositorBackendSpecificData);
+  }
+};
+
+/**
  * Common interface for compositor backends.
  *
  * Compositor provides a cross-platform interface to a set of operations for
  * compositing quads. Compositor knows nothing about the layer tree. It must be
  * told everything about each composited quad - contents, location, transform,
  * opacity, etc.
  *
  * In theory it should be possible for different widgets to use the same
@@ -454,16 +471,20 @@ public:
       fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
       if (fillRatio > 999.0f) {
         fillRatio = 999.0f;
       }
     }
     return fillRatio;
   }
 
+  virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() {
+    return nullptr;
+  }
+
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -177,34 +177,34 @@ 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 ClientTiledLayerBuffer;
 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.
    * 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
+   * ClientTiledLayerBuffer locally. This lock will be retained until the buffer
    * has completed uploading.
    */
-  virtual void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
-                                       const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
+  virtual void UseTiledLayerBuffer(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;
 };
 
@@ -287,16 +287,17 @@ TiledLayerBuffer<Derived, Tile>::Update(
 
   // Pass 1: Recycle valid content from the old buffer
   // Recycle tiles from the old buffer that contain valid regions.
   // Insert placeholders tiles if we have no valid area for that tile
   // which we will allocate in pass 2.
   // TODO: Add a tile pool to reduce new allocation
   int tileX = 0;
   int tileY = 0;
+  int tilesMissing = 0;
   // Iterate over the new drawing bounds in steps of tiles.
   for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
     // Compute tileRect(x,y,width,height) in layer space coordinate
     // giving us the rect of the tile that hits the newBounds.
     int width = GetScaledTileLength() - GetTileStart(x);
     if (x + width > newBound.XMost()) {
       width = newBound.x + newBound.width - x;
     }
@@ -331,29 +332,53 @@ TiledLayerBuffer<Derived, Tile>::Update(
         // This tile is either:
         // 1) Outside the new valid region and will simply be an empty
         // placeholder forever.
         // 2) The old buffer didn't have any data for this tile. We postpone
         // the allocation of this tile after we've reused any tile with
         // valid content because then we know we can safely recycle
         // with taking from a tile that has recyclable content.
         newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
+
+        if (aPaintRegion.Intersects(tileRect)) {
+          tilesMissing++;
+        }
       }
 
       y += height;
     }
 
     x += width;
   }
 
   // Keep track of the number of horizontal/vertical tiles
   // in the buffer so that we can easily look up a tile.
   mRetainedWidth = tileX;
   mRetainedHeight = tileY;
 
+  // Pass 1.5: Release excess tiles in oldRetainedTiles
+  // Tiles in oldRetainedTiles that aren't in newRetainedTiles will be recycled
+  // before creating new ones, but there could still be excess unnecessary
+  // tiles. As tiles may not have a fixed memory cost (for example, due to
+  // double-buffering), we should release these excess tiles first.
+  int oldTileCount = 0;
+  for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
+    Tile oldTile = oldRetainedTiles[i];
+    if (IsPlaceholder(oldTile)) {
+      continue;
+    }
+
+    if (oldTileCount >= tilesMissing) {
+      oldRetainedTiles[i] = AsDerived().GetPlaceholderTile();
+      AsDerived().ReleaseTile(oldTile);
+    } else {
+      oldTileCount ++;
+    }
+  }
+
   NS_ABORT_IF_FALSE(aNewValidRegion.Contains(aPaintRegion), "Painting a region outside the visible region");
 #ifdef DEBUG
   nsIntRegion oldAndPainted(oldValidRegion);
   oldAndPainted.Or(oldAndPainted, aPaintRegion);
 #endif
   NS_ABORT_IF_FALSE(oldAndPainted.Contains(newValidRegion), "newValidRegion has not been fully painted");
 
   nsIntRegion regionToPaint(aPaintRegion);
@@ -410,19 +435,25 @@ TiledLayerBuffer<Derived, Tile>::Update(
       int tileX = floor_div(x - newBufferOrigin.x, GetScaledTileLength());
       int tileY = floor_div(y - newBufferOrigin.y, GetScaledTileLength());
       int index = tileX * mRetainedHeight + tileY;
       NS_ABORT_IF_FALSE(index >= 0 &&
                         static_cast<unsigned>(index) < newRetainedTiles.Length(),
                         "index out of range");
 
       Tile newTile = newRetainedTiles[index];
+
+      // Try to reuse a tile from the old retained tiles that had no partially
+      // valid content.
       while (IsPlaceholder(newTile) && oldRetainedTiles.Length() > 0) {
         AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]);
         oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
+        if (!IsPlaceholder(newTile)) {
+          oldTileCount--;
+        }
       }
 
       // We've done our best effort to recycle a tile but it can be null
       // in which case it's up to the derived class's ValidateTile()
       // implementation to allocate a new tile before drawing
       nsIntPoint tileOrigin(tileStartX, tileStartY);
       newTile = AsDerived().ValidateTile(newTile, nsIntPoint(tileStartX, tileStartY),
                                          tileDrawRegion);
@@ -433,23 +464,18 @@ TiledLayerBuffer<Derived, Tile>::Update(
       newRetainedTiles[index] = newTile;
 
       y += height;
     }
 
     x += width;
   }
 
-  // Throw away any tiles we didn't recycle
-  // TODO: Add a tile pool
-  while (oldRetainedTiles.Length() > 0) {
-    Tile oldTile = oldRetainedTiles[oldRetainedTiles.Length()-1];
-    oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
-    AsDerived().ReleaseTile(oldTile);
-  }
+  // At this point, oldTileCount should be zero
+  NS_ABORT_IF_FALSE(oldTileCount == 0, "Failed to release old tiles");
 
   mRetainedTiles = newRetainedTiles;
   mValidRegion = aNewValidRegion;
   mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
 }
 
 } // layers
 } // mozilla
--- a/gfx/layers/basic/TextureClientX11.h
+++ b/gfx/layers/basic/TextureClientX11.h
@@ -49,16 +49,18 @@ class TextureClientX11
 
   // TextureClientDrawTarget
 
   TemporaryRef<gfx::DrawTarget> GetAsDrawTarget() MOZ_OVERRIDE;
   gfx::SurfaceFormat GetFormat() const {
     return mFormat;
   }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
  private:
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   RefPtr<gfxXlibSurface> mSurface;
   bool mLocked;
 };
 
 } // namespace layers
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -94,23 +94,16 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   }
 
   if (updated) {
     GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
     GetForwarder()->UseTexture(this, mBuffer);
   }
 }
 
-TemporaryRef<BufferTextureClient>
-CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
-{
-  return CompositableClient::CreateBufferTextureClient(aFormat,
-                                                       mTextureInfo.mTextureFlags | aFlags);
-}
-
 CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
                                                      TextureFlags aFlags)
   : CanvasClient(aLayerForwarder, aFlags)
 {
 }
 
 void
 CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -45,17 +45,17 @@ public:
     CanvasClientSurface,
     CanvasClientGLContext,
   };
   static TemporaryRef<CanvasClient> CreateCanvasClient(CanvasClientType aType,
                                                        CompositableForwarder* aFwd,
                                                        TextureFlags aFlags);
 
   CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
-    : CompositableClient(aFwd)
+    : CompositableClient(aFwd, aFlags)
   {
     mTextureInfo.mTextureFlags = aFlags;
   }
 
   virtual ~CanvasClient() {}
 
   virtual void Clear() {};
 
@@ -90,20 +90,16 @@ public:
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
 
   virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE
   {
     MOZ_ASSERT((mTextureInfo.mTextureFlags & aTexture->GetFlags()) == mTextureInfo.mTextureFlags);
     return CompositableClient::AddTextureClient(aTexture);
   }
 
-  virtual TemporaryRef<BufferTextureClient>
-  CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
-                            TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
-
   virtual void OnDetach() MOZ_OVERRIDE
   {
     mBuffer = nullptr;
   }
 
 private:
   RefPtr<TextureClient> mBuffer;
 };
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -15,30 +15,37 @@
 #include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
 #include "mozilla/layers/ContentClient.h"  // for ContentClientRemote
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/PLayerChild.h"  // for PLayerChild
 #include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
 #include "nsAString.h"
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsTArray.h"                   // for AutoInfallibleTArray
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
+#include "TiledLayerBuffer.h"
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
+  TextureClientPoolMember::TextureClientPoolMember(SurfaceFormat aFormat, TextureClientPool* aTexturePool)
+  : mFormat(aFormat)
+  , mTexturePool(aTexturePool)
+{}
+
 ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
   : mPhase(PHASE_NONE)
   , mWidget(aWidget) 
   , mTargetRotation(ROTATION_0)
   , mRepeatTransaction(false)
   , mIsRepeatTransaction(false)
   , mTransactionIncomplete(false)
   , mCompositorMightResample(false)
@@ -48,16 +55,18 @@ ClientLayerManager::ClientLayerManager(n
   MOZ_COUNT_CTOR(ClientLayerManager);
 }
 
 ClientLayerManager::~ClientLayerManager()
 {
   mRoot = nullptr;
 
   MOZ_COUNT_DTOR(ClientLayerManager);
+
+  mTexturePools.clear();
 }
 
 int32_t
 ClientLayerManager::GetMaxTextureSize() const
 {
   return mForwarder->GetMaxTextureSize();
 }
 
@@ -217,16 +226,21 @@ ClientLayerManager::EndTransaction(DrawT
     mRepeatTransaction = false;
     mIsRepeatTransaction = true;
     BeginTransaction();
     ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
     mIsRepeatTransaction = false;
   } else {
     MakeSnapshotIfRequired();
   }
+
+  for (const TextureClientPoolMember* item = mTexturePools.getFirst();
+       item; item = item->getNext()) {
+    item->mTexturePool->ReturnDeferredClients();
+  }
 }
 
 bool
 ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   mInTransaction = false;
 
   if (!mRoot) {
@@ -435,28 +449,52 @@ ClientLayerManager::IsCompositingCheap()
 }
 
 void
 ClientLayerManager::SetIsFirstPaint()
 {
   mForwarder->SetIsFirstPaint();
 }
 
+TextureClientPool*
+ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
+{
+  for (const TextureClientPoolMember* item = mTexturePools.getFirst();
+       item; item = item->getNext()) {
+    if (item->mFormat == aFormat) {
+      return item->mTexturePool;
+    }
+  }
+
+  TextureClientPoolMember* texturePoolMember =
+    new TextureClientPoolMember(aFormat,
+      new TextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
+                                             TILEDLAYERBUFFER_TILE_SIZE),
+                            mForwarder));
+  mTexturePools.insertBack(texturePoolMember);
+
+  return texturePoolMember->mTexturePool;
+}
+
 void
 ClientLayerManager::ClearCachedResources(Layer* aSubtree)
 {
   MOZ_ASSERT(!HasShadowManager() || !aSubtree);
   if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
     manager->SendClearCachedResources();
   }
   if (aSubtree) {
     ClearLayer(aSubtree);
   } else if (mRoot) {
     ClearLayer(mRoot);
   }
+  for (const TextureClientPoolMember* item = mTexturePools.getFirst();
+       item; item = item->getNext()) {
+    item->mTexturePool->Clear();
+  }
 }
 
 void
 ClientLayerManager::ClearLayer(Layer* aLayer)
 {
   ClientLayer::ToClientLayer(aLayer)->ClearCachedResources();
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -5,16 +5,17 @@
 
 #ifndef GFX_CLIENTLAYERMANAGER_H
 #define GFX_CLIENTLAYERMANAGER_H
 
 #include <stdint.h>                     // for int32_t
 #include "Layers.h"
 #include "gfxContext.h"                 // for gfxContext
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
+#include "mozilla/LinkedList.h"         // For LinkedList
 #include "mozilla/WidgetUtils.h"        // for ScreenRotation
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersTypes.h"  // for BufferMode, LayersBackend, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
@@ -27,16 +28,26 @@ class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class ClientThebesLayer;
 class CompositorChild;
 class ImageLayer;
 class PLayerChild;
+class TextureClientPool;
+
+class TextureClientPoolMember
+  : public LinkedListElement<TextureClientPoolMember> {
+public:
+  TextureClientPoolMember(gfx::SurfaceFormat aFormat, TextureClientPool* aTexturePool);
+
+  gfx::SurfaceFormat mFormat;
+  RefPtr<TextureClientPool> mTexturePool;
+};
 
 class ClientLayerManager : public LayerManager
 {
   typedef nsTArray<nsRefPtr<Layer> > LayerRefArray;
 
 public:
   ClientLayerManager(nsIWidget* aWidget);
   virtual ~ClientLayerManager();
@@ -91,16 +102,18 @@ public:
 
   bool HasShadowManager() const { return mForwarder->HasShadowManager(); }
 
   virtual bool IsCompositingCheap();
   virtual bool HasShadowManagerInternal() const { return HasShadowManager(); }
 
   virtual void SetIsFirstPaint() MOZ_OVERRIDE;
 
+  TextureClientPool *GetTexturePool(gfx::SurfaceFormat aFormat);
+
   // Drop cached resources and ask our shadow manager to do the same,
   // if we have one.
   virtual void ClearCachedResources(Layer* aSubtree = nullptr) MOZ_OVERRIDE;
 
   void SetRepeatTransaction() { mRepeatTransaction = true; }
   bool GetRepeatTransaction() { return mRepeatTransaction; }
 
   bool IsRepeatTransaction() { return mIsRepeatTransaction; }
@@ -209,16 +222,17 @@ private:
   // a display list) to support progressive drawing.
   bool mRepeatTransaction;
   bool mIsRepeatTransaction;
   bool mTransactionIncomplete;
   bool mCompositorMightResample;
   bool mNeedsComposite;
 
   RefPtr<ShadowLayerForwarder> mForwarder;
+  LinkedList<TextureClientPoolMember> mTexturePools;
 };
 
 class ClientLayer : public ShadowableLayer
 {
 public:
   ClientLayer()
   {
     MOZ_COUNT_CTOR(ClientLayer);
--- a/gfx/layers/client/ClientThebesLayer.cpp
+++ b/gfx/layers/client/ClientThebesLayer.cpp
@@ -167,17 +167,20 @@ ClientLayerManager::CreateThebesLayer()
 already_AddRefed<ThebesLayer>
 ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   if (
 #ifdef MOZ_B2G
       aHint == SCROLLABLE &&
 #endif
-      gfxPrefs::LayersTilesEnabled() && AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) {
+      gfxPrefs::LayersTilesEnabled() &&
+      (AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL ||
+       AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 ||
+       AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)) {
     nsRefPtr<ClientTiledThebesLayer> layer =
       new ClientTiledThebesLayer(this);
     CREATE_SHADOW(Thebes);
     return layer.forget();
   } else
   {
     nsRefPtr<ClientThebesLayer> layer =
       new ClientThebesLayer(this);
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -33,16 +33,24 @@ ClientTiledThebesLayer::ClientTiledThebe
 }
 
 ClientTiledThebesLayer::~ClientTiledThebesLayer()
 {
   MOZ_COUNT_DTOR(ClientTiledThebesLayer);
 }
 
 void
+ClientTiledThebesLayer::ClearCachedResources()
+{
+  if (mContentClient) {
+    mContentClient->ClearCachedResources();
+  }
+}
+
+void
 ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
 {
   aAttrs = ThebesLayerAttributes(GetValidRegion());
 }
 
 static LayoutDeviceRect
 ApplyScreenToLayoutTransform(const gfx3DMatrix& aTransform, const ScreenRect& aScreenRect)
 {
@@ -184,17 +192,17 @@ ClientTiledThebesLayer::RenderLayer()
     mValidRegion = mVisibleRegion;
 
     NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
 
     mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
                                              callback, data);
 
     ClientManager()->Hold(this);
-    mContentClient->LockCopyAndWrite(TiledContentClient::TILED_BUFFER);
+    mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
 
     return;
   }
 
   // Calculate everything we need to perform the paint.
   BeginPaint();
   if (mPaintData.mPaintFinished) {
     return;
@@ -257,17 +265,17 @@ ClientTiledThebesLayer::RenderLayer()
       }
       mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
       mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
                                                callback, data);
     }
 
     if (updatedBuffer) {
       ClientManager()->Hold(this);
-      mContentClient->LockCopyAndWrite(TiledContentClient::TILED_BUFFER);
+      mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
 
       // If there are low precision updates, mark the paint as unfinished and
       // request a repeat transaction.
       if (!lowPrecisionInvalidRegion.IsEmpty() && mPaintData.mPaintFinished) {
         ClientManager()->SetRepeatTransaction();
         mPaintData.mLowPrecisionPaintCount = 1;
         mPaintData.mPaintFinished = false;
       }
@@ -326,16 +334,16 @@ ClientTiledThebesLayer::RenderLayer()
                                                          callback, data);
   }
 
   // We send a Painted callback if we clear the valid region of the low
   // precision buffer, so that the shadow buffer's valid region can be updated
   // and the associated resources can be freed.
   if (updatedLowPrecision) {
     ClientManager()->Hold(this);
-    mContentClient->LockCopyAndWrite(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
+    mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
   }
 
   EndPaint(false);
 }
 
 } // mozilla
 } // layers
--- a/gfx/layers/client/ClientTiledThebesLayer.h
+++ b/gfx/layers/client/ClientTiledThebesLayer.h
@@ -58,16 +58,18 @@ public:
 
   virtual void Disconnect()
   {
     ClientLayer::Disconnect();
   }
 
   virtual void RenderLayer();
 
+  virtual void ClearCachedResources() MOZ_OVERRIDE;
+
 private:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
 
   /**
    * For the initial PaintThebes of a transaction, calculates all the data
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -7,45 +7,35 @@
 #include <stdint.h>                     // for uint64_t, uint32_t
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/TextureClient.h"  // for DeprecatedTextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "gfxASurface.h"                // for gfxContentType
 #ifdef XP_WIN
-#include "mozilla/layers/TextureD3D9.h"
+#include "gfxWindowsPlatform.h"         // for gfxWindowsPlatform
 #include "mozilla/layers/TextureD3D11.h"
-#include "gfxWindowsPlatform.h"
-#include "gfx2DGlue.h"
-#endif
-#ifdef MOZ_X11
-#include "mozilla/layers/TextureClientX11.h"
-#ifdef GL_PROVIDER_GLX
-#include "GLXLibrary.h"
-#endif
-#endif
-#ifdef MOZ_WIDGET_GONK
-#include <cutils/properties.h>
-#include "mozilla/layers/GrallocTextureClient.h"
+#include "mozilla/layers/TextureD3D9.h"
 #endif
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
-CompositableClient::CompositableClient(CompositableForwarder* aForwarder)
+CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
+                                       TextureFlags aTextureFlags)
 : mCompositableChild(nullptr)
 , mForwarder(aForwarder)
+, mTextureFlags(aTextureFlags)
 {
   MOZ_COUNT_CTOR(CompositableClient);
 }
 
-
 CompositableClient::~CompositableClient()
 {
   MOZ_COUNT_DTOR(CompositableClient);
   Destroy();
 }
 
 LayersBackend
 CompositableClient::GetCompositorBackendType() const
@@ -126,17 +116,17 @@ CompositableClient::CreateDeprecatedText
     break;
   case TEXTURE_CONTENT:
 #ifdef XP_WIN
     if (parentBackend == LayersBackend::LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice()) {
       result = new DeprecatedTextureClientD3D11(GetForwarder(), GetTextureInfo());
       break;
     }
     if (parentBackend == LayersBackend::LAYERS_D3D9 &&
-        !GetForwarder()->ForwardsToDifferentProcess()) {
+        GetForwarder()->IsSameProcess()) {
       // We can't use a d3d9 texture for an RGBA surface because we cannot get a DC for
       // for a gfxWindowsSurface.
       // We have to wait for the compositor thread to create a d3d9 device before we
       // can create d3d9 textures on the main thread (because we need to reset on the
       // compositor thread, and the d3d9 device must be reset on the same thread it was
       // created on).
       if (aContentType == gfxContentType::COLOR_ALPHA ||
           !gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
@@ -176,127 +166,26 @@ CompositableClient::CreateDeprecatedText
 
   return result.forget();
 }
 
 TemporaryRef<BufferTextureClient>
 CompositableClient::CreateBufferTextureClient(SurfaceFormat aFormat,
                                               TextureFlags aTextureFlags)
 {
-// XXX - Once bug 908196 is fixed, we can use gralloc textures here which will
-// improve performances of videos using SharedPlanarYCbCrImage on b2g.
-//#ifdef MOZ_WIDGET_GONK
-//  {
-//    RefPtr<BufferTextureClient> result = new GrallocTextureClientOGL(this,
-//                                                                     aFormat,
-//                                                                     aTextureFlags);
-//    return result.forget();
-//  }
-//#endif
-  if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
-    RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat, aTextureFlags);
-    return result.forget();
-  }
-  RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat, aTextureFlags);
-  return result.forget();
+  return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
+                                                  aTextureFlags | mTextureFlags);
 }
 
-#ifdef MOZ_WIDGET_GONK
-static bool
-DisableGralloc(SurfaceFormat aFormat)
-{
-  if (aFormat == gfx::SurfaceFormat::A8) {
-    return true;
-  }
-#if ANDROID_VERSION <= 15
-  static bool checkedDevice = false;
-  static bool disableGralloc = false;
-
-  if (!checkedDevice) {
-    char propValue[PROPERTY_VALUE_MAX];
-    property_get("ro.product.device", propValue, "None");
-
-    if (strcmp("crespo",propValue) == 0) {
-      NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
-      disableGralloc = true;
-    }
-
-    checkedDevice = true;
-  }
-
-  if (disableGralloc) {
-    return true;
-  }
-  return false;
-#else
-  return false;
-#endif
-}
-#endif
-
 TemporaryRef<TextureClient>
 CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
                                                   TextureFlags aTextureFlags)
 {
-  RefPtr<TextureClient> result;
-
-#ifdef XP_WIN
-  LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
-  if (parentBackend == LayersBackend::LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
-      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
-    result = new TextureClientD3D11(aFormat, aTextureFlags);
-  }
-  if (parentBackend == LayersBackend::LAYERS_D3D9 &&
-      !GetForwarder()->ForwardsToDifferentProcess() &&
-      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
-    if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
-      result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
-    } else {
-      result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
-    }
-  }
-#endif
-
-#ifdef MOZ_X11
-  LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
-  gfxSurfaceType type =
-    gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
-
-  if (parentBackend == LayersBackend::LAYERS_BASIC &&
-      type == gfxSurfaceType::Xlib &&
-      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
-  {
-    result = new TextureClientX11(aFormat, aTextureFlags);
-  }
-#ifdef GL_PROVIDER_GLX
-  if (parentBackend == LayersBackend::LAYERS_OPENGL &&
-      type == gfxSurfaceType::Xlib &&
-      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
-      aFormat != SurfaceFormat::A8 &&
-      gl::sGLXLibrary.UseTextureFromPixmap())
-  {
-    result = new TextureClientX11(aFormat, aTextureFlags);
-  }
-#endif
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-  if (!DisableGralloc(aFormat)) {
-    result = new GrallocTextureClientOGL(this, aFormat, aTextureFlags);
-  }
-#endif
-
-  // Can't do any better than a buffer texture client.
-  if (!result) {
-    result = CreateBufferTextureClient(aFormat, aTextureFlags);
-  }
-
-  MOZ_ASSERT(!result || result->AsTextureClientDrawTarget(),
-             "Not a TextureClientDrawTarget?");
-  return result;
+  return TextureClient::CreateTextureClientForDrawing(GetForwarder(), aFormat,
+                                                      aTextureFlags | mTextureFlags);
 }
 
 bool
 CompositableClient::AddTextureClient(TextureClient* aClient)
 {
   return aClient->InitIPDLActor(mForwarder);
 }
 
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -68,29 +68,29 @@ class TextureClientData;
  * Canvas layers use CanvasClients (but ImageHosts). We have a different subclass
  * where we have a different way of interfacing with the textures - in terms of
  * drawing into the compositable and/or passing its contents to the compostior.
  */
 class CompositableClient : public AtomicRefCounted<CompositableClient>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositableClient)
-  CompositableClient(CompositableForwarder* aForwarder);
+  CompositableClient(CompositableForwarder* aForwarder, TextureFlags aFlags = 0);
 
   virtual ~CompositableClient();
 
   virtual TextureInfo GetTextureInfo() const = 0;
 
   LayersBackend GetCompositorBackendType() const;
 
   TemporaryRef<DeprecatedTextureClient>
   CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType,
                                 gfxContentType aContentType = gfxContentType::SENTINEL);
 
-  virtual TemporaryRef<BufferTextureClient>
+  TemporaryRef<BufferTextureClient>
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
                             TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
 
   // If we return a non-null TextureClient, then AsTextureClientDrawTarget will
   // always be non-null.
   TemporaryRef<TextureClient>
   CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
                                 TextureFlags aTextureFlags);
@@ -138,19 +138,28 @@ public:
    */
   virtual void OnTransaction();
 
   /**
    * A hook for the when the Compositable is detached from it's layer.
    */
   virtual void OnDetach() {}
 
+  /**
+   * Clear any resources that are not immediately necessary. This may be called
+   * in low-memory conditions.
+   */
+  virtual void ClearCachedResources() {}
+
 protected:
   CompositableChild* mCompositableChild;
   CompositableForwarder* mForwarder;
+  // Some layers may want to enforce some flags to all their textures
+  // (like disallowing tiling)
+  TextureFlags mTextureFlags;
 
   friend class CompositableChild;
 };
 
 /**
  * IPDL actor used by CompositableClient to match with its corresponding
  * CompositableHost on the compositor side.
  *
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -77,18 +77,17 @@ ImageClient::CreateImageClient(Composita
   NS_ASSERTION(result, "Failed to create ImageClient");
 
   return result.forget();
 }
 
 ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
                                      TextureFlags aFlags,
                                      CompositableType aType)
-  : ImageClient(aFwd, aType)
-  , mTextureFlags(aFlags)
+  : ImageClient(aFwd, aFlags, aType)
 {
 }
 
 ImageClientBuffered::ImageClientBuffered(CompositableForwarder* aFwd,
                                          TextureFlags aFlags,
                                          CompositableType aType)
   : ImageClientSingle(aFwd, aFlags, aType)
 {
@@ -305,37 +304,32 @@ ImageClientBuffered::UpdateImage(ImageCo
 
 bool
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
   MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   return CompositableClient::AddTextureClient(aTexture);
 }
 
-TemporaryRef<BufferTextureClient>
-ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
-{
-  return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags | aFlags);
-}
-
 void
 ImageClientSingle::OnDetach()
 {
   mFrontBuffer = nullptr;
 }
 
 void
 ImageClientBuffered::OnDetach()
 {
   mFrontBuffer = nullptr;
   mBackBuffer = nullptr;
 }
 
-ImageClient::ImageClient(CompositableForwarder* aFwd, CompositableType aType)
-: CompositableClient(aFwd)
+ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
+                         CompositableType aType)
+: CompositableClient(aFwd, aFlags)
 , mType(aType)
 , mLastPaintedImageSerial(0)
 {}
 
 void
 ImageClient::UpdatePictureRect(nsIntRect aRect)
 {
   if (mPictureRect == aRect) {
@@ -344,17 +338,17 @@ ImageClient::UpdatePictureRect(nsIntRect
   mPictureRect = aRect;
   MOZ_ASSERT(mForwarder);
   GetForwarder()->UpdatePictureRect(this, aRect);
 }
 
 DeprecatedImageClientSingle::DeprecatedImageClientSingle(CompositableForwarder* aFwd,
                                                          TextureFlags aFlags,
                                                          CompositableType aType)
-  : ImageClient(aFwd, aType)
+  : ImageClient(aFwd, aFlags, aType)
   , mTextureInfo(aType)
 {
   mTextureInfo.mTextureFlags = aFlags;
 }
 
 bool
 DeprecatedImageClientSingle::EnsureDeprecatedTextureClient(DeprecatedTextureClientType aType)
 {
@@ -477,17 +471,17 @@ DeprecatedImageClientSingle::UpdateImage
 void
 DeprecatedImageClientSingle::Updated()
 {
   mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
 }
 
 ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
                                      TextureFlags aFlags)
-: ImageClient(aFwd, BUFFER_BRIDGE)
+: ImageClient(aFwd, aFlags, BUFFER_BRIDGE)
 , mAsyncContainerID(0)
 , mLayer(nullptr)
 {
 }
 
 bool
 ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
 {
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -62,17 +62,18 @@ public:
   virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) = 0;
 
   /**
    * Synchronously remove all the textures used by the image client.
    */
   virtual void FlushAllImages(bool aExceptFront) {}
 
 protected:
-  ImageClient(CompositableForwarder* aFwd, CompositableType aType);
+  ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
+              CompositableType aType);
 
   CompositableType mType;
   int32_t mLastPaintedImageSerial;
   nsIntRect mPictureRect;
 };
 
 /**
  * An image client which uses a single texture client.
@@ -85,34 +86,27 @@ public:
                     CompositableType aType);
 
   virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
 
   virtual void OnDetach() MOZ_OVERRIDE;
 
   virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE;
 
-  virtual TemporaryRef<BufferTextureClient>
-  CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
-                            TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
-
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) MOZ_OVERRIDE;
 
   virtual void FlushAllImages(bool aExceptFront) MOZ_OVERRIDE;
 
 protected:
   virtual bool UpdateImageInternal(ImageContainer* aContainer, uint32_t aContentFlags, bool* aIsSwapped);
 
 protected:
   RefPtr<TextureClient> mFrontBuffer;
-  // Some layers may want to enforce some flags to all their textures
-  // (like disallowing tiling)
-  TextureFlags mTextureFlags;
 };
 
 /**
  * An image client which uses two texture clients.
  */
 class ImageClientBuffered : public ImageClientSingle
 {
 public:
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -19,16 +19,35 @@
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
 #include "mozilla/gfx/2D.h"
+#include "mozilla/layers/TextureClientOGL.h"
+
+#ifdef XP_WIN
+#include "mozilla/layers/TextureD3D9.h"
+#include "mozilla/layers/TextureD3D11.h"
+#include "gfxWindowsPlatform.h"
+#include "gfx2DGlue.h"
+#endif
+#ifdef MOZ_X11
+#include "mozilla/layers/TextureClientX11.h"
+#ifdef GL_PROVIDER_GLX
+#include "GLXLibrary.h"
+#endif
+#endif
+
+#ifdef MOZ_WIDGET_GONK
+#include <cutils/properties.h>
+#include "mozilla/layers/GrallocTextureClient.h"
+#endif
 
 #ifdef MOZ_ANDROID_OMTC
 #  include "gfxReusableImageSurfaceWrapper.h"
 #  include "gfxImageSurface.h"
 #else
 #  include "gfxReusableSharedImageSurfaceWrapper.h"
 #  include "gfxSharedImageSurface.h"
 #endif
@@ -188,16 +207,130 @@ TextureClient::InitIPDLActor(Compositabl
 }
 
 PTextureChild*
 TextureClient::GetIPDLActor()
 {
   return mActor;
 }
 
+#ifdef MOZ_WIDGET_GONK
+static bool
+DisableGralloc(SurfaceFormat aFormat)
+{
+  if (aFormat == gfx::SurfaceFormat::A8) {
+    return true;
+  }
+#if ANDROID_VERSION <= 15
+  static bool checkedDevice = false;
+  static bool disableGralloc = false;
+
+  if (!checkedDevice) {
+    char propValue[PROPERTY_VALUE_MAX];
+    property_get("ro.product.device", propValue, "None");
+
+    if (strcmp("crespo",propValue) == 0) {
+      NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
+      disableGralloc = true;
+    }
+
+    checkedDevice = true;
+  }
+
+  if (disableGralloc) {
+    return true;
+  }
+  return false;
+#else
+  return false;
+#endif
+}
+#endif
+
+// static
+TemporaryRef<TextureClient>
+TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
+                                             SurfaceFormat aFormat,
+                                             TextureFlags aTextureFlags)
+{
+  RefPtr<TextureClient> result;
+
+#ifdef XP_WIN
+  LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
+  if (parentBackend == LayersBackend::LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
+      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
+    result = new TextureClientD3D11(aFormat, aTextureFlags);
+  }
+  if (parentBackend == LayersBackend::LAYERS_D3D9 &&
+      aAllocator->IsSameProcess() &&
+      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
+    if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
+      result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
+    } else {
+      result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
+    }
+  }
+#endif
+
+#ifdef MOZ_X11
+  LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
+  gfxSurfaceType type =
+    gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
+
+  if (parentBackend == LayersBackend::LAYERS_BASIC &&
+      type == gfxSurfaceType::Xlib &&
+      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
+  {
+    result = new TextureClientX11(aFormat, aTextureFlags);
+  }
+#ifdef GL_PROVIDER_GLX
+  if (parentBackend == LayersBackend::LAYERS_OPENGL &&
+      type == gfxSurfaceType::Xlib &&
+      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
+      aFormat != SurfaceFormat::A8 &&
+      gl::sGLXLibrary.UseTextureFromPixmap())
+  {
+    result = new TextureClientX11(aFormat, aTextureFlags);
+  }
+#endif
+#endif
+
+#ifdef MOZ_WIDGET_GONK
+  if (!DisableGralloc(aFormat)) {
+    result = new GrallocTextureClientOGL(aAllocator, aFormat, aTextureFlags);
+  }
+#endif
+
+  // Can't do any better than a buffer texture client.
+  if (!result) {
+    result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags);
+  }
+
+  MOZ_ASSERT(!result || result->AsTextureClientDrawTarget(),
+             "Not a TextureClientDrawTarget?");
+  return result;
+}
+
+// static
+TemporaryRef<BufferTextureClient>
+TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
+                                         SurfaceFormat aFormat,
+                                         TextureFlags aTextureFlags)
+{
+  if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
+    RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
+                                                                 aTextureFlags);
+    return result.forget();
+  }
+  RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat,
+                                                              aTextureFlags);
+  return result.forget();
+}
+
+
 class ShmemTextureClientData : public TextureClientData
 {
 public:
   ShmemTextureClientData(ipc::Shmem& aShmem)
   : mShmem(aShmem)
   {
     MOZ_COUNT_CTOR(ShmemTextureClientData);
   }
@@ -291,16 +424,40 @@ void TextureClient::ForceRemove()
       if (mActor->IPCOpen()) {
         mActor->SendRemoveTexture();
       }
     }
   }
   MarkInvalid();
 }
 
+bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
+                                        const gfx::IntRect* aRect,
+                                        const gfx::IntPoint* aPoint)
+{
+  MOZ_ASSERT(IsLocked());
+  MOZ_ASSERT(aTarget->IsLocked());
+
+  if (!aTarget->AsTextureClientDrawTarget() || !AsTextureClientDrawTarget()) {
+    return false;
+  }
+
+  RefPtr<DrawTarget> destinationTarget = aTarget->AsTextureClientDrawTarget()->GetAsDrawTarget();
+  RefPtr<DrawTarget> sourceTarget = AsTextureClientDrawTarget()->GetAsDrawTarget();
+  RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
+  destinationTarget->CopySurface(source,
+                                 aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
+                                 aPoint ? *aPoint : gfx::IntPoint(0, 0));
+  destinationTarget = nullptr;
+  source = nullptr;
+  sourceTarget = nullptr;
+
+  return true;
+}
+
 void
 TextureClient::Finalize()
 {
   // Always make a temporary strong reference to the actor before we use it,
   // in case TextureChild::ActorDestroy might null mActor concurrently.
   RefPtr<TextureChild> actor = mActor;
 
   if (actor) {
@@ -334,22 +491,16 @@ ShmemTextureClient::ToSurfaceDescriptor(
     return false;
   }
 
   aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
 
   return true;
 }
 
-ISurfaceAllocator*
-ShmemTextureClient::GetAllocator() const
-{
-  return mCompositable->GetForwarder();
-}
-
 bool
 ShmemTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(mValid);
   ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType();
   mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
   return mAllocated;
 }
@@ -366,32 +517,32 @@ ShmemTextureClient::GetBuffer() const
 
 size_t
 ShmemTextureClient::GetBufferSize() const
 {
   MOZ_ASSERT(IsValid());
   return mShmem.Size<uint8_t>();
 }
 
-ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable,
+ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
                                        gfx::SurfaceFormat aFormat,
                                        TextureFlags aFlags)
-  : BufferTextureClient(aCompositable, aFormat, aFlags)
+  : BufferTextureClient(aAllocator, aFormat, aFlags)
   , mAllocated(false)
 {
   MOZ_COUNT_CTOR(ShmemTextureClient);
 }
 
 ShmemTextureClient::~ShmemTextureClient()
 {
   MOZ_COUNT_DTOR(ShmemTextureClient);
   if (ShouldDeallocateInDestructor()) {
     // if the buffer has never been shared we must deallocate it or ir would
     // leak.
-    mCompositable->GetForwarder()->DeallocShmem(mShmem);
+    GetAllocator()->DeallocShmem(mShmem);
   }
 }
 
 bool
 MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
@@ -412,20 +563,20 @@ MemoryTextureClient::Allocate(uint32_t a
     NS_WARNING("Failed to allocate buffer");
     return false;
   }
   GfxMemoryImageReporter::DidAlloc(mBuffer);
   mBufSize = aSize;
   return true;
 }
 
-MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable,
+MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
                                          gfx::SurfaceFormat aFormat,
                                          TextureFlags aFlags)
-  : BufferTextureClient(aCompositable, aFormat, aFlags)
+  : BufferTextureClient(aAllocator, aFormat, aFlags)
   , mBuffer(nullptr)
   , mBufSize(0)
 {
   MOZ_COUNT_CTOR(MemoryTextureClient);
 }
 
 MemoryTextureClient::~MemoryTextureClient()
 {
@@ -433,29 +584,35 @@ MemoryTextureClient::~MemoryTextureClien
   if (mBuffer && ShouldDeallocateInDestructor()) {
     // if the buffer has never been shared we must deallocate it or it would
     // leak.
     GfxMemoryImageReporter::WillFree(mBuffer);
     delete mBuffer;
   }
 }
 
-BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
+BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
                                          gfx::SurfaceFormat aFormat,
                                          TextureFlags aFlags)
   : TextureClient(aFlags)
-  , mCompositable(aCompositable)
+  , mAllocator(aAllocator)
   , mFormat(aFormat)
   , mUsingFallbackDrawTarget(false)
   , mLocked(false)
 {}
 
 BufferTextureClient::~BufferTextureClient()
 {}
 
+ISurfaceAllocator*
+BufferTextureClient::GetAllocator() const
+{
+  return mAllocator;
+}
+
 bool
 BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
 {
   MOZ_ASSERT(aSurface);
   MOZ_ASSERT(!IsImmutable());
   MOZ_ASSERT(IsValid());
 
   ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -39,16 +39,17 @@ class ContentClient;
 class CompositableForwarder;
 class ISurfaceAllocator;
 class CompositableClient;
 class PlanarYCbCrImage;
 class PlanarYCbCrData;
 class Image;
 class PTextureChild;
 class TextureChild;
+class BufferTextureClient;
 
 /**
  * TextureClient is the abstraction that allows us to share data between the
  * content and the compositor side.
  * TextureClient can also provide with some more "producer" facing APIs
  * such as TextureClientSurface and TextureClientYCbCr, that can be queried
  * using AsTextureCLientSurface(), etc.
  */
@@ -193,16 +194,26 @@ public:
  */
 class TextureClient
   : public AtomicRefCountedWithFinalize<TextureClient>
 {
 public:
   TextureClient(TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
   virtual ~TextureClient();
 
+  static TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
+                            gfx::SurfaceFormat aFormat,
+                            TextureFlags aTextureFlags);
+
+  static TemporaryRef<TextureClient>
+  CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
+                                gfx::SurfaceFormat aFormat,
+                                TextureFlags aTextureFlags);
+
   virtual TextureClientSurface* AsTextureClientSurface() { return nullptr; }
   virtual TextureClientDrawTarget* AsTextureClientDrawTarget() { return nullptr; }
   virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
 
   /**
    * Locks the shared data, allowing the caller to get access to it.
    *
    * Please always lock/unlock when accessing the shared data.
@@ -210,23 +221,39 @@ public:
    */
   virtual bool Lock(OpenMode aMode) { return IsValid(); }
 
   virtual void Unlock() {}
 
   virtual bool IsLocked() const = 0;
 
   /**
+   * Copies a rectangle from this texture client to a position in aTarget.
+   * It is assumed that the necessary locks are in place; so this should at
+   * least have a read lock and aTarget should at least have a write lock.
+   */
+  virtual bool CopyToTextureClient(TextureClient* aTarget,
+                                   const gfx::IntRect* aRect,
+                                   const gfx::IntPoint* aPoint);
+
+  /**
    * Returns true if this texture has a lock/unlock mechanism.
    * Textures that do not implement locking should be immutable or should
    * use immediate uploads (see TextureFlags in CompositorTypes.h)
    */
   virtual bool ImplementsLocking() const { return false; }
 
   /**
+   * Indicates whether the TextureClient implementation is backed by an
+   * in-memory buffer. The consequence of this is that locking the
+   * TextureClient does not contend with locking the texture on the host side.
+   */
+  virtual bool HasInternalBuffer() const = 0;
+
+  /**
    * Allocate and deallocate a TextureChild actor.
    *
    * TextureChild is an implementation detail of TextureHost that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the maging IPDL protocols only (so that they can
    * implement AllocPextureChild and DeallocPTextureChild).
    */
   static PTextureChild* CreateIPDLActor();
@@ -350,17 +377,17 @@ protected:
  * (see ShmemTextureClient and MemoryTextureClient)
  */
 class BufferTextureClient : public TextureClient
                           , public TextureClientSurface
                           , public TextureClientYCbCr
                           , public TextureClientDrawTarget
 {
 public:
-  BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+  BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
                       TextureFlags aFlags);
 
   virtual ~BufferTextureClient();
 
   virtual bool IsAllocated() const = 0;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
@@ -406,83 +433,88 @@ public:
   // XXX - Bug 908196 - Make Allocate(uint32_t) and GetBufferSize() protected.
   // these two methods should only be called by methods of BufferTextureClient
   // that are overridden in GrallocTextureClient (which does not implement the
   // two methods below)
   virtual bool Allocate(uint32_t aSize) = 0;
 
   virtual size_t GetBufferSize() const = 0;
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
+  ISurfaceAllocator* GetAllocator() const;
+
 protected:
   RefPtr<gfx::DrawTarget> mDrawTarget;
-  CompositableClient* mCompositable;
+  RefPtr<ISurfaceAllocator> mAllocator;
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   OpenMode mOpenMode;
   bool mUsingFallbackDrawTarget;
   bool mLocked;
 };
 
 /**
  * TextureClient that wraps shared memory.
  * the corresponding texture on the host side is ShmemTextureHost.
  */
 class ShmemTextureClient : public BufferTextureClient
 {
 public:
-  ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+  ShmemTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
                      TextureFlags aFlags);
 
   ~ShmemTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE;
 
   virtual size_t GetBufferSize() const MOZ_OVERRIDE;
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return mAllocated; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
-  ISurfaceAllocator* GetAllocator() const;
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
 
   mozilla::ipc::Shmem& GetShmem() { return mShmem; }
 
 protected:
   mozilla::ipc::Shmem mShmem;
-  RefPtr<ISurfaceAllocator> mAllocator;
   bool mAllocated;
 };
 
 /**
  * TextureClient that wraps raw memory.
  * The corresponding texture on the host side is MemoryTextureHost.
  * Can obviously not be used in a cross process setup.
  */
 class MemoryTextureClient : public BufferTextureClient
 {
 public:
-  MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+  MemoryTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
                       TextureFlags aFlags);
 
   ~MemoryTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE { return mBuffer; }
 
   virtual size_t GetBufferSize() const MOZ_OVERRIDE { return mBufSize; }
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return mBuffer != nullptr; }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
 protected:
   uint8_t* mBuffer;
   size_t mBufSize;
 };
 
 struct TextureClientAutoUnlock
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/TextureClientPool.cpp
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* 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 "TextureClientPool.h"
+#include "CompositableClient.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
+
+#include "gfxPrefs.h"
+
+#include "nsComponentManagerUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+static void
+ShrinkCallback(nsITimer *aTimer, void *aClosure)
+{
+  static_cast<TextureClientPool*>(aClosure)->ShrinkToMinimumSize();
+}
+
+TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
+                                     ISurfaceAllocator *aAllocator)
+  : mFormat(aFormat)
+  , mSize(aSize)
+  , mOutstandingClients(0)
+  , mSurfaceAllocator(aAllocator)
+{
+  mTimer = do_CreateInstance("@mozilla.org/timer;1");
+}
+
+TemporaryRef<TextureClient>
+TextureClientPool::GetTextureClient()
+{
+  mOutstandingClients++;
+
+  // Try to fetch a client from the pool
+  RefPtr<TextureClient> textureClient;
+  if (mTextureClients.size()) {
+    textureClient = mTextureClients.top();
+    mTextureClients.pop();
+    return textureClient;
+  }
+
+  // We're increasing the number of outstanding TextureClients without reusing a
+  // client, we may need to free a deferred-return TextureClient.
+  ShrinkToMaximumSize();
+
+  // No unused clients in the pool, create one
+  if (gfxPrefs::ForceShmemTiles()) {
+    textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, mFormat, TEXTURE_IMMEDIATE_UPLOAD);
+  } else {
+    textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, mFormat, TEXTURE_IMMEDIATE_UPLOAD);
+  }
+  textureClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize, ALLOC_DEFAULT);
+
+  return textureClient;
+}
+
+void
+TextureClientPool::ReturnTextureClient(TextureClient *aClient)
+{
+  if (!aClient) {
+    return;
+  }
+  MOZ_ASSERT(mOutstandingClients);
+  mOutstandingClients--;
+
+  // Add the client to the pool and shrink down if we're beyond our maximum size
+  mTextureClients.push(aClient);
+  ShrinkToMaximumSize();
+
+  // Kick off the pool shrinking timer if there are still more unused texture
+  // clients than our desired minimum cache size.
+  if (mTextureClients.size() > sMinCacheSize) {
+    mTimer->InitWithFuncCallback(ShrinkCallback, this, sShrinkTimeout,
+                                 nsITimer::TYPE_ONE_SHOT);
+  }
+}
+
+void
+TextureClientPool::ReturnTextureClientDeferred(TextureClient *aClient)
+{
+  mTextureClientsDeferred.push(aClient);
+  ShrinkToMaximumSize();
+}
+
+void
+TextureClientPool::ShrinkToMaximumSize()
+{
+  uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients;
+
+  // We're over our desired maximum size, immediately shrink down to the
+  // maximum, or zero if we have too many outstanding texture clients.
+  // We cull from the deferred TextureClients first, as we can't reuse those
+  // until they get returned.
+  while (totalClientsOutstanding > sMaxTextureClients) {
+    if (mTextureClientsDeferred.size()) {
+      mOutstandingClients--;
+      mTextureClientsDeferred.pop();
+    } else {
+      if (!mTextureClients.size()) {
+        // Getting here means we're over our desired number of TextureClients
+        // with none in the pool. This can happen for pathological cases, or
+        // it could mean that sMaxTextureClients needs adjusting for whatever
+        // device we're running on.
+        break;
+      }
+      mTextureClients.pop();
+    }
+    totalClientsOutstanding--;
+  }
+}
+
+void
+TextureClientPool::ShrinkToMinimumSize()
+{
+  while (mTextureClients.size() > sMinCacheSize) {
+    mTextureClients.pop();
+  }
+}
+
+void
+TextureClientPool::ReturnDeferredClients()
+{
+  while (!mTextureClientsDeferred.empty()) {
+    ReturnTextureClient(mTextureClientsDeferred.top());
+    mTextureClientsDeferred.pop();
+  }
+}
+
+void
+TextureClientPool::Clear()
+{
+  while (!mTextureClients.empty()) {
+    mTextureClients.pop();
+  }
+  while (!mTextureClientsDeferred.empty()) {
+    mOutstandingClients--;
+    mTextureClientsDeferred.pop();
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/TextureClientPool.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* 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/. */
+
+#ifndef MOZILLA_GFX_TEXTURECLIENTPOOL_H
+#define MOZILLA_GFX_TEXTURECLIENTPOOL_H
+
+#include "mozilla/gfx/Types.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/RefPtr.h"
+#include "TextureClient.h"
+#include "nsITimer.h"
+#include <stack>
+
+namespace mozilla {
+namespace layers {
+
+class ISurfaceAllocator;
+
+class TextureClientPool : public RefCounted<TextureClientPool>
+{
+public:
+  TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
+                    ISurfaceAllocator *aAllocator);
+
+  /**
+   * Gets an allocated TextureClient of size and format that are determined
+   * by the initialisation parameters given to the pool. This will either be
+   * a cached client that was returned to the pool, or a newly allocated
+   * client if one isn't available.
+   *
+   * All clients retrieved by this method should be returned using the return
+   * functions, or reported lost so that the pool can manage its size correctly.
+   */
+  TemporaryRef<TextureClient> GetTextureClient();
+
+  /**
+   * Return a TextureClient that is no longer being used and is ready for
+   * immediate re-use or destruction.
+   */
+  void ReturnTextureClient(TextureClient *aClient);
+
+  /**
+   * Return a TextureClient that is not yet ready to be reused, but will be
+   * imminently.
+   */
+  void ReturnTextureClientDeferred(TextureClient *aClient);
+
+  /**
+   * Attempt to shrink the pool so that there are no more than
+   * sMaxTextureClients clients outstanding.
+   */
+  void ShrinkToMaximumSize();
+
+  /**
+   * Attempt to shrink the pool so that there are no more than sMinCacheSize
+   * unused clients.
+   */
+  void ShrinkToMinimumSize();
+
+  /**
+   * Return any clients to the pool that were previously returned in
+   * ReturnTextureClientDeferred.
+   */
+  void ReturnDeferredClients();
+
+  /**
+   * Report that a client retrieved via GetTextureClient() has become
+   * unusable, so that it will no longer be tracked.
+   */
+  void ReportClientLost() { mOutstandingClients--; }
+
+  /**
+   * Calling this will cause the pool to attempt to relinquish any unused
+   * clients.
+   */
+  void Clear();
+
+private:
+  // The time in milliseconds before the pool will be shrunk to the minimum
+  // size after returning a client.
+  static const uint32_t sShrinkTimeout = 1000;
+
+  // The minimum size of the pool (the number of tiles that will be kept after
+  // shrinking).
+  static const uint32_t sMinCacheSize = 0;
+
+  // The maximum number of texture clients managed by this pool that we want
+  // to remain active.
+  static const uint32_t sMaxTextureClients = 50;
+
+  gfx::SurfaceFormat mFormat;
+  gfx::IntSize mSize;
+
+  uint32_t mOutstandingClients;
+
+  std::stack<RefPtr<TextureClient> > mTextureClients;
+  std::stack<RefPtr<TextureClient> > mTextureClientsDeferred;
+  nsRefPtr<nsITimer> mTimer;
+  RefPtr<ISurfaceAllocator> mSurfaceAllocator;
+};
+
+}
+}
+#endif /* MOZILLA_GFX_TEXTURECLIENTPOOL_H */
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -13,35 +13,41 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/MathAlgorithms.h"     // for Abs
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
+#include "TextureClientPool.h"
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxReusableSharedImageSurfaceWrapper.h"
 #include "nsMathUtils.h"               // for NS_roundf
 #include "gfx2DGlue.h"
 
+// This is the minimum area that we deem reasonable to copy from the front buffer to the
+// back buffer on tile updates. If the valid region is smaller than this, we just
+// redraw it and save on the copy (and requisite surface-locking involved).
+#define MINIMUM_TILE_COPY_AREA ((TILEDLAYERBUFFER_TILE_SIZE * TILEDLAYERBUFFER_TILE_SIZE)/16)
+
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
 #include "cairo.h"
 #include <sstream>
 using mozilla::layers::Layer;
-static void DrawDebugOverlay(gfxASurface* imgSurf, int x, int y)
+static void DrawDebugOverlay(mozilla::gfx::DrawTarget* dt, int x, int y, int width, int height)
 {
-  gfxContext c(imgSurf);
+  gfxContext c(dt);
 
   // Draw border
   c.NewPath();
   c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
-  c.Rectangle(gfxRect(gfxPoint(0,0),imgSurf->GetSize()));
+  c.Rectangle(gfxRect(0, 0, width, height));
   c.Stroke();
 
   // Build tile description
   std::stringstream ss;
   ss << x << ", " << y;
 
   // Draw text using cairo toy text API
   cairo_t* cr = c.GetCairo();
@@ -74,38 +80,47 @@ namespace mozilla {
 using namespace gfx;
 
 namespace layers {
 
 
 TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
                                        ClientLayerManager* aManager)
   : CompositableClient(aManager->AsShadowForwarder())
-  , mTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
-  , mLowPrecisionTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
 {
   MOZ_COUNT_CTOR(TiledContentClient);
 
-  // The preference is int in "thousands", so adjust:
+  mTiledBuffer = ClientTiledLayerBuffer(aThebesLayer, this, aManager,
+                                        &mSharedFrameMetricsHelper);
+  mLowPrecisionTiledBuffer = ClientTiledLayerBuffer(aThebesLayer, this, aManager,
+                                                    &mSharedFrameMetricsHelper);
+
   mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution()/1000.f);
 }
 
 void
-TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
+TiledContentClient::ClearCachedResources()
 {
-  BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
+  mTiledBuffer.DiscardBackBuffers();
+  mLowPrecisionTiledBuffer.DiscardBackBuffers();
+}
+
+void
+TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
+{
+  ClientTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     ? &mLowPrecisionTiledBuffer
     : &mTiledBuffer;
 
-  // Take an extra ReadLock on behalf of the TiledContentHost. This extra
-  // reference will be adopted when the descriptor is opened by
-  // BasicTiledLayerTile::OpenDescriptor.
+  // Take a ReadLock on behalf of the TiledContentHost. This
+  // reference will be adopted when the descriptor is opened in
+  // TiledLayerBufferComposite.
   buffer->ReadLock();
 
-  mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
+  mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
   buffer->ClearPaintedRegion();
 }
 
 SharedFrameMetricsHelper::SharedFrameMetricsHelper()
   : mLastProgressiveUpdateWasLowPrecision(false)
   , mProgressiveUpdateWasInDanger(false)
 {
   MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
@@ -224,91 +239,350 @@ SharedFrameMetricsHelper::FindFallbackCo
 
 bool
 SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetrics,
                                                  const FrameMetrics& aCompositorMetrics)
 {
   return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.mScrollOffset);
 }
 
-BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
+ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
+                                             CompositableClient* aCompositableClient,
                                              ClientLayerManager* aManager,
                                              SharedFrameMetricsHelper* aHelper)
   : mThebesLayer(aThebesLayer)
+  , mCompositableClient(aCompositableClient)
   , mManager(aManager)
   , mLastPaintOpaque(false)
   , mSharedFrameMetricsHelper(aHelper)
 {
 }
 
 bool
-BasicTiledLayerBuffer::HasFormatChanged() const
+ClientTiledLayerBuffer::HasFormatChanged() const
 {
   return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque;
 }
 
 
 gfxContentType
-BasicTiledLayerBuffer::GetContentType() const
+ClientTiledLayerBuffer::GetContentType() const
 {
   if (mThebesLayer->CanUseOpaqueSurface()) {
     return gfxContentType::COLOR;
   } else {
     return gfxContentType::COLOR_ALPHA;
   }
 }
 
+gfxMemorySharedReadLock::gfxMemorySharedReadLock()
+  : mReadCount(1)
+{
+  MOZ_COUNT_CTOR(gfxMemorySharedReadLock);
+}
 
-TileDescriptor
-BasicTiledLayerTile::GetTileDescriptor()
+gfxMemorySharedReadLock::~gfxMemorySharedReadLock()
+{
+  MOZ_COUNT_DTOR(gfxMemorySharedReadLock);
+}
+
+int32_t
+gfxMemorySharedReadLock::ReadLock()
+{
+  NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
+
+  return PR_ATOMIC_INCREMENT(&mReadCount);
+}
+
+int32_t
+gfxMemorySharedReadLock::ReadUnlock()
+{
+  int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
+  NS_ASSERTION(readCount >= 0, "ReadUnlock called without ReadLock.");
+
+  return readCount;
+}
+
+int32_t
+gfxMemorySharedReadLock::GetReadCount()
+{
+  NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
+  return mReadCount;
+}
+
+gfxShmSharedReadLock::gfxShmSharedReadLock(ISurfaceAllocator* aAllocator)
+  : mAllocator(aAllocator)
+{
+  MOZ_COUNT_CTOR(gfxShmSharedReadLock);
+
+  if (mAllocator) {
+#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
+    if (mAllocator->AllocUnsafeShmem(MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)),
+                                     mozilla::ipc::SharedMemory::TYPE_BASIC, &mShmem)) {
+      ShmReadLockInfo* info = GetShmReadLockInfoPtr();
+      info->readCount = 1;
+    }
+  }
+}
+
+gfxShmSharedReadLock::~gfxShmSharedReadLock()
 {
-  gfxReusableSurfaceWrapper* surface = GetSurface();
-  switch (surface->GetType()) {
-  case gfxReusableSurfaceWrapper::TYPE_IMAGE :
-    return BasicTileDescriptor(uintptr_t(surface));
+  MOZ_COUNT_DTOR(gfxShmSharedReadLock);
+}
+
+int32_t
+gfxShmSharedReadLock::ReadLock() {
+  NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
+
+  ShmReadLockInfo* info = GetShmReadLockInfoPtr();
+  return PR_ATOMIC_INCREMENT(&info->readCount);
+}
+
+int32_t
+gfxShmSharedReadLock::ReadUnlock() {
+  ShmReadLockInfo* info = GetShmReadLockInfoPtr();
+  int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
+  NS_ASSERTION(readCount >= 0, "ReadUnlock called without a ReadLock.");
+  if (readCount <= 0) {
+    mAllocator->DeallocShmem(mShmem);
+  }
+  return readCount;
+}
+
+int32_t
+gfxShmSharedReadLock::GetReadCount() {
+  NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
+
+  ShmReadLockInfo* info = GetShmReadLockInfoPtr();
+  return info->readCount;
+}
 
-  case gfxReusableSurfaceWrapper::TYPE_SHARED_IMAGE :
-    return BasicShmTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(surface)->GetShmem());
+// Placeholder
+TileClient::TileClient()
+  : mBackBuffer(nullptr)
+  , mFrontBuffer(nullptr)
+  , mBackLock(nullptr)
+  , mFrontLock(nullptr)
+{
+}
 
-  default :
-    NS_NOTREACHED("Unhandled gfxReusableSurfaceWrapper type");
-    return PlaceholderTileDescriptor();
-  }
+TileClient::TileClient(const TileClient& o)
+{
+  mBackBuffer = o.mBackBuffer;
+  mFrontBuffer = o.mFrontBuffer;
+  mBackLock = o.mBackLock;
+  mFrontLock = o.mFrontLock;
+#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
+  mLastUpdate = o.mLastUpdate;
+#endif
+  mManager = o.mManager;
+  mInvalidFront = o.mInvalidFront;
+  mInvalidBack = o.mInvalidBack;
+}
+
+TileClient&
+TileClient::operator=(const TileClient& o)
+{
+  if (this == &o) return *this;
+  mBackBuffer = o.mBackBuffer;
+  mFrontBuffer = o.mFrontBuffer;
+  mBackLock = o.mBackLock;
+  mFrontLock = o.mFrontLock;
+#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
+  mLastUpdate = o.mLastUpdate;
+#endif
+  mManager = o.mManager;
+  mInvalidFront = o.mInvalidFront;
+  mInvalidBack = o.mInvalidBack;
+  return *this;
 }
 
 
-/* static */ BasicTiledLayerTile
-BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc)
+void
+TileClient::Flip()
+{
+  RefPtr<TextureClient> frontBuffer = mFrontBuffer;
+  mFrontBuffer = mBackBuffer;
+  mBackBuffer = frontBuffer;
+  RefPtr<gfxSharedReadLock> frontLock = mFrontLock;
+  mFrontLock = mBackLock;
+  mBackLock = frontLock;
+  nsIntRegion invalidFront = mInvalidFront;
+  mInvalidFront = mInvalidBack;
+  mInvalidBack = invalidFront;
+}
+
+void
+TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
+                                        bool aCanRerasterizeValidRegion)
 {
-  switch (aDesc.type()) {
-  case TileDescriptor::TBasicShmTileDescriptor : {
-    nsRefPtr<gfxReusableSurfaceWrapper> surface =
-      gfxReusableSharedImageSurfaceWrapper::Open(
-        aAllocator, aDesc.get_BasicShmTileDescriptor().reusableSurface());
-    return BasicTiledLayerTile(
-      new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+  if (mBackBuffer && mFrontBuffer) {
+    const nsIntRect tileRect = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
+
+    if (aDirtyRegion.Contains(tileRect)) {
+      // The dirty region means that we no longer need the front buffer, so
+      // discard it.
+      DiscardFrontBuffer();
+    } else {
+      // Region that needs copying.
+      nsIntRegion regionToCopy = mInvalidBack;
+
+      regionToCopy.Sub(regionToCopy, aDirtyRegion);
+
+      if (regionToCopy.IsEmpty() ||
+          (aCanRerasterizeValidRegion &&
+           regionToCopy.Area() < MINIMUM_TILE_COPY_AREA)) {
+        // Just redraw it all.
+        return;
+      }
+
+      if (!mFrontBuffer->Lock(OPEN_READ)) {
+        NS_WARNING("Failed to lock the tile's front buffer");
+        return;
+      }
+      TextureClientAutoUnlock autoFront(mFrontBuffer);
+
+      if (!mBackBuffer->Lock(OPEN_WRITE)) {
+        NS_WARNING("Failed to lock the tile's back buffer");
+        return;
+      }
+      TextureClientAutoUnlock autoBack(mBackBuffer);
+
+      // Copy the bounding rect of regionToCopy. As tiles are quite small, it
+      // is unlikely that we'd save much by copying each individual rect of the
+      // region, but we can reevaluate this if it becomes an issue.
+      const nsIntRect rectToCopy = regionToCopy.GetBounds();
+      gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.width, rectToCopy.height);
+      gfx::IntPoint gfxRectToCopyTopLeft = gfxRectToCopy.TopLeft();
+      mFrontBuffer->CopyToTextureClient(mBackBuffer, &gfxRectToCopy, &gfxRectToCopyTopLeft);
+
+      mInvalidBack.SetEmpty();
+    }
+  }
+}
+
+void
+TileClient::DiscardFrontBuffer()
+{
+  if (mFrontBuffer) {
+    MOZ_ASSERT(mFrontLock);
+    mManager->GetTexturePool(mFrontBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClientDeferred(mFrontBuffer);
+    mFrontLock->ReadUnlock();
+    mFrontBuffer = nullptr;
+    mFrontLock = nullptr;
+  }
+}
+
+void
+TileClient::DiscardBackBuffer()
+{
+  if (mBackBuffer) {
+    MOZ_ASSERT(mBackLock);
+    mManager->GetTexturePool(mBackBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClient(mBackBuffer);
+    mBackLock->ReadUnlock();
+    mBackBuffer = nullptr;
+    mBackLock = nullptr;
+  }
+}
+
+TextureClient*
+TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion, TextureClientPool *aPool, bool *aCreatedTextureClient, bool aCanRerasterizeValidRegion)
+{
+  // Try to re-use the front-buffer if possible
+  if (mFrontBuffer &&
+      mFrontBuffer->HasInternalBuffer() &&
+      mFrontLock->GetReadCount() == 1) {
+    // If we had a backbuffer we no longer care about it since we'll
+    // re-use the front buffer.
+    DiscardBackBuffer();
+    Flip();
+    return mBackBuffer;
   }
 
-  case TileDescriptor::TBasicTileDescriptor : {
-    nsRefPtr<gfxReusableSurfaceWrapper> surface =
-      reinterpret_cast<gfxReusableSurfaceWrapper*>(
-        aDesc.get_BasicTileDescriptor().reusableSurface());
-    surface->ReadUnlock();
-    return BasicTiledLayerTile(
-      new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+  if (!mBackBuffer ||
+      mBackLock->GetReadCount() > 1) {
+    if (mBackBuffer) {
+      // Our current back-buffer is still locked by the compositor. This can occur
+      // when the client is producing faster than the compositor can consume. In
+      // this case we just want to drop it and not return it to the pool.
+      aPool->ReportClientLost();
+    }
+    mBackBuffer = aPool->GetTextureClient();
+    // Create a lock for our newly created back-buffer.
+    if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
+      // If our compositor is in the same process, we can save some cycles by not
+      // using shared memory.
+      mBackLock = new gfxMemorySharedReadLock();
+    } else {
+      mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
+    }
+    *aCreatedTextureClient = true;
+    mInvalidBack = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
   }
 
-  default :
-    NS_NOTREACHED("Unknown tile descriptor type!");
-    return nullptr;
+  ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion);
+
+  return mBackBuffer;
+}
+
+TileDescriptor
+TileClient::GetTileDescriptor()
+{
+  if (IsPlaceholderTile()) {
+    return PlaceholderTileDescriptor();
+  }
+  MOZ_ASSERT(mFrontLock);
+  if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) {
+    // AddRef here and Release when receiving on the host side to make sure the
+    // reference count doesn't go to zero before the host receives the message.
+    // see TiledLayerBufferComposite::TiledLayerBufferComposite
+    mFrontLock->AddRef();
+  }
+  return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
+            mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY
+              ? TileLock(uintptr_t(mFrontLock.get()))
+              : TileLock(static_cast<gfxShmSharedReadLock*>(mFrontLock.get())->GetShmem()));
+}
+
+void
+ClientTiledLayerBuffer::ReadUnlock() {
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+    mRetainedTiles[i].ReadUnlock();
+  }
+}
+
+void
+ClientTiledLayerBuffer::ReadLock() {
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+    mRetainedTiles[i].ReadLock();
+  }
+}
+
+void
+ClientTiledLayerBuffer::Release()
+{
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+    mRetainedTiles[i].Release();
+  }
+}
+
+void
+ClientTiledLayerBuffer::DiscardBackBuffers()
+{
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+    mRetainedTiles[i].DiscardBackBuffer();
   }
 }
 
 SurfaceDescriptorTiles
-BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
+ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
 {
   InfallibleTArray<TileDescriptor> tiles;
 
   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
     TileDescriptor tileDesc;
     if (mRetainedTiles.SafeElementAt(i, GetPlaceholderTile()) == GetPlaceholderTile()) {
       tileDesc = PlaceholderTileDescriptor();
     } else {
@@ -316,33 +590,18 @@ BasicTiledLayerBuffer::GetSurfaceDescrip
     }
     tiles.AppendElement(tileDesc);
   }
   return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
                                 tiles, mRetainedWidth, mRetainedHeight,
                                 mResolution);
 }
 
-/* static */ BasicTiledLayerBuffer
-BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator,
-                                      const SurfaceDescriptorTiles& aDescriptor,
-                                      SharedFrameMetricsHelper* aHelper)
-{
-  return BasicTiledLayerBuffer(aAllocator,
-                               aDescriptor.validRegion(),
-                               aDescriptor.paintedRegion(),
-                               aDescriptor.tiles(),
-                               aDescriptor.retainedWidth(),
-                               aDescriptor.retainedHeight(),
-                               aDescriptor.resolution(),
-                               aHelper);
-}
-
 void
-BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
+ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
                                    const nsIntRegion& aPaintRegion,
                                    LayerManager::DrawThebesLayerCallback aCallback,
                                    void* aCallbackData)
 {
   mCallback = aCallback;
   mCallbackData = aCallbackData;
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
@@ -366,50 +625,41 @@ BasicTiledLayerBuffer::PaintThebes(const
   }
   */
 
   if (useSinglePaintBuffer) {
     nsRefPtr<gfxContext> ctxt;
 
     const nsIntRect bounds = aPaintRegion.GetBounds();
     {
-      PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
+      PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
       gfxImageFormat format =
         gfxPlatform::GetPlatform()->OptimalFormatForContent(
           GetContentType());
 
-      if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
-        mSinglePaintDrawTarget =
-          gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
-            gfx::IntSize(ceilf(bounds.width * mResolution),
-                         ceilf(bounds.height * mResolution)),
-            gfx::ImageFormatToSurfaceFormat(format));
+      mSinglePaintDrawTarget =
+        gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
+          gfx::IntSize(ceilf(bounds.width * mResolution),
+                       ceilf(bounds.height * mResolution)),
+          gfx::ImageFormatToSurfaceFormat(format));
 
-        ctxt = new gfxContext(mSinglePaintDrawTarget);
-      } else {
-        mSinglePaintBuffer = new gfxImageSurface(
-          gfxIntSize(ceilf(bounds.width * mResolution),
-                     ceilf(bounds.height * mResolution)),
-          format,
-          !mThebesLayer->CanUseOpaqueSurface());
-        ctxt = new gfxContext(mSinglePaintBuffer);
-      }
+      ctxt = new gfxContext(mSinglePaintDrawTarget);
 
       mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
     }
     ctxt->NewPath();
     ctxt->Scale(mResolution, mResolution);
     ctxt->Translate(gfxPoint(-bounds.x, -bounds.y));
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     if (PR_IntervalNow() - start > 3) {
       printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
     }
     start = PR_IntervalNow();
 #endif
-    PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw");
+    PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw");
 
     mCallback(mThebesLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData);
   }
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 30) {
     const nsIntRect bounds = aPaintRegion.GetBounds();
     printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
@@ -419,138 +669,179 @@ BasicTiledLayerBuffer::PaintThebes(const
       for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
         printf_stderr(" rect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
       }
     }
   }
   start = PR_IntervalNow();
 #endif
 
-  PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesUpdate");
+  PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesUpdate");
   Update(aNewValidRegion, aPaintRegion);
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 10) {
     const nsIntRect bounds = aPaintRegion.GetBounds();
     printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
   }
 #endif
 
   mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface();
   mCallback = nullptr;
   mCallbackData = nullptr;
-  mSinglePaintBuffer = nullptr;
   mSinglePaintDrawTarget = nullptr;
 }
 
-BasicTiledLayerTile
-BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
-                                            const nsIntPoint& aTileOrigin,
-                                            const nsIntRect& aDirtyRect)
-{
-  if (aTile.IsPlaceholderTile()) {
-    RefPtr<DeprecatedTextureClient> textureClient =
-      new DeprecatedTextureClientTile(mManager->AsShadowForwarder(), TextureInfo(BUFFER_TILED));
-    aTile.mDeprecatedTextureClient = static_cast<DeprecatedTextureClientTile*>(textureClient.get());
-  }
-  aTile.mDeprecatedTextureClient->EnsureAllocated(gfx::IntSize(GetTileLength(), GetTileLength()), GetContentType());
-  gfxImageSurface* writableSurface = aTile.mDeprecatedTextureClient->LockImageSurface();
-  // Bug 742100, this gfxContext really should live on the stack.
-  nsRefPtr<gfxContext> ctxt;
-
-  RefPtr<gfx::DrawTarget> writableDrawTarget;
-  if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
-    // TODO: Instead of creating a gfxImageSurface to back the tile we should
-    // create an offscreen DrawTarget. This would need to be shared cross-thread
-    // and support copy on write semantics.
-    gfx::SurfaceFormat format =
-      gfx::ImageFormatToSurfaceFormat(writableSurface->Format());
-
-    writableDrawTarget =
-      gfxPlatform::GetPlatform()->CreateDrawTargetForData(
-        writableSurface->Data(),
-        gfx::IntSize(writableSurface->Width(), writableSurface->Height()),
-        writableSurface->Stride(),
-        format);
-    ctxt = new gfxContext(writableDrawTarget);
-  } else {
-    ctxt = new gfxContext(writableSurface);
-    ctxt->SetOperator(gfxContext::OPERATOR_SOURCE);
-  }
-
-  gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
-                   aDirtyRect.width, aDirtyRect.height);
-
-  if (mSinglePaintBuffer || mSinglePaintDrawTarget) {
-    if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
-      gfx::Rect drawRect(aDirtyRect.x - aTileOrigin.x,
-                         aDirtyRect.y - aTileOrigin.y,
-                         aDirtyRect.width,
-                         aDirtyRect.height);
-      drawRect.Scale(mResolution);
-
-      RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
-      writableDrawTarget->CopySurface(
-        source,
-        gfx::IntRect(NS_roundf((aDirtyRect.x - mSinglePaintBufferOffset.x) * mResolution),
-                     NS_roundf((aDirtyRect.y - mSinglePaintBufferOffset.y) * mResolution),
-                     drawRect.width,
-                     drawRect.height),
-        gfx::IntPoint(NS_roundf(drawRect.x), NS_roundf(drawRect.y)));
-    } else {
-      gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
-                       aDirtyRect.width, aDirtyRect.height);
-      drawRect.Scale(mResolution, mResolution);
-
-      ctxt->NewPath();
-      ctxt->SetSource(mSinglePaintBuffer.get(),
-                      gfxPoint((mSinglePaintBufferOffset.x - aDirtyRect.x) * mResolution + drawRect.x,
-                               (mSinglePaintBufferOffset.y - aDirtyRect.y) * mResolution + drawRect.y));
-      ctxt->SnappedRectangle(drawRect);
-      ctxt->Fill();
-    }
-  } else {
-    ctxt->NewPath();
-    ctxt->Scale(mResolution, mResolution);
-    ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
-    nsIntPoint a = nsIntPoint(aTileOrigin.x, aTileOrigin.y);
-    mCallback(mThebesLayer, ctxt,
-              nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(),
-                                                 GetScaledTileLength()))),
-              DrawRegionClip::CLIP_NONE,
-              nsIntRegion(), mCallbackData);
-  }
-
-#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
-  DrawDebugOverlay(writableSurface, aTileOrigin.x * mResolution,
-                   aTileOrigin.y * mResolution);
-#endif
-
-  return aTile;
-}
-
-BasicTiledLayerTile
-BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
+TileClient
+ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
                                     const nsIntPoint& aTileOrigin,
                                     const nsIntRegion& aDirtyRegion)
 {
-  PROFILER_LABEL("BasicTiledLayerBuffer", "ValidateTile");
+  PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (aDirtyRegion.IsComplex()) {
     printf_stderr("Complex region\n");
   }
 #endif
 
-  nsIntRegionRectIterator it(aDirtyRegion);
-  for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
+  if (aTile.IsPlaceholderTile()) {
+    aTile.SetLayerManager(mManager);
+  }
+
+  // Discard our front and backbuffers if our contents changed. In this case
+  // the calling code will already have taken care of invalidating the entire
+  // layer.
+  if (HasFormatChanged()) {
+    aTile.DiscardBackBuffer();
+    aTile.DiscardFrontBuffer();
+  }
+
+  bool createdTextureClient = false;
+  nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
+  bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
+  RefPtr<TextureClient> backBuffer =
+    aTile.GetBackBuffer(offsetDirtyRegion,
+                        mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
+                        &createdTextureClient, !usingSinglePaintBuffer);
+
+  if (!backBuffer->Lock(OPEN_READ_WRITE)) {
+    NS_WARNING("Failed to lock tile TextureClient for updating.");
+    aTile.DiscardFrontBuffer();
+    return aTile;
+  }
+
+  // We must not keep a reference to the DrawTarget after it has been unlocked,
+  // make sure these are null'd before unlocking as destruction of the context
+  // may cause the target to be flushed.
+  RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
+  drawTarget->SetTransform(Matrix());
+
+  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
+
+  if (usingSinglePaintBuffer) {
+    // XXX Perhaps we should just copy the bounding rectangle here?
+    RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
+    nsIntRegionRectIterator it(aDirtyRegion);
+    for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
-    printf_stderr(" break into subrect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
+      printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
+                    dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
 #endif
-    aTile = ValidateTileInternal(aTile, aTileOrigin, *rect);
+      gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
+                         dirtyRect->y - aTileOrigin.y,
+                         dirtyRect->width,
+                         dirtyRect->height);
+      drawRect.Scale(mResolution);
+
+      gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
+                            NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
+                            drawRect.width,
+                            drawRect.height);
+      gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
+      drawTarget->CopySurface(source, copyRect, copyTarget);
+
+      // Mark the newly updated area as invalid in the front buffer
+      aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
+    }
+
+    // The new buffer is now validated, remove the dirty region from it.
+    aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
+                           offsetDirtyRegion);
+  } else {
+    // Area of the full tile...
+    nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
+
+    // Intersect this area with the portion that's dirty.
+    tileRegion = tileRegion.Intersect(aDirtyRegion);
+
+    // Move invalid areas into layer space.
+    aTile.mInvalidFront.MoveBy(aTileOrigin);
+    aTile.mInvalidBack.MoveBy(aTileOrigin);
+
+    // Add the area that's going to be redrawn to the invalid area of the
+    // front region.
+    aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion);
+
+    // Add invalid areas of the backbuffer to the area to redraw.
+    tileRegion.Or(tileRegion, aTile.mInvalidBack);
+
+    // Move invalid areas back into tile space.
+    aTile.mInvalidFront.MoveBy(-aTileOrigin);
+
+    // This will be validated now.
+    aTile.mInvalidBack.SetEmpty();
+
+    nsIntRect bounds = tileRegion.GetBounds();
+    bounds.ScaleRoundOut(mResolution, mResolution);
+    bounds.MoveBy(-aTileOrigin);
+
+    if (GetContentType() != gfxContentType::COLOR) {
+      drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+    }
+
+    ctxt->NewPath();
+    ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
+    ctxt->Scale(mResolution, mResolution);
+    ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
+    mCallback(mThebesLayer, ctxt,
+              tileRegion.GetBounds(),
+              DrawRegionClip::CLIP_NONE,
+              nsIntRegion(), mCallbackData);
+
+  }
+
+#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
+  DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
+                   aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
+#endif
+
+  ctxt = nullptr;
+  drawTarget = nullptr;
+
+  backBuffer->Unlock();
+
+  aTile.Flip();
+
+  if (createdTextureClient) {
+    if (!mCompositableClient->AddTextureClient(backBuffer)) {
+      NS_WARNING("Failed to add tile TextureClient.");
+      aTile.DiscardFrontBuffer();
+      aTile.DiscardBackBuffer();
+      return aTile;
+    }
+  }
+
+  // Note, we don't call UpdatedTexture. The Updated function is called manually
+  // by the TiledContentHost before composition.
+
+  if (backBuffer->HasInternalBuffer()) {
+    // If our new buffer has an internal buffer, we don't want to keep another
+    // TextureClient around unnecessarily, so discard the back-buffer.
+    aTile.DiscardBackBuffer();
   }
 
   return aTile;
 }
 
 static LayoutDeviceRect
 TransformCompositionBounds(const ScreenRect& aCompositionBounds,
                            const CSSToScreenScale& aZoom,
@@ -571,17 +862,17 @@ TransformCompositionBounds(const ScreenR
 
   return LayoutDeviceRect(transformedViewport.x,
                           transformedViewport.y,
                           transformedViewport.width,
                           transformedViewport.height);
 }
 
 bool
-BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
+ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
                                                       const nsIntRegion& aOldValidRegion,
                                                       nsIntRegion& aRegionToPaint,
                                                       BasicTiledLayerPaintData* aPaintData,
                                                       bool aIsRepeated)
 {
   aRegionToPaint = aInvalidRegion;
 
   // If the composition bounds rect is empty, we can't make any sensible
@@ -730,17 +1021,17 @@ BasicTiledLayerBuffer::ComputeProgressiv
   // We're not repeating painting and we've not requested a repeat transaction,
   // so the paint is finished. If there's still a separate low precision
   // paint to do, it will get marked as unfinished later.
   aPaintData->mPaintFinished = true;
   return false;
 }
 
 bool
-BasicTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
+ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
                                          nsIntRegion& aInvalidRegion,
                                          const nsIntRegion& aOldValidRegion,
                                          BasicTiledLayerPaintData* aPaintData,
                                          LayerManager::DrawThebesLayerCallback aCallback,
                                          void* aCallbackData)
 {
   bool repeat = false;
   bool isBufferChanged = false;
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -11,96 +11,221 @@
 #include <algorithm>                    // for swap
 #include "Layers.h"                     // for LayerManager, etc
 #include "TiledLayerBuffer.h"           // for TiledLayerBuffer
 #include "Units.h"                      // for CSSPoint
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
+#include "mozilla/ipc/Shmem.h"          // for Shmem
+#include "mozilla/ipc/SharedMemory.h"   // for SharedMemory
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
+#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
 #include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/TextureClientPool.h"
+#include "ClientLayerManager.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_DTOR
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "gfxReusableSurfaceWrapper.h"
+#include "pratom.h"                     // For PR_ATOMIC_INCREMENT/DECREMENT
+#include "gfxPrefs.h"
 
 class gfxImageSurface;
 
 namespace mozilla {
 namespace layers {
 
 class BasicTileDescriptor;
+class ClientTiledThebesLayer;
+class ClientLayerManager;
+
+
+// A class to help implement copy-on-write semantics for shared tiles.
+class gfxSharedReadLock : public AtomicRefCounted<gfxSharedReadLock> {
+public:
+  virtual ~gfxSharedReadLock() {}
+
+  virtual int32_t ReadLock() = 0;
+  virtual int32_t ReadUnlock() = 0;
+  virtual int32_t GetReadCount() = 0;
+
+  enum gfxSharedReadLockType {
+    TYPE_MEMORY,
+    TYPE_SHMEM
+  };
+  virtual gfxSharedReadLockType GetType() = 0;
+
+protected:
+  NS_DECL_OWNINGTHREAD
+};
+
+class gfxMemorySharedReadLock : public gfxSharedReadLock {
+public:
+  gfxMemorySharedReadLock();
+
+  ~gfxMemorySharedReadLock();
+
+  virtual int32_t ReadLock() MOZ_OVERRIDE;
+
+  virtual int32_t ReadUnlock() MOZ_OVERRIDE;
+
+  virtual int32_t GetReadCount() MOZ_OVERRIDE;
+
+  virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_MEMORY; }
+
+private:
+  int32_t mReadCount;
+};
+
+class gfxShmSharedReadLock : public gfxSharedReadLock {
+private:
+  struct ShmReadLockInfo {
+    int32_t readCount;
+  };
+
+public:
+  gfxShmSharedReadLock(ISurfaceAllocator* aAllocator);
+
+  ~gfxShmSharedReadLock();
+
+  virtual int32_t ReadLock() MOZ_OVERRIDE;
+
+  virtual int32_t ReadUnlock() MOZ_OVERRIDE;
+
+  virtual int32_t GetReadCount() MOZ_OVERRIDE;
+
+  virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_SHMEM; }
+
+  mozilla::ipc::Shmem& GetShmem() { return mShmem; }
+
+  static already_AddRefed<gfxShmSharedReadLock>
+  Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem)
+  {
+    nsRefPtr<gfxShmSharedReadLock> readLock = new gfxShmSharedReadLock(aAllocator, aShmem);
+    return readLock.forget();
+  }
+
+private:
+  gfxShmSharedReadLock(ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem)
+    : mAllocator(aAllocator)
+    , mShmem(aShmem)
+  {
+    MOZ_COUNT_CTOR(gfxShmSharedReadLock);
+  }
+
+  ShmReadLockInfo* GetShmReadLockInfoPtr()
+  {
+    return reinterpret_cast<ShmReadLockInfo*>
+      (mShmem.get<char>() + mShmem.Size<char>() - sizeof(ShmReadLockInfo));
+  }
+
+  RefPtr<ISurfaceAllocator> mAllocator;
+  mozilla::ipc::Shmem mShmem;
+};
 
 /**
  * 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.
+ * each tile keeps a reference to a texture client and a read-lock. This
+ * read-lock is used to help implement a copy-on-write mechanism. The tile
+ * should be locked before being sent to the compositor. The compositor should
+ * unlock the read-lock as soon as it has finished with the buffer in the
+ * TextureHost to prevent more textures being created than is necessary.
  * Ideal place to store per tile debug information.
  */
-struct BasicTiledLayerTile {
-  RefPtr<DeprecatedTextureClientTile> mDeprecatedTextureClient;
+struct TileClient
+{
+  // Placeholder
+  TileClient();
+
+  TileClient(const TileClient& o);
+
+  TileClient& operator=(const TileClient& o);
+
+  bool operator== (const TileClient& o) const
+  {
+    return mFrontBuffer == o.mFrontBuffer;
+  }
+
+  bool operator!= (const TileClient& o) const
+  {
+    return mFrontBuffer != o.mFrontBuffer;
+  }
+
+  void SetLayerManager(ClientLayerManager *aManager)
+  {
+    mManager = aManager;
+  }
+
+  bool IsPlaceholderTile()
+  {
+    return mBackBuffer == nullptr && mFrontBuffer == nullptr;
+  }
+
+  void ReadUnlock()
+  {
+    NS_ASSERTION(mFrontLock != nullptr, "ReadUnlock with no gfxSharedReadLock");
+    mFrontLock->ReadUnlock();
+  }
+
+  void ReadLock()
+  {
+    NS_ASSERTION(mFrontLock != nullptr, "ReadLock with no gfxSharedReadLock");
+    mFrontLock->ReadLock();
+  }
+
+  void Release()
+  {
+    DiscardFrontBuffer();
+    DiscardBackBuffer();
+  }
+
+  TileDescriptor GetTileDescriptor();
+
+  /**
+  * Swaps the front and back buffers.
+  */
+  void Flip();
+
+  /**
+  * Returns an unlocked TextureClient that can be used for writing new
+  * data to the tile. This may flip the front-buffer to the back-buffer if
+  * the front-buffer is still locked by the host, or does not have an
+  * internal buffer (and so will always be locked).
+  */
+  TextureClient* GetBackBuffer(const nsIntRegion& aDirtyRegion,
+                               TextureClientPool *aPool,
+                               bool *aCreatedTextureClient,
+                               bool aCanRerasterizeValidRegion);
+
+  void DiscardFrontBuffer();
+
+  void DiscardBackBuffer();
+
+  RefPtr<TextureClient> mBackBuffer;
+  RefPtr<TextureClient> mFrontBuffer;
+  RefPtr<gfxSharedReadLock> mBackLock;
+  RefPtr<gfxSharedReadLock> mFrontLock;
+  RefPtr<ClientLayerManager> mManager;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   TimeStamp        mLastUpdate;
 #endif
-
-  // Placeholder
-  BasicTiledLayerTile()
-    : mDeprecatedTextureClient(nullptr)
-  {}
-
-  BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient)
-    : mDeprecatedTextureClient(aTextureClient)
-  {}
+  nsIntRegion mInvalidFront;
+  nsIntRegion mInvalidBack;
 
-  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;
-    mDeprecatedTextureClient = o.mDeprecatedTextureClient;
-#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
-    mLastUpdate = o.mLastUpdate;
-#endif
-    return *this;
-  }
-  bool operator== (const BasicTiledLayerTile& o) const {
-    return mDeprecatedTextureClient == o.mDeprecatedTextureClient;
-  }
-  bool operator!= (const BasicTiledLayerTile& o) const {
-    return mDeprecatedTextureClient != o.mDeprecatedTextureClient;
-  }
-
-  bool IsPlaceholderTile() { return mDeprecatedTextureClient == nullptr; }
-
-  void ReadUnlock() {
-    GetSurface()->ReadUnlock();
-  }
-  void ReadLock() {
-    GetSurface()->ReadLock();
-  }
-
-  TileDescriptor GetTileDescriptor();
-  static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc);
-
-  gfxReusableSurfaceWrapper* GetSurface() {
-    return mDeprecatedTextureClient->GetReusableSurfaceWrapper();
-  }
+private:
+  void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
+                                   bool aCanRerasterizeValidRegion);
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it
  * doesn't need to be recalculated on every repeated transaction.
  */
 struct BasicTiledLayerPaintData {
   /*
@@ -160,19 +285,16 @@ struct BasicTiledLayerPaintData {
   /*
    * Whether there is further work to complete this paint. This is used to
    * determine whether or not to repeat the transaction when painting
    * progressively.
    */
   bool mPaintFinished : 1;
 };
 
-class ClientTiledThebesLayer;
-class ClientLayerManager;
-
 class SharedFrameMetricsHelper
 {
 public:
   SharedFrameMetricsHelper();
   ~SharedFrameMetricsHelper();
 
   /**
    * This is called by the BasicTileLayer to determine if it is still interested
@@ -205,82 +327,55 @@ public:
   bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
                            const FrameMetrics& aCompositorMetrics);
 private:
   bool mLastProgressiveUpdateWasLowPrecision;
   bool mProgressiveUpdateWasInDanger;
 };
 
 /**
- * Provide an instance of TiledLayerBuffer backed by image surfaces.
- * This buffer provides an implementation to ValidateTile using a
- * thebes callback and can support painting using a single paint buffer
- * which is much faster then painting directly into the tiles.
+ * Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
+ * This buffer provides an implementation of ValidateTile using a
+ * thebes callback and can support painting using a single paint buffer.
+ * Whether a single paint buffer is used is controlled by
+ * gfxPrefs::PerTileDrawing().
  */
-class BasicTiledLayerBuffer
-  : public TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>
+class ClientTiledLayerBuffer
+  : public TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>
 {
-  friend class TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>;
+  friend class TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>;
 
 public:
-  BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
-                        ClientLayerManager* aManager,
-                        SharedFrameMetricsHelper* aHelper);
-  BasicTiledLayerBuffer()
+  ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
+                         CompositableClient* aCompositableClient,
+                         ClientLayerManager* aManager,
+                         SharedFrameMetricsHelper* aHelper);
+  ClientTiledLayerBuffer()
     : mThebesLayer(nullptr)
+    , mCompositableClient(nullptr)
     , mManager(nullptr)
     , mLastPaintOpaque(false)
     , mSharedFrameMetricsHelper(nullptr)
   {}
 
-  BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator,
-                        const nsIntRegion& aValidRegion,
-                        const nsIntRegion& aPaintedRegion,
-                        const InfallibleTArray<TileDescriptor>& aTiles,
-                        int aRetainedWidth,
-                        int aRetainedHeight,
-                        float aResolution,
-                        SharedFrameMetricsHelper* aHelper)
-  {
-    mSharedFrameMetricsHelper = aHelper;
-    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 {
-        mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, aTiles[i]));
-      }
-    }
-  }
-
   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;
-      mRetainedTiles[i].ReadUnlock();
-    }
-  }
+  void ReadUnlock();
+
+  void ReadLock();
 
-  void ReadLock() {
-    for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
-      if (mRetainedTiles[i].IsPlaceholderTile()) continue;
-      mRetainedTiles[i].ReadLock();
-    }
-  }
+  void Release();
+
+  void DiscardBackBuffers();
 
   const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
+
   void SetFrameResolution(const CSSToScreenScale& aResolution) { mFrameResolution = aResolution; }
 
   bool HasFormatChanged() const;
 
   /**
    * Performs a progressive update of a given tiled buffer.
    * See ComputeProgressiveUpdateRegion below for parameter documentation.
    */
@@ -288,58 +383,48 @@ public:
                          nsIntRegion& aInvalidRegion,
                          const nsIntRegion& aOldValidRegion,
                          BasicTiledLayerPaintData* aPaintData,
                          LayerManager::DrawThebesLayerCallback aCallback,
                          void* aCallbackData);
 
   SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
 
-  static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
-                                              const SurfaceDescriptorTiles& aDescriptor,
-                                              SharedFrameMetricsHelper* aHelper);
-
 protected:
-  BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
-                                   const nsIntPoint& aTileRect,
-                                   const nsIntRegion& dirtyRect);
+  TileClient ValidateTile(TileClient 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
   // each tile individually. Somewhat surprisingly, this turns out to be faster
   // on Android.
-  bool UseSinglePaintBuffer() { return true; }
+  bool UseSinglePaintBuffer() { return !gfxPrefs::PerTileDrawing(); }
 
-  void ReleaseTile(BasicTiledLayerTile aTile) { /* No-op. */ }
+  void ReleaseTile(TileClient aTile) { aTile.Release(); }
 
-  void SwapTiles(BasicTiledLayerTile& aTileA, BasicTiledLayerTile& aTileB) {
-    std::swap(aTileA, aTileB);
-  }
+  void SwapTiles(TileClient& aTileA, TileClient& aTileB) { std::swap(aTileA, aTileB); }
 
-  BasicTiledLayerTile GetPlaceholderTile() const { return BasicTiledLayerTile(); }
+  TileClient GetPlaceholderTile() const { return TileClient(); }
 
 private:
   gfxContentType GetContentType() const;
   ClientTiledThebesLayer* mThebesLayer;
+  CompositableClient* mCompositableClient;
   ClientLayerManager* mManager;
   LayerManager::DrawThebesLayerCallback mCallback;
   void* mCallbackData;
   CSSToScreenScale mFrameResolution;
   bool mLastPaintOpaque;
 
-  // The buffer we use when UseSinglePaintBuffer() above is true.
-  nsRefPtr<gfxImageSurface>     mSinglePaintBuffer;
+  // The DrawTarget we use when UseSinglePaintBuffer() above is true.
   RefPtr<gfx::DrawTarget>       mSinglePaintDrawTarget;
   nsIntPoint                    mSinglePaintBufferOffset;
   SharedFrameMetricsHelper*  mSharedFrameMetricsHelper;
 
-  BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
-                                           const nsIntPoint& aTileOrigin,
-                                           const nsIntRect& aDirtyRect);
-
   /**
    * Calculates the region to update in a single progressive update transaction.
    * This employs some heuristics to update the most 'sensible' region to
    * update at this point in time, and how large an update should be performed
    * at once to maintain visual coherency.
    *
    * aInvalidRegion is the current invalid region.
    * aOldValidRegion is the valid region of mTiledBuffer at the beginning of the
@@ -369,31 +454,36 @@ class TiledContentClient : public Compos
 
 public:
   TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
                      ClientLayerManager* aManager);
 
   ~TiledContentClient()
   {
     MOZ_COUNT_DTOR(TiledContentClient);
+
+    mTiledBuffer.Release();
+    mLowPrecisionTiledBuffer.Release();
   }
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return TextureInfo(BUFFER_TILED);
   }
 
+  virtual void ClearCachedResources() MOZ_OVERRIDE;
+
   enum TiledBufferType {
     TILED_BUFFER,
     LOW_PRECISION_TILED_BUFFER
   };
-  void LockCopyAndWrite(TiledBufferType aType);
+  void UseTiledLayerBuffer(TiledBufferType aType);
 
 private:
   SharedFrameMetricsHelper mSharedFrameMetricsHelper;
-  BasicTiledLayerBuffer mTiledBuffer;
-  BasicTiledLayerBuffer mLowPrecisionTiledBuffer;
+  ClientTiledLayerBuffer mTiledBuffer;
+  ClientTiledLayerBuffer mLowPrecisionTiledBuffer;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -169,17 +169,19 @@ CompositableHost::Create(const TextureIn
     result = new ContentHostSingleBuffered(aTextureInfo);
     break;
   case COMPOSITABLE_CONTENT_DOUBLE:
     result = new ContentHostDoubleBuffered(aTextureInfo);
     break;
   default:
     MOZ_CRASH("Unknown CompositableType");
   }
-  if (result) {
+  // We know that Tiled buffers don't use the compositable backend-specific
+  // data, so don't bother creating it.
+  if (result && aTextureInfo.mCompositableType != BUFFER_TILED) {
     RefPtr<CompositableBackendSpecificData> data = CreateCompositableBackendSpecificDataOGL();
     result->SetCompositableBackendSpecificData(data);
   }
   return result;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -17,16 +17,17 @@
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
+#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 
 class gfxImageSurface;
 class gfxReusableSurfaceWrapper;
 struct nsIntPoint;
 struct nsIntSize;
 struct nsIntRect;
@@ -269,16 +270,17 @@ class TextureHost
    * Called once, just before the destructor.
    *
    * Here goes the shut-down code that uses virtual methods.
    * Must only be called by Release().
    */
   void Finalize();
 
   friend class AtomicRefCountedWithFinalize<TextureHost>;
+
 public:
   TextureHost(TextureFlags aFlags);
 
   virtual ~TextureHost();
 
   /**
    * Factory method.
    */
@@ -422,16 +424,23 @@ public:
 
   // Forget buffer actor. Used only for hacky fix for bug 966446. 
   virtual void ForgetBufferActor() {}
 
   virtual const char *Name() { return "TextureHost"; }
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
   /**
+   * Indicates whether the TextureHost implementation is backed by an
+   * in-memory buffer. The consequence of this is that locking the
+   * TextureHost does not contend with locking the texture on the client side.
+   */
+  virtual bool HasInternalBuffer() const { return false; }
+
+  /**
    * Cast to a TextureHost for each backend.
    */
   virtual TextureHostOGL* AsHostOGL() { return nullptr; }
 
 protected:
   PTextureParent* mActor;
   TextureFlags mFlags;
   RefPtr<CompositableBackendSpecificData> mCompositableBackendData;
@@ -456,16 +465,17 @@ class BufferTextureHost : public Texture
 {
 public:
   BufferTextureHost(gfx::SurfaceFormat aFormat,
                     TextureFlags aFlags);
 
   ~BufferTextureHost();
 
   virtual uint8_t* GetBuffer() = 0;
+
   virtual size_t GetBufferSize() = 0;
 
   virtual void Updated(const nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE;
 
   virtual bool Lock() MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
@@ -483,16 +493,18 @@ public:
    * GetFormat will be RGB32 (even though mFormat is SurfaceFormat::YUV).
    */
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
   Compositor* mCompositor;
   RefPtr<DataTextureSource> mFirstSource;
   nsIntRegion mMaybeUpdatedRegion;
   gfx::IntSize mSize;
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -10,211 +10,358 @@
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
+#include "mozilla/layers/TiledContentClient.h"
 
 class gfxReusableSurfaceWrapper;
 
 namespace mozilla {
 using namespace gfx;
 namespace layers {
 
 class Layer;
 
-void
-TiledLayerBufferComposite::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
-                                  const nsIntRegion& aNewValidRegion,
-                                  const nsIntRegion& aInvalidateRegion,
-                                  const CSSToScreenScale& aResolution)
+TiledLayerBufferComposite::TiledLayerBufferComposite()
+  : mFrameResolution(1.0)
+  , mHasDoubleBufferedTiles(false)
+  , mUninitialized(true)
+{}
+
+TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
+                                                     const SurfaceDescriptorTiles& aDescriptor,
+                                                     const nsIntRegion& aOldPaintedRegion)
 {
-#ifdef GFX_TILEDLAYER_PREF_WARNINGS
-  printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
-  long start = PR_IntervalNow();
-#endif
+  mUninitialized = false;
+  mHasDoubleBufferedTiles = false;
+  mValidRegion = aDescriptor.validRegion();
+  mPaintedRegion = aDescriptor.paintedRegion();
+  mRetainedWidth = aDescriptor.retainedWidth();
+  mRetainedHeight = aDescriptor.retainedHeight();
+  mResolution = aDescriptor.resolution();
+
+  // Combine any valid content that wasn't already uploaded
+  nsIntRegion oldPaintedRegion(aOldPaintedRegion);
+  oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
+  mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
 
-  mFrameResolution = aResolution;
-  mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
-  Update(aNewValidRegion, aInvalidateRegion);
-  mMainMemoryTiledBuffer = nullptr;
-#ifdef GFX_TILEDLAYER_PREF_WARNINGS
-  if (PR_IntervalNow() - start > 10) {
-    printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
+  const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
+  for(size_t i = 0; i < tiles.Length(); i++) {
+    RefPtr<TextureHost> texture;
+    const TileDescriptor& tileDesc = tiles[i];
+    switch (tileDesc.type()) {
+      case TileDescriptor::TTexturedTileDescriptor : {
+        texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent());
+        const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock();
+        nsRefPtr<gfxSharedReadLock> sharedLock;
+        if (ipcLock.type() == TileLock::TShmem) {
+          sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_Shmem());
+        } else {
+          sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
+          // The corresponding AddRef is in TiledClient::GetTileDescriptor
+          sharedLock->Release();
+        }
+        MOZ_ASSERT(sharedLock);
+        if (sharedLock) {
+          mRetainedTiles.AppendElement(TileHost(sharedLock, texture));
+        }
+        break;
+      }
+      default:
+        NS_WARNING("Unrecognised tile descriptor type");
+        // Fall through
+      case TileDescriptor::TPlaceholderTileDescriptor :
+        mRetainedTiles.AppendElement(GetPlaceholderTile());
+        break;
+    }
+    if (texture && !texture->HasInternalBuffer()) {
+      mHasDoubleBufferedTiles = true;
+    }
   }
-#endif
 }
 
-TiledTexture
-TiledLayerBufferComposite::ValidateTile(TiledTexture aTile,
+void
+TiledLayerBufferComposite::ReadUnlock()
+{
+  if (!IsValid()) {
+    return;
+  }
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    mRetainedTiles[i].ReadUnlock();
+  }
+}
+
+void
+TiledLayerBufferComposite::ReleaseTextureHosts()
+{
+  if (!IsValid()) {
+    return;
+  }
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    mRetainedTiles[i].mTextureHost = nullptr;
+  }
+}
+
+void
+TiledLayerBufferComposite::Upload()
+{
+  if(!IsValid()) {
+    return;
+  }
+  // The TextureClients were created with the TEXTURE_IMMEDIATE_UPLOAD flag,
+  // so calling Update on all the texture hosts will perform the texture upload.
+  Update(mValidRegion, mPaintedRegion);
+  ClearPaintedRegion();
+}
+
+TileHost
+TiledLayerBufferComposite::ValidateTile(TileHost aTile,
                                         const nsIntPoint& aTileOrigin,
                                         const nsIntRegion& aDirtyRect)
 {
+  if (aTile.IsPlaceholderTile()) {
+    NS_WARNING("Placeholder tile encountered in painted region");
+    return aTile;
+  }
+
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
   long start = PR_IntervalNow();
 #endif
 
-  aTile.Validate(mMainMemoryTiledBuffer->GetTile(aTileOrigin).GetSurface(), mCompositor, GetTileLength());
+  MOZ_ASSERT(aTile.mTextureHost->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD);
+  // We possibly upload the entire texture contents here. This is a purposeful
+  // decision, as sub-image upload can often be slow and/or unreliable, but
+  // we may want to reevaluate this in the future.
+  // For !HasInternalBuffer() textures, this is likely a no-op.
+  aTile.mTextureHost->Updated(nullptr);
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 1) {
     printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
   }
 #endif
   return aTile;
 }
 
 void
+TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
+{
+  if (!IsValid()) {
+    return;
+  }
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+    mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
+  }
+}
+
+TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
+  : ContentHost(aTextureInfo)
+  , mTiledBuffer(TiledLayerBufferComposite())
+  , mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
+  , mOldTiledBuffer(TiledLayerBufferComposite())
+  , mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
+  , mPendingUpload(false)
+  , mPendingLowPrecisionUpload(false)
+{
+  MOZ_COUNT_CTOR(TiledContentHost);
+}
+
+TiledContentHost::~TiledContentHost()
+{
+  MOZ_COUNT_DTOR(TiledContentHost);
+
+  // Unlock any buffers that may still be locked. If we have a pending upload,
+  // we will need to unlock the buffer that was about to be uploaded.
+  // If a buffer that was being composited had double-buffered tiles, we will
+  // need to unlock that buffer too.
+  if (mPendingUpload) {
+    mTiledBuffer.ReadUnlock();
+    if (mOldTiledBuffer.HasDoubleBufferedTiles()) {
+      mOldTiledBuffer.ReadUnlock();
+    }
+  } else if (mTiledBuffer.HasDoubleBufferedTiles()) {
+    mTiledBuffer.ReadUnlock();
+  }
+
+  if (mPendingLowPrecisionUpload) {
+    mLowPrecisionTiledBuffer.ReadUnlock();
+    if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
+      mOldLowPrecisionTiledBuffer.ReadUnlock();
+    }
+  } else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
+    mLowPrecisionTiledBuffer.ReadUnlock();
+  }
+}
+
+void
 TiledContentHost::Attach(Layer* aLayer,
                          Compositor* aCompositor,
                          AttachFlags aFlags /* = NO_FLAGS */)
 {
   CompositableHost::Attach(aLayer, aCompositor, aFlags);
   static_cast<ThebesLayerComposite*>(aLayer)->EnsureTiled();
 }
 
 void
-TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
-                                          const SurfaceDescriptorTiles& aTiledDescriptor)
+TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                                      const SurfaceDescriptorTiles& aTiledDescriptor)
 {
   if (aTiledDescriptor.resolution() < 1) {
-    mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
-    mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload,
-                                   mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion());
-    mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion();
-    mPendingLowPrecisionUpload = true;
+    if (mPendingLowPrecisionUpload) {
+      mLowPrecisionTiledBuffer.ReadUnlock();
+    } else {
+      mPendingLowPrecisionUpload = true;
+      // If the old buffer has double-buffered tiles, hang onto it so we can
+      // unlock it after we've composited the new buffer.
+      // We only need to hang onto the locks, but not the textures.
+      // Releasing the textures here can help prevent a memory spike in the
+      // situation that the client starts rendering new content before we get
+      // to composite the new buffer.
+      if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
+        mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer;
+        mOldLowPrecisionTiledBuffer.ReleaseTextureHosts();
+      }
+    }
+    mLowPrecisionTiledBuffer =
+      TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
+                                mLowPrecisionTiledBuffer.GetPaintedRegion());
   } else {
-    mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
-    mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
-    mMainMemoryTiledBuffer.ClearPaintedRegion();
-    mPendingUpload = true;
-  }
-}
-
-void
-TiledContentHost::ProcessLowPrecisionUploadQueue()
-{
-  if (!mPendingLowPrecisionUpload) {
-    return;
+    if (mPendingUpload) {
+      mTiledBuffer.ReadUnlock();
+    } else {
+      mPendingUpload = true;
+      if (mTiledBuffer.HasDoubleBufferedTiles()) {
+        mOldTiledBuffer = mTiledBuffer;
+        mOldTiledBuffer.ReleaseTextureHosts();
+      }
+    }
+    mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
+                                             mTiledBuffer.GetPaintedRegion());
   }
-
-  mLowPrecisionRegionToUpload.And(mLowPrecisionRegionToUpload,
-                                  mLowPrecisionMainMemoryTiledBuffer.GetValidRegion());
-  mLowPrecisionVideoMemoryTiledBuffer.SetResolution(
-    mLowPrecisionMainMemoryTiledBuffer.GetResolution());
-  // It's assumed that the video memory tiled buffer has an up-to-date
-  // 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 = BasicTiledLayerBuffer();
-  mLowPrecisionRegionToUpload = nsIntRegion();
-  mPendingLowPrecisionUpload = false;
-}
-
-void
-TiledContentHost::ProcessUploadQueue(nsIntRegion* aNewValidRegion,
-                                     TiledLayerProperties* aLayerProperties)
-{
-  if (!mPendingUpload)
-    return;
-
-  // If we coalesce uploads while the layers' valid region is changing we will
-  // end up trying to upload area outside of the valid region. (bug 756555)
-  mRegionToUpload.And(mRegionToUpload, mMainMemoryTiledBuffer.GetValidRegion());
-
-  mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
-                                 mMainMemoryTiledBuffer.GetValidRegion(),
-                                 mRegionToUpload, aLayerProperties->mEffectiveResolution);
-
-  *aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
-
-  // Release all the tiles by replacing the tile buffer with an empty
-  // tiled buffer.
-  mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
-  mRegionToUpload = nsIntRegion();
-  mPendingUpload = false;
 }
 
 void
 TiledContentHost::Composite(EffectChain& aEffectChain,
                             float aOpacity,
                             const gfx::Matrix4x4& aTransform,
                             const gfx::Filter& aFilter,
                             const gfx::Rect& aClipRect,
                             const nsIntRegion* aVisibleRegion /* = nullptr */,
                             TiledLayerProperties* aLayerProperties /* = nullptr */)
 {
   MOZ_ASSERT(aLayerProperties, "aLayerProperties required for TiledContentHost");
 
-  // note that ProcessUploadQueue updates the valid region which is then used by
-  // the RenderLayerBuffer calls below and then sent back to the layer.
-  ProcessUploadQueue(&aLayerProperties->mValidRegion, aLayerProperties);
-  ProcessLowPrecisionUploadQueue();
-
   // Render valid tiles.
   nsIntRect visibleRect = aVisibleRegion->GetBounds();
 
-  RenderLayerBuffer(mLowPrecisionVideoMemoryTiledBuffer,
-                    mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(), aEffectChain, aOpacity,
+  if (mPendingUpload) {
+    mTiledBuffer.SetCompositor(mCompositor);
+    mTiledBuffer.Upload();
+
+    // For a single-buffered tiled buffer, Upload will upload the shared memory
+    // surface to texture memory and we no longer need to read from them.
+    if (!mTiledBuffer.HasDoubleBufferedTiles()) {
+      mTiledBuffer.ReadUnlock();
+    }
+  }
+  if (mPendingLowPrecisionUpload) {
+    mLowPrecisionTiledBuffer.SetCompositor(mCompositor);
+    mLowPrecisionTiledBuffer.Upload();
+
+    if (!mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
+      mLowPrecisionTiledBuffer.ReadUnlock();
+    }
+  }
+
+  RenderLayerBuffer(mLowPrecisionTiledBuffer,
+                    mLowPrecisionTiledBuffer.GetValidRegion(), aEffectChain, aOpacity,
                     aFilter, aClipRect, aLayerProperties->mValidRegion, visibleRect, aTransform);
-  RenderLayerBuffer(mVideoMemoryTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity,
+  RenderLayerBuffer(mTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity,
                     aFilter, aClipRect, nsIntRegion(), visibleRect, aTransform);
+
+  // Now release the old buffer if it had double-buffered tiles, as we can
+  // guarantee that they're no longer on the screen (and so any locks that may
+  // have been held have been released).
+  if (mPendingUpload && mOldTiledBuffer.HasDoubleBufferedTiles()) {
+    mOldTiledBuffer.ReadUnlock();
+    mOldTiledBuffer = TiledLayerBufferComposite();
+  }
+  if (mPendingLowPrecisionUpload && mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
+    mOldLowPrecisionTiledBuffer.ReadUnlock();
+    mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite();
+  }
+  mPendingUpload = mPendingLowPrecisionUpload = false;
 }
 
 
 void
-TiledContentHost::RenderTile(const TiledTexture& aTile,
+TiledContentHost::RenderTile(const TileHost& aTile,
                              EffectChain& aEffectChain,
                              float aOpacity,
                              const gfx::Matrix4x4& aTransform,
                              const gfx::Filter& aFilter,
                              const gfx::Rect& aClipRect,
                              const nsIntRegion& aScreenRegion,
                              const nsIntPoint& aTextureOffset,
                              const nsIntSize& aTextureBounds)
 {
-  MOZ_ASSERT(aTile.mDeprecatedTextureHost, "Trying to render a placeholder tile?");
+  if (aTile.IsPlaceholderTile()) {
+    // This shouldn't ever happen, but let's fail semi-gracefully. No need
+    // to warn, the texture update would have already caught this.
+    return;
+  }
+
+  nsIntRect screenBounds = aScreenRegion.GetBounds();
+  Matrix mat = aTransform.As2D();
+  Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
+  quad = mat.TransformBounds(quad);
+
+  if (!quad.Intersects(aClipRect)) {
+    return;
+  }
+
+  AutoLockTextureHost autoLock(aTile.mTextureHost);
+  if (autoLock.Failed()) {
+    NS_WARNING("Failed to lock tile");
+    return;
+  }
+  RefPtr<NewTextureSource> source = aTile.mTextureHost->GetTextureSources();
+  if (!source) {
+    return;
+  }
 
   RefPtr<TexturedEffect> effect =
-    CreateTexturedEffect(aTile.mDeprecatedTextureHost, aFilter);
+    CreateTexturedEffect(aTile.mTextureHost->GetFormat(), source, aFilter);
   if (!effect) {
     return;
   }
 
-  if (aTile.mDeprecatedTextureHost->Lock()) {
-    aEffectChain.mPrimaryEffect = effect;
-  } else {
-    return;
-  }
+  aEffectChain.mPrimaryEffect = effect;
 
   nsIntRegionRectIterator it(aScreenRegion);
   for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
     Rect graphicsRect(rect->x, rect->y, rect->width, rect->height);
     Rect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y,
                      rect->width, rect->height);
 
     effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
                                   textureRect.y / aTextureBounds.height,
                                   textureRect.width / aTextureBounds.width,
                                   textureRect.height / aTextureBounds.height);
     mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform);
   }
   mCompositor->DrawDiagnostics(DIAGNOSTIC_CONTENT|DIAGNOSTIC_TILE,
                                aScreenRegion, aClipRect, aTransform);
-
-  aTile.mDeprecatedTextureHost->Unlock();
 }
 
 void
 TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
                                     const nsIntRegion& aValidRegion,
                                     EffectChain& aEffectChain,
                                     float aOpacity,
                                     const gfx::Filter& aFilter,
@@ -226,19 +373,19 @@ TiledContentHost::RenderLayerBuffer(Tile
   if (!mCompositor) {
     NS_WARNING("Can't render tiled content host - no compositor");
     return;
   }
   float resolution = aLayerBuffer.GetResolution();
   gfx::Size layerScale(1, 1);
   // We assume that the current frame resolution is the one used in our primary
   // layer buffer. Compensate for a changing frame resolution.
-  if (aLayerBuffer.GetFrameResolution() != mVideoMemoryTiledBuffer.GetFrameResolution()) {
+  if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
     const CSSToScreenScale& layerResolution = aLayerBuffer.GetFrameResolution();
-    const CSSToScreenScale& localResolution = mVideoMemoryTiledBuffer.GetFrameResolution();
+    const CSSToScreenScale& localResolution = mTiledBuffer.GetFrameResolution();
     layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale;
     aVisibleRect.ScaleRoundOut(layerScale.width, layerScale.height);
   }
   aTransform.Scale(1/(resolution * layerScale.width),
                    1/(resolution * layerScale.height), 1);
 
   uint32_t rowCount = 0;
   uint32_t tileX = 0;
@@ -252,17 +399,17 @@ TiledContentHost::RenderLayerBuffer(Tile
     int tileY = 0;
     for (int32_t y = aVisibleRect.y; y < aVisibleRect.y + aVisibleRect.height;) {
       int32_t tileStartY = aLayerBuffer.GetTileStart(y);
       int32_t h = aLayerBuffer.GetScaledTileLength() - tileStartY;
       if (y + h > aVisibleRect.y + aVisibleRect.height) {
         h = aVisibleRect.y + aVisibleRect.height - y;
       }
 
-      TiledTexture tileTexture = aLayerBuffer.
+      TileHost tileTexture = aLayerBuffer.
         GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x),
                            aLayerBuffer.RoundDownToTileEdge(y)));
       if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
         nsIntRegion tileDrawRegion;
         tileDrawRegion.And(aValidRegion,
                            nsIntRect(x * layerScale.width,
                                      y * layerScale.height,
                                      w * layerScale.width,
@@ -288,33 +435,16 @@ TiledContentHost::RenderLayerBuffer(Tile
   }
   gfx::Rect rect(aVisibleRect.x, aVisibleRect.y,
                  aVisibleRect.width, aVisibleRect.height);
   GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTENT,
                                    rect, aClipRect, aTransform);
 }
 
 void
-TiledTexture::Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor* aCompositor, uint16_t aSize)
-{
-  TextureFlags flags = 0;
-  if (!mDeprecatedTextureHost) {
-    // convert placeholder tile to a real tile
-    mDeprecatedTextureHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptor::Tnull_t,
-                                                  TEXTURE_HOST_TILED,
-                                                  flags,
-                                                  nullptr);
-    mDeprecatedTextureHost->SetCompositor(aCompositor);
-    flags |= TEXTURE_NEW_TILE;
-  }
-
-  mDeprecatedTextureHost->Update(aReusableSurface, flags, gfx::IntSize(aSize, aSize));
-}
-
-void
 TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   aTo += aPrefix;
   aTo += nsPrintfCString("TiledContentHost (0x%p)", this);
 
 }
 
 #ifdef MOZ_DUMP_PAINTING
@@ -322,25 +452,29 @@ void
 TiledContentHost::Dump(FILE* aFile,
                        const char* aPrefix,
                        bool aDumpHtml)
 {
   if (!aFile) {
     aFile = stderr;
   }
 
-  TiledLayerBufferComposite::Iterator it = mVideoMemoryTiledBuffer.TilesBegin();
-  TiledLayerBufferComposite::Iterator stop = mVideoMemoryTiledBuffer.TilesEnd();
+  TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin();
+  TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd();
   if (aDumpHtml) {
     fprintf_stderr(aFile, "<ul>");
   }
   for (;it != stop; ++it) {
     fprintf_stderr(aFile, "%s", aPrefix);
     fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile ");
-    DumpDeprecatedTextureHost(aFile, it->mDeprecatedTextureHost);
+    if (it->IsPlaceholderTile()) {
+      fprintf_stderr(aFile, "empty tile");
+    } else {
+      DumpTextureHost(aFile, it->mTextureHost);
+    }
     fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
   }
     if (aDumpHtml) {
     fprintf_stderr(aFile, "</ul>");
   }
 }
 #endif
 
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -40,144 +40,150 @@ class Matrix4x4;
 namespace layers {
 
 class Compositor;
 class ISurfaceAllocator;
 class Layer;
 class ThebesBufferData;
 class TiledThebesLayerComposite;
 struct EffectChain;
- 
+
 
-class TiledTexture {
+class TileHost {
 public:
-  // Constructs a placeholder TiledTexture. See the comments above
+  // Constructs a placeholder TileHost. See the comments above
   // TiledLayerBuffer for more information on what this is used for;
   // essentially, this is a sentinel used to represent an invalid or blank
   // tile.
-  TiledTexture()
-    : mDeprecatedTextureHost(nullptr)
+  TileHost()
+    : mSharedLock(nullptr)
+    , mTextureHost(nullptr)
   {}
 
-  // Constructs a TiledTexture from a DeprecatedTextureHost.
-  TiledTexture(DeprecatedTextureHost* aDeprecatedTextureHost)
-    : mDeprecatedTextureHost(aDeprecatedTextureHost)
+  // Constructs a TileHost from a gfxSharedReadLock and TextureHost.
+  TileHost(gfxSharedReadLock* aSharedLock,
+               TextureHost* aTextureHost)
+    : mSharedLock(aSharedLock)
+    , mTextureHost(aTextureHost)
   {}
 
-  TiledTexture(const TiledTexture& o) {
-    mDeprecatedTextureHost = o.mDeprecatedTextureHost;
+  TileHost(const TileHost& o) {
+    mTextureHost = o.mTextureHost;
+    mSharedLock = o.mSharedLock;
   }
-  TiledTexture& operator=(const TiledTexture& o) {
+  TileHost& operator=(const TileHost& o) {
     if (this == &o) {
       return *this;
     }
-    mDeprecatedTextureHost = o.mDeprecatedTextureHost;
+    mTextureHost = o.mTextureHost;
+    mSharedLock = o.mSharedLock;
     return *this;
   }
 
-  void Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor* aCompositor, uint16_t aSize);
-
-  bool operator== (const TiledTexture& o) const {
-    if (!mDeprecatedTextureHost || !o.mDeprecatedTextureHost) {
-      return mDeprecatedTextureHost == o.mDeprecatedTextureHost;
-    }
-    return *mDeprecatedTextureHost == *o.mDeprecatedTextureHost;
+  bool operator== (const TileHost& o) const {
+    return mTextureHost == o.mTextureHost;
   }
-  bool operator!= (const TiledTexture& o) const {
-    if (!mDeprecatedTextureHost || !o.mDeprecatedTextureHost) {
-      return mDeprecatedTextureHost != o.mDeprecatedTextureHost;
-    }
-    return *mDeprecatedTextureHost != *o.mDeprecatedTextureHost;
+  bool operator!= (const TileHost& o) const {
+    return mTextureHost != o.mTextureHost;
   }
 
-  RefPtr<DeprecatedTextureHost> mDeprecatedTextureHost;
+  bool IsPlaceholderTile() const { return mTextureHost == nullptr; }
+
+  void ReadUnlock() {
+    // Warn if we have a texture host, but no corresponding lock.
+    NS_WARN_IF_FALSE(mTextureHost == nullptr || mSharedLock != nullptr,
+                     "ReadUnlock with no gfxSharedReadLock");
+    if (mSharedLock) {
+      mSharedLock->ReadUnlock();
+    }
+  }
+
+  RefPtr<gfxSharedReadLock> mSharedLock;
+  RefPtr<TextureHost> mTextureHost;
 };
 
 class TiledLayerBufferComposite
-  : public TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>
+  : public TiledLayerBuffer<TiledLayerBufferComposite, TileHost>
 {
-  friend class TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>;
+  friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
 
 public:
-  typedef TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>::Iterator Iterator;
-  TiledLayerBufferComposite()
-    : mCompositor(nullptr)
-  {}
+  typedef TiledLayerBuffer<TiledLayerBufferComposite, TileHost>::Iterator Iterator;
 
-  void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
-              const nsIntRegion& aNewValidRegion,
-              const nsIntRegion& aInvalidateRegion,
-              const CSSToScreenScale& aResolution);
+  TiledLayerBufferComposite();
+  TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
+                            const SurfaceDescriptorTiles& aDescriptor,
+                            const nsIntRegion& aOldPaintedRegion);
 
-  TiledTexture GetPlaceholderTile() const { return TiledTexture(); }
+  TileHost GetPlaceholderTile() const { return TileHost(); }
 
   // Stores the absolute resolution of the containing frame, calculated
   // by the sum of the resolutions of all parent layers' FrameMetrics.
   const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
 
-  void SetCompositor(Compositor* aCompositor)
-  {
-    mCompositor = aCompositor;
-  }
+  void ReadUnlock();
+
+  void ReleaseTextureHosts();
+
+  /**
+   * This will synchronously upload any necessary texture contents, making the
+   * sources immediately available for compositing. For texture hosts that
+   * don't have an internal buffer, this is unlikely to actually do anything.
+   */
+  void Upload();
+
+  void SetCompositor(Compositor* aCompositor);
+
+  bool HasDoubleBufferedTiles() { return mHasDoubleBufferedTiles; }
+
+  bool IsValid() const { return !mUninitialized; }
 
 protected:
-  TiledTexture ValidateTile(TiledTexture aTile,
-                            const nsIntPoint& aTileRect,
-                            const nsIntRegion& dirtyRect);
+  TileHost ValidateTile(TileHost aTile,
+                        const nsIntPoint& aTileRect,
+                        const nsIntRegion& dirtyRect);
 
   // do nothing, the desctructor in the texture host takes care of releasing resources
-  void ReleaseTile(TiledTexture aTile) {}
+  void ReleaseTile(TileHost aTile) {}
 
-  void SwapTiles(TiledTexture& aTileA, TiledTexture& aTileB) {
-    std::swap(aTileA, aTileB);
-  }
+  void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
 
 private:
-  Compositor* mCompositor;
-  const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
   CSSToScreenScale mFrameResolution;
+  bool mHasDoubleBufferedTiles;
+  bool mUninitialized;
 };
 
 /**
  * ContentHost for tiled Thebes layers. Since tiled layers are special snow
- * flakes, we don't call UpdateThebes or AddTextureHost, etc. We do call Composite
- * in the usual way though.
- *
- * There is no corresponding content client - on the client side we use a
- * BasicTiledLayerBuffer owned by a BasicTiledThebesLayer. On the host side, we
- * just use a regular ThebesLayerComposite, but with a tiled content host.
+ * flakes, we have a unique update process. All the textures that back the
+ * tiles are added in the usual way, but Updated is called on the host side
+ * in response to a message that describes the transaction for every tile.
+ * Composition happens in the normal way.
  *
  * TiledContentHost has a TiledLayerBufferComposite which keeps hold of the tiles.
  * Each tile has a reference to a texture host. During the layers transaction, we
- * receive a copy of the client-side tile buffer (PaintedTiledLayerBuffer). This is
- * copied into the main memory tile buffer and then deleted. Copying copies tiles,
- * but we only copy references to the underlying texture clients.
+ * receive a list of descriptors for the client-side tile buffer tiles
+ * (UseTiledLayerBuffer). If we receive two transactions before a composition,
+ * we immediately unlock and discard the unused buffer.
  *
- * When the content host is composited, we first upload any pending tiles
- * (Process*UploadQueue), then render (RenderLayerBuffer). The former calls Validate
- * on the tile (via ValidateTile and Update), that calls Update on the texture host,
- * which works as for regular texture hosts. Rendering takes us to RenderTile which
+ * When the content host is composited, we first validate the TiledLayerBuffer
+ * (Upload), which calls Updated on each tile's texture host to make sure the
+ * texture data has been uploaded. For single-buffered tiles, we unlock at this
+ * point, for double-buffered tiles we unlock and discard the last composited
+ * buffer after compositing a new one. Rendering takes us to RenderTile which
  * is similar to Composite for non-tiled ContentHosts.
  */
 class TiledContentHost : public ContentHost,
                          public TiledLayerComposer
 {
 public:
-  TiledContentHost(const TextureInfo& aTextureInfo)
-    : ContentHost(aTextureInfo)
-    , mPendingUpload(false)
-    , mPendingLowPrecisionUpload(false)
-  {
-    MOZ_COUNT_CTOR(TiledContentHost);
-  }
+  TiledContentHost(const TextureInfo& aTextureInfo);
 
-  ~TiledContentHost()
-  {
-    MOZ_COUNT_DTOR(TiledContentHost);
-  }
+  ~TiledContentHost();
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE
   {
     return LayerRenderState();
   }
 
 
   virtual bool UpdateThebes(const ThebesBufferData& aData,
@@ -186,24 +192,24 @@ public:
                             nsIntRegion* aUpdatedRegionBack)
   {
     NS_ERROR("N/A for tiled layers");
     return false;
   }
 
   const nsIntRegion& GetValidLowPrecisionRegion() const
   {
-    return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
+    return mLowPrecisionTiledBuffer.GetValidRegion();
   }
 
-  void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
-                               const SurfaceDescriptorTiles& aTiledDescriptor);
+  void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
+                           const SurfaceDescriptorTiles& aTiledDescriptor);
 
   // Renders a single given tile.
-  void RenderTile(const TiledTexture& aTile,
+  void RenderTile(const TileHost& aTile,
                   EffectChain& aEffectChain,
                   float aOpacity,
                   const gfx::Matrix4x4& aTransform,
                   const gfx::Filter& aFilter,
                   const gfx::Rect& aClipRect,
                   const nsIntRegion& aScreenRegion,
                   const nsIntPoint& aTextureOffset,
                   const nsIntSize& aTextureBounds);
@@ -223,58 +229,45 @@ public:
   virtual void EnsureDeprecatedTextureHost(TextureIdentifier aTextureId,
                                  const SurfaceDescriptor& aSurface,
                                  ISurfaceAllocator* aAllocator,
                                  const TextureInfo& aTextureInfo) MOZ_OVERRIDE
   {
     MOZ_CRASH("Does nothing");
   }
 
-  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE
-  {
-    CompositableHost::SetCompositor(aCompositor);
-    mVideoMemoryTiledBuffer.SetCompositor(aCompositor);
-    mLowPrecisionVideoMemoryTiledBuffer.SetCompositor(aCompositor);
-  }
-
   virtual void Attach(Layer* aLayer,
                       Compositor* aCompositor,
                       AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE;
 
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 #endif
 
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
 private:
-  void ProcessUploadQueue(nsIntRegion* aNewValidRegion,
-                          TiledLayerProperties* aLayerProperties);
-  void ProcessLowPrecisionUploadQueue();
-
   void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
                          const nsIntRegion& aValidRegion,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Filter& aFilter,
                          const gfx::Rect& aClipRect,
                          const nsIntRegion& aMaskRegion,
                          nsIntRect aVisibleRect,
                          gfx::Matrix4x4 aTransform);
 
   void EnsureTileStore() {}
 
-  nsIntRegion                  mRegionToUpload;
-  nsIntRegion                  mLowPrecisionRegionToUpload;
-  BasicTiledLayerBuffer        mMainMemoryTiledBuffer;
-  BasicTiledLayerBuffer        mLowPrecisionMainMemoryTiledBuffer;
-  TiledLayerBufferComposite    mVideoMemoryTiledBuffer;
-  TiledLayerBufferComposite    mLowPrecisionVideoMemoryTiledBuffer;
+  TiledLayerBufferComposite    mTiledBuffer;
+  TiledLayerBufferComposite    mLowPrecisionTiledBuffer;
+  TiledLayerBufferComposite    mOldTiledBuffer;
+  TiledLayerBufferComposite    mOldLowPrecisionTiledBuffer;
   bool                         mPendingUpload : 1;
   bool                         mPendingLowPrecisionUpload : 1;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -40,16 +40,18 @@ public:
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
 
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
 
   // TextureClientDrawTarget
 
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -214,16 +214,18 @@ public:
 
   virtual TextureClientDrawTarget* AsTextureClientDrawTarget() MOZ_OVERRIDE { return this; }
 
   virtual TemporaryRef<gfx::DrawTarget> GetAsDrawTarget() MOZ_OVERRIDE;
 
   virtual bool AllocateForSurface(gfx::IntSize aSize,
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
 private:
   RefPtr<IDirect3DTexture9> mTexture;
   nsRefPtr<IDirect3DSurface9> mD3D9Surface;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   nsRefPtr<gfxASurface> mSurface;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
@@ -266,16 +268,18 @@ public:
 
   virtual TextureClientDrawTarget* AsTextureClientDrawTarget() MOZ_OVERRIDE { return this; }
 
   virtual TemporaryRef<gfx::DrawTarget> GetAsDrawTarget() MOZ_OVERRIDE;
 
   virtual bool AllocateForSurface(gfx::IntSize aSize,
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
 protected:
   nsRefPtr<gfxWindowsSurface> mSurface;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
 };
 
@@ -348,16 +352,18 @@ public:
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
   {
     return nullptr;
   }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
+
 protected:
   TextureHostD3D9(TextureFlags aFlags);
   IDirect3DDevice9* GetDevice();
 
   RefPtr<DataTextureSourceD3D9> mTextureSource;
   RefPtr<IDirect3DTexture9> mTexture;
   RefPtr<CompositorD3D9> mCompositor;
   gfx::IntSize mSize;
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -23,17 +23,17 @@ namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class TextureFactoryIdentifier;
 class SurfaceDescriptor;
 class SurfaceDescriptorTiles;
 class ThebesBufferData;
 class DeprecatedTextureClient;
-class BasicTiledLayerBuffer;
+class ClientTiledLayerBuffer;
 class PTextureChild;
 
 /**
  * A transaction is a set of changes that happenned on the content side, that
  * should be sent to the compositor side.
  * CompositableForwarder is an interface to manage a transaction of
  * compositable objetcs.
  *
@@ -44,17 +44,16 @@ class PTextureChild;
 class CompositableForwarder : public ISurfaceAllocator
 {
   friend class AutoOpenSurface;
   friend class DeprecatedTextureClientShmem;
 public:
 
   CompositableForwarder()
     : mSerial(++sSerialCounter)
-    , mMultiProcess(false)
   {}
 
   /**
    * Setup the IPDL actor for aCompositable to be part of layers
    * transactions.
    */
   virtual void Connect(CompositableClient* aCompositable) = 0;
 
@@ -87,18 +86,22 @@ public:
                                         const nsIntRect& aBufferRect) = 0;
 
   /**
    * 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,
-                                       const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
+  /**
+   * Tell the CompositableHost on the compositor side what TiledLayerBuffer to
+   * use for the next composition.
+   */
+  virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
+                                   const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
 
   /**
    * Create a TextureChild/Parent pair as as well as the TextureHost on the parent side.
    */
   virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData, TextureFlags aFlags) = 0;
 
   /**
    * Communicate to the compositor that the texture identified by aCompositable
@@ -217,47 +220,41 @@ public:
 
   bool IsOnCompositorSide() const MOZ_OVERRIDE { return false; }
 
   /**
    * Returns the type of backend that is used off the main thread.
    * We only don't allow changing the backend type at runtime so this value can
    * be queried once and will not change until Gecko is restarted.
    */
-  LayersBackend GetCompositorBackendType() const
+  virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE
   {
     return mTextureFactoryIdentifier.mParentBackend;
   }
 
   bool SupportsTextureBlitting() const
   {
     return mTextureFactoryIdentifier.mSupportsTextureBlitting;
   }
 
   bool SupportsPartialUploads() const
   {
     return mTextureFactoryIdentifier.mSupportsPartialUploads;
   }
 
-  bool ForwardsToDifferentProcess() const
-  {
-    return mMultiProcess;
-  }
-
   const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
   {
     return mTextureFactoryIdentifier;
   }
 
   int32_t GetSerial() { return mSerial; }
 
 protected:
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
   const int32_t mSerial;
   static mozilla::Atomic<int32_t> sSerialCounter;
-  bool mMultiProcess;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -24,17 +24,17 @@
 #include "mozilla/layers/ThebesLayerComposite.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsRegion.h"                   // for nsIntRegion
 
 namespace mozilla {
 namespace layers {
 
-class BasicTiledLayerBuffer;
+class ClientTiledLayerBuffer;
 class Compositor;
 
 template<typename T>
 CompositableHost* AsCompositable(const T& op)
 {
   return static_cast<CompositableParent*>(op.compositableParent())->GetCompositableHost();
 }
 
@@ -219,28 +219,28 @@ CompositableParentManager::ReceiveCompos
     case CompositableOperation::TOpUpdatePictureRect: {
       const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect();
       CompositableHost* compositable
        = static_cast<CompositableParent*>(op.compositableParent())->GetCompositableHost();
       MOZ_ASSERT(compositable);
       compositable->SetPictureRect(op.picture());
       break;
     }
-    case CompositableOperation::TOpPaintTiledLayerBuffer: {
+    case CompositableOperation::TOpUseTiledLayerBuffer: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
-      const OpPaintTiledLayerBuffer& op = aEdit.get_OpPaintTiledLayerBuffer();
+      const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
       CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
       CompositableHost* compositable =
         compositableParent->GetCompositableHost();
 
       TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer();
       NS_ASSERTION(tileComposer, "compositable is not a tile composer");
 
       const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
-      tileComposer->PaintedTiledLayerBuffer(this, tileDesc);
+      tileComposer->UseTiledLayerBuffer(this, tileDesc);
       break;
     }
     case CompositableOperation::TOpRemoveTexture: {
       const OpRemoveTexture& op = aEdit.get_OpRemoveTexture();
       CompositableHost* compositable = AsCompositable(op);
       RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
 
       MOZ_ASSERT(tex.get());
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -9,16 +9,17 @@
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t
 #include "gfxTypes.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/RefPtr.h"
 #include "nsIMemoryReporter.h"          // for nsIMemoryReporter
 #include "mozilla/Atomics.h"            // for Atomic
+#include "LayersTypes.h"
 
 /*
  * FIXME [bjacob] *** PURE CRAZYNESS WARNING ***
  *
  * This #define is actually needed here, because subclasses of ISurfaceAllocator,
  * namely ShadowLayerForwarder, will or will not override AllocGrallocBuffer
  * depending on whether MOZ_HAVE_SURFACEDESCRIPTORGRALLOC is defined.
  */
@@ -75,16 +76,26 @@ bool ReleaseOwnedSurfaceDescriptor(const
  */
 class ISurfaceAllocator : public AtomicRefCounted<ISurfaceAllocator>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
   ISurfaceAllocator() {}
 
   /**
+   * Returns the type of backend that is used off the main thread.
+   * We only don't allow changing the backend type at runtime so this value can
+   * be queried once and will not change until Gecko is restarted.
+   *
+   * XXX - With e10s this may not be true anymore. we can have accelerated widgets
+   * and non-accelerated widgets (small popups, etc.)
+   */
+  virtual LayersBackend GetCompositorBackendType() const = 0;
+
+  /**
    * Allocate shared memory that can be accessed by only one process at a time.
    * Ownership of this memory is passed when the memory is sent in an IPDL
    * message.
    */
   virtual bool AllocShmem(size_t aSize,
                           mozilla::ipc::SharedMemory::SharedMemoryType aType,
                           mozilla::ipc::Shmem* aShmem) = 0;
 
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -27,17 +27,17 @@ class Thread;
 
 namespace mozilla {
 namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
-class BasicTiledLayerBuffer;
+class ClientTiledLayerBuffer;
 class ImageClient;
 class ImageContainer;
 class ImageBridgeParent;
 class CompositableClient;
 class CompositableTransaction;
 class Image;
 class TextureClient;
 
@@ -275,18 +275,18 @@ public:
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) MOZ_OVERRIDE;
 
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) MOZ_OVERRIDE;
 
   virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
 
-  virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                       const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
+  virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
+                                   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/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -53,16 +53,22 @@ ImageBridgeParent::ImageBridgeParent(Mes
 ImageBridgeParent::~ImageBridgeParent()
 {
   if (mTransport) {
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                      new DeleteTask<Transport>(mTransport));
   }
 }
 
+LayersBackend
+ImageBridgeParent::GetCompositorBackendType() const
+{
+  return Compositor::GetBackend();
+}
+
 void
 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   MessageLoop::current()->PostTask(
     FROM_HERE,
     NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
 }
 
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -37,16 +37,18 @@ class ImageBridgeParent : public PImageB
 {
 public:
   typedef InfallibleTArray<CompositableOperation> EditArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
 
   ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport);
   ~ImageBridgeParent();
 
+  virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
+
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   static PImageBridgeParent*
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   virtual PGrallocBufferParent*
   AllocPGrallocBufferParent(const IntSize&, const uint32_t&, const uint32_t&,
                             MaybeMagicGrallocBufferHandle*) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -169,16 +169,22 @@ LayerTransactionParent::Destroy()
   mDestroyed = true;
   for (size_t i = 0; i < ManagedPLayerParent().Length(); ++i) {
     ShadowLayerParent* slp =
       static_cast<ShadowLayerParent*>(ManagedPLayerParent()[i]);
     slp->Destroy();
   }
 }
 
+LayersBackend
+LayerTransactionParent::GetCompositorBackendType() const
+{
+  return mLayerManager->GetBackendType();
+}
+
 /* virtual */
 bool
 LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
                                          const TargetConfig& targetConfig,
                                          const bool& isFirstPaint,
                                          const bool& scheduleComposite)
 {
   return RecvUpdate(cset, targetConfig, isFirstPaint, scheduleComposite, nullptr);
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -70,16 +70,18 @@ public:
     return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem);
   }
 
   virtual void DeallocShmem(ipc::Shmem& aShmem) MOZ_OVERRIDE
   {
     PLayerTransactionParent::DeallocShmem(aShmem);
   }
 
+  virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
+
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
 protected:
   virtual bool RecvUpdate(const EditArray& cset,
                           const TargetConfig& targetConfig,
                           const bool& isFirstPaint,
                           const bool& scheduleComposite,
                           EditReplyArray* reply) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -250,18 +250,44 @@ struct OpSetRoot          { PLayer root;
 struct OpInsertAfter      { PLayer container; PLayer childLayer; PLayer after; };
 struct OpPrependChild     { PLayer container; PLayer childLayer; };
 struct OpRemoveChild      { PLayer container; PLayer childLayer; };
 struct OpRepositionChild  { PLayer container; PLayer childLayer; PLayer after; };
 struct OpRaiseToTopChild  { PLayer container; PLayer childLayer; };
 
 struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
 
-// Paint (buffer update)
-struct OpPaintTiledLayerBuffer {
+union TileLock {
+  Shmem;
+  uintptr_t;
+};
+
+struct TexturedTileDescriptor {
+  PTexture texture;
+  TileLock sharedLock;
+};
+
+struct PlaceholderTileDescriptor {
+};
+
+union TileDescriptor {
+  TexturedTileDescriptor;
+  PlaceholderTileDescriptor;
+};
+
+struct SurfaceDescriptorTiles {
+  nsIntRegion validRegion;
+  nsIntRegion paintedRegion;
+  TileDescriptor[] tiles;
+  int         retainedWidth;
+  int         retainedHeight;
+  float       resolution;
+};
+
+struct OpUseTiledLayerBuffer {
   PCompositable compositable;
   SurfaceDescriptorTiles tileLayerDescriptor;
 };
 
 struct OpCreatedTexture {
   PCompositable compositable;
   uint32_t textureId;
   SurfaceDescriptor descriptor;
@@ -344,17 +370,17 @@ union CompositableOperation {
   OpCreatedTexture;
   OpCreatedIncrementalTexture;
   OpDestroyThebesBuffer;
 
   OpPaintTexture;
   OpPaintTextureRegion;
   OpPaintTextureIncremental;
 
-  OpPaintTiledLayerBuffer;
+  OpUseTiledLayerBuffer;
 
   OpRemoveTexture;
 
   OpUpdateTexture;
   OpUseTexture;
   OpUseComponentAlphaTextures;
 };
 
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -51,42 +51,16 @@ struct SurfaceDescriptorMacIOSurface {
 
 struct SharedTextureDescriptor {
   SharedTextureShareType shareType;
   SharedTextureHandle handle;
   IntSize size;
   bool inverted;
 };
 
-struct BasicShmTileDescriptor {
-  Shmem reusableSurface;
-};
-
-struct BasicTileDescriptor {
-  uintptr_t reusableSurface;
-};
-
-struct PlaceholderTileDescriptor {
-};
-
-union TileDescriptor {
-  BasicTileDescriptor;
-  BasicShmTileDescriptor;
-  PlaceholderTileDescriptor;
-};
-
-struct SurfaceDescriptorTiles {
-  nsIntRegion validRegion;
-  nsIntRegion paintedRegion;
-  TileDescriptor[] tiles;
-  int         retainedWidth;
-  int         retainedHeight;
-  float       resolution;
-};
-
 struct NewSurfaceDescriptorGralloc {
   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.
    */
   IntSize size;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -44,17 +44,17 @@ using namespace mozilla::dom;
 
 namespace mozilla {
 namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
-class BasicTiledLayerBuffer;
+class ClientTiledLayerBuffer;
 
 typedef nsTArray<SurfaceDescriptor> BufferArray;
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
 
 class Transaction
 {
 public:
@@ -172,17 +172,16 @@ struct AutoTxnEnd {
   ~AutoTxnEnd() { mTxn->End(); }
   Transaction* mTxn;
 };
 
 void
 CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
 {
   mTextureFactoryIdentifier = aIdentifier;
-  mMultiProcess = aIdentifier.mParentProcessId != XRE_GetProcessType();
 }
 
 ShadowLayerForwarder::ShadowLayerForwarder()
  : mDiagnosticTypes(DIAGNOSTIC_NONE)
  , mIsFirstPaint(false)
  , mWindowOverlayChanged(false)
 {
   mTxn = new Transaction();
@@ -322,21 +321,21 @@ ShadowLayerForwarder::CheckSurfaceDescri
     shmem.AssertInvariants();
     MOZ_ASSERT(mShadowManager &&
                mShadowManager->IsTrackingSharedMemory(shmem.mSegment));
   }
 }
 #endif
 
 void
-ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                              const SurfaceDescriptorTiles& aTileLayerDescriptor)
+ShadowLayerForwarder::UseTiledLayerBuffer(CompositableClient* aCompositable,
+                                          const SurfaceDescriptorTiles& aTileLayerDescriptor)
 {
-  mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
-                                               aTileLayerDescriptor));
+  mTxn->AddNoSwapPaint(OpUseTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
+                                             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
@@ -23,17 +23,17 @@
  
 struct nsIntPoint;
 struct nsIntRect;
 class gfxASurface;
 
 namespace mozilla {
 namespace layers {
 
-class BasicTiledLayerBuffer;
+class ClientTiledLayerBuffer;
 class CanvasClient;
 class CanvasLayerComposite;
 class CanvasSurface;
 class ColorLayerComposite;
 class CompositableChild;
 class ContainerLayerComposite;
 class ContentClient;
 class ContentClientRemote;
@@ -250,24 +250,20 @@ public:
    * LayerTransactionParent::UpdateMask and accompanying ipdl
    * will need changing to update properties for other kinds
    * of mask layer.
    */
   void SetMask(ShadowableLayer* aLayer,
                ShadowableLayer* aMaskLayer);
 
   /**
-   * 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).
+   * See CompositableForwarder::UseTiledLayerBuffer
    */
-  virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
-                                       const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
+  virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
+                                   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/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -101,16 +101,17 @@ EXPORTS.mozilla.layers += [
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/ImageClient.h',
     'client/TextureClient.h',
+    'client/TextureClientPool.h',
     'client/TiledContentClient.h',
     'composite/APZCTreeManager.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
     'composite/ImageHost.h',
@@ -229,16 +230,17 @@ UNIFIED_SOURCES += [
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
     'client/ClientThebesLayer.cpp',
     'client/ClientTiledThebesLayer.cpp',
     'client/CompositableClient.cpp',
     'client/ContentClient.cpp',
     'client/ImageClient.cpp',
     'client/TextureClient.cpp',
+    'client/TextureClientPool.cpp',
     'client/TiledContentClient.cpp',
     'composite/APZCTreeManager.cpp',
     'composite/AsyncCompositionManager.cpp',
     'composite/CanvasLayerComposite.cpp',
     'composite/ColorLayerComposite.cpp',
     'composite/CompositableHost.cpp',
     'composite/ContainerLayerComposite.cpp',
     'composite/ContentHost.cpp',
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -42,16 +42,17 @@
 #include "nsString.h"                   // for nsString, nsAutoCString, etc
 #include "DecomposeIntoNoRepeatTriangles.h"
 #include "ScopedGLHelpers.h"
 #include "GLReadTexImageHelper.h"
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
+
 #include "GeckoProfiler.h"
 
 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
 
 namespace mozilla {
 
 using namespace std;
 using namespace gfx;
@@ -131,16 +132,82 @@ DrawQuads(GLContext *aGLContext,
   aGLContext->fDisableVertexAttribArray(vertAttribIndex);
   if (texCoords) {
     aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
+#ifdef MOZ_WIDGET_GONK
+CompositorOGLGonkBackendSpecificData::CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor)
+  : mCompositor(aCompositor)
+{
+}
+
+CompositorOGLGonkBackendSpecificData::~CompositorOGLGonkBackendSpecificData()
+{
+  // Delete all textures by calling EndFrame twice
+  gl()->MakeCurrent();
+  EndFrame();
+  EndFrame();
+}
+
+GLContext*
+CompositorOGLGonkBackendSpecificData::gl() const
+{
+  return mCompositor->gl();
+}
+
+GLuint
+CompositorOGLGonkBackendSpecificData::GetTexture()
+{
+  GLuint texture = 0;
+
+  if (!mUnusedTextures.IsEmpty()) {
+    // Try to reuse one from the unused pile first
+    texture = mUnusedTextures[0];
+    mUnusedTextures.RemoveElementAt(0);
+  } else if (gl()->MakeCurrent()) {
+    // There isn't one to reuse, create one.
+    gl()->fGenTextures(1, &texture);
+  }
+
+  if (texture) {
+    mCreatedTextures.AppendElement(texture);
+  }
+
+  return texture;
+}
+
+void
+CompositorOGLGonkBackendSpecificData::EndFrame()
+{
+  gl()->MakeCurrent();
+
+  // Some platforms have issues unlocking Gralloc buffers even when they're
+  // rebound.
+  if (gfxPrefs::OverzealousGrallocUnlocking()) {
+    mUnusedTextures.AppendElements(mCreatedTextures);
+    mCreatedTextures.Clear();
+  }
+
+  // Delete unused textures
+  for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
+    GLuint texture = mUnusedTextures[i];
+    gl()->fDeleteTextures(1, &texture);
+  }
+  mUnusedTextures.Clear();
+
+  // Move all created textures into the unused pile
+  mUnusedTextures.AppendElements(mCreatedTextures);
+  mCreatedTextures.Clear();
+}
+#endif
+
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
@@ -1294,16 +1361,22 @@ CompositorOGL::EndFrame()
     CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     mCurrentRenderTarget = nullptr;
     return;
   }
 
   mCurrentRenderTarget = nullptr;
 
+#ifdef MOZ_WIDGET_GONK
+  if (mCompositorBackendSpecificData) {
+    static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
+  }
+#endif
+
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
 {
   // This lets us reftest and screenshot content rendered externally
@@ -1402,16 +1475,27 @@ CompositorOGL::Resume()
     return false;
 
   // RenewSurface internally calls MakeCurrent.
   return gl()->RenewSurface();
 #endif
   return true;
 }
 
+#ifdef MOZ_WIDGET_GONK
+CompositorBackendSpecificData*
+CompositorOGL::GetCompositorBackendSpecificData()
+{
+  if (!mCompositorBackendSpecificData) {
+    mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
+  }
+  return mCompositorBackendSpecificData;
+}
+#endif
+
 TemporaryRef<DataTextureSource>
 CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
 {
   RefPtr<DataTextureSource> result =
     new TextureImageTextureSourceOGL(mGLContext, aFlags);
   return result;
 }
 
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -26,16 +26,19 @@
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
 #include "VBOArena.h"                   // for gl::VBOArena
+#ifdef MOZ_WIDGET_GONK
+#include <ui/GraphicBuffer.h>
+#endif
 
 class gfx3DMatrix;
 class nsIWidget;
 
 namespace mozilla {
 class TimeStamp;
 
 namespace gfx {
@@ -154,16 +157,20 @@ public:
     return LayersBackend::LAYERS_OPENGL;
   }
 
   virtual void Pause() MOZ_OVERRIDE;
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
+#ifdef MOZ_WIDGET_GONK
+  virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
+#endif
+
   GLContext* gl() const { return mGLContext; }
   gfx::SurfaceFormat GetFBOFormat() const {
     return gfx::SurfaceFormat::R8G8B8A8;
   }
 
   /**
    * The compositor provides with temporary textures for use with direct
    * textruing like gralloc texture.
@@ -308,14 +315,38 @@ private:
   // The index of the texture in this array must correspond to the texture unit.
   nsTArray<GLuint> mTextures;
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
    */
   GLint mHeight;
+
+#ifdef MOZ_WIDGET_GONK
+  RefPtr<CompositorBackendSpecificData> mCompositorBackendSpecificData;
+#endif
 };
 
+#ifdef MOZ_WIDGET_GONK
+class CompositorOGLGonkBackendSpecificData : public CompositorBackendSpecificData
+{
+public:
+  CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor);
+  virtual ~CompositorOGLGonkBackendSpecificData();
+
+  GLuint GetTexture();
+  void EndFrame();
+
+private:
+  gl::GLContext* gl() const;
+
+  RefPtr<CompositorOGL> mCompositor;
+
+  nsTArray<GLuint> mCreatedTextures;
+  nsTArray<GLuint> mUnusedTextures;
+};
+#endif
+
 }
 }
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -2,17 +2,16 @@
 //  * 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/. */
 
 #ifdef MOZ_WIDGET_GONK
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/layers/GrallocTextureClient.h"
-#include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "gfx2DGlue.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "GrallocImages.h"
 
@@ -90,38 +89,26 @@ GrallocTextureClientOGL::DropTextureData
     return result;
   }
 }
 
 GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
                                                  gfx::IntSize aSize,
                                                  TextureFlags aFlags)
 : BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aFlags)
-, mAllocator(nullptr)
 , mMappedBuffer(nullptr)
 {
   InitWith(aActor, aSize);
   MOZ_COUNT_CTOR(GrallocTextureClientOGL);
 }
 
-GrallocTextureClientOGL::GrallocTextureClientOGL(CompositableClient* aCompositable,
-                                                 gfx::SurfaceFormat aFormat,
-                                                 TextureFlags aFlags)
-: BufferTextureClient(aCompositable, aFormat, aFlags)
-, mAllocator(nullptr)
-, mMappedBuffer(nullptr)
-{
-  MOZ_COUNT_CTOR(GrallocTextureClientOGL);
-}
-
 GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
                                                  gfx::SurfaceFormat aFormat,
                                                  TextureFlags aFlags)
-: BufferTextureClient(nullptr, aFormat, aFlags)
-, mAllocator(aAllocator)
+: BufferTextureClient(aAllocator, aFormat, aFlags)
 , mMappedBuffer(nullptr)
 {
   MOZ_COUNT_CTOR(GrallocTextureClientOGL);
 }
 
 GrallocTextureClientOGL::~GrallocTextureClientOGL()
 {
   MOZ_COUNT_DTOR(GrallocTextureClientOGL);
@@ -452,21 +439,12 @@ GrallocTextureClientOGL::Allocate(uint32
 size_t
 GrallocTextureClientOGL::GetBufferSize() const
 {
   // see Bug 908196
   MOZ_CRASH("This method should never be called.");
   return 0;
 }
 
-ISurfaceAllocator*
-GrallocTextureClientOGL::GetAllocator()
-{
-  MOZ_ASSERT(mCompositable || mAllocator);
-  return mCompositable ?
-         mCompositable->GetForwarder() :
-         mAllocator;
-}
-
 } // namesapace layers
 } // namesapace mozilla
 
 #endif // MOZ_WIDGET_GONK
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -32,31 +32,30 @@ class GraphicBufferLocked;
  * This is only used in Firefox OS
  */
 class GrallocTextureClientOGL : public BufferTextureClient
 {
 public:
   GrallocTextureClientOGL(GrallocBufferActor* aActor,
                           gfx::IntSize aSize,
                           TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
-  GrallocTextureClientOGL(CompositableClient* aCompositable,
-                          gfx::SurfaceFormat aFormat,
-                          TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
   GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
                           gfx::SurfaceFormat aFormat,
                           TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
 
   ~GrallocTextureClientOGL();
 
   virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
@@ -102,29 +101,25 @@ public:
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual size_t GetBufferSize() const MOZ_OVERRIDE;
 
   void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
 
 protected:
-  ISurfaceAllocator* GetAllocator();
-
   /**
    * Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
    */
   GrallocBufferActor* mGrallocActor;
 
   RefPtr<GraphicBufferLocked> mBufferLocked;
 
   android::sp<android::GraphicBuffer> mGraphicBuffer;
 
-  RefPtr<ISurfaceAllocator> mAllocator;
-
   /**
    * Points to a mapped gralloc buffer between calls to lock and unlock.
    * Should be null outside of the lock-unlock pair.
    */
   uint8_t* mMappedBuffer;
 
   RefPtr<gfx::DrawTarget> mDrawTarget;
 
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -99,17 +99,18 @@ GrallocTextureSourceOGL::GrallocTextureS
 }
 
 GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
 {
   DeallocateDeviceData();
   mCompositor = nullptr;
 }
 
-void GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
+void
+GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
 {
   /*
    * The job of this function is to ensure that the texture is tied to the
    * android::GraphicBuffer, so that texturing will source the GraphicBuffer.
    *
    * To this effect we create an EGLImage wrapping this GraphicBuffer,
    * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
    * texture using fEGLImageTargetTexture2D.
@@ -120,27 +121,56 @@ void GrallocTextureSourceOGL::BindTextur
   }
   gl()->MakeCurrent();
 
   GLuint tex = GetGLTexture();
   GLuint textureTarget = GetTextureTarget();
 
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(textureTarget, tex);
+
+  if (mCompositableBackendData) {
+    // There are two paths for locking/unlocking - if mCompositableBackendData is
+    // set, we use the texture on there, otherwise we use
+    // CompositorBackendSpecificData from the compositor and bind the EGLImage
+    // only in Lock().
+    if (!mEGLImage) {
+      mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
+    }
+    gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
+  }
+
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+}
+
+void GrallocTextureSourceOGL::Lock()
+{
+  if (mCompositableBackendData) return;
+
+  MOZ_ASSERT(IsValid());
+
+  CompositorOGLGonkBackendSpecificData* backendData =
+    static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
+  mTexture = backendData->GetTexture();
+
+  GLuint textureTarget = GetTextureTarget();
+
+  gl()->MakeCurrent();
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl()->fBindTexture(textureTarget, mTexture);
   if (!mEGLImage) {
     mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
   }
   gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 bool
 GrallocTextureSourceOGL::IsValid() const
 {
-  return !!gl() && !!mGraphicBuffer.get();
+  return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
 }
 
 gl::GLContext*
 GrallocTextureSourceOGL::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
@@ -173,17 +203,17 @@ GrallocTextureSourceOGL::GetFormat() con
     return gfx::SurfaceFormat::R8G8B8A8;
   }
   return mFormat;
 }
 
 void
 GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
 {
-  if (!aBackendData || !mGraphicBuffer.get()) {
+  if (!aBackendData) {
     mCompositableBackendData = nullptr;
     DeallocateDeviceData();
     return;
   }
 
   if (mCompositableBackendData != aBackendData) {
     mNeedsReset = true;
   }
@@ -280,17 +310,21 @@ void
 GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
 {
   mTextureSource->SetCompositor(static_cast<CompositorOGL*>(aCompositor));
 }
 
 bool
 GrallocTextureHostOGL::Lock()
 {
-  return IsValid();
+  if (IsValid()) {
+    mTextureSource->Lock();
+    return true;
+  }
+  return false;
 }
 
 void
 GrallocTextureHostOGL::Unlock()
 {
   // Unlock is done internally by binding the texture to another gralloc buffer
 }
 
@@ -379,18 +413,22 @@ GrallocTextureSourceOGL::GetAsSurface() 
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   return surf.forget();
 }
 
 GLuint
 GrallocTextureSourceOGL::GetGLTexture()
 {
-  mCompositableBackendData->SetCompositor(mCompositor);
-  return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
+  if (mCompositableBackendData) {
+    mCompositableBackendData->SetCompositor(mCompositor);
+    return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
+  }
+
+  return mTexture;
 }
 
 void
 GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
 {
   mCompositableBackendData = aBackendData;
   if (mTextureSource) {
     mTextureSource->SetCompositableBackendSpecificData(aBackendData);
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -57,20 +57,23 @@ public:
   {
     mGraphicBuffer = nullptr;
   }
 
   TemporaryRef<gfx::DataSourceSurface> GetAsSurface();
 
   GLuint GetGLTexture();
 
+  void Lock();
+
 protected:
   CompositorOGL* mCompositor;
   android::sp<android::GraphicBuffer> mGraphicBuffer;
   EGLImage mEGLImage;
+  GLuint mTexture;
   gfx::SurfaceFormat mFormat;
   bool mNeedsReset;
 };
 
 class GrallocTextureHostOGL : public TextureHost
 #if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
                             , public TextureHostOGL
 #endif
--- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
@@ -31,16 +31,18 @@ public:
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mSurface; }
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
 protected:
   RefPtr<MacIOSurface> mSurface;
   bool mIsLocked;
 };
 
 }
 }
 
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -41,16 +41,18 @@ public:
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual bool Lock(OpenMode mode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
   void InitWith(gl::SharedTextureHandle aHandle,
                 gfx::IntSize aSize,
                 gl::SharedTextureShareType aShareType,
                 bool aInverted = false);
 
   virtual gfx::IntSize GetSize() const { return mSize; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE
@@ -87,16 +89,18 @@ public:
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
 
+  virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
+
   void InitWith(gfx::SurfaceStream* aStream);
 
   virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
 
 protected:
   bool mIsLocked;
   RefPtr<gfx::SurfaceStream> mStream;
   RefPtr<gl::GLContext> mGL;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -151,16 +151,19 @@ private:
   // preference value, defaulting to true.
   DECL_GFX_PREF(Once, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, true);
 #endif
   DECL_GFX_PREF(Live, "layers.draw-bigimage-borders",          DrawBigImageBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-borders",                   DrawLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-tile-borders",              DrawTileBorders, bool, false);
   DECL_GFX_PREF(Once, "layers.dump",                           LayersDump, bool, false);
   DECL_GFX_PREF(Once, "layers.enable-tiles",                   LayersTilesEnabled, bool, false);
+  DECL_GFX_PREF(Once, "layers.force-per-tile-drawing",         PerTileDrawing, bool, false);
+  DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking",  OverzealousGrallocUnlocking, bool, false);
+  DECL_GFX_PREF(Once, "layers.force-shmem-tiles",              ForceShmemTiles, bool, false);
   DECL_GFX_PREF(Live, "layers.frame-counter",                  DrawFrameCounter, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-buffer",           UseLowPrecisionBuffer, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-resolution",       LowPrecisionResolution, int32_t, 250);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.enabled", LayersOffMainThreadCompositionEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-enabled", LayersOffMainThreadCompositionForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.testing.enabled", LayersOffMainThreadCompositionTestingEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.orientation.sync.timeout",       OrientationSyncMillis, uint32_t, (uint32_t)0);