Bug 952507 - Flush the back buffer after syncing with the front buffer in the buffered ContentClient. r=Bas
authorNicolas Silva <nical@mozilla.com>
Tue, 04 Feb 2014 21:35:22 +0100
changeset 166817 145a831ad90ae29dc196fac657d9246406971e32
parent 166816 4f3b4bbccb54a0706e19e299d3feda6f2b63bf21
child 166818 dbeb31399750e6e46599e89c76cfcef5f8a7553c
push id39292
push usernsilva@mozilla.com
push dateTue, 04 Feb 2014 20:36:01 +0000
treeherdermozilla-inbound@145a831ad90a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs952507
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952507 - Flush the back buffer after syncing with the front buffer in the buffered ContentClient. r=Bas
gfx/layers/client/ClientThebesLayer.cpp
gfx/layers/client/ClientThebesLayer.h
gfx/layers/client/ContentClient.cpp
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d9/TextureD3D9.cpp
gfx/layers/d3d9/TextureD3D9.h
--- a/gfx/layers/client/ClientThebesLayer.cpp
+++ b/gfx/layers/client/ClientThebesLayer.cpp
@@ -128,18 +128,18 @@ ClientThebesLayer::PaintBuffer(gfxContex
   // NB: this just throws away the entire valid region if there are
   // too many rects.
   mValidRegion.SimplifyInward(8);
 
   if (!ClientManager()->GetThebesLayerCallback()) {
     ClientManager()->SetTransactionIncomplete();
     return;
   }
-  ClientManager()->GetThebesLayerCallback()(this, 
-                                            aContext, 
+  ClientManager()->GetThebesLayerCallback()(this,
+                                            aContext,
                                             aExtendedRegionToDraw,
                                             aClip,
                                             aRegionToInvalidate,
                                             ClientManager()->GetThebesLayerCallbackData());
 
   // Everything that's visible has been validated. Do this instead of just
   // OR-ing with aRegionToDraw, since that can lead to a very complex region
   // here (OR doesn't automatically simplify to the simplest possible
--- a/gfx/layers/client/ClientThebesLayer.h
+++ b/gfx/layers/client/ClientThebesLayer.h
@@ -102,17 +102,17 @@ public:
 protected:
   void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
               bool aDidSelfCopy,
               DrawRegionClip aClip);
-  
+
   void PaintThebes();
   
   void DestroyBackBuffer()
   {
     mContentClient = nullptr;
   }
 
   RefPtr<ContentClient> mContentClient;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -625,28 +625,32 @@ ContentClientDoubleBuffered::FinalizeFra
   if (!mFrontClient->Lock(OPEN_READ_ONLY)) {
     return;
   }
   if (mFrontClientOnWhite &&
       !mFrontClientOnWhite->Lock(OPEN_READ_ONLY)) {
     mFrontClient->Unlock();
     return;
   }
-  RefPtr<DrawTarget> dt =
-    mFrontClient->AsTextureClientDrawTarget()->GetAsDrawTarget();
-  RefPtr<DrawTarget> dtOnWhite = mFrontClientOnWhite
-    ? mFrontClientOnWhite->AsTextureClientDrawTarget()->GetAsDrawTarget()
-    : nullptr;
-  RotatedBuffer frontBuffer(dt,
-                            dtOnWhite,
-                            mFrontBufferRect,
-                            mFrontBufferRotation);
-  UpdateDestinationFrom(frontBuffer, updateRegion);
-  // We need to flush our buffers before we unlock our front textures
-  FlushBuffers();
+  {
+    // 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.
+    RefPtr<DrawTarget> dt =
+      mFrontClient->AsTextureClientDrawTarget()->GetAsDrawTarget();
+    RefPtr<DrawTarget> dtOnWhite = mFrontClientOnWhite
+      ? mFrontClientOnWhite->AsTextureClientDrawTarget()->GetAsDrawTarget()
+      : nullptr;
+    RotatedBuffer frontBuffer(dt,
+                              dtOnWhite,
+                              mFrontBufferRect,
+                              mFrontBufferRotation);
+    UpdateDestinationFrom(frontBuffer, updateRegion);
+  }
+
   mFrontClient->Unlock();
   if (mFrontClientOnWhite) {
     mFrontClientOnWhite->Unlock();
   }
 }
 
 void
 ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
@@ -662,16 +666,18 @@ ContentClientDoubleBuffered::UpdateDesti
   if (isClippingCheap) {
     gfxUtils::ClipToRegion(destDT, aUpdateRegion);
   }
 
   aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
   if (isClippingCheap) {
     destDT->PopClip();
   }
