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.
This commit is contained in:
Bas Schouten 2014-12-13 01:50:47 +00:00
parent cee30634bf
commit b24ee3fde9
13 changed files with 254 additions and 4 deletions

View File

@ -815,6 +815,7 @@ struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
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<mozilla::layers::TextureFactoryIdentifier>
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;
}

View File

@ -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)
{}
};

View File

@ -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());
}
}

View File

@ -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();

View File

@ -255,10 +255,13 @@ ContentClientRemoteBuffer::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadba
}
mTextureClient->Unlock();
mTextureClient->SyncWithObject(mForwarder->GetSyncObject());
}
if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
mTextureClientOnWhite->Unlock();
mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject());
}
ContentClientRemote::EndPaint(aReadbackUpdates);
}

View File

@ -242,6 +242,9 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
mLastPaintedImageSerial = image->GetSerial();
aContainer->NotifyPaintedImage(image);
texture->SyncWithObject(GetForwarder()->GetSyncObject());
return true;
}

View File

@ -886,5 +886,21 @@ SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescripto
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
}
}
}

View File

@ -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<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.
*/
@ -433,6 +459,8 @@ public:
virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
mReadbackSink = aReadbackSink;
}
virtual void SyncWithObject(SyncObject* aSyncObject) { }
private:
/**

View File

@ -66,6 +66,7 @@ struct DeviceAttachmentsD3D11
RefPtr<ID3D11BlendState> mNonPremulBlendState;
RefPtr<ID3D11BlendState> mComponentBlendState;
RefPtr<ID3D11BlendState> mDisabledBlendState;
RefPtr<IDXGIResource> 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<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;
@ -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<IDXGIKeyedMutex> mutex;
mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
MOZ_ASSERT(mutex);
mutex->AcquireSync(0, INFINITE);
mutex->ReleaseSync(0);
}
void

View File

@ -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<SyncObjectD3D11*>(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<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();
}
}
}
}

View File

@ -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<ID3D10Texture2D> mTexture10;
@ -230,6 +232,25 @@ private:
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;

View File

@ -232,10 +232,13 @@ public:
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;
};

View File

@ -163,6 +163,8 @@ void
CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
{
mTextureFactoryIdentifier = aIdentifier;
mSyncObject = SyncObject::CreateSyncObject(aIdentifier.mSyncHandle);
}
ShadowLayerForwarder::ShadowLayerForwarder()