Bug 1088414: Use a single synchronization texture for D3D11. r=jrmuizel
☠☠ backed out by dadec018f807 ☠ ☠
authorBas Schouten <bschouten@mozilla.com>
Sat, 13 Dec 2014 01:50:47 +0000
changeset 219613 2cd43e5ae2c1e749cdcc3e739b9300d9c64a1e34
parent 219612 a65478d63b75e94aafce63a22959e71f39d3bc70
child 219614 3127df59e0dc4d863898b9b03ba5809133716214
push id27967
push userryanvm@gmail.com
push dateMon, 15 Dec 2014 18:52:54 +0000
treeherdermozilla-central@5d6e0d038f95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1088414
milestone37.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 1088414: Use a single synchronization texture for D3D11. r=jrmuizel This patch adds a cross platform 'sync object' that is used to synchronize the drawing of individual textures. For the D3D11 implementation all textures that are written to will have one pixel copied into the D3D11 sync texture while holding its lock. The compositor will then, before composition acquire and release sync once, this should ensure all drawing on the content side has completed.
gfx/ipc/GfxMessageUtils.h
gfx/layers/CompositorTypes.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ContentClient.cpp
gfx/layers/client/ImageClient.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/ShadowLayers.cpp
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -810,26 +810,28 @@ struct ParamTraits<mozilla::layers::Text
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mParentBackend);
     WriteParam(aMsg, aParam.mSupportedBlendModes.serialize());
     WriteParam(aMsg, aParam.mMaxTextureSize);
     WriteParam(aMsg, aParam.mSupportsTextureBlitting);
     WriteParam(aMsg, aParam.mSupportsPartialUploads);
+    WriteParam(aMsg, aParam.mSyncHandle);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     uint32_t supportedBlendModes = 0;
     bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
                   ReadParam(aMsg, aIter, &supportedBlendModes) &&
                   ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
