Bug 1180326 - Part 1: Abstract parts of the client side tiling that we need. r=jrmuizel
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 29 Jul 2015 12:01:11 -0400
changeset 286895 24d32648073cc05efbfa67421aa035dc5b041ff4
parent 286894 646c99efe919cbd123437448deb5dce8a3429720
child 286896 e1bfa923a761d62b92657ccbbfbc5774fac4b7f3
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1180326
milestone42.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 1180326 - Part 1: Abstract parts of the client side tiling that we need. r=jrmuizel
gfx/layers/client/ClientTiledPaintedLayer.cpp
gfx/layers/client/TextureClientPool.h
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -279,73 +279,73 @@ ClientTiledPaintedLayer::RenderHighPreci
   // If we have no high-precision stuff to draw, or we have started drawing low-precision
   // already, then we shouldn't do anything there.
   if (aInvalidRegion.IsEmpty() || mPaintData.mLowPrecisionPaintCount != 0) {
     return false;
   }
 
   // Only draw progressively when the resolution is unchanged
   if (UseProgressiveDraw() &&
-      mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
+      mContentClient->GetTiledBuffer()->GetFrameResolution() == mPaintData.mResolution) {
     // Store the old valid region, then clear it before painting.
     // We clip the old valid region to the visible region, as it only gets
     // used to decide stale content (currently valid and previously visible)
-    nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
+    nsIntRegion oldValidRegion = mContentClient->GetTiledBuffer()->GetValidRegion();
     oldValidRegion.And(oldValidRegion, aVisibleRegion);
     if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
       oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
     }
 
     TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());
 
-    return mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, aInvalidRegion,
+    return mContentClient->GetTiledBuffer()->ProgressiveUpdate(mValidRegion, aInvalidRegion,
                       oldValidRegion, &mPaintData, aCallback, aCallbackData);
   }
 
   // Otherwise do a non-progressive paint
 
   mValidRegion = aVisibleRegion;
   if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
     mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
   }
 
   TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
   TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(mValidRegion).c_str());
 
-  mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
-  mContentClient->mTiledBuffer.PaintThebes(mValidRegion, aInvalidRegion, aInvalidRegion,
-                                           aCallback, aCallbackData);
+  mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
+  mContentClient->GetTiledBuffer()->PaintThebes(mValidRegion, aInvalidRegion, aInvalidRegion,
+                                                aCallback, aCallbackData);
   mPaintData.mPaintFinished = true;
   return true;
 }
 
 bool
 ClientTiledPaintedLayer::RenderLowPrecision(nsIntRegion& aInvalidRegion,
                                            const nsIntRegion& aVisibleRegion,
                                            LayerManager::DrawPaintedLayerCallback aCallback,
                                            void* aCallbackData)
 {
   // Render the low precision buffer, if the visible region is larger than the
   // critical display port.
   if (!nsIntRegion(LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)).Contains(aVisibleRegion)) {
-    nsIntRegion oldValidRegion = mContentClient->mLowPrecisionTiledBuffer.GetValidRegion();
+    nsIntRegion oldValidRegion = mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
     oldValidRegion.And(oldValidRegion, aVisibleRegion);
 
     bool updatedBuffer = false;
 
     // If the frame resolution or format have changed, invalidate the buffer
-    if (mContentClient->mLowPrecisionTiledBuffer.GetFrameResolution() != mPaintData.mResolution ||
-        mContentClient->mLowPrecisionTiledBuffer.HasFormatChanged()) {
+    if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() != mPaintData.mResolution ||
+        mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
       if (!mLowPrecisionValidRegion.IsEmpty()) {
         updatedBuffer = true;
       }
       oldValidRegion.SetEmpty();
       mLowPrecisionValidRegion.SetEmpty();
-      mContentClient->mLowPrecisionTiledBuffer.ResetPaintedAndValidState();
-      mContentClient->mLowPrecisionTiledBuffer.SetFrameResolution(mPaintData.mResolution);
+      mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
+      mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
       aInvalidRegion = aVisibleRegion;
     }
 
     // Invalidate previously valid content that is no longer visible
     if (mPaintData.mLowPrecisionPaintCount == 1) {
       mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
     }
     mPaintData.mLowPrecisionPaintCount++;
@@ -353,29 +353,29 @@ ClientTiledPaintedLayer::RenderLowPrecis
     // Remove the valid high-precision region from the invalid low-precision
     // region. We don't want to spend time drawing things twice.
     aInvalidRegion.Sub(aInvalidRegion, mValidRegion);
 
     TILING_LOG("TILING %p: Progressive paint: low-precision invalid region is %s\n", this, Stringify(aInvalidRegion).c_str());
     TILING_LOG("TILING %p: Progressive paint: low-precision old valid region is %s\n", this, Stringify(oldValidRegion).c_str());
 
     if (!aInvalidRegion.IsEmpty()) {
-      updatedBuffer = mContentClient->mLowPrecisionTiledBuffer.ProgressiveUpdate(
+      updatedBuffer = mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
                             mLowPrecisionValidRegion, aInvalidRegion, oldValidRegion,
                             &mPaintData, aCallback, aCallbackData);
     }
 
     TILING_LOG("TILING %p: Progressive paint: low-precision new valid region is %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
     return updatedBuffer;
   }
   if (!mLowPrecisionValidRegion.IsEmpty()) {
     TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
     // Clear the low precision tiled buffer.
     mLowPrecisionValidRegion.SetEmpty();
-    mContentClient->mLowPrecisionTiledBuffer.ResetPaintedAndValidState();
+    mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
     // Return true here so we send a Painted callback after clearing the valid
     // region of the low precision buffer. This allows the shadow buffer's valid
     // region to be updated and the associated resources to be freed.
     return true;
   }
   return false;
 }
 
