Backed out 9 changesets (bug 1399692) for failing reftest/tests/layout/reftests/svg/dynamic-text-06.svg Windows 10 x64 Stylo Disabled debug R-e10s2 r=backout on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Thu, 09 Nov 2017 21:55:32 +0200
changeset 695887 ee367696744a7af745f67019dec7c6d0275b2a24
parent 695886 9a78c51b2bd409dbff05d4546000d1d655849e3f
child 695888 5fa0729021dccefb542e8703d45471e1c58e3d81
push id88577
push usermozilla@noorenberghe.ca
push dateThu, 09 Nov 2017 23:43:51 +0000
reviewersbackout
bugs1399692
milestone58.0a1
backs out7d9324e2ab34946539be9f17d74f639aae5ba7e5
76bf99decf0906f0a6a4ad99539fd40f97c4539f
0fc2414f146d8f5d08c97e5b7eedb25c5632ab2d
f235b12eda6efe0bdec8e6590d813738f53ffe82
467532fd5b7a2385ba0dbdb9201e28e8f2b4a583
dce585be0737f3c9b6b241afb0851d85fb9453c9
b971c1aa5a78c17d49d1d64389516437024be72a
8ba8bda8521a6460b1213d2d0f14ebefc0a3e14a
2c41a712dff22de4fb2bbfd7c5a418fbc3a26f11
Backed out 9 changesets (bug 1399692) for failing reftest/tests/layout/reftests/svg/dynamic-text-06.svg Windows 10 x64 Stylo Disabled debug R-e10s2 r=backout on a CLOSED TREE Backed out changeset 7d9324e2ab34 (bug 1399692) Backed out changeset 76bf99decf09 (bug 1399692) Backed out changeset 0fc2414f146d (bug 1399692) Backed out changeset f235b12eda6e (bug 1399692) Backed out changeset 467532fd5b7a (bug 1399692) Backed out changeset dce585be0737 (bug 1399692) Backed out changeset b971c1aa5a78 (bug 1399692) Backed out changeset 8ba8bda8521a (bug 1399692) Backed out changeset 2c41a712dff2 (bug 1399692)
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/RotatedBuffer.cpp
gfx/layers/RotatedBuffer.h
gfx/layers/client/ClientPaintedLayer.cpp
gfx/layers/client/ContentClient.cpp
gfx/layers/client/ContentClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/moz.build
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -16,68 +16,16 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/SyncRunnable.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
-bool
-CapturedBufferState::Copy::CopyBuffer()
-{
-  if (mSource->Lock(OpenMode::OPEN_READ_ONLY)) {
-    mDestination->UpdateDestinationFrom(*mSource, mBounds);
-    mSource->Unlock();
-    return true;
-  }
-  return false;
-}
-
-bool
-CapturedBufferState::Unrotate::UnrotateBuffer()
-{
-  return mBuffer->UnrotateBufferTo(mParameters);
-}
-
-bool
-CapturedBufferState::PrepareBuffer()
-{
-  return (!mBufferCopy || mBufferCopy->CopyBuffer()) &&
-         (!mBufferUnrotate || mBufferUnrotate->UnrotateBuffer());
-}
-
-void
-CapturedBufferState::GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients)
-{
-  if (mBufferCopy) {
-    if (TextureClient* source = mBufferCopy->mSource->GetClient()) {
-      aTextureClients.AppendElement(source);
-    }
-    if (TextureClient* sourceOnWhite = mBufferCopy->mSource->GetClientOnWhite()) {
-      aTextureClients.AppendElement(sourceOnWhite);
-    }
-    if (TextureClient* destination = mBufferCopy->mDestination->GetClient()) {
-      aTextureClients.AppendElement(destination);
-    }
-    if (TextureClient* destinationOnWhite = mBufferCopy->mDestination->GetClientOnWhite()) {
-      aTextureClients.AppendElement(destinationOnWhite);
-    }
-  }
-
-  if (mBufferUnrotate) {
-    if (TextureClient* client = mBufferUnrotate->mBuffer->GetClient()) {
-      aTextureClients.AppendElement(client);
-    }
-    if (TextureClient* clientOnWhite = mBufferUnrotate->mBuffer->GetClientOnWhite()) {
-      aTextureClients.AppendElement(clientOnWhite);
-    }
-  }
-}
-
 StaticAutoPtr<PaintThread> PaintThread::sSingleton;
 StaticRefPtr<nsIThread> PaintThread::sThread;
 PlatformThreadId PaintThread::sThreadId;
 
 // RAII make sure we clean up and restore our draw targets
 // when we paint async.
 struct MOZ_STACK_CLASS AutoCapturedPaintSetup
 {
@@ -206,80 +154,36 @@ void
 PaintThread::BeginLayerTransaction()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MOZ_ASSERT(!mInAsyncPaintGroup);
 }
 
 void
-PaintThread::PrepareBuffer(CapturedBufferState* aState)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aState);
-
-  // If painting asynchronously, we need to acquire the compositor bridge which
-  // owns the underlying MessageChannel. Otherwise we leave it null and use
-  // synchronous dispatch.
-  RefPtr<CompositorBridgeChild> cbc;
-  if (!gfxPrefs::LayersOMTPForceSync()) {
-    cbc = CompositorBridgeChild::Get();
-    cbc->NotifyBeginAsyncPrepareBuffer(aState);
-  }
-  RefPtr<CapturedBufferState> state(aState);
-
-  RefPtr<PaintThread> self = this;
-  RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PrepareBuffer",
-    [self, cbc, state]() -> void
-  {
-    self->AsyncPrepareBuffer(cbc,
-                             state);
-  });
-
-  if (cbc) {
-    sThread->Dispatch(task.forget());
-  } else {
-    SyncRunnable::DispatchToThread(sThread, task);
-  }
-}
-
-void
-PaintThread::AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
-                                CapturedBufferState* aState)
-{
-  MOZ_ASSERT(IsOnPaintThread());
-  MOZ_ASSERT(aState);
-
-  if (!aState->PrepareBuffer()) {
-    gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
-  }
-
-  aBridge->NotifyFinishedAsyncPrepareBuffer(aState);
-}
-
-void
 PaintThread::PaintContents(CapturedPaintState* aState,
                            PrepDrawTargetForPaintingCallback aCallback)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aState);
 
   // If painting asynchronously, we need to acquire the compositor bridge which
   // owns the underlying MessageChannel. Otherwise we leave it null and use
   // synchronous dispatch.
   RefPtr<CompositorBridgeChild> cbc;
   if (!gfxPrefs::LayersOMTPForceSync()) {
     cbc = CompositorBridgeChild::Get();
     cbc->NotifyBeginAsyncPaint(aState);
   }
   RefPtr<CapturedPaintState> state(aState);
+  RefPtr<DrawTargetCapture> capture(aState->mCapture);
 
   RefPtr<PaintThread> self = this;
   RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintContents",