+  // Flush the destination before the sources become inaccessible (Unlock).
+  destDT->Flush();
   ReturnDrawTargetToBuffer(destDT);
 
   if (aSource.HaveBufferOnWhite()) {
     MOZ_ASSERT(HaveBufferOnWhite());
     DrawTarget* destDT =
       BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
     if (!destDT) {
       return;
@@ -681,16 +687,18 @@ ContentClientDoubleBuffered::UpdateDesti
     if (isClippingCheap) {
       gfxUtils::ClipToRegion(destDT, aUpdateRegion);
     }
 
     aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
     if (isClippingCheap) {
       destDT->PopClip();
     }
+    // Flush the destination before the sources become inaccessible (Unlock).
+    destDT->Flush();
     ReturnDrawTargetToBuffer(destDT);
   }
 }
 
 DeprecatedContentClientDoubleBuffered::~DeprecatedContentClientDoubleBuffered()
 {
   if (mDeprecatedTextureClient) {
     MOZ_ASSERT(mFrontClient);
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -150,53 +150,53 @@ TextureClientD3D11::TextureClientD3D11(g
 {}
 
 TextureClientD3D11::~TextureClientD3D11()
 {}
 
 bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
-  if (!IsValid() || !IsAllocated()) {
-    return false;
-  }
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
   LockD3DTexture(mTexture.get());
+  mIsLocked = true;
 
   if (mNeedsClear) {
+    mDrawTarget = GetAsDrawTarget();
     mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
     mNeedsClear = false;
   }
 
-  mIsLocked = true;
   return true;
 }
 
 void
 TextureClientD3D11::Unlock()
 {
   MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
   if (mDrawTarget) {
+    MOZ_ASSERT(mDrawTarget->refCount() == 1);
     mDrawTarget->Flush();
   }
+
+  // The DrawTarget is created only once, and is only usable between calls
+  // to Lock and Unlock.
   UnlockD3DTexture(mTexture.get());
   mIsLocked = false;
 }
 
 TemporaryRef<DrawTarget>
 TextureClientD3D11::GetAsDrawTarget()
 {
   MOZ_ASSERT(mIsLocked, "Calling TextureClient::GetAsDrawTarget without locking :(");
 
   if (mDrawTarget) {
     return mDrawTarget;
   }
 
-  // The DrawTarget is created only once, and is only usable between calls
-  // to Lock and Unlock.
   mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
   return mDrawTarget;
 }
 
 bool
 TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
 {
   mSize = aSize;
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -67,19 +67,21 @@ CreateTextureHostD3D9(const SurfaceDescr
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorShmem:
     case SurfaceDescriptor::TSurfaceDescriptorMemory: {
       result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D9: {
       result = new TextureHostD3D9(aFlags, aDesc);
+      break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorDIB: {
       result = new DIBTextureHostD3D9(aFlags, aDesc);
+      break;
     }
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type");
     }
   }
   return result.forget();
 }
 
@@ -1250,32 +1252,37 @@ DataTextureSourceD3D9::GetTileRect()
 {
   return ThebesIntRect(GetTileRect(mCurrentTile));
 }
 
 CairoTextureClientD3D9::CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
   : TextureClient(aFlags)
   , mFormat(aFormat)
   , mIsLocked(false)
+  , mNeedsClear(false)
 {
   MOZ_COUNT_CTOR(CairoTextureClientD3D9);
 }
 
 CairoTextureClientD3D9::~CairoTextureClientD3D9()
 {
   MOZ_COUNT_DTOR(CairoTextureClientD3D9);
 }
 
 bool
 CairoTextureClientD3D9::Lock(OpenMode)
 {
   MOZ_ASSERT(!mIsLocked);
   if (!IsValid() || !IsAllocated()) {
     return false;
   }
+  if (mNeedsClear) {
+    mDrawTarget = GetAsDrawTarget();
+    mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
+  }
   mIsLocked = true;
   return true;
 }
 
 void
 CairoTextureClientD3D9::Unlock()
 {
   MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
@@ -1348,23 +1355,17 @@ CairoTextureClientD3D9::AllocateForSurfa
 
   DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
   if (!deviceManager ||
       !(mTexture = deviceManager->CreateTexture(mSize, format, D3DPOOL_SYSTEMMEM, nullptr))) {
     NS_WARNING("Could not create d3d9 texture");
     return false;
   }
 
-  if (aFlags & ALLOC_CLEAR_BUFFER) {
-    DebugOnly<bool> locked = Lock(OPEN_WRITE_ONLY);
-    MOZ_ASSERT(locked);
-    RefPtr<DrawTarget> dt = GetAsDrawTarget();
-    dt->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
-    Unlock();
-  }
+  mNeedsClear = aFlags & ALLOC_CLEAR_BUFFER;
 
   MOZ_ASSERT(mTexture);
   return true;
 }
 
 TextureClientData*
 CairoTextureClientD3D9::DropTextureData()
 {
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -222,16 +222,17 @@ public:
 private:
   RefPtr<IDirect3DTexture9> mTexture;
   nsRefPtr<IDirect3DSurface9> mD3D9Surface;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   nsRefPtr<gfxASurface> mSurface;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
+  bool mNeedsClear;
 };
 
 /**
  * Can only be drawn into through Cairo.
  * Supports opaque surfaces. Prefer CairoTextureClientD3D9 when possible.
  * The coresponding TextureHost is DIBTextureHostD3D9.
  */
 class DIBTextureClientD3D9 : public TextureClient