-                  ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads);
+                  ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
+                  ReadParam(aMsg, aIter, &aResult->mSyncHandle);
     aResult->mSupportedBlendModes.deserialize(supportedBlendModes);
     return result;
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureInfo>
 {
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -153,41 +153,46 @@ MOZ_BEGIN_ENUM_CLASS(DeprecatedTextureHo
   DEFAULT = 0,       // The default texture host for the given SurfaceDescriptor
   TILED = 1 << 0,    // A texture host that supports tiling
   COPY_PREVIOUS = 1 << 1, // Texture contents should be initialized
                                       // from the previous texture.
   ALL_BITS = (1 << 2) - 1
 MOZ_END_ENUM_CLASS(DeprecatedTextureHostFlags)
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DeprecatedTextureHostFlags)
 
+typedef void* SyncHandle;
+
 /**
  * Sent from the compositor to the content-side LayerManager, includes properties
  * of the compositor and should (in the future) include information about what
  * kinds of buffer and texture clients to create.
  */
 struct TextureFactoryIdentifier
 {
   LayersBackend mParentBackend;
   GeckoProcessType mParentProcessId;
   EnumSet<gfx::CompositionOp> mSupportedBlendModes;
   int32_t mMaxTextureSize;
   bool mSupportsTextureBlitting;
   bool mSupportsPartialUploads;
+  SyncHandle mSyncHandle;
 
   explicit TextureFactoryIdentifier(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
                                     GeckoProcessType aParentProcessId = GeckoProcessType_Default,
                                     int32_t aMaxTextureSize = 4096,
                                     bool aSupportsTextureBlitting = false,
-                                    bool aSupportsPartialUploads = false)
+                                    bool aSupportsPartialUploads = false,
+                                    SyncHandle aSyncHandle = nullptr)
     : mParentBackend(aLayersBackend)
     , mParentProcessId(aParentProcessId)
     , mSupportedBlendModes(gfx::CompositionOp::OP_OVER)
     , mMaxTextureSize(aMaxTextureSize)
     , mSupportsTextureBlitting(aSupportsTextureBlitting)
     , mSupportsPartialUploads(aSupportsPartialUploads)
+    , mSyncHandle(aSyncHandle)
   {}
 };
 
 /**
  * Identify a texture to a compositable. Many textures can have the same id, but
  * the id is unique for any texture owned by a particular compositable.
  * XXX - We don't really need this, it will be removed along with the incremental
  * ContentClient/Host.
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -107,16 +107,17 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   if (bufferCreated && !AddTextureClient(mBuffer)) {
     mBuffer = nullptr;
     return;
   }
 
   if (updated) {
     GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
     GetForwarder()->UseTexture(this, mBuffer);
+    mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
   }
 }
 
 TemporaryRef<TextureClient>
 CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
                                              gfx::IntSize aSize,
                                              TextureFlags aFlags,
                                              ClientCanvasLayer* aLayer)
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -524,16 +524,20 @@ ClientLayerManager::StopFrameTimeRecordi
   if (renderer) {
     renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
   }
 }
 
 void
 ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
 {
+  if (mForwarder->GetSyncObject()) {
+    mForwarder->GetSyncObject()->FinalizeFrame();
+  }
+
   mPhase = PHASE_FORWARD;
 
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
   TimeStamp transactionStart;
   if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) {
     transactionStart = mTransactionIdAllocator->GetTransactionStart();
   } else {
     transactionStart = mTransactionStart;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -250,20 +250,23 @@ ContentClientRemoteBuffer::EndPaint(nsTA
   if (mTextureClient && mTextureClient->IsLocked()) {
     if (aReadbackUpdates->Length() > 0) {
       RefPtr<TextureReadbackSink> readbackSink = new RemoteBufferReadbackProcessor(aReadbackUpdates, mBufferRect, mBufferRotation);
 
       mTextureClient->SetReadbackSink(readbackSink);
     }
 
     mTextureClient->Unlock();
+    mTextureClient->SyncWithObject(mForwarder->GetSyncObject());
   }
   if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
     mTextureClientOnWhite->Unlock();
+    mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject());
   }
+
   ContentClientRemote::EndPaint(aReadbackUpdates);
 }
 
 void
 ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
                                                const nsIntRect& aRect,
                                                uint32_t aFlags)
 {
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -237,16 +237,19 @@ ImageClientSingle::UpdateImage(ImageCont
   mFrontBuffer = texture;
   GetForwarder()->UpdatedTexture(this, texture, nullptr);
   GetForwarder()->UseTexture(this, texture);
 
   UpdatePictureRect(image->GetPictureRect());
 
   mLastPaintedImageSerial = image->GetSerial();
   aContainer->NotifyPaintedImage(image);
+
+  texture->SyncWithObject(GetForwarder()->GetSyncObject());
+
   return true;
 }
 
 bool
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
   MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   return CompositableClient::AddTextureClient(aTexture);
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -881,10 +881,26 @@ SharedSurfaceTextureClient::~SharedSurfa
 
 bool
 SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   aOutDescriptor = SharedSurfaceDescriptor((uintptr_t)mSurf);
   return true;
 }
 
+TemporaryRef<SyncObject>
+SyncObject::CreateSyncObject(SyncHandle aHandle)
+{
+  if (!aHandle) {
+    return nullptr;
+  }
+
+#ifdef XP_WIN
+  RefPtr<SyncObject> syncObject = new SyncObjectD3D11(aHandle);
+  return syncObject;
+#else
+  MOZ_ASSERT_UNREACHABLE();
+  return nullptr;
+#endif
+}
+
 }
 }
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -16,16 +16,17 @@
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/FenceUtils.h"  // for FenceHandle
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
+#include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for TextureImage::AddRef, etc
 #include "GfxTexturesReporter.h"
 
 class gfxReusableSurfaceWrapper;
@@ -68,16 +69,37 @@ class KeepAlive;
  */
 
 enum TextureAllocationFlags {
   ALLOC_DEFAULT = 0,
   ALLOC_CLEAR_BUFFER = 1,
   ALLOC_CLEAR_BUFFER_WHITE = 2
 };
 
