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) {
|
: 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 SetExternalMemoryReservation(WGPUDevice device,
|
||||||
uint64_t requestedReservationSize,
|
uint64_t requestedReservationSize,
|
||||||
MemorySegment memorySegment) {
|
MemorySegment memorySegment) {
|
||||||
|
@ -62,11 +139,18 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
WGPUTexture WrapSharedHandle(WGPUDevice device,
|
WGPUTexture WrapSharedHandle(WGPUDevice device,
|
||||||
const ExternalImageDescriptorDXGISharedHandle* descriptor) {
|
const ExternalImageDescriptorDXGISharedHandle* descriptor) {
|
||||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
std::unique_ptr<ExternalImageDXGI> externalImage =
|
||||||
Ref<TextureBase> texture = backendDevice->WrapSharedHandle(
|
ExternalImageDXGI::Create(device, descriptor);
|
||||||
descriptor, descriptor->sharedHandle, ExternalMutexSerial(descriptor->acquireMutexKey),
|
if (externalImage == nullptr) {
|
||||||
descriptor->isSwapChainTexture);
|
return nullptr;
|
||||||
return reinterpret_cast<WGPUTexture>(texture.Detach());
|
}
|
||||||
|
|
||||||
|
ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc = {};
|
||||||
|
externalAccessDesc.isInitialized = descriptor->isInitialized;
|
||||||
|
externalAccessDesc.isSwapChainTexture = descriptor->isSwapChainTexture;
|
||||||
|
externalAccessDesc.acquireMutexKey = descriptor->acquireMutexKey;
|
||||||
|
|
||||||
|
return externalImage->ProduceTexture(device, &externalAccessDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdapterDiscoveryOptions::AdapterDiscoveryOptions(ComPtr<IDXGIAdapter> adapter)
|
AdapterDiscoveryOptions::AdapterDiscoveryOptions(ComPtr<IDXGIAdapter> adapter)
|
||||||
|
|
|
@ -436,14 +436,16 @@ namespace dawn_native { namespace d3d12 {
|
||||||
initialUsage);
|
initialUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<TextureBase> Device::WrapSharedHandle(const ExternalImageDescriptor* descriptor,
|
Ref<TextureBase> Device::CreateExternalTexture(const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture) {
|
bool isSwapChainTexture,
|
||||||
|
bool isInitialized) {
|
||||||
Ref<Texture> dawnTexture;
|
Ref<Texture> dawnTexture;
|
||||||
if (ConsumedError(Texture::Create(this, descriptor, sharedHandle, acquireMutexKey,
|
if (ConsumedError(
|
||||||
isSwapChainTexture),
|
Texture::CreateExternalImage(this, descriptor, std::move(d3d12Texture),
|
||||||
&dawnTexture)) {
|
acquireMutexKey, isSwapChainTexture, isInitialized),
|
||||||
|
&dawnTexture)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return {dawnTexture};
|
return {dawnTexture};
|
||||||
|
|
|
@ -121,10 +121,11 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
|
StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
|
||||||
|
|
||||||
Ref<TextureBase> WrapSharedHandle(const ExternalImageDescriptor* descriptor,
|
Ref<TextureBase> CreateExternalTexture(const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture);
|
bool isSwapChainTexture,
|
||||||
|
bool isInitialized);
|
||||||
ResultOrError<ComPtr<IDXGIKeyedMutex>> CreateKeyedMutexForTexture(
|
ResultOrError<ComPtr<IDXGIKeyedMutex>> CreateKeyedMutexForTexture(
|
||||||
ID3D12Resource* d3d12Resource);
|
ID3D12Resource* d3d12Resource);
|
||||||
void ReleaseKeyedMutexForTexture(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex);
|
void ReleaseKeyedMutexForTexture(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex);
|
||||||
|
|
|
@ -418,27 +418,25 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ResultOrError<Ref<Texture>> Texture::Create(Device* device,
|
ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device,
|
||||||
const ExternalImageDescriptor* descriptor,
|
const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture) {
|
bool isSwapChainTexture,
|
||||||
const TextureDescriptor* textureDescriptor =
|
bool isInitialized) {
|
||||||
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
|
|
||||||
|
|
||||||
Ref<Texture> dawnTexture =
|
Ref<Texture> dawnTexture =
|
||||||
AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal));
|
AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal));
|
||||||
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(textureDescriptor, sharedHandle,
|
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(descriptor, std::move(d3d12Texture),
|
||||||
acquireMutexKey, isSwapChainTexture));
|
acquireMutexKey, isSwapChainTexture));
|
||||||
|
|
||||||
// Importing a multi-planar format must be initialized. This is required because
|
// Importing a multi-planar format must be initialized. This is required because
|
||||||
// a shared multi-planar format cannot be initialized by Dawn.
|
// 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(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Cannot create a multi-planar formatted texture without being initialized");
|
"Cannot create a multi-planar formatted texture without being initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
dawnTexture->SetIsSubresourceContentInitialized(descriptor->isInitialized,
|
dawnTexture->SetIsSubresourceContentInitialized(isInitialized,
|
||||||
dawnTexture->GetAllSubresources());
|
dawnTexture->GetAllSubresources());
|
||||||
return std::move(dawnTexture);
|
return std::move(dawnTexture);
|
||||||
}
|
}
|
||||||
|
@ -454,30 +452,13 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor,
|
MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture) {
|
bool isSwapChainTexture) {
|
||||||
Device* dawnDevice = ToBackend(GetDevice());
|
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;
|
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
|
||||||
DAWN_TRY_ASSIGN(dxgiKeyedMutex,
|
DAWN_TRY_ASSIGN(dxgiKeyedMutex, dawnDevice->CreateKeyedMutexForTexture(d3d12Texture.Get()));
|
||||||
dawnDevice->CreateKeyedMutexForTexture(d3d12Resource.Get()));
|
|
||||||
|
|
||||||
DAWN_TRY(CheckHRESULT(dxgiKeyedMutex->AcquireSync(uint64_t(acquireMutexKey), INFINITE),
|
DAWN_TRY(CheckHRESULT(dxgiKeyedMutex->AcquireSync(uint64_t(acquireMutexKey), INFINITE),
|
||||||
"D3D12 acquiring shared mutex"));
|
"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
|
// 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
|
// texture is owned externally. The texture's owning entity must remain responsible for
|
||||||
// memory management.
|
// memory management.
|
||||||
mResourceAllocation = {info, 0, std::move(d3d12Resource), nullptr};
|
mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr};
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,16 +33,18 @@ namespace dawn_native { namespace d3d12 {
|
||||||
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
|
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
|
||||||
const TextureDescriptor* descriptor);
|
const TextureDescriptor* descriptor);
|
||||||
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor);
|
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor);
|
||||||
|
MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat);
|
||||||
|
|
||||||
class Texture final : public TextureBase {
|
class Texture final : public TextureBase {
|
||||||
public:
|
public:
|
||||||
static ResultOrError<Ref<Texture>> Create(Device* device,
|
static ResultOrError<Ref<Texture>> Create(Device* device,
|
||||||
const TextureDescriptor* descriptor);
|
const TextureDescriptor* descriptor);
|
||||||
static ResultOrError<Ref<Texture>> Create(Device* device,
|
static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device,
|
||||||
const ExternalImageDescriptor* descriptor,
|
const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture);
|
bool isSwapChainTexture,
|
||||||
|
bool isInitialized);
|
||||||
static ResultOrError<Ref<Texture>> Create(Device* device,
|
static ResultOrError<Ref<Texture>> Create(Device* device,
|
||||||
const TextureDescriptor* descriptor,
|
const TextureDescriptor* descriptor,
|
||||||
ComPtr<ID3D12Resource> d3d12Texture);
|
ComPtr<ID3D12Resource> d3d12Texture);
|
||||||
|
@ -85,7 +87,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
MaybeError InitializeAsInternalTexture();
|
MaybeError InitializeAsInternalTexture();
|
||||||
MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor,
|
MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor,
|
||||||
HANDLE sharedHandle,
|
ComPtr<ID3D12Resource> d3d12Texture,
|
||||||
ExternalMutexSerial acquireMutexKey,
|
ExternalMutexSerial acquireMutexKey,
|
||||||
bool isSwapChainTexture);
|
bool isSwapChainTexture);
|
||||||
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
|
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
|
||||||
|
|
|
@ -19,10 +19,14 @@
|
||||||
#include <dawn_native/DawnNative.h>
|
#include <dawn_native/DawnNative.h>
|
||||||
|
|
||||||
#include <DXGI1_4.h>
|
#include <DXGI1_4.h>
|
||||||
|
#include <d3d12.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
struct ID3D12Device;
|
struct ID3D12Device;
|
||||||
|
struct ID3D12Resource;
|
||||||
|
|
||||||
namespace dawn_native { namespace d3d12 {
|
namespace dawn_native { namespace d3d12 {
|
||||||
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<ID3D12Device> GetD3D12Device(WGPUDevice device);
|
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<ID3D12Device> GetD3D12Device(WGPUDevice device);
|
||||||
|
@ -45,10 +49,46 @@ namespace dawn_native { namespace d3d12 {
|
||||||
ExternalImageDescriptorDXGISharedHandle();
|
ExternalImageDescriptorDXGISharedHandle();
|
||||||
|
|
||||||
HANDLE sharedHandle;
|
HANDLE sharedHandle;
|
||||||
|
|
||||||
|
// Warning: depreciated, replaced by ExternalImageAccessDescriptorDXGIKeyedMutex.
|
||||||
uint64_t acquireMutexKey;
|
uint64_t acquireMutexKey;
|
||||||
bool isSwapChainTexture = false;
|
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.
|
// Note: SharedHandle must be a handle to a texture object.
|
||||||
DAWN_NATIVE_EXPORT WGPUTexture
|
DAWN_NATIVE_EXPORT WGPUTexture
|
||||||
WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor);
|
WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor);
|
||||||
|
|
|
@ -228,6 +228,11 @@ namespace dawn_native {
|
||||||
ExternalImageDescriptor(ExternalImageType type);
|
ExternalImageDescriptor(ExternalImageType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DAWN_NATIVE_EXPORT ExternalImageAccessDescriptor {
|
||||||
|
public:
|
||||||
|
bool isInitialized; // Whether the texture is initialized on import
|
||||||
|
};
|
||||||
|
|
||||||
struct DAWN_NATIVE_EXPORT ExternalImageExportInfo {
|
struct DAWN_NATIVE_EXPORT ExternalImageExportInfo {
|
||||||
public:
|
public:
|
||||||
const ExternalImageType type;
|
const ExternalImageType type;
|
||||||
|
|
|
@ -86,7 +86,9 @@ namespace {
|
||||||
void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc,
|
void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc,
|
||||||
const D3D11_TEXTURE2D_DESC* baseD3dDescriptor,
|
const D3D11_TEXTURE2D_DESC* baseD3dDescriptor,
|
||||||
wgpu::Texture* dawnTexture,
|
wgpu::Texture* dawnTexture,
|
||||||
ID3D11Texture2D** d3d11TextureOut) const {
|
ID3D11Texture2D** d3d11TextureOut,
|
||||||
|
std::unique_ptr<dawn_native::d3d12::ExternalImageDXGI>*
|
||||||
|
externalImageOut = nullptr) const {
|
||||||
ComPtr<ID3D11Texture2D> d3d11Texture;
|
ComPtr<ID3D11Texture2D> d3d11Texture;
|
||||||
HRESULT hr = mD3d11Device->CreateTexture2D(baseD3dDescriptor, nullptr, &d3d11Texture);
|
HRESULT hr = mD3d11Device->CreateTexture2D(baseD3dDescriptor, nullptr, &d3d11Texture);
|
||||||
ASSERT_EQ(hr, S_OK);
|
ASSERT_EQ(hr, S_OK);
|
||||||
|
@ -101,19 +103,33 @@ namespace {
|
||||||
&sharedHandle);
|
&sharedHandle);
|
||||||
ASSERT_EQ(hr, S_OK);
|
ASSERT_EQ(hr, S_OK);
|
||||||
|
|
||||||
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc;
|
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc;
|
||||||
externDesc.cTextureDescriptor =
|
externalImageDesc.cTextureDescriptor =
|
||||||
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc);
|
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc);
|
||||||
externDesc.sharedHandle = sharedHandle;
|
externalImageDesc.sharedHandle = sharedHandle;
|
||||||
externDesc.acquireMutexKey = 0;
|
|
||||||
WGPUTexture texture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc);
|
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
|
// Now that we've created all of our resources, we can close the handle
|
||||||
// since we no longer need it.
|
// since we no longer need it.
|
||||||
::CloseHandle(sharedHandle);
|
::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();
|
*d3d11TextureOut = d3d11Texture.Detach();
|
||||||
|
|
||||||
|
if (externalImageOut != nullptr) {
|
||||||
|
*externalImageOut = std::move(externalImage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t kTestWidth = 10;
|
static constexpr size_t kTestWidth = 10;
|
||||||
|
@ -334,15 +350,20 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
|
||||||
hr = dxgiKeyedMutex->ReleaseSync(1);
|
hr = dxgiKeyedMutex->ReleaseSync(1);
|
||||||
ASSERT_EQ(hr, S_OK);
|
ASSERT_EQ(hr, S_OK);
|
||||||
|
|
||||||
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc;
|
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc = {};
|
||||||
externDesc.cTextureDescriptor =
|
externalImageDesc.sharedHandle = sharedHandle;
|
||||||
|
externalImageDesc.cTextureDescriptor =
|
||||||
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDescriptor);
|
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();
|
*d3d11TextureOut = d3d11Texture.Detach();
|
||||||
*dxgiKeyedMutexOut = dxgiKeyedMutex.Detach();
|
*dxgiKeyedMutexOut = dxgiKeyedMutex.Detach();
|
||||||
}
|
}
|
||||||
|
@ -519,5 +540,50 @@ TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) {
|
||||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), dawnTexture, 0, 0);
|
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(D3D12SharedHandleValidation, D3D12Backend());
|
||||||
DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend());
|
DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend());
|
||||||
|
|
|
@ -139,9 +139,10 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::Texture CreateVideoTextureForTest(wgpu::TextureFormat format,
|
void CreateVideoTextureForTest(wgpu::TextureFormat format,
|
||||||
wgpu::TextureUsage usage,
|
wgpu::TextureUsage usage,
|
||||||
bool isCheckerboard = false) {
|
bool isCheckerboard,
|
||||||
|
wgpu::Texture* dawnTextureOut) {
|
||||||
wgpu::TextureDescriptor textureDesc;
|
wgpu::TextureDescriptor textureDesc;
|
||||||
textureDesc.format = format;
|
textureDesc.format = format;
|
||||||
textureDesc.dimension = wgpu::TextureDimension::e2D;
|
textureDesc.dimension = wgpu::TextureDimension::e2D;
|
||||||
|
@ -171,24 +172,17 @@ namespace {
|
||||||
|
|
||||||
ComPtr<ID3D11Texture2D> d3d11Texture;
|
ComPtr<ID3D11Texture2D> d3d11Texture;
|
||||||
HRESULT hr = mD3d11Device->CreateTexture2D(&d3dDescriptor, &subres, &d3d11Texture);
|
HRESULT hr = mD3d11Device->CreateTexture2D(&d3dDescriptor, &subres, &d3d11Texture);
|
||||||
EXPECT_EQ(hr, S_OK);
|
ASSERT_EQ(hr, S_OK);
|
||||||
|
|
||||||
ComPtr<IDXGIResource1> dxgiResource;
|
ComPtr<IDXGIResource1> dxgiResource;
|
||||||
hr = d3d11Texture.As(&dxgiResource);
|
hr = d3d11Texture.As(&dxgiResource);
|
||||||
EXPECT_EQ(hr, S_OK);
|
ASSERT_EQ(hr, S_OK);
|
||||||
|
|
||||||
HANDLE sharedHandle;
|
HANDLE sharedHandle;
|
||||||
hr = dxgiResource->CreateSharedHandle(
|
hr = dxgiResource->CreateSharedHandle(
|
||||||
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
|
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
|
||||||
&sharedHandle);
|
&sharedHandle);
|
||||||
EXPECT_EQ(hr, S_OK);
|
ASSERT_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;
|
|
||||||
|
|
||||||
// DX11 texture should be initialized upon CreateTexture2D. However, if we do not
|
// 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
|
// 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
|
// Open the DX11 texture in Dawn from the shared handle and return it as a WebGPU
|
||||||
// texture.
|
// texture.
|
||||||
wgpu::Texture wgpuTexture = wgpu::Texture::Acquire(
|
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc;
|
||||||
dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc));
|
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.
|
// Handle is no longer needed once resources are created.
|
||||||
::CloseHandle(sharedHandle);
|
::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.
|
// 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
|
// 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.
|
// output attachment and checks for the expected pixel value in the rendered quad.
|
||||||
TEST_P(D3D12VideoViewsTests, NV12SampleYtoR) {
|
TEST_P(D3D12VideoViewsTests, NV12SampleYtoR) {
|
||||||
wgpu::Texture wgpuTexture = CreateVideoTextureForTest(
|
wgpu::Texture wgpuTexture;
|
||||||
wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled);
|
CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
|
||||||
|
wgpu::TextureUsage::Sampled, /*isCheckerboard*/ false, &wgpuTexture);
|
||||||
|
|
||||||
wgpu::TextureViewDescriptor viewDesc;
|
wgpu::TextureViewDescriptor viewDesc;
|
||||||
viewDesc.aspect = wgpu::TextureAspect::Plane0Only;
|
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
|
// 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.
|
// attachment and checks for the expected pixel value in the rendered quad.
|
||||||
TEST_P(D3D12VideoViewsTests, NV12SampleUVtoRG) {
|
TEST_P(D3D12VideoViewsTests, NV12SampleUVtoRG) {
|
||||||
wgpu::Texture wgpuTexture = CreateVideoTextureForTest(
|
wgpu::Texture wgpuTexture;
|
||||||
wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled);
|
CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
|
||||||
|
wgpu::TextureUsage::Sampled, /*isCheckerboard*/ false, &wgpuTexture);
|
||||||
|
|
||||||
wgpu::TextureViewDescriptor viewDesc;
|
wgpu::TextureViewDescriptor viewDesc;
|
||||||
viewDesc.aspect = wgpu::TextureAspect::Plane1Only;
|
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
|
// Renders a NV12 "checkerboard" texture into a RGB quad then checks the color at specific
|
||||||
// points to ensure the image has not been flipped.
|
// points to ensure the image has not been flipped.
|
||||||
TEST_P(D3D12VideoViewsTests, NV12SampleYUVtoRGB) {
|
TEST_P(D3D12VideoViewsTests, NV12SampleYUVtoRGB) {
|
||||||
wgpu::Texture wgpuTexture = CreateVideoTextureForTest(
|
wgpu::Texture wgpuTexture;
|
||||||
wgpu::TextureFormat::R8BG8Biplanar420Unorm, wgpu::TextureUsage::Sampled, true);
|
CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
|
||||||
|
wgpu::TextureUsage::Sampled, /*isCheckerboard*/ true, &wgpuTexture);
|
||||||
|
|
||||||
wgpu::TextureViewDescriptor lumaViewDesc;
|
wgpu::TextureViewDescriptor lumaViewDesc;
|
||||||
lumaViewDesc.aspect = wgpu::TextureAspect::Plane0Only;
|
lumaViewDesc.aspect = wgpu::TextureAspect::Plane0Only;
|
||||||
|
|
Loading…
Reference in New Issue