D3D12: Enable external texture reuse
This change allows multiple Dawn textures to be created from the same
D3D11 resource. This avoids re-opening the shared handle by caching the
D3D12 resource outside of the Dawn texture.
Re-opening the handle costs 5-10% of CPU cycles per frame, which far
exceeded syncronization costs.
In a future change, WrapSharedHandle will be depreciated.
BUG=dawn:625
Change-Id: If0d2dc9b7445ec3ae718bc5305164db88057c4ea
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/42140
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp
index aac8968..8d992f4 100644
--- a/src/dawn_native/d3d12/D3D12Backend.cpp
+++ b/src/dawn_native/d3d12/D3D12Backend.cpp
@@ -51,6 +51,83 @@
: ExternalImageDescriptor(ExternalImageType::DXGISharedHandle) {
}
+ ExternalImageDXGI::ExternalImageDXGI(ComPtr<ID3D12Resource> 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*>(device);
+
+ TextureDescriptor textureDescriptor = {};
+ textureDescriptor.usage = static_cast<wgpu::TextureUsage>(mUsage);
+ textureDescriptor.dimension = static_cast<wgpu::TextureDimension>(mDimension);
+ textureDescriptor.size = {mSize.width, mSize.height, mSize.depth};
+ textureDescriptor.format = static_cast<wgpu::TextureFormat>(mFormat);
+ textureDescriptor.mipLevelCount = mMipLevelCount;
+ textureDescriptor.sampleCount = mSampleCount;
+
+ Ref<TextureBase> texture = backendDevice->CreateExternalTexture(
+ &textureDescriptor, mD3D12Resource, ExternalMutexSerial(descriptor->acquireMutexKey),
+ descriptor->isSwapChainTexture, descriptor->isInitialized);
+ return reinterpret_cast<WGPUTexture>(texture.Detach());
+ }
+
+ // static
+ std::unique_ptr<ExternalImageDXGI> ExternalImageDXGI::Create(
+ WGPUDevice device,
+ const ExternalImageDescriptorDXGISharedHandle* descriptor) {
+ Device* backendDevice = reinterpret_cast<Device*>(device);
+
+ Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource;
+ if (FAILED(backendDevice->GetD3D12Device()->OpenSharedHandle(
+ descriptor->sharedHandle, IID_PPV_ARGS(&d3d12Resource)))) {
+ return nullptr;
+ }
+
+ const TextureDescriptor* textureDescriptor =
+ reinterpret_cast<const TextureDescriptor*>(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<ExternalImageDXGI> result(
+ new ExternalImageDXGI(std::move(d3d12Resource), descriptor->cTextureDescriptor));
+ return result;
+ }
+
uint64_t SetExternalMemoryReservation(WGPUDevice device,
uint64_t requestedReservationSize,
MemorySegment memorySegment) {
@@ -62,11 +139,18 @@
WGPUTexture WrapSharedHandle(WGPUDevice device,
const ExternalImageDescriptorDXGISharedHandle* descriptor) {
- Device* backendDevice = reinterpret_cast<Device*>(device);
- Ref<TextureBase> texture = backendDevice->WrapSharedHandle(
- descriptor, descriptor->sharedHandle, ExternalMutexSerial(descriptor->acquireMutexKey),
- descriptor->isSwapChainTexture);
- return reinterpret_cast<WGPUTexture>(texture.Detach());
+ std::unique_ptr<ExternalImageDXGI> 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<IDXGIAdapter> adapter)
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 9d5041f..6b66900 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -436,14 +436,16 @@
initialUsage);
}
- Ref<TextureBase> Device::WrapSharedHandle(const ExternalImageDescriptor* descriptor,
- HANDLE sharedHandle,
- ExternalMutexSerial acquireMutexKey,
- bool isSwapChainTexture) {
+ Ref<TextureBase> Device::CreateExternalTexture(const TextureDescriptor* descriptor,
+ ComPtr<ID3D12Resource> d3d12Texture,
+ ExternalMutexSerial acquireMutexKey,
+ bool isSwapChainTexture,
+ bool isInitialized) {
Ref<Texture> 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 113f819..40f029f 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -121,10 +121,11 @@
StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
- Ref<TextureBase> WrapSharedHandle(const ExternalImageDescriptor* descriptor,
- HANDLE sharedHandle,
- ExternalMutexSerial acquireMutexKey,
- bool isSwapChainTexture);
+ Ref<TextureBase> CreateExternalTexture(const TextureDescriptor* descriptor,
+ ComPtr<ID3D12Resource> d3d12Texture,
+ ExternalMutexSerial acquireMutexKey,
+ bool isSwapChainTexture,
+ bool isInitialized);
ResultOrError<ComPtr<IDXGIKeyedMutex>> CreateKeyedMutexForTexture(
ID3D12Resource* d3d12Resource);
void ReleaseKeyedMutexForTexture(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex);
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 960b09a..4ef7175 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -418,27 +418,25 @@
}
// static
- ResultOrError<Ref<Texture>> Texture::Create(Device* device,
- const ExternalImageDescriptor* descriptor,
- HANDLE sharedHandle,
- ExternalMutexSerial acquireMutexKey,
- bool isSwapChainTexture) {
- const TextureDescriptor* textureDescriptor =
- reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
-
+ ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device,
+ const TextureDescriptor* descriptor,
+ ComPtr<ID3D12Resource> d3d12Texture,
+ ExternalMutexSerial acquireMutexKey,
+ bool isSwapChainTexture,
+ bool isInitialized) {
Ref<Texture> 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 @@
}
MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor,
- HANDLE sharedHandle,
+ ComPtr<ID3D12Resource> d3d12Texture,
ExternalMutexSerial acquireMutexKey,
bool isSwapChainTexture) {
Device* dawnDevice = ToBackend(GetDevice());
- DAWN_TRY(ValidateTextureDescriptor(dawnDevice, descriptor));
- DAWN_TRY(ValidateTextureDescriptorCanBeWrapped(descriptor));
-
- ComPtr<ID3D12Resource> 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<IDXGIKeyedMutex> 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 @@
// 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 2e2e089..8c55b3e 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -33,16 +33,18 @@
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<Ref<Texture>> Create(Device* device,
const TextureDescriptor* descriptor);
- static ResultOrError<Ref<Texture>> Create(Device* device,
- const ExternalImageDescriptor* descriptor,
- HANDLE sharedHandle,
- ExternalMutexSerial acquireMutexKey,
- bool isSwapChainTexture);
+ static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device,
+ const TextureDescriptor* descriptor,
+ ComPtr<ID3D12Resource> d3d12Texture,
+ ExternalMutexSerial acquireMutexKey,
+ bool isSwapChainTexture,
+ bool isInitialized);
static ResultOrError<Ref<Texture>> Create(Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture);
@@ -85,7 +87,7 @@
MaybeError InitializeAsInternalTexture();
MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor,
- HANDLE sharedHandle,
+ ComPtr<ID3D12Resource> d3d12Texture,
ExternalMutexSerial acquireMutexKey,
bool isSwapChainTexture);
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
diff --git a/src/include/dawn_native/D3D12Backend.h b/src/include/dawn_native/D3D12Backend.h
index 035ad96..e713623 100644
--- a/src/include/dawn_native/D3D12Backend.h
+++ b/src/include/dawn_native/D3D12Backend.h
@@ -19,10 +19,14 @@
#include <dawn_native/DawnNative.h>
#include <DXGI1_4.h>
+#include <d3d12.h>
#include <windows.h>
#include <wrl/client.h>
+#include <memory>
+
struct ID3D12Device;
+struct ID3D12Resource;
namespace dawn_native { namespace d3d12 {
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<ID3D12Device> GetD3D12Device(WGPUDevice device);
@@ -45,10 +49,46 @@
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<ExternalImageDXGI> Create(
+ WGPUDevice device,
+ const ExternalImageDescriptorDXGISharedHandle* descriptor);
+
+ WGPUTexture ProduceTexture(WGPUDevice device,
+ const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor);
+
+ private:
+ ExternalImageDXGI(Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
+ const WGPUTextureDescriptor* descriptor);
+
+ Microsoft::WRL::ComPtr<ID3D12Resource> 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 f161d4a..68e2feb 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -228,6 +228,11 @@
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 003d011..72de44c 100644
--- a/src/tests/end2end/D3D12ResourceWrappingTests.cpp
+++ b/src/tests/end2end/D3D12ResourceWrappingTests.cpp
@@ -86,7 +86,9 @@
void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc,
const D3D11_TEXTURE2D_DESC* baseD3dDescriptor,
wgpu::Texture* dawnTexture,
- ID3D11Texture2D** d3d11TextureOut) const {
+ ID3D11Texture2D** d3d11TextureOut,
+ std::unique_ptr<dawn_native::d3d12::ExternalImageDXGI>*
+ externalImageOut = nullptr) const {
ComPtr<ID3D11Texture2D> d3d11Texture;
HRESULT hr = mD3d11Device->CreateTexture2D(baseD3dDescriptor, nullptr, &d3d11Texture);
ASSERT_EQ(hr, S_OK);
@@ -101,19 +103,33 @@
&sharedHandle);
ASSERT_EQ(hr, S_OK);
- dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc;
- externDesc.cTextureDescriptor =
+ dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc;
+ externalImageDesc.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc);
- externDesc.sharedHandle = sharedHandle;
- externDesc.acquireMutexKey = 0;
- WGPUTexture texture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc);
+ externalImageDesc.sharedHandle = sharedHandle;
+
+ std::unique_ptr<dawn_native::d3d12::ExternalImageDXGI> 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 @@
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<const WGPUTextureDescriptor*>(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<dawn_native::d3d12::ExternalImageDXGI> 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 @@
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<ID3D11Texture2D> d3d11Texture;
+ std::unique_ptr<dawn_native::d3d12::ExternalImageDXGI> 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 a3f6551..6f7938d 100644
--- a/src/tests/end2end/D3D12VideoViewsTests.cpp
+++ b/src/tests/end2end/D3D12VideoViewsTests.cpp
@@ -139,9 +139,10 @@
}
}
- 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 @@
ComPtr<ID3D11Texture2D> d3d11Texture;
HRESULT hr = mD3d11Device->CreateTexture2D(&d3dDescriptor, &subres, &d3d11Texture);
- EXPECT_EQ(hr, S_OK);
+ ASSERT_EQ(hr, S_OK);
ComPtr<IDXGIResource1> 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<const WGPUTextureDescriptor*>(&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 @@
// 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<const WGPUTextureDescriptor*>(&textureDesc);
+ externalImageDesc.sharedHandle = sharedHandle;
+
+ std::unique_ptr<dawn_native::d3d12::ExternalImageDXGI> 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 @@
// 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 @@
// 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 @@
// 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;