+typedef void* SyncHandle;
+
+class SyncObject : public RefCounted<SyncObject>
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SyncObject)
+  virtual ~SyncObject() { }
+
+  static TemporaryRef<SyncObject> CreateSyncObject(SyncHandle aHandle);
+
+  MOZ_BEGIN_NESTED_ENUM_CLASS(SyncType)
+    D3D11,
+  MOZ_END_NESTED_ENUM_CLASS(SyncType)
+
+  virtual SyncType GetSyncType() = 0;
+  virtual void FinalizeFrame() = 0;
+
+protected:
+  SyncObject() { }
+};
+
 /**
  * Interface for TextureClients that can be updated using YCbCr data.
  */
 class TextureClientYCbCr
 {
 public:
   /**
    * Copy aData into this texture client.
@@ -428,16 +450,18 @@ public:
    /**
     * This sets the readback sink that this texture is to use. This will
     * receive the data for this texture as soon as it becomes available after
     * texture unlock.
     */
    virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
      mReadbackSink = aReadbackSink;
    }
+   
+   virtual void SyncWithObject(SyncObject* aSyncObject) { }
 
 private:
   /**
    * Called once, just before the destructor.
    *
    * Here goes the shut-down code that uses virtual methods.
    * Must only be called by Release().
    */
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -61,16 +61,17 @@ struct DeviceAttachmentsD3D11
   RefPtr<ID3D11Buffer> mVSConstantBuffer;
   RefPtr<ID3D11RasterizerState> mRasterizerState;
   RefPtr<ID3D11SamplerState> mLinearSamplerState;
   RefPtr<ID3D11SamplerState> mPointSamplerState;
   RefPtr<ID3D11BlendState> mPremulBlendState;
   RefPtr<ID3D11BlendState> mNonPremulBlendState;
   RefPtr<ID3D11BlendState> mComponentBlendState;
   RefPtr<ID3D11BlendState> mDisabledBlendState;
+  RefPtr<IDXGIResource> mSyncTexture;
 };
 
 CompositorD3D11::CompositorD3D11(nsIWidget* aWidget)
   : mAttachments(nullptr)
   , mWidget(aWidget)
   , mHwnd(nullptr)
   , mDisableSequenceForNextFrame(false)
 {
@@ -268,16 +269,34 @@ CompositorD3D11::Initialize()
       D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendDisabled;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mDisabledBlendState));
     if (FAILED(hr)) {
       return false;
     }
+
+    CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
+                                D3D11_BIND_SHADER_RESOURCE |
+                                D3D11_BIND_RENDER_TARGET);
+    desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+
+    RefPtr<ID3D11Texture2D> texture;
+    hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
+    
+    if (FAILED(hr)) {
+      return false;
+    }
+
+    hr = texture->QueryInterface((IDXGIResource**)byRef(mAttachments->mSyncTexture));
+
+    if (FAILED(hr)) {
+      return false;
+    }
   }
 
   nsRefPtr<IDXGIDevice> dxgiDevice;
   nsRefPtr<IDXGIAdapter> dxgiAdapter;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
   dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
 
@@ -372,16 +391,23 @@ CompositorD3D11::CreateDataTextureSource
 
 TextureFactoryIdentifier
 CompositorD3D11::GetTextureFactoryIdentifier()
 {
   TextureFactoryIdentifier ident;
   ident.mMaxTextureSize = GetMaxTextureSize();
   ident.mParentProcessId = XRE_GetProcessType();
   ident.mParentBackend = LayersBackend::LAYERS_D3D11;
+  if (mAttachments->mSyncTexture) {
+    HRESULT hr = mAttachments->mSyncTexture->GetSharedHandle(&ident.mSyncHandle);
+    if (FAILED(hr) || !ident.mSyncHandle) {
+      gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: " << hr;
+      MOZ_CRASH();
+    }
+  }
   return ident;
 }
 
 bool
 CompositorD3D11::CanUseCanvasLayerForSize(const gfx::IntSize& aSize)
 {
   int32_t maxTextureSize = GetMaxTextureSize();
 
@@ -877,16 +903,23 @@ CompositorD3D11::BeginFrame(const nsIntR
   mCurrentClip = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
 
   mContext->RSSetState(mAttachments->mRasterizerState);
 
   SetRenderTarget(mDefaultRT);
 
   // ClearRect will set the correct blend state for us.
   ClearRect(Rect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height));
+
+  RefPtr<IDXGIKeyedMutex> mutex;
+  mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+
+  MOZ_ASSERT(mutex);
+  mutex->AcquireSync(0, INFINITE);
+  mutex->ReleaseSync(0);
 }
 
 void
 CompositorD3D11::EndFrame()
 {
   mContext->Flush();
 
   nsIntSize oldSize = mSize;
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -209,16 +209,34 @@ TextureClientD3D11::CreateSimilar(Textur
 
   if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
     return nullptr;
   }
 
   return tex;
 }
 