-    [self, cbc, state, aCallback]() -> void
+    [self, cbc, capture, state, aCallback]() -> void
   {
     self->AsyncPaintContents(cbc,
                              state,
                              aCallback);
   });
 
   if (cbc) {
     sThread->Dispatch(task.forget());
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -7,17 +7,16 @@
 #ifndef MOZILLA_LAYERS_PAINTTHREAD_H
 #define MOZILLA_LAYERS_PAINTTHREAD_H
 
 #include "base/platform_thread.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/layers/TextureClient.h"
-#include "RotatedBuffer.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 class DrawTargetCapture;
 };
 
@@ -54,66 +53,16 @@ public:
   gfx::Matrix mTargetTransform;
   SurfaceMode mSurfaceMode;
   gfxContentType mContentType;
 
 protected:
   virtual ~CapturedPaintState() {}
 };
 
-// Holds the key operations for a ContentClient to prepare
-// its buffers for painting
-class CapturedBufferState final {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedBufferState)
-public:
-  struct Copy {
-    Copy(RefPtr<RotatedBuffer> aSource,
-         RefPtr<RotatedBuffer> aDestination,
-         gfx::IntRect aBounds)
-      : mSource(aSource)
-      , mDestination(aDestination)
-      , mBounds(aBounds)
-    {}
-
-    bool CopyBuffer();
-
-    RefPtr<RotatedBuffer> mSource;
-    RefPtr<RotatedBuffer> mDestination;
-    gfx::IntRect mBounds;
-  };
-
-  struct Unrotate {
-    Unrotate(RotatedBuffer::Parameters aParameters,
-             RefPtr<RotatedBuffer> aBuffer)
-      : mParameters(aParameters)
-      , mBuffer(aBuffer)
-    {}
-
-    bool UnrotateBuffer();
-
-    RotatedBuffer::Parameters mParameters;
-    RefPtr<RotatedBuffer> mBuffer;
-  };
-
-  /**
-   * Prepares the rotated buffers for painting by copying a previous frame
-   * into the buffer and/or unrotating the pixels and returns whether the
-   * operations were successful. If this fails a new buffer should be created
-   * for the frame.
-   */
-  bool PrepareBuffer();
-  void GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients);
-
-  Maybe<Copy> mBufferCopy;
-  Maybe<Unrotate> mBufferUnrotate;
-
-protected:
-  ~CapturedBufferState() {}
-};
-
 typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState* aPaintState);
 
 class CompositorBridgeChild;
 
 class PaintThread final
 {
   friend void DestroyPaintThread(UniquePtr<PaintThread>&& aPaintThread);
 
@@ -126,18 +75,16 @@ public:
   static bool IsOnPaintThread();
 
   // Must be called on the main thread. Signifies that a new layer transaction
   // is beginning. This must be called immediately after FlushAsyncPaints, and
   // before any new painting occurs, as there can't be any async paints queued
   // or running while this is executing.
   void BeginLayerTransaction();
 
-  void PrepareBuffer(CapturedBufferState* aState);
-
   void PaintContents(CapturedPaintState* aState,
                      PrepDrawTargetForPaintingCallback aCallback);
 
   // Must be called on the main thread. Signifies that the current
   // batch of CapturedPaintStates* for PaintContents have been recorded
   // and the main thread is finished recording this layer.
   void EndLayer();
 
@@ -158,18 +105,16 @@ public:
 
 private:
   PaintThread();
 
   bool Init();
   void ShutdownOnPaintThread();
   void InitOnPaintThread();
 
-  void AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
-                          CapturedBufferState* aState);
   void AsyncPaintContents(CompositorBridgeChild* aBridge,
                           CapturedPaintState* aState,
                           PrepDrawTargetForPaintingCallback aCallback);
   void AsyncEndLayer();
   void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge,
                                 SyncObjectClient* aSyncObject);
 
   static StaticAutoPtr<PaintThread> sSingleton;
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -286,126 +286,114 @@ WrapRotationAxis(int32_t* aRotationPoint
   if (*aRotationPoint < 0) {
     *aRotationPoint += aSize;
   } else if (*aRotationPoint >= aSize) {
     *aRotationPoint -= aSize;
   }
 }
 
 bool
