Call ExecutePendingCommandContext() in ExternalImageDXGIImpl::Destroy()

Before destroying ExternalImageDXGI we should execute all the pending
commands before calling NextSerial(), or the device will be lost as
the CommandAllocator will be destroyed before the pending commands are
executed.

Bug: dawn:576
Test: dawn_end2end_tests
Change-Id: I6e291586cd78a7e0feaf2f8dfee87a289ec27f77
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100100
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp b/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
index 1fdf7d6..8bf2c6c 100644
--- a/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
+++ b/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
@@ -64,6 +64,7 @@
         RemoveFromList();
 
         // Keep fence alive until any pending signal calls are done on the GPU.
+        mBackendDevice->ConsumedError(mBackendDevice->ExecutePendingCommandContext());
         mBackendDevice->ConsumedError(mBackendDevice->NextSerial());
         mBackendDevice->ReferenceUntilUnused(mD3D12Fence.Get());
         mBackendDevice = nullptr;
diff --git a/src/dawn/tests/end2end/D3D12ResourceWrappingTests.cpp b/src/dawn/tests/end2end/D3D12ResourceWrappingTests.cpp
index f715f60..d3112fe 100644
--- a/src/dawn/tests/end2end/D3D12ResourceWrappingTests.cpp
+++ b/src/dawn/tests/end2end/D3D12ResourceWrappingTests.cpp
@@ -849,6 +849,28 @@
     EXPECT_EQ(texture, nullptr);
 }
 
+// Verify there is no error generated when we destroy an external image with CommandRecordingContext
+// open.
+TEST_P(D3D12SharedHandleUsageTests, CallWriteBufferBeforeDestroyingExternalImage) {
+    DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+
+    wgpu::Texture texture;
+    ComPtr<ID3D11Texture2D> d3d11Texture;
+    std::unique_ptr<dawn::native::d3d12::ExternalImageDXGI> externalImage;
+    WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture,
+                     &externalImage, /*fenceSignalValue=*/1);
+
+    // In utils::CreateBufferFromData() we will call queue.WriteBuffer(), which will make a
+    // recording context pending.
+    constexpr uint32_t kExpected = 1u;
+    wgpu::Buffer buffer = utils::CreateBufferFromData(
+        device, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst, {kExpected});
+
+    externalImage = nullptr;
+
+    EXPECT_BUFFER_U32_EQ(kExpected, buffer, 0);
+}
+
 DAWN_INSTANTIATE_TEST_P(D3D12SharedHandleValidation,
                         {D3D12Backend()},
                         {SyncMode::kKeyedMutex, SyncMode::kFence});