+void
+TextureClientD3D11::SyncWithObject(SyncObject* aSyncObject)
+{
+  if (!aSyncObject) {
+    return;
+  }
+
+  MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObject::SyncType::D3D11);
+
+  SyncObjectD3D11* sync = static_cast<SyncObjectD3D11*>(aSyncObject);
+
+  if (mTexture) {
+    sync->RegisterTexture(mTexture);
+  } else {
+    sync->RegisterTexture(mTexture10);
+  }
+}
+
 bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
   if (!IsAllocated()) {
     return false;
   }
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
 
@@ -353,29 +371,29 @@ TextureClientD3D11::AllocateForSurface(g
   ID3D11Device* d3d11device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
 
   if (gfxPrefs::Direct2DUse1_1() && d3d11device) {
 
     CD3D11_TEXTURE2D_DESC newDesc(mFormat == SurfaceFormat::A8 ? DXGI_FORMAT_A8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM,
                                   aSize.width, aSize.height, 1, 1,
                                   D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
 
-    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
 
     hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
   } else
 #endif
   {
     ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
 
     CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
       aSize.width, aSize.height, 1, 1,
       D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
 
-    newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+    newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED;
 
     hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture10));
   }
 
   if (FAILED(hr)) {
     gfxCriticalError() << "[D3D11] CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
     return false;
   }
@@ -669,10 +687,117 @@ CompositingRenderTargetD3D11::BindRender
 }
 
 IntSize
 CompositingRenderTargetD3D11::GetSize() const
 {
   return TextureSourceD3D11::GetSize();
 }
 
+SyncObjectD3D11::SyncObjectD3D11(SyncHandle aHandle)
+{
+  MOZ_ASSERT(aHandle);
+
+  mHandle = aHandle;
+}
+
+void
+SyncObjectD3D11::RegisterTexture(ID3D11Texture2D* aTexture)
+{
+  mD3D11SyncedTextures.push_back(aTexture);
+}
+
+void
+SyncObjectD3D11::RegisterTexture(ID3D10Texture2D* aTexture)
+{
+  mD3D10SyncedTextures.push_back(aTexture);
+}
+
+void
+SyncObjectD3D11::FinalizeFrame()
+{
+  HRESULT hr;
+
+  if (!mD3D10Texture && mD3D10SyncedTextures.size()) {
+    ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
+
+    hr = device->OpenSharedResource(mHandle, __uuidof(ID3D10Texture2D), (void**)(ID3D10Texture2D**)byRef(mD3D10Texture));
+    
+    if (FAILED(hr) || !mD3D10Texture) {
+      gfxCriticalError() << "Failed to OpenSharedResource: " << hexa(hr);
+      MOZ_CRASH();
+    }
+
+    // test QI
+    RefPtr<IDXGIKeyedMutex> mutex;
+    hr = mD3D10Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+
+    if (FAILED(hr) || !mutex) {
+      gfxCriticalError() << "Failed to get KeyedMutex: " << hexa(hr);
+      MOZ_CRASH();
+    }
+  }
+
+  if (!mD3D11Texture && mD3D11SyncedTextures.size()) {
+    ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
+
+    hr = device->OpenSharedResource(mHandle, __uuidof(ID3D11Texture2D), (void**)(ID3D11Texture2D**)byRef(mD3D11Texture));
+    
+    if (FAILED(hr) || !mD3D11Texture) {
+      gfxCriticalError() << "Failed to OpenSharedResource: " << hexa(hr);
+      MOZ_CRASH();
+    }
+
+    // test QI
+    RefPtr<IDXGIKeyedMutex> mutex;
+    hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+
+    if (FAILED(hr) || !mutex) {
+      gfxCriticalError() << "Failed to get KeyedMutex: " << hexa(hr);
+      MOZ_CRASH();
+    }
+  }
+
+  if (mD3D10SyncedTextures.size()) {
+    RefPtr<IDXGIKeyedMutex> mutex;
+    hr = mD3D10Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+    mutex->AcquireSync(0, INFINITE);
+
+    D3D10_BOX box;
+    box.front = box.top = box.left = 0;
+    box.back = box.bottom = box.right = 1;
+
+    ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
+
+    for (auto iter = mD3D10SyncedTextures.begin(); iter != mD3D10SyncedTextures.end(); iter++) {
+      device->CopySubresourceRegion(mD3D10Texture, 0, 0, 0, 0, *iter, 0, &box);
+    }
+
+    mutex->ReleaseSync(0);
+
+    mD3D10SyncedTextures.clear();
+  }
+
+  if (mD3D11SyncedTextures.size()) {
+    RefPtr<IDXGIKeyedMutex> mutex;
+    hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+    mutex->AcquireSync(0, INFINITE);
+
+    D3D11_BOX box;
+    box.front = box.top = box.left = 0;
+    box.back = box.bottom = box.right = 1;
+
+    ID3D11Device* dev = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
+    RefPtr<ID3D11DeviceContext> ctx;
+    dev->GetImmediateContext(byRef(ctx));
+
+    for (auto iter = mD3D11SyncedTextures.begin(); iter != mD3D11SyncedTextures.end(); iter++) {
+      ctx->CopySubresourceRegion(mD3D11Texture, 0, 0, 0, 0, *iter, 0, &box);
+    }
+
+    mutex->ReleaseSync(0);
+
+    mD3D11SyncedTextures.clear();
+  }
+}
+
 }
 }
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -58,16 +58,18 @@ public:
 
   virtual bool AllocateForSurface(gfx::IntSize aSize,
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
   virtual TemporaryRef<TextureClient>
   CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const MOZ_OVERRIDE;
 
+  virtual void SyncWithObject(SyncObject* aSyncObject) MOZ_OVERRIDE;
+
 protected:
   gfx::IntSize mSize;
   RefPtr<ID3D10Texture2D> mTexture10;
   RefPtr<ID3D11Texture2D> mTexture;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
   bool mNeedsClear;
@@ -225,16 +227,35 @@ public:
   void SetSize(const gfx::IntSize& aSize) { mSize = aSize; }
 
 private:
   friend class CompositorD3D11;
 
   RefPtr<ID3D11RenderTargetView> mRTView;
 };
 
+class SyncObjectD3D11 : public SyncObject
+{
+public:
+  SyncObjectD3D11(SyncHandle aSyncHandle);
+
+  virtual SyncType GetSyncType() { return SyncType::D3D11; }
+  virtual void FinalizeFrame();
+
+  void RegisterTexture(ID3D11Texture2D* aTexture);
+  void RegisterTexture(ID3D10Texture2D* aTexture);
+
+private:
+  RefPtr<ID3D11Texture2D> mD3D11Texture;
+  RefPtr<ID3D10Texture2D> mD3D10Texture;
+  std::vector<ID3D10Texture2D*> mD3D10SyncedTextures;
+  std::vector<ID3D11Texture2D*> mD3D11SyncedTextures;
+  SyncHandle mHandle;
+};
+
 inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel)
 {
   int32_t maxTextureSize;
   switch (aFeatureLevel) {
   case D3D_FEATURE_LEVEL_11_1:
   case D3D_FEATURE_LEVEL_11_0:
     maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
     break;
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -227,20 +227,23 @@ public:
 
   const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
   {
     return mTextureFactoryIdentifier;
   }
 
   int32_t GetSerial() { return mSerial; }
 
+  SyncObject* GetSyncObject() { return mSyncObject; }
+
 protected:
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
   std::vector<uint64_t> mTransactionsToRespond;
+  RefPtr<SyncObject> mSyncObject;
   const int32_t mSerial;
   static mozilla::Atomic<int32_t> sSerialCounter;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -158,16 +158,18 @@ struct AutoTxnEnd {
   ~AutoTxnEnd() { mTxn->End(); }
   Transaction* mTxn;
 };
 
 void
 CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
 {
   mTextureFactoryIdentifier = aIdentifier;
+
+  mSyncObject = SyncObject::CreateSyncObject(aIdentifier.mSyncHandle);
 }
 
 ShadowLayerForwarder::ShadowLayerForwarder()
  : mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
  , mIsFirstPaint(false)
  , mWindowOverlayChanged(false)
 {
   mTxn = new Transaction();