@@ -391,26 +391,26 @@ ClientTiledPaintedLayer::EndPaint()
 void
 ClientTiledPaintedLayer::RenderLayer()
 {
   LayerManager::DrawPaintedLayerCallback callback =
     ClientManager()->GetPaintedLayerCallback();
   void *data = ClientManager()->GetPaintedLayerCallbackData();
 
   if (!mContentClient) {
-    mContentClient = new TiledContentClient(this, ClientManager());
+    mContentClient = new MultiTiledContentClient(this, ClientManager());
 
     mContentClient->Connect();
     ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
     MOZ_ASSERT(mContentClient->GetForwarder());
   }
 
-  if (mContentClient->mTiledBuffer.HasFormatChanged()) {
+  if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
     mValidRegion = nsIntRegion();
-    mContentClient->mTiledBuffer.ResetPaintedAndValidState();
+    mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
   }
 
   TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str());
   TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(mValidRegion).c_str());
   TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
 
   nsIntRegion neededRegion = mVisibleRegion;
 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
@@ -469,30 +469,30 @@ ClientTiledPaintedLayer::RenderLayer()
   } else {
     if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
       invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
     }
     TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
   }
 
   nsIntRegion lowPrecisionInvalidRegion;
-  if (gfxPrefs::UseLowPrecisionBuffer()) {
+  if (mContentClient->GetLowPrecisionTiledBuffer()) {
     // Calculate the invalid region for the low precision buffer. Make sure
     // to remove the valid high-precision area so we don't double-paint it.
     lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
     lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion);
   }
   TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str());
 
   bool updatedHighPrecision = RenderHighPrecision(invalidRegion,
                                                   neededRegion,
                                                   callback, data);
   if (updatedHighPrecision) {
     ClientManager()->Hold(this);
-    mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
+    mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
 
     if (!mPaintData.mPaintFinished) {
       // There is still more high-res stuff to paint, so we're not
       // done yet. A subsequent transaction will take care of this.
       ClientManager()->SetRepeatTransaction();
       return;
     }
   }
@@ -515,17 +515,17 @@ ClientTiledPaintedLayer::RenderLayer()
     return;
   }
 
   bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
                                                 neededRegion,
                                                 callback, data);
   if (updatedLowPrecision) {
     ClientManager()->Hold(this);
-    mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
+    mContentClient->UpdatedBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
 
     if (!mPaintData.mPaintFinished) {
       // There is still more low-res stuff to paint, so we're not
       // done yet. A subsequent transaction will take care of this.
       ClientManager()->SetRepeatTransaction();
       return;
     }
   }