-RotatedBuffer::Parameters::IsRotated() const
-{
-  return mBufferRotation != IntPoint(0,0);
-}
-
-bool
-RotatedBuffer::Parameters::RectWrapsBuffer(const gfx::IntRect& aRect) const
-{
-  int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
-  int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
-  return (aRect.x < xBoundary && xBoundary < aRect.XMost()) ||
-         (aRect.y < yBoundary && yBoundary < aRect.YMost());
-}
-
-void
-RotatedBuffer::Parameters::SetUnrotated()
-{
-  mBufferRotation = IntPoint(0,0);
-  mDidSelfCopy = true;
-}
-
-RotatedBuffer::Parameters
-RotatedBuffer::AdjustedParameters(const gfx::IntRect& aDestBufferRect) const
+RotatedBuffer::AdjustTo(const gfx::IntRect& aDestBufferRect,
+                        const gfx::IntRect& aDrawBounds,
+                        bool aCanHaveRotation,
+                        bool aCanDrawRotated)
 {
   IntRect keepArea;
   if (keepArea.IntersectRect(aDestBufferRect, mBufferRect)) {
     // Set mBufferRotation so that the pixels currently in mDTBuffer
     // will still be rendered in the right place when mBufferRect
     // changes to aDestBufferRect.
     IntPoint newRotation = mBufferRotation +
       (aDestBufferRect.TopLeft() - mBufferRect.TopLeft());
     WrapRotationAxis(&newRotation.x, mBufferRect.Width());
     WrapRotationAxis(&newRotation.y, mBufferRect.Height());
     NS_ASSERTION(gfx::IntRect(gfx::IntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
                  "newRotation out of bounds");
 
-    return Parameters{aDestBufferRect, newRotation};
-  }
+    int32_t xBoundary = aDestBufferRect.XMost() - newRotation.x;
+    int32_t yBoundary = aDestBufferRect.YMost() - newRotation.y;
+    bool drawWrapsBuffer = (aDrawBounds.x < xBoundary && xBoundary < aDrawBounds.XMost()) ||
+                           (aDrawBounds.y < yBoundary && yBoundary < aDrawBounds.YMost());
+
+    if ((drawWrapsBuffer && !aCanDrawRotated) ||
+        (newRotation != IntPoint(0,0) && !aCanHaveRotation)) {
+      // The stuff we need to redraw will wrap around an edge of the
+      // buffer (and the caller doesn't know how to support that), so
+      // move the pixels we can keep into a position that lets us
+      // redraw in just one quadrant.
+      RefPtr<gfx::DrawTarget> dtBuffer = GetDTBuffer();
+      RefPtr<gfx::DrawTarget> dtBufferOnWhite = GetDTBufferOnWhite();
 
-  // No pixels are going to be kept. The whole visible region
-  // will be redrawn, so we don't need to copy anything, so we don't
-  // set destBuffer.
-  return Parameters{aDestBufferRect, IntPoint(0,0)};
-}
+      if (mBufferRotation == IntPoint(0,0)) {
+        IntRect srcRect(IntPoint(0, 0), mBufferRect.Size());
+        IntPoint dest = mBufferRect.TopLeft() - aDestBufferRect.TopLeft();
+
+        MOZ_ASSERT(dtBuffer && dtBuffer->IsValid());
+        dtBuffer->CopyRect(srcRect, dest);
+        if (HaveBufferOnWhite()) {
+          MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
+          dtBufferOnWhite->CopyRect(srcRect, dest);
+        }
+
+        mDidSelfCopy = true;
+        mBufferRect = aDestBufferRect;
+      } else {
+        // With azure and a data surface perform an buffer unrotate
+        // (SelfCopy).
+        unsigned char* data;
+        IntSize size;
+        int32_t stride;
+        SurfaceFormat format;
 
-bool
-RotatedBuffer::UnrotateBufferTo(const Parameters& aParameters)
-{
-  RefPtr<gfx::DrawTarget> dtBuffer = GetDTBuffer();
-  RefPtr<gfx::DrawTarget> dtBufferOnWhite = GetDTBufferOnWhite();
+        if (dtBuffer->LockBits(&data, &size, &stride, &format)) {
+          uint8_t bytesPerPixel = BytesPerPixel(format);
+          BufferUnrotate(data,
+                         size.width * bytesPerPixel,
+                         size.height, stride,
+                         newRotation.x * bytesPerPixel, newRotation.y);
+          dtBuffer->ReleaseBits(data);
 
-  if (mBufferRotation == IntPoint(0,0)) {
-    IntRect srcRect(IntPoint(0, 0), mBufferRect.Size());
-    IntPoint dest = mBufferRect.TopLeft() - aParameters.mBufferRect.TopLeft();
+          if (HaveBufferOnWhite()) {
+            MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
+            dtBufferOnWhite->LockBits(&data, &size, &stride, &format);
+            uint8_t bytesPerPixel = BytesPerPixel(format);
+            BufferUnrotate(data,
+                           size.width * bytesPerPixel,
+                           size.height, stride,
+                           newRotation.x * bytesPerPixel, newRotation.y);
+            dtBufferOnWhite->ReleaseBits(data);
+          }
 
-    MOZ_ASSERT(dtBuffer && dtBuffer->IsValid());
-    dtBuffer->CopyRect(srcRect, dest);
-    if (HaveBufferOnWhite()) {
-      MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
-      dtBufferOnWhite->CopyRect(srcRect, dest);
+          // Buffer unrotate moves all the pixels
+          mDidSelfCopy = true;
+          mBufferRect = aDestBufferRect;
+          mBufferRotation = IntPoint(0, 0);
+        }
+
+        if (!mDidSelfCopy) {
+          // We couldn't unrotate the buffer, so we need to create a
+          // new one and start from scratch
+          return false;
+        }
+      }
+    } else {
+      mBufferRect = aDestBufferRect;
+      mBufferRotation = newRotation;
     }
   } else {
-    // With azure and a data surface perform an buffer unrotate
-    // (SelfCopy).
-    unsigned char* data;
-    IntSize size;
-    int32_t stride;
-    SurfaceFormat format;
-
-    if (dtBuffer->LockBits(&data, &size, &stride, &format)) {
-      uint8_t bytesPerPixel = BytesPerPixel(format);
-      BufferUnrotate(data,
-                     size.width * bytesPerPixel,
-                     size.height, stride,
-                     aParameters.mBufferRotation.x * bytesPerPixel,
-                     aParameters.mBufferRotation.y);
-      dtBuffer->ReleaseBits(data);
+    // No pixels are going to be kept. The whole visible region
+    // will be redrawn, so we don't need to copy anything, so we don't
+    // set destBuffer.
+    mBufferRect = aDestBufferRect;
+    mBufferRotation = IntPoint(0,0);
+  }
 
-      if (HaveBufferOnWhite()) {
-        MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
-        dtBufferOnWhite->LockBits(&data, &size, &stride, &format);
-        uint8_t bytesPerPixel = BytesPerPixel(format);
-        BufferUnrotate(data,
-                       size.width * bytesPerPixel,
-                       size.height, stride,
-                       aParameters.mBufferRotation.x * bytesPerPixel,
-                       aParameters.mBufferRotation.y);
-        dtBufferOnWhite->ReleaseBits(data);
-      }
-    } else {
-      return false;
-    }
-  }
   return true;
 }
 
-void
-RotatedBuffer::SetParameters(const RotatedBuffer::Parameters& aParameters)
-{
-  mBufferRect = aParameters.mBufferRect;
-  mBufferRotation = aParameters.mBufferRotation;
-  mDidSelfCopy = aParameters.mDidSelfCopy;
-}
-
-RotatedBuffer::ContentType
-RotatedBuffer::GetContentType() const
-{
-  return ContentForFormat(GetFormat());
-}
-
 DrawTarget*
 RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
                                                  ContextSource aSource,
                                                  DrawIterator* aIter,
                                                  bool aSetTransform,
                                                  Matrix* aOutMatrix)
 {
   IntRect bounds = aBounds;
@@ -492,27 +480,27 @@ RemoteRotatedBuffer::Lock(OpenMode aMode
   if (!locked) {
     Unlock();
     return false;
   }
 
   mTarget = mClient->BorrowDrawTarget();
   if (!mTarget || !mTarget->IsValid()) {
     gfxCriticalNote << "Invalid draw target " << hexa(mTarget)
-                    << " in RemoteRotatedBuffer::Lock";
+                    << "in RemoteRotatedBuffer::Lock";
     Unlock();
     return false;
   }
 
   if (mClientOnWhite) {
     mTargetOnWhite = mClientOnWhite->BorrowDrawTarget();
     if (!mTargetOnWhite || !mTargetOnWhite->IsValid()) {
       gfxCriticalNote << "Invalid draw target(s) " << hexa(mTarget)
                       << " and " << hexa(mTargetOnWhite)
-                      << " in RemoteRotatedBuffer::Lock";
+                      << "in RemoteRotatedBuffer::Lock";
       Unlock();
       return false;
     }
   }
 
   return true;
 }
 
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -18,19 +18,21 @@
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
 #include "LayersTypes.h"
 
 namespace mozilla {
 namespace layers {
 
+class CapturedPaintState;
+
+typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
+
 class PaintedLayer;
-class CapturedBufferState;
-class ContentClient;
 
 // Mixin class for classes which need logic for loaning out a draw target.
 // See comments on BorrowDrawTargetForQuadrantUpdate.
 class BorrowDrawTarget
 {
 public:
   void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
 
@@ -150,48 +152,25 @@ public:
    */
   gfx::DrawTarget*
   BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
                                     ContextSource aSource,
                                     DrawIterator* aIter,
                                     bool aSetTransform = true,
                                     gfx::Matrix* aOutTransform = nullptr);
 
-  struct Parameters {
-    Parameters(const gfx::IntRect& aBufferRect,
-               const gfx::IntPoint& aBufferRotation)
-      : mBufferRect(aBufferRect)
-      , mBufferRotation(aBufferRotation)
-      , mDidSelfCopy(false)
-    {
-    }
-
-    bool IsRotated() const;
-    bool RectWrapsBuffer(const gfx::IntRect& aRect) const;
-
-    void SetUnrotated();
-
-    gfx::IntRect  mBufferRect;
-    gfx::IntPoint mBufferRotation;
-    bool mDidSelfCopy;
-  };
-
   /**
-   * Returns the new buffer parameters for rotating to a
-   * destination buffer rect.
+   * Adjusts the buffer to be centered on the destination buffer rect,
+   * and ready to draw the specified bounds. Returns whether a new buffer
+   * needs to be created.
    */
-  Parameters AdjustedParameters(const gfx::IntRect& aDestBufferRect) const;
-
-  /**
-   * Unrotates the pixels of the rotated buffer for the specified
-   * new buffer parameters.
-   */
-  bool UnrotateBufferTo(const Parameters& aParameters);
-
-  void SetParameters(const Parameters& aParameters);
+  bool AdjustTo(const gfx::IntRect& aDestBufferRect,
+                const gfx::IntRect& aDrawBounds,
+                bool aCanHaveRotation,
+                bool aCanDrawRotated);
 
   /**
    * |BufferRect()| is the rect of device pixels that this
    * RotatedBuffer covers.  That is what DrawBufferWithRotation()
    * will paint when it's called.
    */
   const gfx::IntRect& BufferRect() const { return mBufferRect; }
   const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
@@ -219,49 +198,30 @@ public:
    */
   bool DidSelfCopy() const { return mDidSelfCopy; }
 
   /**
    * Clears the self copy flag.
    */
   void ClearDidSelfCopy() { mDidSelfCopy = false; }
 
-  /**
-   * Gets the content type for this buffer.
-   */
-  ContentType GetContentType() const;
-
   virtual bool IsLocked() = 0;
   virtual bool Lock(OpenMode aMode) = 0;
   virtual void Unlock() = 0;
 
   virtual bool HaveBuffer() const = 0;
   virtual bool HaveBufferOnWhite() const = 0;
 
   virtual gfx::SurfaceFormat GetFormat() const = 0;
 
   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
 
   virtual gfx::DrawTarget* GetDTBuffer() const = 0;
   virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
 
-  virtual TextureClient* GetClient() const {
-    return nullptr;
-  }
-  virtual TextureClient* GetClientOnWhite() const {
-    return nullptr;
-  }
-
-  /**
-   * Creates a shallow copy of the rotated buffer with the same underlying
-   * texture clients and draw targets. Rotated buffers are not thread safe,
-   * so a copy needs to be sent for off main thread painting.
-   */
-  virtual RefPtr<RotatedBuffer> ShallowCopy() const = 0;
-
 protected:
   virtual ~RotatedBuffer() {}
 
   enum XSide {
     LEFT, RIGHT
   };
   enum YSide {
     TOP, BOTTOM
@@ -329,42 +289,23 @@ public:
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
 
   virtual gfx::DrawTarget* GetDTBuffer() const override;
   virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
 
-  virtual TextureClient* GetClient() const override { return mClient; }
-  virtual TextureClient* GetClientOnWhite() const override { return mClientOnWhite; }
-
-  virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
-    return new RemoteRotatedBuffer {
-      mClient, mClientOnWhite,
-      mTarget, mTargetOnWhite,
-      mBufferRect, mBufferRotation
-    };
-  }
+  TextureClient* GetClient() const { return mClient; }
+  TextureClient* GetClientOnWhite() const { return mClientOnWhite; }
 
   void SyncWithObject(SyncObjectClient* aSyncObject);
   void Clear();
 
 private:
-  RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
-                      gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite,
-                      const gfx::IntRect& aBufferRect,
-                      const gfx::IntPoint& aBufferRotation)
-    : RotatedBuffer(aBufferRect, aBufferRotation)
-    , mClient(aClient)
-    , mClientOnWhite(aClientOnWhite)
-    , mTarget(aTarget)
-    , mTargetOnWhite(aTargetOnWhite)
-  { }
-
   RefPtr<TextureClient> mClient;
   RefPtr<TextureClient> mClientOnWhite;
 
   RefPtr<gfx::DrawTarget> mTarget;
   RefPtr<gfx::DrawTarget> mTargetOnWhite;
 };
 
 /**
@@ -391,23 +332,16 @@ public:
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
 
   virtual gfx::DrawTarget* GetDTBuffer() const override;
   virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
 
-  virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
-    return new DrawTargetRotatedBuffer {
-        mTarget, mTargetOnWhite,
-        mBufferRect, mBufferRotation
-      };
-  }
-
 private:
   RefPtr<gfx::DrawTarget> mTarget;
   RefPtr<gfx::DrawTarget> mTargetOnWhite;
 };
 
 /**
  * SourceRotatedBuffer is a rotated buffer that is backed by source surfaces,
  * and may only be used to draw into other buffers or be read directly.
@@ -432,20 +366,16 @@ public:
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual bool HaveBuffer() const override { return !!mSource; }
   virtual bool HaveBufferOnWhite() const override { return !!mSourceOnWhite; }
 
   virtual gfx::DrawTarget* GetDTBuffer() const override { return nullptr; }
   virtual gfx::DrawTarget* GetDTBufferOnWhite() const override { return nullptr; }
 
-  virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
-    return nullptr;
-  }
-
 private:
   RefPtr<gfx::SourceSurface> mSource;
   RefPtr<gfx::SourceSurface> mSourceOnWhite;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -205,27 +205,21 @@ ClientPaintedLayer::PaintThebes(nsTArray
  *     the main thread. Sync OMTP is only meant to be used as a debugging tool.
  */
 bool
 ClientPaintedLayer::PaintOffMainThread()
 {
   uint32_t flags = GetPaintFlags();
 
   PaintState state = mContentClient->BeginPaint(this, flags | ContentClient::PAINT_ASYNC);
-  bool didUpdate = false;
-
-  if (state.mBufferState) {
-    PaintThread::Get()->PrepareBuffer(state.mBufferState);
-    didUpdate = true;
-  }
-
   if (!UpdatePaintRegion(state)) {
     return false;
   }
 
+  bool didUpdate = false;
   RotatedBuffer::DrawIterator iter;
 
   // Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
   while (RefPtr<CapturedPaintState> captureState =
           mContentClient->BorrowDrawTargetForRecording(state, &iter))
   {
     DrawTarget* target = captureState->mTargetDual;
     if (!target || !target->IsValid()) {
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -18,17 +18,16 @@
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"
 #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
 #include "mozilla/layers/LayersTypes.h"
-#include "mozilla/layers/PaintThread.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLayoutUtils.h"
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 #ifdef MOZ_WIDGET_GTK
@@ -123,170 +122,124 @@ ContentClient::BeginPaint(PaintedLayer* 
 
   if (!dest.mCanKeepBufferContents) {
     // We're effectively clearing the valid region, so we need to draw
     // the entire needed region now.
     MOZ_ASSERT(!dest.mCanReuseBuffer);
     MOZ_ASSERT(dest.mValidRegion.IsEmpty());
 
     result.mRegionToInvalidate = aLayer->GetValidRegion();
+    Clear();
 
 #if defined(MOZ_DUMP_PAINTING)
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-      if (result.mContentType != mBuffer->GetContentType()) {
+      if (result.mContentType != BufferContentType()) {
         printf_stderr("Invalidating entire rotated buffer (layer %p): content type changed\n", aLayer);
       } else if ((dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mBuffer->HaveBufferOnWhite()) {
         printf_stderr("Invalidating entire rotated buffer (layer %p): component alpha changed\n", aLayer);
       }
     }
 #endif
-    Clear();
   }
 
   result.mRegionToDraw.Sub(dest.mNeededRegion,
                            dest.mValidRegion);
 
   if (result.mRegionToDraw.IsEmpty())
     return result;
 
+  OpenMode lockMode = aFlags & PAINT_ASYNC ? OpenMode::OPEN_READ_ASYNC_WRITE
+                                           : OpenMode::OPEN_READ_WRITE;
+
+  if (mBuffer) {
+    if (mBuffer->Lock(lockMode)) {
+      // Do not modify result.mRegionToDraw or result.mContentType after this call.
+      // Do not modify the back buffer's bufferRect, bufferRotation, or didSelfCopy.
+      FinalizeFrame(result.mRegionToDraw);
+    } else {
+      // Abandon everything and redraw it all. Ideally we'd reallocate and copy
+      // the old to the new and then call FinalizeFrame on the new buffer so that
+      // we only need to draw the latest bits, but we need a big refactor to support
+      // that ordering.
+      result.mRegionToDraw = dest.mNeededRegion;
+      dest.mCanReuseBuffer = false;
+      Clear();
+    }
+  }
+
   // We need to disable rotation if we're going to be resampled when
   // drawing, because we might sample across the rotation boundary.
   // Also disable buffer rotation when using webrender.
   bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
                          !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
                          !(aLayer->Manager()->AsWebRenderLayerManager());
   bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
-  bool asyncPaint = (aFlags & PAINT_ASYNC);
 
   IntRect drawBounds = result.mRegionToDraw.GetBounds();
-  OpenMode lockMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC_WRITE
-                                 : OpenMode::OPEN_READ_WRITE;
-
-  if (dest.mCanReuseBuffer) {
-    MOZ_ASSERT(mBuffer);
-
-    bool canReuseBuffer = false;
-
-    if (mBuffer->Lock(lockMode)) {
-      RefPtr<CapturedBufferState> bufferState = new CapturedBufferState();
-
-      // Do not modify result.mRegionToDraw or result.mContentType after this call.
-      FinalizeFrame(result.mRegionToDraw, bufferState);
-
-      auto newParameters = mBuffer->AdjustedParameters(dest.mBufferRect);
-
-      if ((!canHaveRotation && newParameters.IsRotated()) ||
-          (!canDrawRotated && newParameters.RectWrapsBuffer(drawBounds))) {
-        bufferState->mBufferUnrotate = Some(CapturedBufferState::Unrotate {
-          newParameters,
-          mBuffer->ShallowCopy(),
-        });
-      }
+  RefPtr<RotatedBuffer> newBuffer;
+  uint32_t bufferFlags = 0;
+  if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+    bufferFlags |= BUFFER_COMPONENT_ALPHA;
+  }
+  if (dest.mCanReuseBuffer && mBuffer) {
+    if (!mBuffer->AdjustTo(dest.mBufferRect,
+                           drawBounds,
+                           canHaveRotation,
+                           canDrawRotated)) {
+      dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
+      newBuffer = CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags);
 
-      // If we're async painting then return the buffer state to
-      // be dispatched to the paint thread, otherwise do it now
-      if (asyncPaint) {
-        // We cannot do a buffer unrotate if the buffer is already rotated
-        // and we're async painting as that may fail
-        if (!bufferState->mBufferUnrotate ||
-            mBuffer->BufferRotation() == IntPoint(0,0)) {
-          result.mBufferState = bufferState;
-
-          // We can then assume that preparing the buffer will always
-          // succeed and update our parameters unconditionally
-          if (bufferState->mBufferUnrotate) {
-            newParameters.SetUnrotated();
-          }
-          mBuffer->SetParameters(newParameters);
-          canReuseBuffer = true;
+      if (!newBuffer) {
+        if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+          gfxCriticalNote << "Failed 1 buffer for "
+                          << dest.mBufferRect.x << ", "
+                          << dest.mBufferRect.y << ", "
+                          << dest.mBufferRect.Width() << ", "
+                          << dest.mBufferRect.Height();
         }
-      } else {
-        if (bufferState->PrepareBuffer()) {
-          if (bufferState->mBufferUnrotate) {
-            newParameters.SetUnrotated();
-          }
-          mBuffer->SetParameters(newParameters);
-          canReuseBuffer = true;
-        }
+        return result;
       }
     }
-
-    if (!canReuseBuffer) {
-      if (mBuffer->IsLocked()) {
-        mBuffer->Unlock();
-      }
-      dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
-      dest.mCanReuseBuffer = false;
-      dest.mMustRemoveFrontBuffer = true;
-    }
-  }
-
-  NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
-               "If we're resampling, we need to validate the entire buffer");
-
-  // We never had a buffer, the buffer wasn't big enough, the content changed
-  // types, or we failed to unrotate the buffer when requested. In any case,
-  // we need to allocate a new one and prepare it for drawing.
-  if (!dest.mCanReuseBuffer) {
-    uint32_t bufferFlags = 0;
-    if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-      bufferFlags |= BUFFER_COMPONENT_ALPHA;
-    }
-
-    RefPtr<RotatedBuffer> newBuffer = CreateBuffer(result.mContentType,
-                                                   dest.mBufferRect,
-                                                   bufferFlags);
-
+  } else {
+    // The buffer's not big enough, so allocate a new one
+    newBuffer = CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags);
     if (!newBuffer) {
       if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
-        gfxCriticalNote << "Failed buffer for "
+        gfxCriticalNote << "Failed 2 buffer for "
                         << dest.mBufferRect.x << ", "
                         << dest.mBufferRect.y << ", "
                         << dest.mBufferRect.Width() << ", "
                         << dest.mBufferRect.Height();
       }
       return result;
     }
+  }
 
+  NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
+               "If we're resampling, we need to validate the entire buffer");
+
+  // If needed, copy the old buffer over to the new one
+  if (newBuffer) {
     if (!newBuffer->Lock(lockMode)) {
       gfxCriticalNote << "Failed to lock new back buffer.";
+      Clear();
       return result;
     }
 
-    // If we have an existing front buffer, copy it into the new back buffer
-    if (RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer()) {
-      nsIntRegion updateRegion = newBuffer->BufferRect();
-      updateRegion.Sub(updateRegion, result.mRegionToDraw);
-
-      if (!updateRegion.IsEmpty()) {
-        RefPtr<CapturedBufferState> bufferState = new CapturedBufferState();
-
-        bufferState->mBufferCopy = Some(CapturedBufferState::Copy {
-          frontBuffer->ShallowCopy(),
-          newBuffer->ShallowCopy(),
-          updateRegion.GetBounds(),
-        });
+    if (mBuffer) {
+      newBuffer->UpdateDestinationFrom(*mBuffer, newBuffer->BufferRect());
 
-        // If we're async painting then return the buffer state to
-        // be dispatched to the paint thread, otherwise do it now
-        if (asyncPaint) {
-          MOZ_ASSERT(!result.mBufferState);
-          result.mBufferState = bufferState;
-        } else {
-          if (!bufferState->PrepareBuffer()) {
-            gfxCriticalNote << "Failed to copy front buffer to back buffer.";
-            return result;
-          }
-        }
-      }
+      // We are done with the old back buffer now and it is about to be
+      // destroyed, so unlock it.
+      mBuffer->Unlock();
+    }
 
-      if (dest.mMustRemoveFrontBuffer) {
-        Clear();
-      }
-    }
+    // Ensure our reference to the front buffer is released
+    // as well as the old back buffer.
+    Clear();
 
     mBuffer = newBuffer;
   }
 
   NS_ASSERTION(canHaveRotation || mBuffer->BufferRotation() == IntPoint(0,0),
                "Rotation disabled, but we have nonzero rotation?");
 
   nsIntRegion invalidate;
@@ -414,64 +367,45 @@ ContentClient::PrepareDrawTargetForPaint
 ContentClient::BufferDecision
 ContentClient::CalculateBufferForPaint(PaintedLayer* aLayer,
                                        uint32_t aFlags)
 {
   gfxContentType layerContentType =
     aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
                                     gfxContentType::COLOR_ALPHA;
 
-  RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer();
-
   SurfaceMode mode;
   gfxContentType contentType;
   IntRect destBufferRect;
   nsIntRegion neededRegion;
   nsIntRegion validRegion = aLayer->GetValidRegion();
 
   bool canReuseBuffer = !!mBuffer;
   bool canKeepBufferContents = true;
-  bool mustRemoveFrontBuffer = false;
 
   while (true) {
     mode = aLayer->GetSurfaceMode();
     neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
-    canReuseBuffer = canReuseBuffer && ValidBufferSize(mBufferSizePolicy,
-                                                       mBuffer->BufferRect().Size(),
-                                                       neededRegion.GetBounds().Size());
+    canReuseBuffer = canReuseBuffer && BufferSizeOkFor(neededRegion.GetBounds().Size());
     contentType = layerContentType;
 
     if (canReuseBuffer) {
       if (mBuffer->BufferRect().Contains(neededRegion.GetBounds())) {
         // We don't need to adjust mBufferRect.
         destBufferRect = mBuffer->BufferRect();
       } else if (neededRegion.GetBounds().Size() <= mBuffer->BufferRect().Size()) {
         // The buffer's big enough but doesn't contain everything that's
         // going to be visible. We'll move it.
         destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBuffer->BufferRect().Size());
       } else {
         destBufferRect = neededRegion.GetBounds();
       }
     } else {
-      // We won't be reusing the buffer. Compute a new rect.
-      if (frontBuffer) {
-        // We must create a buffer that is the same size as the front buffer,
-        // or else we need to remove the front buffer
-        if (ValidBufferSize(mBufferSizePolicy,
-                            frontBuffer->BufferRect().Size(),
-                            neededRegion.GetBounds().Size())) {
-          destBufferRect = frontBuffer->BufferRect();
-          destBufferRect.MoveTo(neededRegion.GetBounds().TopLeft());
-        } else {
-          destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
-          mustRemoveFrontBuffer = true;
-        }
-      } else {
-        destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
-      }
+      // We won't be reusing the buffer.  Compute a new rect.
+      destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
     }
 
     if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
 #if defined(MOZ_GFX_OPTIMIZE_MOBILE)
       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
 #else
       if (!aLayer->GetParent() ||
           !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
@@ -496,30 +430,21 @@ ContentClient::CalculateBufferForPaint(P
 
       // We need to validate the entire buffer, to make sure that only valid
       // pixels are sampled.
       neededRegion = destBufferRect;
     }
 
     // If we have an existing buffer, but the content type has changed or we
     // have transitioned into/out of component alpha, then we need to recreate it.
-    bool needsComponentAlpha = (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA);
-    bool backBufferChangedSurface = mBuffer &&
-                                    (contentType != mBuffer->GetContentType() ||
-                                     needsComponentAlpha != mBuffer->HaveBufferOnWhite());
-    if (canKeepBufferContents && backBufferChangedSurface) {
-      // We cannot reuse the back buffer if the surface type or content type
-      // changed. We may have to also invalidate, but only if the front buffer
-      // also changed.
-      canReuseBuffer = false;
-    }
-    bool frontBufferChangedSurface = frontBuffer &&
-                                     (contentType != frontBuffer->GetContentType() ||
-                                      needsComponentAlpha != frontBuffer->HaveBufferOnWhite());
-    if (canKeepBufferContents && frontBufferChangedSurface) {
+    if (canKeepBufferContents &&
+        mBuffer &&
+        (contentType != BufferContentType() ||
+        (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mBuffer->HaveBufferOnWhite()))
+    {
       // Restart the decision process; we won't re-enter since we guard on
       // being able to keep the buffer contents.
       canReuseBuffer = false;
       canKeepBufferContents = false;
       validRegion.SetEmpty();
       continue;
     }
 
@@ -532,34 +457,35 @@ ContentClient::CalculateBufferForPaint(P
   BufferDecision dest;
   dest.mNeededRegion = Move(neededRegion);
   dest.mValidRegion = Move(validRegion);
   dest.mBufferRect = destBufferRect;
   dest.mBufferMode = mode;
   dest.mBufferContentType = contentType;
   dest.mCanReuseBuffer = canReuseBuffer;
   dest.mCanKeepBufferContents = canKeepBufferContents;
-  dest.mMustRemoveFrontBuffer = mustRemoveFrontBuffer;
   return dest;
 }
 
+gfxContentType
+ContentClient::BufferContentType()
+{
+  if (mBuffer) {
+    return ContentForFormat(mBuffer->GetFormat());
+  }
+  return gfxContentType::SENTINEL;
+}
+
 bool
-ContentClient::ValidBufferSize(BufferSizePolicy aPolicy,
-                               const gfx::IntSize& aBufferSize,
-                               const gfx::IntSize& aVisibleBoundsSize)
+ContentClient::BufferSizeOkFor(const IntSize& aSize)
 {
-  return (aVisibleBoundsSize == aBufferSize ||
-          (SizedToVisibleBounds != aPolicy &&
-           aVisibleBoundsSize < aBufferSize));
-}
-
-RefPtr<RotatedBuffer>
-ContentClient::GetFrontBuffer() const
-{
-  return mBuffer;
+  MOZ_ASSERT(mBuffer);
+  return (aSize == mBuffer->BufferRect().Size() ||
+          (SizedToVisibleBounds != mBufferSizePolicy &&
+           aSize < mBuffer->BufferRect().Size()));
 }
 
 void
 ContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
 }
@@ -910,85 +836,97 @@ ContentClientDoubleBuffered::SwapBuffers
 
   mFrontAndBackBufferDiffer = true;
 }
 
 ContentClient::PaintState
 ContentClientDoubleBuffered::BeginPaint(PaintedLayer* aLayer,
                                         uint32_t aFlags)
 {
+  EnsureBackBufferIfFrontBuffer();
+
   mIsNewBuffer = false;
+
   if (!mFrontBuffer || !mBuffer) {
     mFrontAndBackBufferDiffer = false;
   }
 
-  return ContentClient::BeginPaint(aLayer, aFlags);
-}
+  if (mFrontAndBackBufferDiffer) {
+    if (mFrontBuffer->DidSelfCopy()) {
+      // We can't easily draw our front buffer into us, since we're going to be
+      // copying stuff around anyway it's easiest if we just move our situation
+      // to non-rotated while we're at it. If this situation occurs we'll have
+      // hit a self-copy path in PaintThebes before as well anyway.
+      gfx::IntRect backBufferRect = mBuffer->BufferRect();
+      backBufferRect.MoveTo(mFrontBuffer->BufferRect().TopLeft());
 
-RefPtr<RotatedBuffer>
-ContentClientDoubleBuffered::GetFrontBuffer() const
-{
-  return mFrontBuffer;
+      mBuffer->SetBufferRect(backBufferRect);
+      mBuffer->SetBufferRotation(IntPoint(0,0));
+    } else {
+      mBuffer->SetBufferRect(mFrontBuffer->BufferRect());
+      mBuffer->SetBufferRotation(mFrontBuffer->BufferRotation());
+    }
+  }
+
+  return ContentClient::BeginPaint(aLayer, aFlags);
 }
 
 // Sync front/back buffers content
 // After executing, the new back buffer has the same (interesting) pixels as
 // the new front buffer, and mValidRegion et al. are correct wrt the new
 // back buffer (i.e. as they were for the old back buffer)
 void
-ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw,
-                                           CapturedBufferState* aPrepareState)
+ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
 {
   if (!mFrontAndBackBufferDiffer) {
-    MOZ_ASSERT(!mFrontBuffer || !mFrontBuffer->DidSelfCopy(),
-               "If the front buffer did a self copy then our front and back buffer must be different.");
+    MOZ_ASSERT(!mFrontBuffer->DidSelfCopy(), "If we have to copy the world, then our buffers are different, right?");
     return;
   }
-
-  MOZ_ASSERT(mFrontBuffer && mBuffer);
-  if (!mFrontBuffer || !mBuffer) {
+  MOZ_ASSERT(mFrontBuffer);
+  if (!mFrontBuffer) {
     return;
   }
 
   MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
                   this,
                   mFrontUpdatedRegion.GetBounds().x,
                   mFrontUpdatedRegion.GetBounds().y,
                   mFrontUpdatedRegion.GetBounds().Width(),
                   mFrontUpdatedRegion.GetBounds().Height()));
 
   mFrontAndBackBufferDiffer = false;
 
-  // Move the back buffer rect and rotation to the front buffer rect and rotation
-  // so that we can update the pixels that changed between frames
-  gfx::IntRect backBufferRect = mBuffer->BufferRect();
-  backBufferRect.MoveTo(mFrontBuffer->BufferRect().TopLeft());
-  mBuffer->SetBufferRect(backBufferRect);
-  mBuffer->SetBufferRotation(mFrontBuffer->BufferRotation());
-
-  // Calculate the region to update
   nsIntRegion updateRegion = mFrontUpdatedRegion;
   if (mFrontBuffer->DidSelfCopy()) {
-    // If we did an unrotate operation on the front buffer we might as well
-    // unrotate as well because we will be reading back the whole front buffer
-    mBuffer->SetBufferRotation(IntPoint(0,0));
-
     mFrontBuffer->ClearDidSelfCopy();
     updateRegion = mBuffer->BufferRect();
   }
 
   // No point in sync'ing what we are going to draw over anyway. And if there is
   // nothing to sync at all, there is nothing to do and we can go home early.
   updateRegion.Sub(updateRegion, aRegionToDraw);
   if (updateRegion.IsEmpty()) {
     return;
   }
 
-  MOZ_ASSERT(!aPrepareState->mBufferCopy);
-  aPrepareState->mBufferCopy = Some(CapturedBufferState::Copy {
-    mFrontBuffer->ShallowCopy(),
-    mBuffer->ShallowCopy(),
-    updateRegion.GetBounds(),
-  });
+  if (!mBuffer) {
+    return;
+  }
+
+  if (mFrontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
+    mBuffer->UpdateDestinationFrom(*mFrontBuffer, updateRegion.GetBounds());
+    mFrontBuffer->Unlock();
+  }
+}
+
+void
+ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
+{
+  if (!mBuffer && mFrontBuffer) {
+    mBuffer = CreateBufferInternal(mFrontBuffer->BufferRect(),
+                                   mFrontBuffer->GetFormat(),
+                                   mTextureFlags);
+    MOZ_ASSERT(mBuffer);
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -17,17 +17,16 @@
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
-#include "mozilla/layers/PaintThread.h"  // for CapturedBufferState
 #include "mozilla/Maybe.h"              // for Maybe
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "ReadbackProcessor.h"          // For ReadbackProcessor::Update
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
@@ -36,19 +35,16 @@ namespace mozilla {
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 
 class PaintedLayer;
 class CapturedPaintState;
-class CapturedBufferState;
-
-typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
 
 /**
  * A compositable client for PaintedLayers. These are different to Image/Canvas
  * clients due to sending a valid region across IPC and because we do a lot more
  * optimisation work, encapsulated in RotatedBuffers.
  *
  * We use content clients for OMTC and non-OMTC, basic rendering so that
  * BasicPaintedLayer has only one interface to deal with. We support single and
@@ -113,17 +109,16 @@ public:
       , mContentType(gfxContentType::SENTINEL)
     {}
 
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     SurfaceMode mMode;
     DrawRegionClip mClip;
     gfxContentType mContentType;
-    RefPtr<CapturedBufferState> mBufferState;
   };
 
   enum {
     PAINT_WILL_RESAMPLE = 0x01,
     PAINT_NO_ROTATION = 0x02,
     PAINT_CAN_DRAW_ROTATED = 0x04,
     PAINT_ASYNC = 0x08,
   };
@@ -193,42 +188,44 @@ protected:
   struct BufferDecision {
     nsIntRegion mNeededRegion;
     nsIntRegion mValidRegion;
     gfx::IntRect mBufferRect;
     SurfaceMode mBufferMode;
     gfxContentType mBufferContentType;
     bool mCanReuseBuffer;
     bool mCanKeepBufferContents;
-    bool mMustRemoveFrontBuffer;
   };
 
   /**
    * Decide whether we can keep our current buffer and its contents,
    * and return a struct containing the regions to paint, invalidate,
    * the new buffer rect, surface mode, and content type.
    */
   BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer,
                                          uint32_t aFlags);
 
-  static bool ValidBufferSize(BufferSizePolicy aPolicy,
-                              const gfx::IntSize& aBufferSize,
-                              const gfx::IntSize& aVisibleBoundsSize);
-
-  virtual RefPtr<RotatedBuffer> GetFrontBuffer() const;
+  /**
+   * Return the buffer's content type.  Requires a valid buffer.
+   */
+  gfxContentType BufferContentType();
+  /**
+   * Returns whether the specified size is adequate for the current
+   * buffer and buffer size policy.
+   */
+  bool BufferSizeOkFor(const gfx::IntSize& aSize);
 
   /**
    * Any actions that should be performed at the last moment before we begin
    * rendering the next frame. I.e., after we calculate what we will draw,
    * but before we rotate the buffer and possibly create new buffers.
    * aRegionToDraw is the region which is guaranteed to be overwritten when
    * drawing the next frame.
    */
-  virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw,
-                             CapturedBufferState* aState) {}
+  virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
 
   /**
    * Create a new rotated buffer for the specified content type, buffer rect,
    * and buffer flags.
    */
   virtual RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
                                              const gfx::IntRect& aRect,
                                              uint32_t aFlags) = 0;
@@ -361,27 +358,26 @@ public:
                     TextureDumpMode aCompress=TextureDumpMode::Compress) override;
 
   virtual void Clear() override;
 
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
 
   virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) override;
 
-  virtual RefPtr<RotatedBuffer> GetFrontBuffer() const override;
-
-  virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw,
-                             CapturedBufferState* aState) override;
+  virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
 
   virtual TextureInfo GetTextureInfo() const override
   {
     return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
   }
 
 private:
+  void EnsureBackBufferIfFrontBuffer();
+
   RefPtr<RemoteRotatedBuffer> mFrontBuffer;
   nsIntRegion mFrontUpdatedRegion;
   bool mFrontAndBackBufferDiffer;
 };
 
 /**
  * A single buffered ContentClientRemoteBuffer. We have a single
  * TextureClient/Host which we update and then send a message to the
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -687,16 +687,20 @@ TextureClient::BorrowDrawTarget()
   // the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
   // but we should have a way to get a SourceSurface directly instead.
   //MOZ_ASSERT(mOpenMode & OpenMode::OPEN_WRITE);
 
   if (!IsValid() || !mIsLocked) {
     return nullptr;
   }
 
+  if (!NS_IsMainThread()) {
+    return nullptr;
+  }
+
   if (!mBorrowedDrawTarget) {
     mBorrowedDrawTarget = mData->BorrowDrawTarget();
 #ifdef DEBUG
     mExpectedDtRefs = mBorrowedDrawTarget ? mBorrowedDrawTarget->refCount() : 0;
 #endif
   }
 
   return mBorrowedDrawTarget;
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -759,17 +759,17 @@ CreateTextureHostD3D11(const SurfaceDesc
   }
   return result.forget();
 }
 
 
 already_AddRefed<DrawTarget>
 D3D11TextureData::BorrowDrawTarget()
 {
-  MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
+  MOZ_ASSERT(NS_IsMainThread());
 
   if (!mDrawTarget && mTexture) {
     // This may return a null DrawTarget
     mDrawTarget = Factory::CreateDrawTargetForD3D11Texture(mTexture, mFormat);
     if (!mDrawTarget) {
       gfxCriticalNote << "Could not borrow DrawTarget (D3D11) " << (int)mFormat;
     }
   }
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1189,44 +1189,16 @@ CompositorBridgeChild::FlushAsyncPaints(
 
     double ratio = double(mSlowFlushCount) / double(mTotalFlushCount);
     Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO,
                          uint32_t(ratio * 100 * 100));
   }
 }
 
 void
-CompositorBridgeChild::NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MonitorAutoLock lock(mPaintLock);
-
-  // We must not be waiting for paints (or buffer copying) to complete yet. This
-  // would imply we started a new paint without waiting for a previous one, which
-  // could lead to incorrect rendering or IPDL deadlocks.
-  MOZ_ASSERT(!mIsDelayingForAsyncPaints);
-
-  mOutstandingAsyncPaints++;
-
-  // Mark texture clients that they are being used for async painting, and
-  // make sure we hold them alive on the main thread.
-  aState->GetTextureClients(mTextureClientsForAsyncPaint);
-}
-
-void
-CompositorBridgeChild::NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState)
-{
-  MOZ_ASSERT(PaintThread::IsOnPaintThread());
-
-  MonitorAutoLock lock(mPaintLock);
-  mOutstandingAsyncPaints--;
-}
-
-void
 CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MonitorAutoLock lock(mPaintLock);
 
   // We must not be waiting for paints to complete yet. This would imply we
   // started a new paint without waiting for a previous one, which could lead to
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -40,17 +40,16 @@ using mozilla::dom::TabChild;
 class IAPZCTreeManager;
 class APZCTreeManagerChild;
 class ClientLayerManager;
 class CompositorBridgeParent;
 class CompositorManagerChild;
 class CompositorOptions;
 class TextureClient;
 class TextureClientPool;
-class CapturedBufferState;
 class CapturedPaintState;
 struct FrameMetrics;
 
 class CompositorBridgeChild final : public PCompositorBridgeChild,
                                     public TextureForwarder
 {
   typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
 
@@ -224,24 +223,16 @@ public:
   wr::PipelineId GetNextPipelineId();
 
   // Must only be called from the main thread. Ensures that any paints from
   // previous frames have been flushed. The main thread blocks until the
   // operation completes.
   void FlushAsyncPaints();
 
   // Must only be called from the main thread. Notifies the CompositorBridge
-  // that the paint thread is going to begin preparing a buffer asynchronously.
-  void NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState);
-
-  // Must only be called from the paint thread. Notifies the CompositorBridge
-  // that the paint thread has finished an asynchronous buffer prepare.
-  void NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState);
-
-  // Must only be called from the main thread. Notifies the CompositorBridge
   // that the paint thread is going to begin painting asynchronously.
   void NotifyBeginAsyncPaint(CapturedPaintState* aState);
 
   // Must only be called from the paint thread. Notifies the CompositorBridge
   // that the paint thread has finished an asynchronous paint request.
   void NotifyFinishedAsyncPaint(CapturedPaintState* aState);
 
   // Must only be called from the main thread. Notifies the CompositorBridge
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -218,17 +218,16 @@ EXPORTS.mozilla.layers += [
     'opengl/CompositorOGL.h',
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'PaintThread.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
-    'RotatedBuffer.h',
     'ShareableCanvasRenderer.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'SyncObject.h',
     'TextureSourceProvider.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
     'UpdateImageHelper.h',