diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp index aac8968c31..8d992f4aa4 100644 --- a/src/dawn_native/d3d12/D3D12Backend.cpp +++ b/src/dawn_native/d3d12/D3D12Backend.cpp @@ -51,6 +51,83 @@ namespace dawn_native { namespace d3d12 { : ExternalImageDescriptor(ExternalImageType::DXGISharedHandle) { } + ExternalImageDXGI::ExternalImageDXGI(ComPtr d3d12Resource, + const WGPUTextureDescriptor* descriptor) + : mD3D12Resource(std::move(d3d12Resource)), + mUsage(descriptor->usage), + mDimension(descriptor->dimension), + mSize(descriptor->size), + mFormat(descriptor->format), + mMipLevelCount(descriptor->mipLevelCount), + mSampleCount(descriptor->sampleCount) { + ASSERT(descriptor->nextInChain == nullptr); + } + + WGPUTexture ExternalImageDXGI::ProduceTexture( + WGPUDevice device, + const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor) { + Device* backendDevice = reinterpret_cast(device); + + TextureDescriptor textureDescriptor = {}; + textureDescriptor.usage = static_cast(mUsage); + textureDescriptor.dimension = static_cast(mDimension); + textureDescriptor.size = {mSize.width, mSize.height, mSize.depth}; + textureDescriptor.format = static_cast(mFormat); + textureDescriptor.mipLevelCount = mMipLevelCount; + textureDescriptor.sampleCount = mSampleCount; + + Ref texture = backendDevice->CreateExternalTexture( + &textureDescriptor, mD3D12Resource, ExternalMutexSerial(descriptor->acquireMutexKey), + descriptor->isSwapChainTexture, descriptor->isInitialized); + return reinterpret_cast(texture.Detach()); + } + + // static + std::unique_ptr ExternalImageDXGI::Create( + WGPUDevice device, + const ExternalImageDescriptorDXGISharedHandle* descriptor) { + Device* backendDevice = reinterpret_cast(device); + + Microsoft::WRL::ComPtr d3d12Resource; + if (FAILED(backendDevice->GetD3D12Device()->OpenSharedHandle( + descriptor->sharedHandle, IID_PPV_ARGS(&d3d12Resource)))) { + return nullptr; + } + + const TextureDescriptor* textureDescriptor = + reinterpret_cast(descriptor->cTextureDescriptor); + + if (backendDevice->ConsumedError( + ValidateTextureDescriptor(backendDevice, textureDescriptor))) { + return nullptr; + } + + if (backendDevice->ConsumedError( + ValidateTextureDescriptorCanBeWrapped(textureDescriptor))) { + return nullptr; + } + + if (backendDevice->ConsumedError( + ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), textureDescriptor))) { + return nullptr; + } + + // Shared handle is assumed to support resource sharing capability. The resource + // shared capability tier must agree to share resources between D3D devices. + const Format* format = + backendDevice->GetInternalFormat(textureDescriptor->format).AcquireSuccess(); + if (format->IsMultiPlanar()) { + if (backendDevice->ConsumedError(ValidateD3D12VideoTextureCanBeShared( + backendDevice, D3D12TextureFormat(textureDescriptor->format)))) { + return nullptr; + } + } + + std::unique_ptr result( + new ExternalImageDXGI(std::move(d3d12Resource), descriptor->cTextureDescriptor)); + return result; + } + uint64_t SetExternalMemoryReservation(WGPUDevice device, uint64_t requestedReservationSize, MemorySegment memorySegment) { @@ -62,11 +139,18 @@ namespace dawn_native { namespace d3d12 { WGPUTexture WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor) { - Device* backendDevice = reinterpret_cast(device); - Ref texture = backendDevice->WrapSharedHandle( - descriptor, descriptor->sharedHandle, ExternalMutexSerial(descriptor->acquireMutexKey), - descriptor->isSwapChainTexture); - return reinterpret_cast(texture.Detach()); + std::unique_ptr externalImage = + ExternalImageDXGI::Create(device, descriptor); + if (externalImage == nullptr) { + return nullptr; + } + + ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc = {}; + externalAccessDesc.isInitialized = descriptor->isInitialized; + externalAccessDesc.isSwapChainTexture = descriptor->isSwapChainTexture; + externalAccessDesc.acquireMutexKey = descriptor->acquireMutexKey; + + return externalImage->ProduceTexture(device, &externalAccessDesc); } AdapterDiscoveryOptions::AdapterDiscoveryOptions(ComPtr adapter) diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 9d5041f969..6b66900beb 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -436,14 +436,16 @@ namespace dawn_native { namespace d3d12 { initialUsage); } - Ref Device::WrapSharedHandle(const ExternalImageDescriptor* descriptor, - HANDLE sharedHandle, - ExternalMutexSerial acquireMutexKey, - bool isSwapChainTexture) { + Ref Device::CreateExternalTexture(const TextureDescriptor* descriptor, + ComPtr d3d12Texture, + ExternalMutexSerial acquireMutexKey, + bool isSwapChainTexture, + bool isInitialized) { Ref dawnTexture; - if (ConsumedError(Texture::Create(this, descriptor, sharedHandle, acquireMutexKey, - isSwapChainTexture), - &dawnTexture)) { + if (ConsumedError( + Texture::CreateExternalImage(this, descriptor, std::move(d3d12Texture), + acquireMutexKey, isSwapChainTexture, isInitialized), + &dawnTexture)) { return nullptr; } return {dawnTexture}; diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h index 113f819746..40f029f41c 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.h +++ b/src/dawn_native/d3d12/DeviceD3D12.h @@ -121,10 +121,11 @@ namespace dawn_native { namespace d3d12 { StagingDescriptorAllocator* GetDepthStencilViewAllocator() const; - Ref WrapSharedHandle(const ExternalImageDescriptor* descriptor, - HANDLE sharedHandle, - ExternalMutexSerial acquireMutexKey, - bool isSwapChainTexture); + Ref CreateExternalTexture(const TextureDescriptor* descriptor, + ComPtr d3d12Texture, + ExternalMutexSerial acquireMutexKey, + bool isSwapChainTexture, + bool isInitialized); ResultOrError> CreateKeyedMutexForTexture( ID3D12Resource* d3d12Resource); void ReleaseKeyedMutexForTexture(ComPtr dxgiKeyedMutex); diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index 960b09a68c..4ef71753f7 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -418,27 +418,25 @@ namespace dawn_native { namespace d3d12 { } // static - ResultOrError> Texture::Create(Device* device, - const ExternalImageDescriptor* descriptor, - HANDLE sharedHandle, - ExternalMutexSerial acquireMutexKey, - bool isSwapChainTexture) { - const TextureDescriptor* textureDescriptor = - reinterpret_cast(descriptor->cTextureDescriptor); - + ResultOrError> Texture::CreateExternalImage(Device* device, + const TextureDescriptor* descriptor, + ComPtr d3d12Texture, + ExternalMutexSerial acquireMutexKey, + bool isSwapChainTexture, + bool isInitialized) { Ref dawnTexture = - AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal)); - DAWN_TRY(dawnTexture->InitializeAsExternalTexture(textureDescriptor, sharedHandle, + AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal)); + DAWN_TRY(dawnTexture->InitializeAsExternalTexture(descriptor, std::move(d3d12Texture), acquireMutexKey, isSwapChainTexture)); // Importing a multi-planar format must be initialized. This is required because // a shared multi-planar format cannot be initialized by Dawn. - if (!descriptor->isInitialized && dawnTexture->GetFormat().IsMultiPlanar()) { + if (!isInitialized && dawnTexture->GetFormat().IsMultiPlanar()) { return DAWN_VALIDATION_ERROR( "Cannot create a multi-planar formatted texture without being initialized"); } - dawnTexture->SetIsSubresourceContentInitialized(descriptor->isInitialized, + dawnTexture->SetIsSubresourceContentInitialized(isInitialized, dawnTexture->GetAllSubresources()); return std::move(dawnTexture); } @@ -454,30 +452,13 @@ namespace dawn_native { namespace d3d12 { } MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor, - HANDLE sharedHandle, + ComPtr d3d12Texture, ExternalMutexSerial acquireMutexKey, bool isSwapChainTexture) { Device* dawnDevice = ToBackend(GetDevice()); - DAWN_TRY(ValidateTextureDescriptor(dawnDevice, descriptor)); - DAWN_TRY(ValidateTextureDescriptorCanBeWrapped(descriptor)); - - ComPtr d3d12Resource; - DAWN_TRY(CheckHRESULT(dawnDevice->GetD3D12Device()->OpenSharedHandle( - sharedHandle, IID_PPV_ARGS(&d3d12Resource)), - "D3D12 opening shared handle")); - - DAWN_TRY(ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), descriptor)); - - // Shared handle is assumed to support resource sharing capability. The resource - // shared capability tier must agree to share resources between D3D devices. - if (GetFormat().IsMultiPlanar()) { - DAWN_TRY(ValidateD3D12VideoTextureCanBeShared(ToBackend(GetDevice()), - D3D12TextureFormat(descriptor->format))); - } ComPtr dxgiKeyedMutex; - DAWN_TRY_ASSIGN(dxgiKeyedMutex, - dawnDevice->CreateKeyedMutexForTexture(d3d12Resource.Get())); + DAWN_TRY_ASSIGN(dxgiKeyedMutex, dawnDevice->CreateKeyedMutexForTexture(d3d12Texture.Get())); DAWN_TRY(CheckHRESULT(dxgiKeyedMutex->AcquireSync(uint64_t(acquireMutexKey), INFINITE), "D3D12 acquiring shared mutex")); @@ -491,7 +472,7 @@ namespace dawn_native { namespace d3d12 { // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the // texture is owned externally. The texture's owning entity must remain responsible for // memory management. - mResourceAllocation = {info, 0, std::move(d3d12Resource), nullptr}; + mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr}; return {}; } diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h index 2e2e089e64..8c55b3eb88 100644 --- a/src/dawn_native/d3d12/TextureD3D12.h +++ b/src/dawn_native/d3d12/TextureD3D12.h @@ -33,16 +33,18 @@ namespace dawn_native { namespace d3d12 { MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, const TextureDescriptor* descriptor); MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor); + MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat); class Texture final : public TextureBase { public: static ResultOrError> Create(Device* device, const TextureDescriptor* descriptor); - static ResultOrError> Create(Device* device, - const ExternalImageDescriptor* descriptor, - HANDLE sharedHandle, - ExternalMutexSerial acquireMutexKey, - bool isSwapChainTexture); + static ResultOrError> CreateExternalImage(Device* device, + const TextureDescriptor* descriptor, + ComPtr d3d12Texture, + ExternalMutexSerial acquireMutexKey, + bool isSwapChainTexture, + bool isInitialized); static ResultOrError> Create(Device* device, const TextureDescriptor* descriptor, ComPtr d3d12Texture); @@ -85,7 +87,7 @@ namespace dawn_native { namespace d3d12 { MaybeError InitializeAsInternalTexture(); MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor, - HANDLE sharedHandle, + ComPtr d3d12Texture, ExternalMutexSerial acquireMutexKey, bool isSwapChainTexture); MaybeError InitializeAsSwapChainTexture(ComPtr d3d12Texture); diff --git a/src/include/dawn_native/D3D12Backend.h b/src/include/dawn_native/D3D12Backend.h index 035ad96188..e71362349d 100644 --- a/src/include/dawn_native/D3D12Backend.h +++ b/src/include/dawn_native/D3D12Backend.h @@ -19,10 +19,14 @@ #include #include +#include #include #include +#include + struct ID3D12Device; +struct ID3D12Resource; namespace dawn_native { namespace d3d12 { DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr GetD3D12Device(WGPUDevice device); @@ -45,10 +49,46 @@ namespace dawn_native { namespace d3d12 { ExternalImageDescriptorDXGISharedHandle(); HANDLE sharedHandle; + + // Warning: depreciated, replaced by ExternalImageAccessDescriptorDXGIKeyedMutex. uint64_t acquireMutexKey; bool isSwapChainTexture = false; }; + struct DAWN_NATIVE_EXPORT ExternalImageAccessDescriptorDXGIKeyedMutex + : ExternalImageAccessDescriptor { + public: + uint64_t acquireMutexKey; + bool isSwapChainTexture = false; + }; + + class DAWN_NATIVE_EXPORT ExternalImageDXGI { + public: + // Note: SharedHandle must be a handle to a texture object. + static std::unique_ptr Create( + WGPUDevice device, + const ExternalImageDescriptorDXGISharedHandle* descriptor); + + WGPUTexture ProduceTexture(WGPUDevice device, + const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor); + + private: + ExternalImageDXGI(Microsoft::WRL::ComPtr d3d12Resource, + const WGPUTextureDescriptor* descriptor); + + Microsoft::WRL::ComPtr mD3D12Resource; + + // Contents of WGPUTextureDescriptor are stored individually since the descriptor + // could outlive this image. + WGPUTextureUsageFlags mUsage; + WGPUTextureDimension mDimension; + WGPUExtent3D mSize; + WGPUTextureFormat mFormat; + uint32_t mMipLevelCount; + uint32_t mSampleCount; + }; + + // Warning: depreciated, replaced by ExternalImageDXGI::Create. // Note: SharedHandle must be a handle to a texture object. DAWN_NATIVE_EXPORT WGPUTexture WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor); diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h index f161d4ae9f..68e2feb870 100644 --- a/src/include/dawn_native/DawnNative.h +++ b/src/include/dawn_native/DawnNative.h @@ -228,6 +228,11 @@ namespace dawn_native { ExternalImageDescriptor(ExternalImageType type); }; + struct DAWN_NATIVE_EXPORT ExternalImageAccessDescriptor { + public: + bool isInitialized; // Whether the texture is initialized on import + }; + struct DAWN_NATIVE_EXPORT ExternalImageExportInfo { public: const ExternalImageType type; diff --git a/src/tests/end2end/D3D12ResourceWrappingTests.cpp b/src/tests/end2end/D3D12ResourceWrappingTests.cpp index 003d01126e..72de44c07c 100644 --- a/src/tests/end2end/D3D12ResourceWrappingTests.cpp +++ b/src/tests/end2end/D3D12ResourceWrappingTests.cpp @@ -86,7 +86,9 @@ namespace { void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc, const D3D11_TEXTURE2D_DESC* baseD3dDescriptor, wgpu::Texture* dawnTexture, - ID3D11Texture2D** d3d11TextureOut) const { + ID3D11Texture2D** d3d11TextureOut, + std::unique_ptr* + externalImageOut = nullptr) const { ComPtr d3d11Texture; HRESULT hr = mD3d11Device->CreateTexture2D(baseD3dDescriptor, nullptr, &d3d11Texture); ASSERT_EQ(hr, S_OK); @@ -101,19 +103,33 @@ namespace { &sharedHandle); ASSERT_EQ(hr, S_OK); - dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc; - externDesc.cTextureDescriptor = + dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc; + externalImageDesc.cTextureDescriptor = reinterpret_cast(dawnDesc); - externDesc.sharedHandle = sharedHandle; - externDesc.acquireMutexKey = 0; - WGPUTexture texture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc); + externalImageDesc.sharedHandle = sharedHandle; + + std::unique_ptr externalImage = + dawn_native::d3d12::ExternalImageDXGI::Create(device.Get(), &externalImageDesc); // Now that we've created all of our resources, we can close the handle // since we no longer need it. ::CloseHandle(sharedHandle); - *dawnTexture = wgpu::Texture::Acquire(texture); + // Cannot access a non-existent external image (ex. validation error). + if (externalImage == nullptr) { + return; + } + + dawn_native::d3d12::ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc; + externalAccessDesc.acquireMutexKey = 0; + + *dawnTexture = wgpu::Texture::Acquire( + externalImage->ProduceTexture(device.Get(), &externalAccessDesc)); *d3d11TextureOut = d3d11Texture.Detach(); + + if (externalImageOut != nullptr) { + *externalImageOut = std::move(externalImage); + } } static constexpr size_t kTestWidth = 10; @@ -334,15 +350,20 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase { hr = dxgiKeyedMutex->ReleaseSync(1); ASSERT_EQ(hr, S_OK); - dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc; - externDesc.cTextureDescriptor = + dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc = {}; + externalImageDesc.sharedHandle = sharedHandle; + externalImageDesc.cTextureDescriptor = reinterpret_cast(dawnDescriptor); - externDesc.sharedHandle = sharedHandle; - externDesc.acquireMutexKey = 1; - externDesc.isInitialized = isInitialized; - WGPUTexture dawnTexture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc); - *dawnTextureOut = wgpu::Texture::Acquire(dawnTexture); + std::unique_ptr externalImage = + dawn_native::d3d12::ExternalImageDXGI::Create(device.Get(), &externalImageDesc); + + dawn_native::d3d12::ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc; + externalAccessDesc.acquireMutexKey = 1; + externalAccessDesc.isInitialized = isInitialized; + + *dawnTextureOut = wgpu::Texture::Acquire( + externalImage->ProduceTexture(device.Get(), &externalAccessDesc)); *d3d11TextureOut = d3d11Texture.Detach(); *dxgiKeyedMutexOut = dxgiKeyedMutex.Detach(); } @@ -519,5 +540,50 @@ TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) { EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), dawnTexture, 0, 0); } +// 1. Create an external image from the DX11 texture. +// 2. Produce two Dawn textures from the external image. +// 3. Clear each Dawn texture and verify the texture was cleared to a unique color. +TEST_P(D3D12SharedHandleUsageTests, ReuseExternalImage) { + DAWN_SKIP_TEST_IF(UsesWire()); + + // Create the first Dawn texture then clear it to red. + wgpu::Texture texture; + ComPtr d3d11Texture; + std::unique_ptr externalImage; + WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, + &externalImage); + { + const wgpu::Color solidRed{1.0f, 0.0f, 0.0f, 1.0f}; + ASSERT_NE(texture.Get(), nullptr); + ClearImage(texture.Get(), solidRed); + + EXPECT_PIXEL_RGBA8_EQ(RGBA8(0xFF, 0, 0, 0xFF), texture.Get(), 0, 0); + } + + // Once finished with the first texture, destroy it so we may re-acquire the external image + // again. + texture.Destroy(); + + // Create another Dawn texture then clear it with another color. + dawn_native::d3d12::ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc; + externalAccessDesc.acquireMutexKey = 1; + externalAccessDesc.isInitialized = true; + + texture = + wgpu::Texture::Acquire(externalImage->ProduceTexture(device.Get(), &externalAccessDesc)); + + // Check again that the new texture is still red + EXPECT_PIXEL_RGBA8_EQ(RGBA8(0xFF, 0, 0, 0xFF), texture.Get(), 0, 0); + + // Clear the new texture to blue + { + const wgpu::Color solidBlue{0.0f, 0.0f, 1.0f, 1.0f}; + ASSERT_NE(texture.Get(), nullptr); + ClearImage(texture.Get(), solidBlue); + + EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0xFF, 0xFF), texture.Get(), 0, 0); + } +} + DAWN_INSTANTIATE_TEST(D3D12SharedHandleValidation, D3D12Backend()); DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend()); diff --git a/src/tests/end2end/D3D12VideoViewsTests.cpp b/src/tests/end2end/D3D12VideoViewsTests.cpp index a3f6551e81..6f7938de58 100644 --- a/src/tests/end2end/D3D12VideoViewsTests.cpp +++ b/src/tests/end2end/D3D12VideoViewsTests.cpp @@ -139,9 +139,10 @@ namespace { } } - wgpu::Texture CreateVideoTextureForTest(wgpu::TextureFormat format, - wgpu::TextureUsage usage, - bool isCheckerboard = false) { + void CreateVideoTextureForTest(wgpu::TextureFormat format, + wgpu::TextureUsage usage, + bool isCheckerboard, + wgpu::Texture* dawnTextureOut) { wgpu::TextureDescriptor textureDesc; textureDesc.format = format; textureDesc.dimension = wgpu::TextureDimension::e2D; @@ -171,24 +172,17 @@ namespace { ComPtr d3d11Texture; HRESULT hr = mD3d11Device->CreateTexture2D(&d3dDescriptor, &subres, &d3d11Texture); - EXPECT_EQ(hr, S_OK); + ASSERT_EQ(hr, S_OK); ComPtr dxgiResource; hr = d3d11Texture.As(&dxgiResource); - EXPECT_EQ(hr, S_OK); + ASSERT_EQ(hr, S_OK); HANDLE sharedHandle; hr = dxgiResource->CreateSharedHandle( nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, &sharedHandle); - EXPECT_EQ(hr, S_OK); - - dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc; - externDesc.cTextureDescriptor = - reinterpret_cast(&textureDesc); - externDesc.sharedHandle = sharedHandle; - externDesc.acquireMutexKey = 1; - externDesc.isInitialized = true; + ASSERT_EQ(hr, S_OK); // DX11 texture should be initialized upon CreateTexture2D. However, if we do not // acquire/release the keyed mutex before using the wrapped WebGPU texture, the WebGPU @@ -205,13 +199,23 @@ namespace { // Open the DX11 texture in Dawn from the shared handle and return it as a WebGPU // texture. - wgpu::Texture wgpuTexture = wgpu::Texture::Acquire( - dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc)); + dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc; + externalImageDesc.cTextureDescriptor = + reinterpret_cast(&textureDesc); + externalImageDesc.sharedHandle = sharedHandle; + + std::unique_ptr externalImage = + dawn_native::d3d12::ExternalImageDXGI::Create(device.Get(), &externalImageDesc); // Handle is no longer needed once resources are created. ::CloseHandle(sharedHandle); - return wgpuTexture; + dawn_native::d3d12::ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc; + externalAccessDesc.acquireMutexKey = 1; + externalAccessDesc.isInitialized = true; + + *dawnTextureOut = wgpu::Texture::Acquire( + externalImage->ProduceTexture(device.Get(), &externalAccessDesc)); } // Vertex shader used to render a sampled texture into a quad. @@ -259,8 +263,9 @@ namespace { // Samples the luminance (Y) plane from an imported NV12 texture into a single channel of an RGBA // output attachment and checks for the expected pixel value in the rendered quad. TEST_P(D3D12VideoViewsTests, NV12SampleYtoR) { - wgpu::Texture wgpuTexture = CreateVideoTextureForTest( - wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled); + wgpu::Texture wgpuTexture; + CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm, + wgpu::TextureUsage::Sampled, /*isCheckerboard*/ false, &wgpuTexture); wgpu::TextureViewDescriptor viewDesc; viewDesc.aspect = wgpu::TextureAspect::Plane0Only; @@ -310,8 +315,9 @@ TEST_P(D3D12VideoViewsTests, NV12SampleYtoR) { // Samples the chrominance (UV) plane from an imported texture into two channels of an RGBA output // attachment and checks for the expected pixel value in the rendered quad. TEST_P(D3D12VideoViewsTests, NV12SampleUVtoRG) { - wgpu::Texture wgpuTexture = CreateVideoTextureForTest( - wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled); + wgpu::Texture wgpuTexture; + CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm, + wgpu::TextureUsage::Sampled, /*isCheckerboard*/ false, &wgpuTexture); wgpu::TextureViewDescriptor viewDesc; viewDesc.aspect = wgpu::TextureAspect::Plane1Only; @@ -362,8 +368,9 @@ TEST_P(D3D12VideoViewsTests, NV12SampleUVtoRG) { // Renders a NV12 "checkerboard" texture into a RGB quad then checks the color at specific // points to ensure the image has not been flipped. TEST_P(D3D12VideoViewsTests, NV12SampleYUVtoRGB) { - wgpu::Texture wgpuTexture = CreateVideoTextureForTest( - wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled, true); + wgpu::Texture wgpuTexture; + CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm, + wgpu::TextureUsage::Sampled, /*isCheckerboard*/ true, &wgpuTexture); wgpu::TextureViewDescriptor lumaViewDesc; lumaViewDesc.aspect = wgpu::TextureAspect::Plane0Only;