--- a/gfx/layers/client/TextureClientPool.h
+++ b/gfx/layers/client/TextureClientPool.h
@@ -13,50 +13,66 @@
 #include "nsITimer.h"
 #include <stack>
 
 namespace mozilla {
 namespace layers {
 
 class ISurfaceAllocator;
 
-class TextureClientPool final
+class TextureClientAllocator
+{
+protected:
+  virtual ~TextureClientAllocator() {}
+public:
+  NS_INLINE_DECL_REFCOUNTING(TextureClientAllocator)
+
+  virtual already_AddRefed<TextureClient> GetTextureClient() = 0;
+
+  /**
+   * Return a TextureClient that is not yet ready to be reused, but will be
+   * imminently.
+   */
+  virtual void ReturnTextureClientDeferred(TextureClient *aClient) = 0;
+
+  virtual void ReportClientLost() = 0;
+};
+
+class TextureClientPool final : public TextureClientAllocator
 {
   ~TextureClientPool();
 
 public:
-  NS_INLINE_DECL_REFCOUNTING(TextureClientPool)
-
   TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
                     uint32_t aMaxTextureClients,
                     uint32_t aShrinkTimeoutMsec,
                     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.
    */
-  already_AddRefed<TextureClient> GetTextureClient();
+  already_AddRefed<TextureClient> GetTextureClient() override;
 
   /**
    * 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);
+  void ReturnTextureClientDeferred(TextureClient *aClient) override;
 
   /**
    * Attempt to shrink the pool so that there are no more than
    * mMaxTextureClients clients outstanding.
    */
   void ShrinkToMaximumSize();
 
   /**
@@ -70,17 +86,17 @@ public:
    * ReturnTextureClientDeferred.
    */
   void ReturnDeferredClients();
 
   /**
    * Report that a client retrieved via GetTextureClient() has become
    * unusable, so that it will no longer be tracked.
    */
-  void ReportClientLost();
+  virtual void ReportClientLost() override;
 
   /**
    * Calling this will cause the pool to attempt to relinquish any unused
    * clients.
    */
   void Clear();
 
   gfx::SurfaceFormat GetFormat() { return mFormat; }
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -82,45 +82,48 @@ static void DrawDebugOverlay(mozilla::gf
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 
-TiledContentClient::TiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
-                                       ClientLayerManager* aManager)
-  : CompositableClient(aManager->AsShadowForwarder())
+MultiTiledContentClient::MultiTiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
+                                                 ClientLayerManager* aManager)
+  : TiledContentClient(aManager)
 {
-  MOZ_COUNT_CTOR(TiledContentClient);
+  MOZ_COUNT_CTOR(MultiTiledContentClient);
 
-  mTiledBuffer = ClientTiledLayerBuffer(aPaintedLayer, this, aManager,
-                                        &mSharedFrameMetricsHelper);
-  mLowPrecisionTiledBuffer = ClientTiledLayerBuffer(aPaintedLayer, this, aManager,
-                                                    &mSharedFrameMetricsHelper);
+  mTiledBuffer = ClientMultiTiledLayerBuffer(aPaintedLayer, this, aManager,
+                                             &mSharedFrameMetricsHelper);
+  mLowPrecisionTiledBuffer = ClientMultiTiledLayerBuffer(aPaintedLayer, this, aManager,
+                                                         &mSharedFrameMetricsHelper);
 
   mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution());
+  mHasLowPrecision = gfxPrefs::UseLowPrecisionBuffer();
 }
 
 void
-TiledContentClient::ClearCachedResources()
+MultiTiledContentClient::ClearCachedResources()
 {
   CompositableClient::ClearCachedResources();
   mTiledBuffer.DiscardBuffers();
   mLowPrecisionTiledBuffer.DiscardBuffers();
 }
 
 void
-TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
+MultiTiledContentClient::UpdatedBuffer(TiledBufferType aType)
 {
-  ClientTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
+  ClientMultiTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     ? &mLowPrecisionTiledBuffer
     : &mTiledBuffer;
 
+  MOZ_ASSERT(aType != LOW_PRECISION_TILED_BUFFER || mHasLowPrecision);
+
   // Take a ReadLock on behalf of the TiledContentHost. This
   // reference will be adopted when the descriptor is opened in
   // TiledLayerBufferComposite.
   buffer->ReadLock();
 
   mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
   buffer->ClearPaintedRegion();
 }
@@ -278,25 +281,22 @@ SharedFrameMetricsHelper::AboutToChecker
     TILING_LOG("TILING: About to checkerboard; painted %s\n", Stringify(painted).c_str());
     TILING_LOG("TILING: About to checkerboard; compositor %s\n", Stringify(aCompositorMetrics).c_str());
     TILING_LOG("TILING: About to checkerboard; showing %s\n", Stringify(showing).c_str());
     return true;
   }
   return false;
 }
 
-ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
-                                               CompositableClient* aCompositableClient,
-                                               ClientLayerManager* aManager,
-                                               SharedFrameMetricsHelper* aHelper)
-  : mPaintedLayer(aPaintedLayer)
-  , mCompositableClient(aCompositableClient)
+ClientMultiTiledLayerBuffer::ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
+                                                         CompositableClient* aCompositableClient,
+                                                         ClientLayerManager* aManager,
+                                                         SharedFrameMetricsHelper* aHelper)
+  : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient)
   , mManager(aManager)
