diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp index d9cbf74f15..fbf4344d50 100644 --- a/src/dawn_native/d3d12/D3D12Backend.cpp +++ b/src/dawn_native/d3d12/D3D12Backend.cpp @@ -62,7 +62,8 @@ namespace dawn_native { namespace d3d12 { const ExternalImageDescriptorDXGISharedHandle* descriptor) { Device* backendDevice = reinterpret_cast(device); TextureBase* texture = backendDevice->WrapSharedHandle(descriptor, descriptor->sharedHandle, - descriptor->acquireMutexKey); + descriptor->acquireMutexKey, + descriptor->isSwapChainTexture); return reinterpret_cast(texture); } diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index efa383755c..7dcf8c807d 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -64,6 +64,10 @@ namespace dawn_native { namespace d3d12 { CheckHRESULT(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)), "D3D12 create command queue")); + // If PIX is not attached, the QueryInterface fails. Hence, no need to check the return + // value. + mCommandQueue.As(&mD3d12SharingContract); + DAWN_TRY(CheckHRESULT(mD3d12Device->CreateFence(mLastSubmittedSerial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)), "D3D12 create fence")); @@ -124,6 +128,10 @@ namespace dawn_native { namespace d3d12 { return mCommandQueue; } + ID3D12SharingContract* Device::GetSharingContract() const { + return mD3d12SharingContract.Get(); + } + ComPtr Device::GetDispatchIndirectSignature() const { return mDispatchIndirectSignature; } @@ -322,9 +330,11 @@ namespace dawn_native { namespace d3d12 { TextureBase* Device::WrapSharedHandle(const ExternalImageDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey) { + uint64_t acquireMutexKey, + bool isSwapChainTexture) { TextureBase* dawnTexture; - if (ConsumedError(Texture::Create(this, descriptor, sharedHandle, acquireMutexKey), + if (ConsumedError(Texture::Create(this, descriptor, sharedHandle, acquireMutexKey, + isSwapChainTexture), &dawnTexture)) return nullptr; diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h index b844d7bfb5..1f0c42f7cc 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.h +++ b/src/dawn_native/d3d12/DeviceD3D12.h @@ -59,6 +59,7 @@ namespace dawn_native { namespace d3d12 { ComPtr GetD3D12Device() const; ComPtr GetCommandQueue() const; + ID3D12SharingContract* GetSharingContract() const; ComPtr GetDispatchIndirectSignature() const; ComPtr GetDrawIndirectSignature() const; @@ -102,7 +103,8 @@ namespace dawn_native { namespace d3d12 { TextureBase* WrapSharedHandle(const ExternalImageDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey); + uint64_t acquireMutexKey, + bool isSwapChainTexture); ResultOrError> CreateKeyedMutexForTexture( ID3D12Resource* d3d12Resource); void ReleaseKeyedMutexForTexture(ComPtr dxgiKeyedMutex); @@ -146,6 +148,7 @@ namespace dawn_native { namespace d3d12 { ComPtr mD3d12Device; // Device is owned by adapter and will not be outlived. ComPtr mCommandQueue; + ComPtr mD3d12SharingContract; // 11on12 device and device context corresponding to mCommandQueue ComPtr mD3d11On12Device; diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index cb570793fd..c9242c15ea 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -284,14 +284,15 @@ namespace dawn_native { namespace d3d12 { ResultOrError Texture::Create(Device* device, const ExternalImageDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey) { + uint64_t acquireMutexKey, + bool isSwapChainTexture) { const TextureDescriptor* textureDescriptor = reinterpret_cast(descriptor->cTextureDescriptor); Ref dawnTexture = AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal)); DAWN_TRY(dawnTexture->InitializeAsExternalTexture(textureDescriptor, sharedHandle, - acquireMutexKey)); + acquireMutexKey, isSwapChainTexture)); dawnTexture->SetIsSubresourceContentInitialized(descriptor->isCleared, 0, textureDescriptor->mipLevelCount, 0, @@ -301,7 +302,8 @@ namespace dawn_native { namespace d3d12 { MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey) { + uint64_t acquireMutexKey, + bool isSwapChainTexture) { Device* dawnDevice = ToBackend(GetDevice()); DAWN_TRY(ValidateTextureDescriptor(dawnDevice, descriptor)); DAWN_TRY(ValidateTextureDescriptorCanBeWrapped(descriptor)); @@ -322,6 +324,7 @@ namespace dawn_native { namespace d3d12 { mAcquireMutexKey = acquireMutexKey; mDxgiKeyedMutex = std::move(dxgiKeyedMutex); + mSwapChainTexture = isSwapChainTexture; AllocationInfo info; info.mMethod = AllocationMethod::kExternal; @@ -391,6 +394,20 @@ namespace dawn_native { namespace d3d12 { void Texture::DestroyImpl() { Device* device = ToBackend(GetDevice()); + + // In PIX's D3D12-only mode, there is no way to determine frame boundaries + // for WebGPU since Dawn does not manage DXGI swap chains. Without assistance, + // PIX will wait forever for a present that never happens. + // If we know we're dealing with a swapbuffer texture, inform PIX we've + // "presented" the texture so it can determine frame boundaries and use its + // contents for the UI. + if (mSwapChainTexture) { + ID3D12SharingContract* d3dSharingContract = device->GetSharingContract(); + if (d3dSharingContract != nullptr) { + d3dSharingContract->Present(mResourceAllocation.GetD3D12Resource().Get(), 0, 0); + } + } + device->DeallocateMemory(mResourceAllocation); if (mDxgiKeyedMutex != nullptr) { diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h index 69656903bb..6c63b5602a 100644 --- a/src/dawn_native/d3d12/TextureD3D12.h +++ b/src/dawn_native/d3d12/TextureD3D12.h @@ -39,7 +39,8 @@ namespace dawn_native { namespace d3d12 { static ResultOrError Create(Device* device, const ExternalImageDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey); + uint64_t acquireMutexKey, + bool isSwapChainTexture); Texture(Device* device, const TextureDescriptor* descriptor, ComPtr d3d12Texture); @@ -75,7 +76,8 @@ namespace dawn_native { namespace d3d12 { MaybeError InitializeAsInternalTexture(); MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor, HANDLE sharedHandle, - uint64_t acquireMutexKey); + uint64_t acquireMutexKey, + bool isSwapChainTexture); // Dawn API void DestroyImpl() override; @@ -100,6 +102,7 @@ namespace dawn_native { namespace d3d12 { Serial mLastUsedSerial = UINT64_MAX; bool mValidToDecay = false; + bool mSwapChainTexture = false; Serial mAcquireMutexKey = 0; ComPtr mDxgiKeyedMutex; diff --git a/src/include/dawn_native/D3D12Backend.h b/src/include/dawn_native/D3D12Backend.h index 229be3b0be..0cef24c002 100644 --- a/src/include/dawn_native/D3D12Backend.h +++ b/src/include/dawn_native/D3D12Backend.h @@ -36,6 +36,7 @@ namespace dawn_native { namespace d3d12 { HANDLE sharedHandle; uint64_t acquireMutexKey; + bool isSwapChainTexture = false; }; DAWN_NATIVE_EXPORT uint64_t SetExternalMemoryReservation(WGPUDevice device,