From b24ee3fde95c4561bf88f92281d328300e851f2d Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Sat, 13 Dec 2014 01:50:47 +0000 Subject: [PATCH] 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 | 4 +- gfx/layers/CompositorTypes.h | 11 +- gfx/layers/client/CanvasClient.cpp | 1 + gfx/layers/client/ClientLayerManager.cpp | 4 + gfx/layers/client/ContentClient.cpp | 3 + gfx/layers/client/ImageClient.cpp | 3 + gfx/layers/client/TextureClient.cpp | 16 +++ gfx/layers/client/TextureClient.h | 28 +++++ gfx/layers/d3d11/CompositorD3D11.cpp | 33 ++++++ gfx/layers/d3d11/TextureD3D11.cpp | 129 ++++++++++++++++++++++- gfx/layers/d3d11/TextureD3D11.h | 21 ++++ gfx/layers/ipc/CompositableForwarder.h | 3 + gfx/layers/ipc/ShadowLayers.cpp | 2 + 13 files changed, 254 insertions(+), 4 deletions(-) diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index b0b355e2960..114857693c7 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -815,6 +815,7 @@ struct ParamTraits 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) @@ -824,7 +825,8 @@ struct ParamTraits 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; } diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index 477b81b2470..9642f00058b 100644 --- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -158,6 +158,12 @@ MOZ_BEGIN_ENUM_CLASS(DeprecatedTextureHostFlags, uint8_t) MOZ_END_ENUM_CLASS(DeprecatedTextureHostFlags) MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DeprecatedTextureHostFlags) +#ifdef XP_WIN +typedef void* SyncHandle; +#else +typedef uintptr_t SyncHandle; +#endif // XP_WIN + /** * Sent from the compositor to the content-side LayerManager, includes properties * of the compositor and should (in the future) include information about what @@ -171,18 +177,21 @@ struct TextureFactoryIdentifier 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 = 0) : mParentBackend(aLayersBackend) , mParentProcessId(aParentProcessId) , mSupportedBlendModes(gfx::CompositionOp::OP_OVER) , mMaxTextureSize(aMaxTextureSize) , mSupportsTextureBlitting(aSupportsTextureBlitting) , mSupportsPartialUploads(aSupportsPartialUploads) + , mSyncHandle(aSyncHandle) {} }; diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index b9cf79bdb2e..b524aa65279 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -112,6 +112,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) if (updated) { GetForwarder()->UpdatedTexture(this, mBuffer, nullptr); GetForwarder()->UseTexture(this, mBuffer); + mBuffer->SyncWithObject(GetForwarder()->GetSyncObject()); } } diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 24247f7df8e..d453a0d8844 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -529,6 +529,10 @@ ClientLayerManager::StopFrameTimeRecording(uint32_t aStartIndex, void ClientLayerManager::ForwardTransaction(bool aScheduleComposite) { + if (mForwarder->GetSyncObject()) { + mForwarder->GetSyncObject()->FinalizeFrame(); + } + mPhase = PHASE_FORWARD; mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(); diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 07f8604f8ea..0c7c9f94126 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -255,10 +255,13 @@ ContentClientRemoteBuffer::EndPaint(nsTArray* aReadba } mTextureClient->Unlock(); + mTextureClient->SyncWithObject(mForwarder->GetSyncObject()); } if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) { mTextureClientOnWhite->Unlock(); + mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject()); } + ContentClientRemote::EndPaint(aReadbackUpdates); } diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index 9c68981ad08..de76542717a 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -242,6 +242,9 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); + + texture->SyncWithObject(GetForwarder()->GetSyncObject()); + return true; } diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 76494921e89..c1858938335 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -886,5 +886,21 @@ SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescripto return true; } +TemporaryRef +SyncObject::CreateSyncObject(SyncHandle aHandle) +{ + if (!aHandle) { + return nullptr; + } + +#ifdef XP_WIN + RefPtr syncObject = new SyncObjectD3D11(aHandle); + return syncObject; +#else + MOZ_ASSERT_UNREACHABLE(); + return nullptr; +#endif +} + } } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index e6e9fcfbb74..394aecda03d 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -21,6 +21,7 @@ #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 @@ -73,6 +74,31 @@ enum TextureAllocationFlags { ALLOC_CLEAR_BUFFER_WHITE = 2 }; +#ifdef XP_WIN +typedef void* SyncHandle; +#else +typedef uintptr_t SyncHandle; +#endif // XP_WIN + +class SyncObject : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SyncObject) + virtual ~SyncObject() { } + + static TemporaryRef 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. */ @@ -433,6 +459,8 @@ public: virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) { mReadbackSink = aReadbackSink; } + + virtual void SyncWithObject(SyncObject* aSyncObject) { } private: /** diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index a1a030182ea..7cbef319775 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -66,6 +66,7 @@ struct DeviceAttachmentsD3D11 RefPtr mNonPremulBlendState; RefPtr mComponentBlendState; RefPtr mDisabledBlendState; + RefPtr mSyncTexture; }; CompositorD3D11::CompositorD3D11(nsIWidget* aWidget) @@ -273,6 +274,24 @@ CompositorD3D11::Initialize() 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 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 dxgiDevice; @@ -377,6 +396,13 @@ CompositorD3D11::GetTextureFactoryIdentifier() 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; } @@ -882,6 +908,13 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion, // ClearRect will set the correct blend state for us. ClearRect(Rect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height)); + + RefPtr mutex; + mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); + + MOZ_ASSERT(mutex); + mutex->AcquireSync(0, INFINITE); + mutex->ReleaseSync(0); } void diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 7f7e6f37b21..caa7774536c 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -214,6 +214,24 @@ TextureClientD3D11::CreateSimilar(TextureFlags aFlags, return tex; } +void +TextureClientD3D11::SyncWithObject(SyncObject* aSyncObject) +{ + if (!aSyncObject) { + return; + } + + MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObject::SyncType::D3D11); + + SyncObjectD3D11* sync = static_cast(aSyncObject); + + if (mTexture) { + sync->RegisterTexture(mTexture); + } else { + sync->RegisterTexture(mTexture10); + } +} + bool TextureClientD3D11::Lock(OpenMode aMode) { @@ -358,7 +376,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag 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 @@ -370,7 +388,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag 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)); } @@ -674,5 +692,112 @@ 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 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 mutex; + hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); + + if (FAILED(hr) || !mutex) { + gfxCriticalError() << "Failed to get KeyedMutex: " << hexa(hr); + MOZ_CRASH(); + } + } + + if (mD3D10SyncedTextures.size()) { + RefPtr 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 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 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(); + } +} + } } diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h index 4e2f635b78c..ee6d22927c6 100644 --- a/gfx/layers/d3d11/TextureD3D11.h +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -63,6 +63,8 @@ public: CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const MOZ_OVERRIDE; + virtual void SyncWithObject(SyncObject* aSyncObject) MOZ_OVERRIDE; + protected: gfx::IntSize mSize; RefPtr mTexture10; @@ -230,6 +232,25 @@ private: RefPtr 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 mD3D11Texture; + RefPtr mD3D10Texture; + std::vector mD3D10SyncedTextures; + std::vector mD3D11SyncedTextures; + SyncHandle mHandle; +}; + inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel) { int32_t maxTextureSize; diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 6bac768cf63..d3f45914833 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -232,10 +232,13 @@ public: int32_t GetSerial() { return mSerial; } + SyncObject* GetSyncObject() { return mSyncObject; } + protected: TextureFactoryIdentifier mTextureFactoryIdentifier; nsTArray > mTexturesToRemove; std::vector mTransactionsToRespond; + RefPtr mSyncObject; const int32_t mSerial; static mozilla::Atomic sSerialCounter; }; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index e9c24b42597..914e77fc6e8 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -163,6 +163,8 @@ void CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier) { mTextureFactoryIdentifier = aIdentifier; + + mSyncObject = SyncObject::CreateSyncObject(aIdentifier.mSyncHandle); } ShadowLayerForwarder::ShadowLayerForwarder()