-  , mLastPaintContentType(gfxContentType::COLOR)
-  , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
   , mSharedFrameMetricsHelper(aHelper)
 {
 }
 
 bool
 ClientTiledLayerBuffer::HasFormatChanged() const
 {
   SurfaceMode mode;
@@ -323,17 +323,17 @@ ClientTiledLayerBuffer::GetContentType(S
         !gfxPrefs::TiledDrawTargetEnabled()) {
       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
     } else {
       content = gfxContentType::COLOR;
     }
 #endif
   } else if (mode == SurfaceMode::SURFACE_OPAQUE) {
 #if defined(MOZ_GFX_OPTIMIZE_MOBILE) || defined(MOZ_WIDGET_GONK)
-    if (mResolution != 1) {
+    if (IsLowPrecision()) {
       // If we're in low-res mode, drawing can sample from outside the visible
       // region. Make sure that we only sample transparency if that happens.
       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
       content = gfxContentType::COLOR_ALPHA;
     }
 #else
     if (mPaintedLayer->MayResample()) {
       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
@@ -518,16 +518,17 @@ TileClient::TileClient(const TileClient&
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
   mCompositableClient = o.mCompositableClient;
   mUpdateRect = o.mUpdateRect;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
+  mAllocator = o.mAllocator;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
 }
 
 TileClient&
 TileClient::operator=(const TileClient& o)
 {
   if (this == &o) return *this;
@@ -538,16 +539,17 @@ TileClient::operator=(const TileClient& 
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
   mCompositableClient = o.mCompositableClient;
   mUpdateRect = o.mUpdateRect;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
+  mAllocator = o.mAllocator;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
   return *this;
 }
 
 void
 TileClient::Dump(std::stringstream& aStream)
 {
@@ -675,19 +677,19 @@ TileClient::DiscardFrontBuffer()
       tracker->SetTextureClient(mFrontBuffer);
       mFrontBuffer->SetRemoveFromCompositableWaiter(waiter);
       // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
       mManager->AsShadowForwarder()->RemoveTextureFromCompositableAsync(tracker,
                                                                         mCompositableClient,
                                                                         mFrontBuffer);
     }
 #endif
-    mManager->ReturnTextureClientDeferred(*mFrontBuffer);
+    mAllocator->ReturnTextureClientDeferred(mFrontBuffer);
     if (mFrontBufferOnWhite) {
-      mManager->ReturnTextureClientDeferred(*mFrontBufferOnWhite);
+      mAllocator->ReturnTextureClientDeferred(mFrontBufferOnWhite);
     }
     mFrontLock->ReadUnlock();
     if (mFrontBuffer->IsLocked()) {
       mFrontBuffer->Unlock();
     }
     if (mFrontBufferOnWhite && mFrontBufferOnWhite->IsLocked()) {
       mFrontBufferOnWhite->Unlock();
     }
@@ -701,24 +703,24 @@ void
 TileClient::DiscardBackBuffer()
 {
   if (mBackBuffer) {
     MOZ_ASSERT(mBackLock);
     if (!mBackBuffer->ImplementsLocking() && mBackLock->GetReadCount() > 1) {
       // 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.
-     mManager->ReportClientLost(*mBackBuffer);
+     mAllocator->ReportClientLost();
      if (mBackBufferOnWhite) {
-       mManager->ReportClientLost(*mBackBufferOnWhite);
+       mAllocator->ReportClientLost();
      }
     } else {
-      mManager->ReturnTextureClientDeferred(*mBackBuffer);
+      mAllocator->ReturnTextureClientDeferred(mBackBuffer);
       if (mBackBufferOnWhite) {
-        mManager->ReturnTextureClientDeferred(*mBackBufferOnWhite);
+        mAllocator->ReturnTextureClientDeferred(mBackBufferOnWhite);
       }
     }
     mBackLock->ReadUnlock();
     if (mBackBuffer->IsLocked()) {
       mBackBuffer->Unlock();
     }
     if (mBackBufferOnWhite && mBackBufferOnWhite->IsLocked()) {
       mBackBufferOnWhite->Unlock();
@@ -757,32 +759,30 @@ TileClient::GetBackBuffer(const nsIntReg
       // Before we Replacing the lock by another one we need to unlock it!
       mBackLock->ReadUnlock();
     }
 
     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.
-      mManager->ReportClientLost(*mBackBuffer);
+      mAllocator->ReportClientLost();
     }
     if (mBackBufferOnWhite) {
-      mManager->ReportClientLost(*mBackBufferOnWhite);
+      mAllocator->ReportClientLost();
       mBackBufferOnWhite = nullptr;
     }
 
-    TextureClientPool *pool =
-      mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent));
-    mBackBuffer.Set(this, pool->GetTextureClient());
+    mBackBuffer.Set(this, mAllocator->GetTextureClient());
     if (!mBackBuffer) {
       return nullptr;
     }
 
     if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-      mBackBufferOnWhite = pool->GetTextureClient();
+      mBackBufferOnWhite = mAllocator->GetTextureClient();
       if (!mBackBufferOnWhite) {
         mBackBuffer.Set(this, nullptr);
         return nullptr;
       }
     }
 
     // Create a lock for our newly created back-buffer.
     if (mManager->AsShadowForwarder()->IsSameProcess()) {
@@ -829,34 +829,34 @@ TileClient::GetTileDescriptor()
     return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
                                   mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
                                   mUpdateRect,
                                   TileLock(lock->GetShmemSection()));
   }
 }
 
 void
-ClientTiledLayerBuffer::ReadLock() {
+ClientMultiTiledLayerBuffer::ReadLock() {
   for (TileClient& tile : mRetainedTiles) {
     if (!tile.IsPlaceholderTile()) {
       tile.ReadLock();
     }
   }
 }
 
 void
-ClientTiledLayerBuffer::DiscardBuffers()
+ClientMultiTiledLayerBuffer::DiscardBuffers()
 {
   for (TileClient& tile : mRetainedTiles) {
     tile.DiscardBuffers();
   }
 }
 
 SurfaceDescriptorTiles
-ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
+ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles()
 {
   InfallibleTArray<TileDescriptor> tiles;
 
   for (TileClient& tile : mRetainedTiles) {
     TileDescriptor tileDesc;
     if (tile.IsPlaceholderTile()) {
       tileDesc = PlaceholderTileDescriptor();
     } else {
@@ -870,21 +870,21 @@ ClientTiledLayerBuffer::GetSurfaceDescri
                                 tiles,
                                 mTiles.mFirst.x, mTiles.mFirst.y,
                                 mTiles.mSize.width, mTiles.mSize.height,
                                 mResolution, mFrameResolution.xScale,
                                 mFrameResolution.yScale);
 }
 
 void
-ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
-                                   const nsIntRegion& aPaintRegion,
-                                   const nsIntRegion& aDirtyRegion,
-                                   LayerManager::DrawPaintedLayerCallback aCallback,
-                                   void* aCallbackData)
+ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
+                                         const nsIntRegion& aPaintRegion,
+                                         const nsIntRegion& aDirtyRegion,
+                                         LayerManager::DrawPaintedLayerCallback aCallback,
+                                         void* aCallbackData)
 {
   TILING_LOG("TILING %p: PaintThebes painting region %s\n", mPaintedLayer, Stringify(aPaintRegion).c_str());
   TILING_LOG("TILING %p: PaintThebes new valid region %s\n", mPaintedLayer, Stringify(aNewValidRegion).c_str());
 
   mCallback = aCallback;
   mCallbackData = aCallbackData;
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
@@ -894,17 +894,17 @@ ClientTiledLayerBuffer::PaintThebes(cons
   // If this region is empty XMost() - 1 will give us a negative value.
   NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n");
 
   if (!gfxPrefs::TiledDrawTargetEnabled()) {
     nsRefPtr<gfxContext> ctxt;
 
     const IntRect bounds = aPaintRegion.GetBounds();
     {
-      PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferAlloc",
+      PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferAlloc",
         js::ProfileEntry::Category::GRAPHICS);
 
       mSinglePaintDrawTarget =
         gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
           gfx::IntSize(ceilf(bounds.width * mResolution),
                        ceilf(bounds.height * mResolution)),
           gfxPlatform::GetPlatform()->Optimal2DFormatForContent(
             GetContentType()));
@@ -922,17 +922,17 @@ ClientTiledLayerBuffer::PaintThebes(cons
       ctxt->CurrentMatrix().Scale(mResolution, mResolution).
                             Translate(-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("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
+    PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferDraw",
       js::ProfileEntry::Category::GRAPHICS);
 
     mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
               DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
   }
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 30) {
@@ -944,17 +944,17 @@ ClientTiledLayerBuffer::PaintThebes(cons
       for (const IntRect* 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("ClientTiledLayerBuffer", "PaintThebesUpdate",
+  PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesUpdate",
     js::ProfileEntry::Category::GRAPHICS);
 
   mNewValidRegion = aNewValidRegion;
   Update(aNewValidRegion, aPaintRegion, aDirtyRegion);
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 10) {
     const IntRect bounds = aPaintRegion.GetBounds();
@@ -1063,19 +1063,19 @@ ClientTiledLayerBuffer::UnlockTile(TileC
   if (aTile.mBackBuffer && aTile.mBackBuffer->IsLocked()) {
     aTile.mBackBuffer->Unlock();
   }
   if (aTile.mBackBufferOnWhite && aTile.mBackBufferOnWhite->IsLocked()) {
     aTile.mBackBufferOnWhite->Unlock();
   }
 }
 
-void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
-                                    const nsIntRegion& aPaintRegion,
-                                    const nsIntRegion& aDirtyRegion)
+void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
+                                         const nsIntRegion& aPaintRegion,
+                                         const nsIntRegion& aDirtyRegion)
 {
   const IntSize scaledTileSize = GetScaledTileSize();
   const gfx::IntRect newBounds = newValidRegion.GetBounds();
 
   const TilesPlacement oldTiles = mTiles;
   const TilesPlacement newTiles(floor_div(newBounds.x, scaledTileSize.width),
                           floor_div(newBounds.y, scaledTileSize.height),
                           floor_div(GetTileStart(newBounds.x, scaledTileSize.width)
@@ -1182,43 +1182,46 @@ void ClientTiledLayerBuffer::Update(cons
   }
 
   mTiles = newTiles;
   mValidRegion = newValidRegion;
   mPaintedRegion.OrWith(aPaintRegion);
 }
 
 bool
-ClientTiledLayerBuffer::ValidateTile(TileClient& aTile,
-                                    const nsIntPoint& aTileOrigin,
-                                    const nsIntRegion& aDirtyRegion)
+ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
+                                          const nsIntPoint& aTileOrigin,
+                                          const nsIntRegion& aDirtyRegion)
 {
-  PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile",
+  PROFILER_LABEL("ClientMultiTiledLayerBuffer", "ValidateTile",
     js::ProfileEntry::Category::GRAPHICS);
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (aDirtyRegion.IsComplex()) {
     printf_stderr("Complex region\n");
   }
 #endif
 
+  SurfaceMode mode;
+  gfxContentType content = GetContentType(&mode);
+
   if (aTile.IsPlaceholderTile()) {
     aTile.SetLayerManager(mManager);
+    aTile.SetTextureAllocator(mManager->GetTexturePool(
+      gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content)));
   }
   aTile.SetCompositableClient(mCompositableClient);
 
   bool createdTextureClient = false;
   nsIntRegion offsetScaledDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
   offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
 
   bool usingTiledDrawTarget = gfxPrefs::TiledDrawTargetEnabled();
   MOZ_ASSERT(usingTiledDrawTarget || !!mSinglePaintDrawTarget);
 
-  SurfaceMode mode;
-  gfxContentType content = GetContentType(&mode);
   nsIntRegion extraPainted;
   RefPtr<TextureClient> backBufferOnWhite;
   RefPtr<TextureClient> backBuffer =
     aTile.GetBackBuffer(offsetScaledDirtyRegion,
                         content, mode,
                         &createdTextureClient, extraPainted,
                         &backBufferOnWhite);
 
@@ -1408,21 +1411,21 @@ GetCompositorSideCompositionBounds(const
                                    const ViewTransform& aAPZTransform)
 {
   Matrix4x4 transform = aTransformToCompBounds * Matrix4x4(aAPZTransform);
   return TransformTo<LayerPixel>(transform.Inverse(),
             aScrollAncestor.Metrics().GetCompositionBounds());
 }
 
 bool
-ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
-                                                       const nsIntRegion& aOldValidRegion,
-                                                       nsIntRegion& aRegionToPaint,
-                                                       BasicTiledLayerPaintData* aPaintData,
-                                                       bool aIsRepeated)
+ClientMultiTiledLayerBuffer::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
   // decision about how to update coherently. In this case, just update
   // everything in one transaction.
   if (aPaintData->mCompositionBounds.IsEmpty()) {
     aPaintData->mPaintFinished = true;
@@ -1475,17 +1478,17 @@ ClientTiledLayerBuffer::ComputeProgressi
   TILING_LOG("TILING %p: Progressive update view transform %s zoom %f abort %d\n",
       mPaintedLayer, ToString(viewTransform.mTranslation).c_str(), viewTransform.mScale.scale, abortPaint);
 
   if (abortPaint) {
     // We ignore if front-end wants to abort if this is the first,
     // non-low-precision paint, as in that situation, we're about to override
     // front-end's page/viewport metrics.
     if (!aPaintData->mFirstPaint || drawingLowPrecision) {
-      PROFILER_LABEL("ClientTiledLayerBuffer", "ComputeProgressiveUpdateRegion",
+      PROFILER_LABEL("ClientMultiTiledLayerBuffer", "ComputeProgressiveUpdateRegion",
         js::ProfileEntry::Category::GRAPHICS);
 
       aRegionToPaint.SetEmpty();
       return aIsRepeated;
     }
   }
 
   LayerRect transformedCompositionBounds =
@@ -1601,22 +1604,22 @@ ClientTiledLayerBuffer::ComputeProgressi
   // 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
-ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
-                                         nsIntRegion& aInvalidRegion,
-                                         const nsIntRegion& aOldValidRegion,
-                                         BasicTiledLayerPaintData* aPaintData,
-                                         LayerManager::DrawPaintedLayerCallback aCallback,
-                                         void* aCallbackData)
+ClientMultiTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
+                                               nsIntRegion& aInvalidRegion,
+                                               const nsIntRegion& aOldValidRegion,
+                                               BasicTiledLayerPaintData* aPaintData,
+                                               LayerManager::DrawPaintedLayerCallback aCallback,
+                                               void* aCallbackData)
 {
   TILING_LOG("TILING %p: Progressive update valid region %s\n", mPaintedLayer, Stringify(aValidRegion).c_str());
   TILING_LOG("TILING %p: Progressive update invalid region %s\n", mPaintedLayer, Stringify(aInvalidRegion).c_str());
   TILING_LOG("TILING %p: Progressive update old valid region %s\n", mPaintedLayer, Stringify(aOldValidRegion).c_str());
 
   bool repeat = false;
   bool isBufferChanged = false;
   do {
@@ -1672,16 +1675,16 @@ TiledContentClient::PrintInfo(std::strin
     pfx += "  ";
 
     Dump(aStream, pfx.get(), false);
   }
 }
 
 void
 TiledContentClient::Dump(std::stringstream& aStream,
-                       const char* aPrefix,
-                       bool aDumpHtml)
+                         const char* aPrefix,
+                         bool aDumpHtml)
 {
-  mTiledBuffer.Dump(aStream, aPrefix, aDumpHtml);
+  GetTiledBuffer()->Dump(aStream, aPrefix, aDumpHtml);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -169,16 +169,20 @@ struct TileClient
   {
     return mFrontBuffer != o.mFrontBuffer;
   }
 
   void SetLayerManager(ClientLayerManager *aManager)
   {
     mManager = aManager;
   }
+  void SetTextureAllocator(TextureClientAllocator* aAllocator)
+  {
+    mAllocator = aAllocator;
+  }
 
   void SetCompositableClient(CompositableClient* aCompositableClient)
   {
     mCompositableClient = aCompositableClient;
   }
 
   bool IsPlaceholderTile() const
   {
@@ -264,16 +268,17 @@ struct TileClient
       RefPtr<TextureClient> mBuffer;
   } mBackBuffer;
   RefPtr<TextureClient> mBackBufferOnWhite;
   RefPtr<TextureClient> mFrontBuffer;
   RefPtr<TextureClient> mFrontBufferOnWhite;
   RefPtr<gfxSharedReadLock> mBackLock;
   RefPtr<gfxSharedReadLock> mFrontLock;
   RefPtr<ClientLayerManager> mManager;
+  RefPtr<TextureClientAllocator> mAllocator;
   gfx::IntRect mUpdateRect;
   CompositableClient* mCompositableClient;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   TimeStamp        mLastUpdate;
 #endif
   nsIntRegion mInvalidFront;
   nsIntRegion mInvalidBack;
   nsExpirationState mExpirationState;
@@ -385,108 +390,158 @@ private:
 /**
  * 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 ClientTiledLayerBuffer
-  : public TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>
 {
-  friend class TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>;
-
 public:
   ClientTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
-                         CompositableClient* aCompositableClient,
-                         ClientLayerManager* aManager,
-                         SharedFrameMetricsHelper* aHelper);
-  ClientTiledLayerBuffer()
-    : mPaintedLayer(nullptr)
-    , mCompositableClient(nullptr)
+                         CompositableClient* aCompositableClient)
+    : mPaintedLayer(aPaintedLayer)
+    , mCompositableClient(aCompositableClient)
+    , mLastPaintContentType(gfxContentType::COLOR)
+    , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
+  {}
+
+  virtual void PaintThebes(const nsIntRegion& aNewValidRegion,
+                   const nsIntRegion& aPaintRegion,
+                   const nsIntRegion& aDirtyRegion,
+                   LayerManager::DrawPaintedLayerCallback aCallback,
+                   void* aCallbackData) = 0;
+
+  virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion,
+                         nsIntRegion& aInvalidRegion,
+                         const nsIntRegion& aOldValidRegion,
+                         BasicTiledLayerPaintData* aPaintData,
+                         LayerManager::DrawPaintedLayerCallback aCallback,
+                         void* aCallbackData) = 0;
+  virtual void ResetPaintedAndValidState() = 0;
+
+  virtual const nsIntRegion& GetValidRegion() = 0;
+
+  virtual bool IsLowPrecision() const = 0;
+
+  virtual void Dump(std::stringstream& aStream,
+                    const char* aPrefix,
+                    bool aDumpHtml) {}
+
+  const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
+  void SetFrameResolution(const CSSToParentLayerScale2D& aResolution) { mFrameResolution = aResolution; }
+
+  bool HasFormatChanged() const;
+
+protected:
+  void UnlockTile(TileClient& aTile);
+  gfxContentType GetContentType(SurfaceMode* aMode = nullptr) const;
+
+  ClientTiledPaintedLayer* mPaintedLayer;
+  CompositableClient* mCompositableClient;
+
+  gfxContentType mLastPaintContentType;
+  SurfaceMode mLastPaintSurfaceMode;
+  CSSToParentLayerScale2D mFrameResolution;
+};
+
+class ClientMultiTiledLayerBuffer
+  : public TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>
+  , public ClientTiledLayerBuffer
+{
+  friend class TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>;
+public:
+  ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
+                              CompositableClient* aCompositableClient,
+                              ClientLayerManager* aManager,
+                              SharedFrameMetricsHelper* aHelper);
+  ClientMultiTiledLayerBuffer()
+    : ClientTiledLayerBuffer(nullptr, nullptr)
     , mManager(nullptr)
     , mCallback(nullptr)
     , mCallbackData(nullptr)
-    , mLastPaintContentType(gfxContentType::COLOR)
-    , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
     , mSharedFrameMetricsHelper(nullptr)
     , mTilingOrigin(std::numeric_limits<int32_t>::max(),
                     std::numeric_limits<int32_t>::max())
   {}
 
   void PaintThebes(const nsIntRegion& aNewValidRegion,
                    const nsIntRegion& aPaintRegion,
                    const nsIntRegion& aDirtyRegion,
                    LayerManager::DrawPaintedLayerCallback aCallback,
-                   void* aCallbackData);
-
-  void Update(const nsIntRegion& aNewValidRegion,
-              const nsIntRegion& aPaintRegion,
-              const nsIntRegion& aDirtyRegion);
-
-  void ReadLock();
-
-  void DiscardBuffers();
-
-  const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
-
-  void SetFrameResolution(const CSSToParentLayerScale2D& aResolution) { mFrameResolution = aResolution; }
-
-  bool HasFormatChanged() const;
+                   void* aCallbackData) override;
 
   /**
    * Performs a progressive update of a given tiled buffer.
    * See ComputeProgressiveUpdateRegion below for parameter documentation.
    */
   bool ProgressiveUpdate(nsIntRegion& aValidRegion,
                          nsIntRegion& aInvalidRegion,
                          const nsIntRegion& aOldValidRegion,
                          BasicTiledLayerPaintData* aPaintData,
                          LayerManager::DrawPaintedLayerCallback aCallback,
-                         void* aCallbackData);
+                         void* aCallbackData) override;
+  
+  void ResetPaintedAndValidState() override {
+    mPaintedRegion.SetEmpty();
+    mValidRegion.SetEmpty();
+    mTiles.mSize.width = 0;
+    mTiles.mSize.height = 0;
+    DiscardBuffers();
+    mRetainedTiles.Clear();
+  }
+
+
+  const nsIntRegion& GetValidRegion() override {
+    return TiledLayerBuffer::GetValidRegion();
+  }
+
+  bool IsLowPrecision() const override {
+    return TiledLayerBuffer::IsLowPrecision();
+  }
+
+  void Dump(std::stringstream& aStream,
+            const char* aPrefix,
+            bool aDumpHtml) override {
+    TiledLayerBuffer::Dump(aStream, aPrefix, aDumpHtml);
+  }
+
+  void ReadLock();
+
+  void Release();
+
+  void DiscardBuffers();
 
   SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
 
   void SetResolution(float aResolution) {
     if (mResolution == aResolution) {
       return;
     }
 
     Update(nsIntRegion(), nsIntRegion(), nsIntRegion());
     mResolution = aResolution;
   }
 
-  void ResetPaintedAndValidState() {
-    mPaintedRegion.SetEmpty();
-    mValidRegion.SetEmpty();
-    mTiles.mSize.width = 0;
-    mTiles.mSize.height = 0;
-    DiscardBuffers();
-    mRetainedTiles.Clear();
-  }
-
 protected:
   bool ValidateTile(TileClient& aTile,
                     const nsIntPoint& aTileRect,
                     const nsIntRegion& dirtyRect);
-
-  void UnlockTile(TileClient& aTile);
+  
+  void Update(const nsIntRegion& aNewValidRegion,
+              const nsIntRegion& aPaintRegion,
+              const nsIntRegion& aDirtyRegion);
 
   TileClient GetPlaceholderTile() const { return TileClient(); }
 
 private:
-  gfxContentType GetContentType(SurfaceMode* aMode = nullptr) const;
-  ClientTiledPaintedLayer* mPaintedLayer;
-  CompositableClient* mCompositableClient;
   ClientLayerManager* mManager;
   LayerManager::DrawPaintedLayerCallback mCallback;
   void* mCallbackData;
-  CSSToParentLayerScale2D mFrameResolution;
-  gfxContentType mLastPaintContentType;
-  SurfaceMode mLastPaintSurfaceMode;
 
   // The region that will be made valid during Update(). Once Update() is
   // completed then this is identical to mValidRegion.
   nsIntRegion mNewValidRegion;
 
   // The DrawTarget we use when UseSinglePaintBuffer() above is true.
   RefPtr<gfx::DrawTarget>       mSinglePaintDrawTarget;
   nsIntPoint                    mSinglePaintBufferOffset;
@@ -524,58 +579,83 @@ private:
                                       const nsIntRegion& aOldValidRegion,
                                       nsIntRegion& aRegionToPaint,
                                       BasicTiledLayerPaintData* aPaintData,
                                       bool aIsRepeated);
 };
 
 class TiledContentClient : public CompositableClient
 {
-  // XXX: for now the layer which owns us interacts directly with our buffers.
-  // We should have a content client for each tiled buffer which manages its
-  // own valid region, resolution, etc. Then we could have a much cleaner
-  // interface and tidy up BasicTiledPaintedLayer::PaintThebes (bug 862547).
-  friend class ClientTiledPaintedLayer;
-
 public:
-  TiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
-                     ClientLayerManager* aManager);
+  TiledContentClient(ClientLayerManager* aManager)
+    : CompositableClient(aManager->AsShadowForwarder())
+  {}
 
 protected:
   ~TiledContentClient()
-  {
-    MOZ_COUNT_DTOR(TiledContentClient);
+  {}
 
-    mDestroyed = true;
-    mTiledBuffer.DiscardBuffers();
-    mLowPrecisionTiledBuffer.DiscardBuffers();
-  }
-
+public:
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false);
 
-public:
   virtual TextureInfo GetTextureInfo() const override
   {
     return TextureInfo(CompositableType::CONTENT_TILED);
   }
 
-  virtual void ClearCachedResources() override;
+
+  virtual ClientTiledLayerBuffer* GetTiledBuffer() = 0;
+  virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() = 0;
 
   enum TiledBufferType {
     TILED_BUFFER,
     LOW_PRECISION_TILED_BUFFER
   };
-  void UseTiledLayerBuffer(TiledBufferType aType);
+  virtual void UpdatedBuffer(TiledBufferType aType) = 0;
+};
+
+/**
+ * An implementation of TiledContentClient that supports
+ * multiple tiles and a low precision buffer.
+ */
+class MultiTiledContentClient : public TiledContentClient
+{
+public:
+  MultiTiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
+                          ClientLayerManager* aManager);
+
+protected:
+  ~MultiTiledContentClient()
+  {
+    MOZ_COUNT_DTOR(MultiTiledContentClient);
+ 
+    mDestroyed = true;
+    mTiledBuffer.DiscardBuffers();
+    mLowPrecisionTiledBuffer.DiscardBuffers();
+  }
+
+public:
+  void ClearCachedResources() override;
+  void UpdatedBuffer(TiledBufferType aType) override;
+
+  ClientTiledLayerBuffer* GetTiledBuffer() override { return &mTiledBuffer; }
+  ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override {
+    if (mHasLowPrecision) {
+      return &mLowPrecisionTiledBuffer;
+    }
+    return nullptr;
+  }
 
 private:
   SharedFrameMetricsHelper mSharedFrameMetricsHelper;
-  ClientTiledLayerBuffer mTiledBuffer;
-  ClientTiledLayerBuffer mLowPrecisionTiledBuffer;
+  ClientMultiTiledLayerBuffer mTiledBuffer;
+  ClientMultiTiledLayerBuffer mLowPrecisionTiledBuffer;
+  bool mHasLowPrecision;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif