Use a RemoteRotatedBuffer for the front buffer of ContentClientDoubleBuffered. (bug 1409871 part 5, r=nical) draft
authorRyan Hunt <rhunt@eqrion.net>
Wed, 11 Oct 2017 15:22:57 -0400
changeset 684127 9a369bc08fe994fd7e722931631085e9aa3dad80
parent 684126 5a3030b14c133cbbe7b3002061e7873c0109d3b9
child 684128 78cf5c683fba1640f3bb95bb345bb437d660c347
push id85567
push userbmo:rhunt@eqrion.net
push dateFri, 20 Oct 2017 22:13:22 +0000
reviewersnical
bugs1409871
milestone58.0a1
Use a RemoteRotatedBuffer for the front buffer of ContentClientDoubleBuffered. (bug 1409871 part 5, r=nical) The front buffer for a double buffered content client is really just another rotated buffer, so it can simplify the code to use the class we just added. The goal is to have the back and the front buffer using remote rotated buffers, but this is a good first step. Note: The front buffer is represented as a Maybe<RemoteRotatedBuffer> in this commit, but in the future it will be a RefPtr. That can't be done yet, because rotated buffer can't implement refcounting in addition to compositable client. MozReview-Commit-ID: Czk3otkf1pb
gfx/layers/RotatedBuffer.cpp
gfx/layers/RotatedBuffer.h
gfx/layers/client/ContentClient.cpp
gfx/layers/client/ContentClient.h
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -391,16 +391,24 @@ RemoteRotatedBuffer::Unlock()
   if (mClient->IsLocked()) {
     mClient->Unlock();
   }
   if (mClientOnWhite && mClientOnWhite->IsLocked()) {
     mClientOnWhite->Unlock();
   }
 }
 
+void
+RemoteRotatedBuffer::Clear()
+{
+  MOZ_ASSERT(!mTarget && !mTargetOnWhite);
+  mClient = nullptr;
+  mClientOnWhite = nullptr;
+}
+
 already_AddRefed<gfx::SourceSurface>
 RemoteRotatedBuffer::GetSourceSurface(ContextSource aSource) const
 {
   if (aSource == ContextSource::BUFFER_BLACK) {
     return mTarget->Snapshot();
   } else {
     MOZ_ASSERT(aSource == ContextSource::BUFFER_WHITE);
     return mTargetOnWhite->Snapshot();
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -209,16 +209,21 @@ public:
     : RotatedBuffer(aBufferRect, aBufferRotation)
     , mClient(aClient)
     , mClientOnWhite(aClientOnWhite)
   { }
 
   bool Lock(OpenMode aMode);
   void Unlock();
 
+  void Clear();
+
+  TextureClient* GetClient() const { return mClient; }
+  TextureClient* GetClientOnWhite() const { return mClientOnWhite; }
+
   virtual bool HaveBuffer() const override { return !!mClient; }
   virtual bool HaveBufferOnWhite() const override { return !!mClientOnWhite; }
 
   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
 
 protected:
   virtual gfx::DrawTarget* GetDTBuffer() const override;
   virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -527,89 +527,102 @@ void
 ContentClientDoubleBuffered::Dump(std::stringstream& aStream,
                                   const char* aPrefix,
                                   bool aDumpHtml, TextureDumpMode aCompress)
 {
   // TODO We should combine the OnWhite/OnBlack here an just output a single image.
   if (!aDumpHtml) {
     aStream << "\n" << aPrefix << "Surface: ";
   }
-  CompositableClient::DumpTextureClient(aStream, mFrontClient, aCompress);
+  if (mFrontBuffer) {
+    CompositableClient::DumpTextureClient(aStream, mFrontBuffer->GetClient(), aCompress);
+  }
 }
 
 void
 ContentClientDoubleBuffered::DestroyFrontBuffer()
 {
-  if (mFrontClient) {
-    mOldTextures.AppendElement(mFrontClient);
-    mFrontClient = nullptr;
-  }
+  if (mFrontBuffer) {
+    RefPtr<TextureClient> client = mFrontBuffer->GetClient();
+    RefPtr<TextureClient> clientOnWhite = mFrontBuffer->GetClientOnWhite();
 
-  if (mFrontClientOnWhite) {
-    mOldTextures.AppendElement(mFrontClientOnWhite);
-    mFrontClientOnWhite = nullptr;
+    if (client) {
+      mOldTextures.AppendElement(client);
+    }
+    if (clientOnWhite) {
+      mOldTextures.AppendElement(clientOnWhite);
+    }
+
+    mFrontBuffer = Nothing();
   }
 }
 
 void
 ContentClientDoubleBuffered::Updated(const nsIntRegion& aRegionToDraw,
                                      const nsIntRegion& aVisibleRegion,
                                      bool aDidSelfCopy)
 {
   ContentClientRemoteBuffer::Updated(aRegionToDraw, aVisibleRegion, aDidSelfCopy);
 }
 
 void
 ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
 {
   mFrontUpdatedRegion = aFrontUpdatedRegion;
 
-  RefPtr<TextureClient> oldBack = mTextureClient;
-  mTextureClient = mFrontClient;
-  mFrontClient = oldBack;
-
-  oldBack = mTextureClientOnWhite;
-  mTextureClientOnWhite = mFrontClientOnWhite;
-  mFrontClientOnWhite = oldBack;
+  RefPtr<TextureClient> newBack;
+  RefPtr<TextureClient> newBackOnWhite;
+  IntRect newBackBufferRect;
+  nsIntPoint newBackBufferRotation;
 
-  IntRect oldBufferRect = mBufferRect;
-  mBufferRect = mFrontBufferRect;
-  mFrontBufferRect = oldBufferRect;
+  if (mFrontBuffer) {
+    newBack = mFrontBuffer->GetClient();
+    newBackOnWhite = mFrontBuffer->GetClientOnWhite();
+    newBackBufferRect = mFrontBuffer->BufferRect();
+    newBackBufferRotation = mFrontBuffer->BufferRotation();
+  }
 
-  nsIntPoint oldBufferRotation = mBufferRotation;
-  mBufferRotation = mFrontBufferRotation;
-  mFrontBufferRotation = oldBufferRotation;
+  mFrontBuffer = Some(RemoteRotatedBuffer(mTextureClient, mTextureClientOnWhite,
+                                          mBufferRect, mBufferRotation));
 
-  MOZ_ASSERT(mFrontClient);
+  mTextureClient = newBack;
+  mTextureClientOnWhite = newBackOnWhite;
+  mBufferRect = newBackBufferRect;
+  mBufferRotation = newBackBufferRotation;
 
   ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
 }
 
 void
 ContentClientDoubleBuffered::BeginPaint()
 {
   ContentClientRemoteBuffer::BeginPaint();
 
   mIsNewBuffer = false;
 
   if (!mFrontAndBackBufferDiffer) {
     return;
   }
 
+  if (!mFrontBuffer) {
+    mFrontAndBackBufferDiffer = false;
+    return;
+  }
+
   if (mDidSelfCopy) {
     // 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.
-    mBufferRect.MoveTo(mFrontBufferRect.TopLeft());
+    mBufferRect.MoveTo(mFrontBuffer->BufferRect().TopLeft());
     mBufferRotation = nsIntPoint();
     return;
   }
-  mBufferRect = mFrontBufferRect;
-  mBufferRotation = mFrontBufferRotation;
+  mBufferRect = mFrontBuffer->BufferRect();
+  mBufferRotation = mFrontBuffer->BufferRotation();
 }
 
 void
 ContentClientDoubleBuffered::BeginAsyncPaint()
 {
   BeginPaint();
   mInAsyncPaint = true;
 }
@@ -620,18 +633,18 @@ ContentClientDoubleBuffered::BeginAsyncP
 // back buffer (i.e. as they were for the old back buffer)
 void
 ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
 {
   if (!mFrontAndBackBufferDiffer) {
     MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
     return;
   }
-  MOZ_ASSERT(mFrontClient);
-  if (!mFrontClient) {
+  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(),
@@ -652,55 +665,27 @@ ContentClientDoubleBuffered::FinalizeFra
     return;
   }
 
   if (!EnsureBuffer() ||
       (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
     return;
   }
 
-  // We need to ensure that we lock these two buffers in the same
-  // order as the compositor to prevent deadlocks.
-  TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
-  if (!frontLock.Succeeded()) {
-    return;
-  }
-  Maybe<TextureClientAutoLock> frontOnWhiteLock;
-  if (mFrontClientOnWhite) {
-    frontOnWhiteLock.emplace(mFrontClientOnWhite, OpenMode::OPEN_READ_ONLY);
-    if (!frontOnWhiteLock->Succeeded()) {
-      return;
-    }
-  }
-
-  // Restrict the DrawTargets and frontBuffer to a scope to make
-  // sure there is no more external references to the DrawTargets
-  // when we Unlock the TextureClients.
-  gfx::DrawTarget* dt = mFrontClient->BorrowDrawTarget();
-  gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr;
-  if (dt && dt->IsValid()) {
-    RefPtr<SourceSurface> surf = dt->Snapshot();
-    RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr;
-    SourceRotatedBuffer frontBuffer(surf,
-                                    surfOnWhite,
-                                    mFrontBufferRect,
-                                    mFrontBufferRotation);
-    UpdateDestinationFrom(frontBuffer, updateRegion);
-  } else {
-    // We know this can happen, but we want to track it somewhat, in case it leads
-    // to other problems.
-    gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw);
+  if (mFrontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
+    UpdateDestinationFrom(*mFrontBuffer, updateRegion);
+    mFrontBuffer->Unlock();
   }
 }
 
 void
 ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
 {
-  if (!mTextureClient && mFrontClient) {
-    CreateBackBuffer(mFrontBufferRect);
+  if (!mTextureClient && mFrontBuffer) {
+    CreateBackBuffer(mFrontBuffer->BufferRect());
 
-    mBufferRect = mFrontBufferRect;
-    mBufferRotation = mFrontBufferRotation;
+    mBufferRect = mFrontBuffer->BufferRect();
+    mBufferRotation = mFrontBuffer->BufferRotation();
   }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -16,16 +16,17 @@
 #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/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
 
@@ -324,18 +325,17 @@ public:
     : ContentClientRemoteBuffer(aFwd)
   {}
 
   virtual ~ContentClientDoubleBuffered() {}
 
   virtual void Clear() override
   {
     ContentClientRemoteBuffer::Clear();
-    mFrontClient = nullptr;
-    mFrontClientOnWhite = nullptr;
+    mFrontBuffer = Nothing();
   }
 
   virtual void Updated(const nsIntRegion& aRegionToDraw,
                        const nsIntRegion& aVisibleRegion,
                        bool aDidSelfCopy) override;
 
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
 
@@ -359,25 +359,21 @@ protected:
   virtual void DestroyFrontBuffer() override;
 
 private:
 
   virtual void AbortTextureClientCreation() override
   {
     mTextureClient = nullptr;
     mTextureClientOnWhite = nullptr;
-    mFrontClient = nullptr;
-    mFrontClientOnWhite = nullptr;
+    mFrontBuffer = Nothing();
   }
 
-  RefPtr<TextureClient> mFrontClient;
-  RefPtr<TextureClient> mFrontClientOnWhite;
+  Maybe<RemoteRotatedBuffer> mFrontBuffer;
   nsIntRegion mFrontUpdatedRegion;
-  gfx::IntRect mFrontBufferRect;
-  nsIntPoint mFrontBufferRotation;
 };
 
 /**
  * A single buffered ContentClient. We have a single TextureClient/Host
  * which we update and then send a message to the compositor that we are
  * done updating. It is not safe for the compositor to use the corresponding
  * TextureHost's memory directly, it must upload it to video memory of some
  * kind. We are free to modify the TextureClient once we receive reply from