Call ID3D12SharingContract::Present on WebGPU swap buffer destroy

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 the
texture's contents for the UI.

Bug: dawn:364
Change-Id: I7eb628c460e1e7c446ad91b29b03dd7b54545afb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/18060
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com>
diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp
index d9cbf74..fbf4344 100644
--- a/src/dawn_native/d3d12/D3D12Backend.cpp
+++ b/src/dawn_native/d3d12/D3D12Backend.cpp
@@ -62,7 +62,8 @@
                                  const ExternalImageDescriptorDXGISharedHandle* descriptor) {
         Device* backendDevice = reinterpret_cast<Device*>(device);
         TextureBase* texture = backendDevice->WrapSharedHandle(descriptor, descriptor->sharedHandle,
-                                                               descriptor->acquireMutexKey);
+                                                               descriptor->acquireMutexKey,
+                                                               descriptor->isSwapChainTexture);
         return reinterpret_cast<WGPUTexture>(texture);
     }
 
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index efa3837..7dcf8c8 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -64,6 +64,10 @@
             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 @@
         return mCommandQueue;
     }
 
+    ID3D12SharingContract* Device::GetSharingContract() const {
+        return mD3d12SharingContract.Get();
+    }
+
     ComPtr<ID3D12CommandSignature> Device::GetDispatchIndirectSignature() const {
         return mDispatchIndirectSignature;
     }
@@ -322,9 +330,11 @@
 
     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 b844d7b..1f0c42f 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -59,6 +59,7 @@
 
         ComPtr<ID3D12Device> GetD3D12Device() const;
         ComPtr<ID3D12CommandQueue> GetCommandQueue() const;
+        ID3D12SharingContract* GetSharingContract() const;
 
         ComPtr<ID3D12CommandSignature> GetDispatchIndirectSignature() const;
         ComPtr<ID3D12CommandSignature> GetDrawIndirectSignature() const;
@@ -102,7 +103,8 @@
 
         TextureBase* WrapSharedHandle(const ExternalImageDescriptor* descriptor,
                                       HANDLE sharedHandle,
-                                      uint64_t acquireMutexKey);
+                                      uint64_t acquireMutexKey,
+                                      bool isSwapChainTexture);
         ResultOrError<ComPtr<IDXGIKeyedMutex>> CreateKeyedMutexForTexture(
             ID3D12Resource* d3d12Resource);
         void ReleaseKeyedMutexForTexture(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex);
@@ -146,6 +148,7 @@
 
         ComPtr<ID3D12Device> mD3d12Device;  // Device is owned by adapter and will not be outlived.
         ComPtr<ID3D12CommandQueue> mCommandQueue;
+        ComPtr<ID3D12SharingContract> mD3d12SharingContract;
 
         // 11on12 device and device context corresponding to mCommandQueue
         ComPtr<ID3D11On12Device> mD3d11On12Device;
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index cb57079..c9242c1 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -284,14 +284,15 @@
     ResultOrError<TextureBase*> Texture::Create(Device* device,
                                                 const ExternalImageDescriptor* descriptor,
                                                 HANDLE sharedHandle,
-                                                uint64_t acquireMutexKey) {
+                                                uint64_t acquireMutexKey,
+                                                bool isSwapChainTexture) {
         const TextureDescriptor* textureDescriptor =
             reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
 
         Ref<Texture> 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 @@
 
     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 @@
 
         mAcquireMutexKey = acquireMutexKey;
         mDxgiKeyedMutex = std::move(dxgiKeyedMutex);
+        mSwapChainTexture = isSwapChainTexture;
 
         AllocationInfo info;
         info.mMethod = AllocationMethod::kExternal;
@@ -391,6 +394,20 @@
 
     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 6965690..6c63b56 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -39,7 +39,8 @@
         static ResultOrError<TextureBase*> Create(Device* device,
                                                   const ExternalImageDescriptor* descriptor,
                                                   HANDLE sharedHandle,
-                                                  uint64_t acquireMutexKey);
+                                                  uint64_t acquireMutexKey,
+                                                  bool isSwapChainTexture);
         Texture(Device* device,
                 const TextureDescriptor* descriptor,
                 ComPtr<ID3D12Resource> d3d12Texture);
@@ -75,7 +76,8 @@
         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 @@
 
         Serial mLastUsedSerial = UINT64_MAX;
         bool mValidToDecay = false;
+        bool mSwapChainTexture = false;
 
         Serial mAcquireMutexKey = 0;
         ComPtr<IDXGIKeyedMutex> mDxgiKeyedMutex;
diff --git a/src/include/dawn_native/D3D12Backend.h b/src/include/dawn_native/D3D12Backend.h
index 229be3b..0cef24c 100644
--- a/src/include/dawn_native/D3D12Backend.h
+++ b/src/include/dawn_native/D3D12Backend.h
@@ -36,6 +36,7 @@
 
         HANDLE sharedHandle;
         uint64_t acquireMutexKey;
+        bool isSwapChainTexture = false;
     };
 
     DAWN_NATIVE_EXPORT uint64_t SetExternalMemoryReservation(WGPUDevice device,