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>
This commit is contained in:
parent
4d9f2ca07d
commit
9c3aefa4bd
|
@ -51,6 +51,83 @@ namespace dawn_native { namespace d3d12 {
|
|||
: 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 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
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)
|
||||
|
|
|
@ -436,14 +436,16 @@ namespace dawn_native { namespace d3d12 {
|
|||
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};
|
||||
|
|
|
@ -121,10 +121,11 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
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);
|
||||
|
|
|
@ -418,27 +418,25 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
|
||||
// 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 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
|
||||
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 @@ 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 {};
|
||||
}
|
||||
|
|
|
@ -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<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 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
MaybeError InitializeAsInternalTexture();
|
||||
MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor,
|
||||
HANDLE sharedHandle,
|
||||
ComPtr<ID3D12Resource> d3d12Texture,
|
||||
ExternalMutexSerial acquireMutexKey,
|
||||
bool isSwapChainTexture);
|
||||
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
|
||||
|
|
|
@ -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 @@ 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<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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<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 @@ namespace {
|
|||
&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 @@ 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<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 @@ 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<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());
|
||||
|
|
|
@ -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<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 @@ 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<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 @@ 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;
|
||||
|
|
Loading…
Reference in New Issue