d3d11: support external image

This CL implements external image for d3d11 backend and enables
related tests.

Bug: dawn:1705
Bug: dawn:1724
Change-Id: Ib95e024fdc1837e3edb198dcf9255ebde8fa9fe7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131201
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Peng Huang <penghuang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Peng Huang 2023-05-09 23:11:53 +00:00 committed by Dawn LUCI CQ
parent 5e7807f02b
commit 49db496a51
32 changed files with 756 additions and 449 deletions

View File

@ -29,8 +29,6 @@ namespace dawn::native::d3d12 {
class Device; class Device;
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<ID3D12Device> GetD3D12Device(WGPUDevice device);
enum MemorySegment { enum MemorySegment {
Local, Local,
NonLocal, NonLocal,

View File

@ -28,6 +28,8 @@ namespace dawn::native::d3d {
class ExternalImageDXGIImpl; class ExternalImageDXGIImpl;
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<IDXGIAdapter> GetDXGIAdapter(WGPUAdapter adapter);
struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase { struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase {
AdapterDiscoveryOptions(WGPUBackendType type, Microsoft::WRL::ComPtr<IDXGIAdapter> adapter); AdapterDiscoveryOptions(WGPUBackendType type, Microsoft::WRL::ComPtr<IDXGIAdapter> adapter);
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter; Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter;

View File

@ -410,6 +410,8 @@ source_set("sources") {
"d3d/DeviceD3D.h", "d3d/DeviceD3D.h",
"d3d/ExternalImageDXGIImpl.cpp", "d3d/ExternalImageDXGIImpl.cpp",
"d3d/ExternalImageDXGIImpl.h", "d3d/ExternalImageDXGIImpl.h",
"d3d/Fence.cpp",
"d3d/Fence.h",
"d3d/Forward.h", "d3d/Forward.h",
"d3d/PhysicalDeviceD3D.cpp", "d3d/PhysicalDeviceD3D.cpp",
"d3d/PhysicalDeviceD3D.h", "d3d/PhysicalDeviceD3D.h",
@ -419,6 +421,8 @@ source_set("sources") {
"d3d/ShaderUtils.h", "d3d/ShaderUtils.h",
"d3d/SwapChainD3D.cpp", "d3d/SwapChainD3D.cpp",
"d3d/SwapChainD3D.h", "d3d/SwapChainD3D.h",
"d3d/TextureD3D.cpp",
"d3d/TextureD3D.h",
"d3d/UtilsD3D.cpp", "d3d/UtilsD3D.cpp",
"d3d/UtilsD3D.h", "d3d/UtilsD3D.h",
"d3d/d3d_platform.h", "d3d/d3d_platform.h",
@ -448,6 +452,8 @@ source_set("sources") {
"d3d11/DeviceD3D11.h", "d3d11/DeviceD3D11.h",
"d3d11/DeviceInfoD3D11.cpp", "d3d11/DeviceInfoD3D11.cpp",
"d3d11/DeviceInfoD3D11.h", "d3d11/DeviceInfoD3D11.h",
"d3d11/FenceD3D11.cpp",
"d3d11/FenceD3D11.h",
"d3d11/Forward.h", "d3d11/Forward.h",
"d3d11/PhysicalDeviceD3D11.cpp", "d3d11/PhysicalDeviceD3D11.cpp",
"d3d11/PhysicalDeviceD3D11.h", "d3d11/PhysicalDeviceD3D11.h",
@ -497,8 +503,6 @@ source_set("sources") {
"d3d12/D3D12Info.h", "d3d12/D3D12Info.h",
"d3d12/DeviceD3D12.cpp", "d3d12/DeviceD3D12.cpp",
"d3d12/DeviceD3D12.h", "d3d12/DeviceD3D12.h",
"d3d12/ExternalImageDXGIImplD3D12.cpp",
"d3d12/ExternalImageDXGIImplD3D12.h",
"d3d12/FenceD3D12.cpp", "d3d12/FenceD3D12.cpp",
"d3d12/FenceD3D12.h", "d3d12/FenceD3D12.h",
"d3d12/Forward.h", "d3d12/Forward.h",

View File

@ -267,6 +267,8 @@ if (DAWN_ENABLE_D3D11 OR DAWN_ENABLE_D3D12)
"d3d/DeviceD3D.h" "d3d/DeviceD3D.h"
"d3d/ExternalImageDXGIImpl.cpp" "d3d/ExternalImageDXGIImpl.cpp"
"d3d/ExternalImageDXGIImpl.h" "d3d/ExternalImageDXGIImpl.h"
"d3d/Fence.cpp"
"d3d/Fence.h"
"d3d/Forward.h" "d3d/Forward.h"
"d3d/PhysicalDeviceD3D.cpp" "d3d/PhysicalDeviceD3D.cpp"
"d3d/PhysicalDeviceD3D.h" "d3d/PhysicalDeviceD3D.h"
@ -276,6 +278,8 @@ if (DAWN_ENABLE_D3D11 OR DAWN_ENABLE_D3D12)
"d3d/ShaderUtils.h" "d3d/ShaderUtils.h"
"d3d/SwapChainD3D.cpp" "d3d/SwapChainD3D.cpp"
"d3d/SwapChainD3D.h" "d3d/SwapChainD3D.h"
"d3d/TextureD3D.cpp"
"d3d/TextureD3D.h"
"d3d/UtilsD3D.cpp" "d3d/UtilsD3D.cpp"
"d3d/UtilsD3D.h" "d3d/UtilsD3D.h"
"d3d/d3d_platform.h" "d3d/d3d_platform.h"
@ -305,6 +309,8 @@ if (DAWN_ENABLE_D3D11)
"d3d11/DeviceD3D11.h" "d3d11/DeviceD3D11.h"
"d3d11/DeviceInfoD3D11.cpp" "d3d11/DeviceInfoD3D11.cpp"
"d3d11/DeviceInfoD3D11.h" "d3d11/DeviceInfoD3D11.h"
"d3d11/FenceD3D11.cpp"
"d3d11/FenceD3D11.h"
"d3d11/Forward.h" "d3d11/Forward.h"
"d3d11/PhysicalDeviceD3D11.cpp" "d3d11/PhysicalDeviceD3D11.cpp"
"d3d11/PhysicalDeviceD3D11.h" "d3d11/PhysicalDeviceD3D11.h"
@ -354,8 +360,6 @@ if (DAWN_ENABLE_D3D12)
"d3d12/D3D12Info.h" "d3d12/D3D12Info.h"
"d3d12/DeviceD3D12.cpp" "d3d12/DeviceD3D12.cpp"
"d3d12/DeviceD3D12.h" "d3d12/DeviceD3D12.h"
"d3d12/ExternalImageDXGIImplD3D12.cpp"
"d3d12/ExternalImageDXGIImplD3D12.h"
"d3d12/FenceD3D12.cpp" "d3d12/FenceD3D12.cpp"
"d3d12/FenceD3D12.h" "d3d12/FenceD3D12.h"
"d3d12/Forward.h" "d3d12/Forward.h"

View File

@ -21,12 +21,18 @@
#include <utility> #include <utility>
#include "dawn/common/Log.h" #include "dawn/common/Log.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/d3d/DeviceD3D.h" #include "dawn/native/d3d/DeviceD3D.h"
#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d/Forward.h" #include "dawn/native/d3d/Forward.h"
#include "dawn/native/d3d/PhysicalDeviceD3D.h"
namespace dawn::native::d3d { namespace dawn::native::d3d {
Microsoft::WRL::ComPtr<IDXGIAdapter> GetDXGIAdapter(WGPUAdapter adapter) {
return ToBackend(FromAPI(adapter)->GetPhysicalDevice())->GetHardwareAdapter();
}
AdapterDiscoveryOptions::AdapterDiscoveryOptions(WGPUBackendType type, AdapterDiscoveryOptions::AdapterDiscoveryOptions(WGPUBackendType type,
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter) Microsoft::WRL::ComPtr<IDXGIAdapter> adapter)
: AdapterDiscoveryOptionsBase(type), dxgiAdapter(std::move(adapter)) {} : AdapterDiscoveryOptionsBase(type), dxgiAdapter(std::move(adapter)) {}

View File

@ -15,6 +15,7 @@
#include "dawn/native/d3d/DeviceD3D.h" #include "dawn/native/d3d/DeviceD3D.h"
#include "dawn/native/d3d/BackendD3D.h" #include "dawn/native/d3d/BackendD3D.h"
#include "dawn/native/d3d/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d/Forward.h" #include "dawn/native/d3d/Forward.h"
#include "dawn/native/d3d/PhysicalDeviceD3D.h" #include "dawn/native/d3d/PhysicalDeviceD3D.h"
@ -25,7 +26,25 @@ Device::Device(AdapterBase* adapter,
const TogglesState& deviceToggles) const TogglesState& deviceToggles)
: DeviceBase(adapter, descriptor, deviceToggles) {} : DeviceBase(adapter, descriptor, deviceToggles) {}
Device::~Device() = default; Device::~Device() {
Destroy();
// Close the handle here instead of in DestroyImpl. The handle is returned from
// ExternalImageDXGI, so it needs to live as long as the Device ref does, even if the device
// state is destroyed.
if (mFenceHandle != nullptr) {
::CloseHandle(mFenceHandle);
mFenceHandle = nullptr;
}
}
void Device::DestroyImpl() {
while (!mExternalImageList.empty()) {
d3d::ExternalImageDXGIImpl* externalImage = mExternalImageList.head()->value();
// ExternalImageDXGIImpl::DestroyInternal() calls RemoveFromList().
externalImage->DestroyInternal();
}
}
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl( ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const { const Surface* surface) const {
@ -54,4 +73,18 @@ ComPtr<IDxcValidator> Device::GetDxcValidator() const {
return ToBackend(GetPhysicalDevice())->GetBackend()->GetDxcValidator(); return ToBackend(GetPhysicalDevice())->GetBackend()->GetDxcValidator();
} }
HANDLE Device::GetFenceHandle() const {
return mFenceHandle;
}
std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl(
const ExternalImageDescriptorDXGISharedHandle* descriptor) {
std::unique_ptr<ExternalImageDXGIImpl> externalImage;
if (!ConsumedError(CreateExternalImageDXGIImplImpl(descriptor), &externalImage)) {
mExternalImageList.Append(externalImage.get());
return externalImage;
}
return {};
}
} // namespace dawn::native::d3d } // namespace dawn::native::d3d

View File

@ -16,6 +16,7 @@
#define SRC_DAWN_NATIVE_D3D_DEVICED3D_H_ #define SRC_DAWN_NATIVE_D3D_DEVICED3D_H_
#include <memory> #include <memory>
#include <vector>
#include "dawn/native/Device.h" #include "dawn/native/Device.h"
#include "dawn/native/d3d/d3d_platform.h" #include "dawn/native/d3d/d3d_platform.h"
@ -23,7 +24,9 @@
namespace dawn::native::d3d { namespace dawn::native::d3d {
struct ExternalImageDescriptorDXGISharedHandle; struct ExternalImageDescriptorDXGISharedHandle;
struct ExternalImageDXGIFenceDescriptor;
class ExternalImageDXGIImpl; class ExternalImageDXGIImpl;
class Fence;
class PlatformFunctions; class PlatformFunctions;
class Device : public DeviceBase { class Device : public DeviceBase {
@ -46,8 +49,30 @@ class Device : public DeviceBase {
ComPtr<IDxcCompiler> GetDxcCompiler() const; ComPtr<IDxcCompiler> GetDxcCompiler() const;
ComPtr<IDxcValidator> GetDxcValidator() const; ComPtr<IDxcValidator> GetDxcValidator() const;
virtual std::unique_ptr<ExternalImageDXGIImpl> CreateExternalImageDXGIImpl( HANDLE GetFenceHandle() const;
std::unique_ptr<ExternalImageDXGIImpl> CreateExternalImageDXGIImpl(
const ExternalImageDescriptorDXGISharedHandle* descriptor);
virtual ResultOrError<Ref<Fence>> CreateFence(
const ExternalImageDXGIFenceDescriptor* descriptor) = 0;
virtual Ref<TextureBase> CreateD3DExternalTexture(const TextureDescriptor* descriptor,
ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized) = 0;
protected:
void DestroyImpl() override;
virtual ResultOrError<std::unique_ptr<ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl(
const ExternalImageDescriptorDXGISharedHandle* descriptor) = 0; const ExternalImageDescriptorDXGISharedHandle* descriptor) = 0;
HANDLE mFenceHandle = nullptr;
private:
// List of external image resources opened using this device.
LinkedList<d3d::ExternalImageDXGIImpl> mExternalImageList;
}; };
} // namespace dawn::native::d3d } // namespace dawn::native::d3d

View File

@ -20,13 +20,35 @@
#include "dawn/common/Log.h" #include "dawn/common/Log.h"
#include "dawn/native/D3D12Backend.h" #include "dawn/native/D3D12Backend.h"
#include "dawn/native/DawnNative.h" #include "dawn/native/DawnNative.h"
#include "dawn/native/d3d12/DeviceD3D12.h" #include "dawn/native/d3d/DeviceD3D.h"
#include "dawn/native/d3d/Fence.h"
#include "dawn/native/d3d/Forward.h"
#include "dawn/native/d3d/TextureD3D.h"
namespace dawn::native::d3d { namespace dawn::native::d3d {
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) {
DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
"Texture dimension (%s) is not %s.", descriptor->dimension,
wgpu::TextureDimension::e2D);
DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.",
descriptor->mipLevelCount);
DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1, "Array layer count (%u) is not 1.",
descriptor->size.depthOrArrayLayers);
DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
descriptor->sampleCount);
return {};
}
ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice, ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice,
ComPtr<IUnknown> d3dResource,
const TextureDescriptor* textureDescriptor) const TextureDescriptor* textureDescriptor)
: mBackendDevice(backendDevice), : mBackendDevice(backendDevice),
mD3DResource(std::move(d3dResource)),
mUsage(textureDescriptor->usage), mUsage(textureDescriptor->usage),
mDimension(textureDescriptor->dimension), mDimension(textureDescriptor->dimension),
mSize(textureDescriptor->size), mSize(textureDescriptor->size),
@ -64,6 +86,10 @@ bool ExternalImageDXGIImpl::IsValid() const {
} }
void ExternalImageDXGIImpl::DestroyInternal() { void ExternalImageDXGIImpl::DestroyInternal() {
if (IsInList()) {
mD3DResource = nullptr;
}
// Linked list is not thread safe. A mutex must already be locked before // Linked list is not thread safe. A mutex must already be locked before
// endtering this method. Either via Device::DestroyImpl() or ~ExternalImageDXGIImpl. // endtering this method. Either via Device::DestroyImpl() or ~ExternalImageDXGIImpl.
ASSERT(mBackendDevice == nullptr || mBackendDevice->IsLockedByCurrentThreadIfNeeded()); ASSERT(mBackendDevice == nullptr || mBackendDevice->IsLockedByCurrentThreadIfNeeded());
@ -72,4 +98,82 @@ void ExternalImageDXGIImpl::DestroyInternal() {
} }
} }
WGPUTexture ExternalImageDXGIImpl::BeginAccess(
const d3d::ExternalImageDXGIBeginAccessDescriptor* descriptor) {
ASSERT(descriptor != nullptr);
auto deviceLock(GetScopedDeviceLock());
if (!IsInList()) {
dawn::ErrorLog() << "Cannot use external image after device destruction";
return nullptr;
}
// Ensure the texture usage is allowed
if (!IsSubset(descriptor->usage, static_cast<WGPUTextureUsageFlags>(mUsage))) {
dawn::ErrorLog() << "Texture usage is not valid for external image";
return nullptr;
}
ASSERT(mBackendDevice != nullptr);
TextureDescriptor textureDescriptor = {};
textureDescriptor.usage = static_cast<wgpu::TextureUsage>(descriptor->usage);
textureDescriptor.dimension = mDimension;
textureDescriptor.size = {mSize.width, mSize.height, mSize.depthOrArrayLayers};
textureDescriptor.format = mFormat;
textureDescriptor.mipLevelCount = mMipLevelCount;
textureDescriptor.sampleCount = mSampleCount;
textureDescriptor.viewFormats = mViewFormats.data();
textureDescriptor.viewFormatCount = static_cast<uint32_t>(mViewFormats.size());
DawnTextureInternalUsageDescriptor internalDesc = {};
if (mUsageInternal != wgpu::TextureUsage::None) {
textureDescriptor.nextInChain = &internalDesc;
internalDesc.internalUsage = mUsageInternal;
}
std::vector<Ref<Fence>> waitFences;
for (const d3d::ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) {
Ref<Fence> fence;
if (mBackendDevice->ConsumedError(
ToBackend(mBackendDevice.Get())->CreateFence(&fenceDescriptor), &fence)) {
dawn::ErrorLog() << "Unable to create D3D11 fence for external image";
return nullptr;
}
waitFences.push_back(std::move(fence));
}
Ref<TextureBase> texture =
ToBackend(mBackendDevice.Get())
->CreateD3DExternalTexture(&textureDescriptor, mD3DResource, std::move(waitFences),
descriptor->isSwapChainTexture, descriptor->isInitialized);
return ToAPI(texture.Detach());
}
void ExternalImageDXGIImpl::EndAccess(WGPUTexture texture,
d3d::ExternalImageDXGIFenceDescriptor* signalFence) {
auto deviceLock(GetScopedDeviceLock());
if (!IsInList()) {
dawn::ErrorLog() << "Cannot use external image after device destruction";
return;
}
ASSERT(mBackendDevice != nullptr);
ASSERT(signalFence != nullptr);
Texture* backendTexture = ToBackend(FromAPI(texture));
ASSERT(backendTexture != nullptr);
ExecutionSerial fenceValue;
if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) {
dawn::ErrorLog() << "D3D11 fence end access failed";
return;
}
signalFence->fenceHandle = ToBackend(mBackendDevice.Get())->GetFenceHandle();
signalFence->fenceValue = static_cast<uint64_t>(fenceValue);
}
} // namespace dawn::native::d3d } // namespace dawn::native::d3d

View File

@ -25,6 +25,7 @@
#include "dawn/native/Error.h" #include "dawn/native/Error.h"
#include "dawn/native/Forward.h" #include "dawn/native/Forward.h"
#include "dawn/native/IntegerTypes.h" #include "dawn/native/IntegerTypes.h"
#include "dawn/native/d3d/d3d_platform.h"
#include "dawn/webgpu_cpp.h" #include "dawn/webgpu_cpp.h"
namespace dawn::native::d3d { namespace dawn::native::d3d {
@ -34,29 +35,32 @@ struct ExternalImageDXGIBeginAccessDescriptor;
struct ExternalImageDXGIFenceDescriptor; struct ExternalImageDXGIFenceDescriptor;
struct ExternalImageDescriptorDXGISharedHandle; struct ExternalImageDescriptorDXGISharedHandle;
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor);
class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> { class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> {
public: public:
ExternalImageDXGIImpl(Device* backendDevice, const TextureDescriptor* textureDescriptor); ExternalImageDXGIImpl(Device* backendDevice,
virtual ~ExternalImageDXGIImpl(); ComPtr<IUnknown> d3dResource,
const TextureDescriptor* textureDescriptor);
~ExternalImageDXGIImpl();
ExternalImageDXGIImpl(const ExternalImageDXGIImpl&) = delete; ExternalImageDXGIImpl(const ExternalImageDXGIImpl&) = delete;
ExternalImageDXGIImpl& operator=(const ExternalImageDXGIImpl&) = delete; ExternalImageDXGIImpl& operator=(const ExternalImageDXGIImpl&) = delete;
bool IsValid() const; bool IsValid() const;
virtual WGPUTexture BeginAccess(const ExternalImageDXGIBeginAccessDescriptor* descriptor) = 0; WGPUTexture BeginAccess(const ExternalImageDXGIBeginAccessDescriptor* descriptor);
void EndAccess(WGPUTexture texture, ExternalImageDXGIFenceDescriptor* signalFence);
virtual void EndAccess(WGPUTexture texture, ExternalImageDXGIFenceDescriptor* signalFence) = 0;
// This method should only be called by internal code. Don't call this from D3D12Backend side, // This method should only be called by internal code. Don't call this from D3D12Backend side,
// or without locking. // or without locking.
virtual void DestroyInternal(); void DestroyInternal();
protected: protected:
[[nodiscard]] Mutex::AutoLock GetScopedDeviceLock() const; [[nodiscard]] Mutex::AutoLock GetScopedDeviceLock() const;
Ref<DeviceBase> mBackendDevice; Ref<DeviceBase> mBackendDevice;
ComPtr<IUnknown> mD3DResource;
wgpu::TextureUsage mUsage; wgpu::TextureUsage mUsage;
wgpu::TextureUsage mUsageInternal = wgpu::TextureUsage::None; wgpu::TextureUsage mUsageInternal = wgpu::TextureUsage::None;
wgpu::TextureDimension mDimension; wgpu::TextureDimension mDimension;

View File

@ -0,0 +1,38 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/d3d/Fence.h"
#include <utility>
#include "dawn/common/Log.h"
#include "dawn/native/Error.h"
#include "dawn/native/d3d/D3DError.h"
namespace dawn::native::d3d {
Fence::Fence(UINT64 fenceValue, HANDLE sharedHandle)
: mFenceValue(fenceValue), mSharedHandle(sharedHandle) {}
Fence::~Fence() {
if (mSharedHandle != nullptr) {
::CloseHandle(mSharedHandle);
}
}
UINT64 Fence::GetFenceValue() const {
return mFenceValue;
}
} // namespace dawn::native::d3d

View File

@ -0,0 +1,39 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_D3D_FENCED3D_H_
#define SRC_DAWN_NATIVE_D3D_FENCED3D_H_
#include "dawn/common/RefCounted.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/Error.h"
#include "dawn/native/d3d12/d3d12_platform.h"
namespace dawn::native::d3d {
class Fence : public RefCounted {
public:
UINT64 GetFenceValue() const;
protected:
Fence(UINT64 fenceValue, HANDLE sharedHandle);
~Fence() override;
const UINT64 mFenceValue;
const HANDLE mSharedHandle;
};
} // namespace dawn::native::d3d
#endif // SRC_DAWN_NATIVE_D3D_FENCE_H_

View File

@ -22,11 +22,13 @@ namespace dawn::native::d3d {
class PhysicalDevice; class PhysicalDevice;
class Device; class Device;
class SwapChain; class SwapChain;
class Texture;
struct D3DBackendTraits { struct D3DBackendTraits {
using DeviceType = Device; using DeviceType = Device;
using PhysicalDeviceType = PhysicalDevice; using PhysicalDeviceType = PhysicalDevice;
using SwapChainType = SwapChain; using SwapChainType = SwapChain;
using TextureType = Texture;
}; };
template <typename T> template <typename T>

View File

@ -0,0 +1,21 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/d3d/TextureD3D.h"
namespace dawn::native::d3d {
Texture::~Texture() = default;
} // namespace dawn::native::d3d

View File

@ -0,0 +1,35 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_D3D_TEXTURED3D_H_
#define SRC_DAWN_NATIVE_D3D_TEXTURED3D_H_
#include "dawn/native/Error.h"
#include "dawn/native/IntegerTypes.h"
#include "dawn/native/Texture.h"
namespace dawn::native::d3d {
class Texture : public TextureBase {
public:
virtual ResultOrError<ExecutionSerial> EndAccess() = 0;
protected:
using TextureBase::TextureBase;
~Texture() override;
};
} // namespace dawn::native::d3d
#endif // SRC_DAWN_NATIVE_D3D_TEXTURED3D_H_

View File

@ -25,12 +25,14 @@
#include "dawn/native/Instance.h" #include "dawn/native/Instance.h"
#include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d/UtilsD3D.h"
#include "dawn/native/d3d11/BackendD3D11.h" #include "dawn/native/d3d11/BackendD3D11.h"
#include "dawn/native/d3d11/BindGroupD3D11.h" #include "dawn/native/d3d11/BindGroupD3D11.h"
#include "dawn/native/d3d11/BindGroupLayoutD3D11.h" #include "dawn/native/d3d11/BindGroupLayoutD3D11.h"
#include "dawn/native/d3d11/BufferD3D11.h" #include "dawn/native/d3d11/BufferD3D11.h"
#include "dawn/native/d3d11/CommandBufferD3D11.h" #include "dawn/native/d3d11/CommandBufferD3D11.h"
#include "dawn/native/d3d11/ComputePipelineD3D11.h" #include "dawn/native/d3d11/ComputePipelineD3D11.h"
#include "dawn/native/d3d11/FenceD3D11.h"
#include "dawn/native/d3d11/PhysicalDeviceD3D11.h" #include "dawn/native/d3d11/PhysicalDeviceD3D11.h"
#include "dawn/native/d3d11/PipelineLayoutD3D11.h" #include "dawn/native/d3d11/PipelineLayoutD3D11.h"
#include "dawn/native/d3d11/PlatformFunctionsD3D11.h" #include "dawn/native/d3d11/PlatformFunctionsD3D11.h"
@ -126,17 +128,7 @@ MaybeError Device::Initialize(const DeviceDescriptor* descriptor) {
return {}; return {};
} }
Device::~Device() { Device::~Device() = default;
Destroy();
// Close the handle here instead of in DestroyImpl. The handle is returned from
// ExternalImageDXGI, so it needs to live as long as the Device ref does, even if the device
// state is destroyed.
if (mFenceHandle != nullptr) {
::CloseHandle(mFenceHandle);
mFenceHandle = nullptr;
}
}
ID3D11Device* Device::GetD3D11Device() const { ID3D11Device* Device::GetD3D11Device() const {
return mD3d11Device.Get(); return mD3d11Device.Get();
@ -390,6 +382,8 @@ void Device::AppendDebugLayerMessages(ErrorData* error) {
void Device::DestroyImpl() { void Device::DestroyImpl() {
ASSERT(GetState() == State::Disconnected); ASSERT(GetState() == State::Disconnected);
Base::DestroyImpl();
if (mFenceEvent != nullptr) { if (mFenceEvent != nullptr) {
::CloseHandle(mFenceEvent); ::CloseHandle(mFenceEvent);
mFenceEvent = nullptr; mFenceEvent = nullptr;
@ -412,11 +406,43 @@ float Device::GetTimestampPeriodInNS() const {
void Device::SetLabelImpl() {} void Device::SetLabelImpl() {}
std::unique_ptr<d3d::ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl( ResultOrError<Ref<d3d::Fence>> Device::CreateFence(
const d3d::ExternalImageDXGIFenceDescriptor* descriptor) {
return Fence::CreateFromHandle(mD3d11Device5.Get(), descriptor->fenceHandle,
descriptor->fenceValue);
}
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> Device::CreateExternalImageDXGIImplImpl(
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) { const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) {
// TODO(dawn:1724): Implement this // ExternalImageDXGIImpl holds a weak reference to the device. If the device is destroyed before
UNREACHABLE(); // the image is created, the image will have a dangling reference to the device which can cause
return {}; // a use-after-free.
DAWN_TRY(ValidateIsAlive());
ComPtr<ID3D11Resource> d3d11Resource;
DAWN_TRY(CheckHRESULT(
mD3d11Device5->OpenSharedResource1(descriptor->sharedHandle, IID_PPV_ARGS(&d3d11Resource)),
"D3D11 OpenSharedResource1"));
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
DAWN_TRY(ValidateTextureDescriptor(this, textureDescriptor));
DAWN_TRY_CONTEXT(d3d::ValidateTextureDescriptorCanBeWrapped(textureDescriptor),
"validating that a D3D11 external image can be wrapped with %s",
textureDescriptor);
DAWN_TRY(ValidateTextureCanBeWrapped(d3d11Resource.Get(), textureDescriptor));
// 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 = GetInternalFormat(textureDescriptor->format).AcquireSuccess();
if (format->IsMultiPlanar()) {
DAWN_TRY(ValidateVideoTextureCanBeShared(
this, d3d::DXGITextureFormat(textureDescriptor->format)));
}
return std::make_unique<d3d::ExternalImageDXGIImpl>(this, std::move(d3d11Resource),
textureDescriptor);
} }
bool Device::MayRequireDuplicationOfIndirectParameters() const { bool Device::MayRequireDuplicationOfIndirectParameters() const {
@ -427,8 +453,19 @@ uint64_t Device::GetBufferCopyOffsetAlignmentForDepthStencil() const {
return DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil(); return DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil();
} }
HANDLE Device::GetFenceHandle() const { Ref<TextureBase> Device::CreateD3DExternalTexture(const TextureDescriptor* descriptor,
return mFenceHandle; ComPtr<IUnknown> d3dTexture,
std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture;
if (ConsumedError(
Texture::CreateExternalImage(this, descriptor, std::move(d3dTexture),
std::move(waitFences), isSwapChainTexture, isInitialized),
&dawnTexture)) {
return nullptr;
}
return {dawnTexture};
} }
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -51,12 +51,11 @@ class Device final : public d3d::Device {
void ReferenceUntilUnused(ComPtr<IUnknown> object); void ReferenceUntilUnused(ComPtr<IUnknown> object);
MaybeError ExecutePendingCommandContext(); MaybeError ExecutePendingCommandContext();
HANDLE GetFenceHandle() const; Ref<TextureBase> CreateD3DExternalTexture(const TextureDescriptor* descriptor,
Ref<TextureBase> CreateD3D11ExternalTexture(const TextureDescriptor* descriptor, ComPtr<IUnknown> d3dTexture,
ComPtr<ID3D11Resource> d3d11Texture, std::vector<Ref<d3d::Fence>> waitFences,
std::vector<Ref<Fence>> waitFences,
bool isSwapChainTexture, bool isSwapChainTexture,
bool isInitialized); bool isInitialized) override;
ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer( ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
CommandEncoder* encoder, CommandEncoder* encoder,
@ -79,7 +78,9 @@ class Device final : public d3d::Device {
uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const override; uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const override;
void SetLabelImpl() override; void SetLabelImpl() override;
std::unique_ptr<d3d::ExternalImageDXGIImpl> CreateExternalImageDXGIImpl( ResultOrError<Ref<d3d::Fence>> CreateFence(
const d3d::ExternalImageDXGIFenceDescriptor* descriptor) override;
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl(
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override; const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override;
private: private:
@ -127,7 +128,6 @@ class Device final : public d3d::Device {
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override; ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
ComPtr<ID3D11Fence> mFence; ComPtr<ID3D11Fence> mFence;
HANDLE mFenceHandle = nullptr;
HANDLE mFenceEvent = nullptr; HANDLE mFenceEvent = nullptr;
ComPtr<ID3D11Device> mD3d11Device; ComPtr<ID3D11Device> mD3d11Device;

View File

@ -0,0 +1,53 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/d3d11/FenceD3D11.h"
#include <utility>
#include "dawn/common/Log.h"
#include "dawn/native/Error.h"
#include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
namespace dawn::native::d3d11 {
// static
ResultOrError<Ref<Fence>> Fence::CreateFromHandle(ID3D11Device5* device,
HANDLE unownedHandle,
UINT64 fenceValue) {
ASSERT(unownedHandle != nullptr);
HANDLE ownedHandle = nullptr;
if (!::DuplicateHandle(::GetCurrentProcess(), unownedHandle, ::GetCurrentProcess(),
&ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
return DAWN_DEVICE_LOST_ERROR("D3D11 fence dup handle");
}
ComPtr<ID3D11Fence> d3d11Fence;
DAWN_TRY_WITH_CLEANUP(
CheckHRESULT(device->OpenSharedFence(ownedHandle, IID_PPV_ARGS(&d3d11Fence)),
"D3D11 fence open handle"),
{ ::CloseHandle(ownedHandle); });
return AcquireRef(new Fence(std::move(d3d11Fence), fenceValue, ownedHandle));
}
Fence::Fence(ComPtr<ID3D11Fence> d3d11Fence, UINT64 fenceValue, HANDLE sharedHandle)
: Base(fenceValue, sharedHandle), mD3D11Fence(std::move(d3d11Fence)) {}
Fence::~Fence() = default;
ID3D11Fence* Fence::GetD3D11Fence() const {
return mD3D11Fence.Get();
}
} // namespace dawn::native::d3d11

View File

@ -0,0 +1,45 @@
// Copyright 2023 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_D3D11_FENCED3D11_H_
#define SRC_DAWN_NATIVE_D3D11_FENCED3D11_H_
#include "dawn/common/RefCounted.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/Error.h"
#include "dawn/native/d3d/Fence.h"
#include "dawn/native/d3d/d3d_platform.h"
namespace dawn::native::d3d11 {
class Fence : public d3d::Fence {
public:
static ResultOrError<Ref<Fence>> CreateFromHandle(ID3D11Device5* device,
HANDLE unownedHandle,
UINT64 fenceValue);
ID3D11Fence* GetD3D11Fence() const;
private:
using Base = d3d::Fence;
Fence(ComPtr<ID3D11Fence> d3d11Fence, UINT64 fenceValue, HANDLE sharedHandle);
~Fence() override;
ComPtr<ID3D11Fence> mD3D11Fence;
};
} // namespace dawn::native::d3d11
#endif // SRC_DAWN_NATIVE_D3D11_FENCED3D11_H_

View File

@ -28,6 +28,7 @@
#include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d/UtilsD3D.h" #include "dawn/native/d3d/UtilsD3D.h"
#include "dawn/native/d3d11/DeviceD3D11.h" #include "dawn/native/d3d11/DeviceD3D11.h"
#include "dawn/native/d3d11/FenceD3D11.h"
#include "dawn/native/d3d11/Forward.h" #include "dawn/native/d3d11/Forward.h"
#include "dawn/native/d3d11/UtilsD3D11.h" #include "dawn/native/d3d11/UtilsD3D11.h"
@ -63,6 +64,47 @@ Aspect D3D11Aspect(Aspect aspect) {
} // namespace } // namespace
MaybeError ValidateTextureCanBeWrapped(ID3D11Resource* d3d11Resource,
const TextureDescriptor* dawnDescriptor) {
ComPtr<ID3D11Texture2D> d3d11Texture;
DAWN_TRY(
CheckHRESULT(d3d11Resource->QueryInterface(IID_PPV_ARGS(&d3d11Texture)), "QueryInterface"));
D3D11_TEXTURE2D_DESC d3dDescriptor;
d3d11Texture->GetDesc(&d3dDescriptor);
DAWN_INVALID_IF(
(dawnDescriptor->size.width != d3dDescriptor.Width) ||
(dawnDescriptor->size.height != d3dDescriptor.Height) ||
(dawnDescriptor->size.depthOrArrayLayers != 1),
"D3D11 texture size (Width: %u, Height: %u, DepthOrArraySize: 1) doesn't match Dawn "
"descriptor size (width: %u, height: %u, depthOrArrayLayers: %u).",
d3dDescriptor.Width, d3dDescriptor.Height, dawnDescriptor->size.width,
dawnDescriptor->size.height, dawnDescriptor->size.depthOrArrayLayers);
const DXGI_FORMAT dxgiFormatFromDescriptor = d3d::DXGITextureFormat(dawnDescriptor->format);
DAWN_INVALID_IF(dxgiFormatFromDescriptor != d3dDescriptor.Format,
"D3D11 texture format (%x) is not compatible with Dawn descriptor format (%s).",
d3dDescriptor.Format, dawnDescriptor->format);
DAWN_INVALID_IF(d3dDescriptor.ArraySize != 1, "D3D12 texture array size (%u) is not 1.",
d3dDescriptor.ArraySize);
DAWN_INVALID_IF(d3dDescriptor.MipLevels != 1,
"D3D11 texture number of miplevels (%u) is not 1.", d3dDescriptor.MipLevels);
// Shared textures cannot be multi-sample so no need to check those.
ASSERT(d3dDescriptor.SampleDesc.Count == 1);
ASSERT(d3dDescriptor.SampleDesc.Quality == 0);
return {};
}
MaybeError ValidateVideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat) {
// TODO(dawn:1724): support video textures
return DAWN_UNIMPLEMENTED_ERROR("Video textures are not supported.");
}
// static // static
ResultOrError<Ref<Texture>> Texture::Create(Device* device, const TextureDescriptor* descriptor) { ResultOrError<Ref<Texture>> Texture::Create(Device* device, const TextureDescriptor* descriptor) {
Ref<Texture> texture = AcquireRef( Ref<Texture> texture = AcquireRef(
@ -89,6 +131,31 @@ ResultOrError<Ref<Texture>> Texture::CreateStaging(Device* device,
return std::move(texture); return std::move(texture);
} }
// static
ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device,
const TextureDescriptor* descriptor,
ComPtr<IUnknown> d3dTexture,
std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture = AcquireRef(
new Texture(device, descriptor, TextureState::OwnedExternal, /*isStaging=*/false));
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(std::move(d3dTexture), std::move(waitFences),
isSwapChainTexture));
// Importing a multi-planar format must be initialized. This is required because
// a shared multi-planar format cannot be initialized by Dawn.
DAWN_INVALID_IF(
!isInitialized && dawnTexture->GetFormat().IsMultiPlanar(),
"Cannot create a texture with a multi-planar format (%s) with uninitialized data.",
dawnTexture->GetFormat().format);
dawnTexture->SetIsSubresourceContentInitialized(isInitialized,
dawnTexture->GetAllSubresources());
return std::move(dawnTexture);
}
template <typename T> template <typename T>
T Texture::GetD3D11TextureDesc() const { T Texture::GetD3D11TextureDesc() const {
T desc; T desc;
@ -182,11 +249,30 @@ MaybeError Texture::InitializeAsSwapChainTexture(ComPtr<ID3D11Resource> d3d11Tex
return {}; return {};
} }
MaybeError Texture::InitializeAsExternalTexture(ComPtr<IUnknown> d3dTexture,
std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture) {
ComPtr<ID3D11Resource> d3d11Texture;
DAWN_TRY(CheckHRESULT(d3dTexture.As(&d3d11Texture), "Query ID3D11Resource from IUnknown"));
CommandRecordingContext* commandContext = ToBackend(GetDevice())->GetPendingCommandContext();
ID3D11DeviceContext4* d3d11DeviceContext4 = commandContext->GetD3D11DeviceContext4();
for (Ref<d3d::Fence>& fence : waitFences) {
DAWN_TRY(CheckHRESULT(
d3d11DeviceContext4->Wait(static_cast<Fence*>(fence.Get())->GetD3D11Fence(),
fence->GetFenceValue()),
"ID3D11DeviceContext4::Wait"));
}
mD3d11Resource = std::move(d3d11Texture);
SetLabelHelper("Dawn_ExternalTexture");
return {};
}
Texture::Texture(Device* device, Texture::Texture(Device* device,
const TextureDescriptor* descriptor, const TextureDescriptor* descriptor,
TextureState state, TextureState state,
bool isStaging) bool isStaging)
: TextureBase(device, descriptor, state), mIsStaging(isStaging) {} : Base(device, descriptor, state), mIsStaging(isStaging) {}
Texture::~Texture() = default; Texture::~Texture() = default;
@ -600,6 +686,11 @@ MaybeError Texture::Copy(CommandRecordingContext* commandContext, CopyTextureToT
return {}; return {};
} }
ResultOrError<ExecutionSerial> Texture::EndAccess() {
// TODO(dawn:1705): submit pending commands if deferred context is used.
return GetDevice()->GetLastSubmittedCommandSerial();
}
// static // static
Ref<TextureView> TextureView::Create(TextureBase* texture, Ref<TextureView> TextureView::Create(TextureBase* texture,
const TextureViewDescriptor* descriptor) { const TextureViewDescriptor* descriptor) {

View File

@ -15,29 +15,44 @@
#ifndef SRC_DAWN_NATIVE_D3D11_TEXTURED3D11_H_ #ifndef SRC_DAWN_NATIVE_D3D11_TEXTURED3D11_H_
#define SRC_DAWN_NATIVE_D3D11_TEXTURED3D11_H_ #define SRC_DAWN_NATIVE_D3D11_TEXTURED3D11_H_
#include <vector>
#include "dawn/native/DawnNative.h" #include "dawn/native/DawnNative.h"
#include "dawn/native/Error.h" #include "dawn/native/Error.h"
#include "dawn/native/IntegerTypes.h" #include "dawn/native/IntegerTypes.h"
#include "dawn/native/PassResourceUsage.h" #include "dawn/native/PassResourceUsage.h"
#include "dawn/native/Texture.h" #include "dawn/native/d3d/TextureD3D.h"
#include "dawn/native/d3d/d3d_platform.h" #include "dawn/native/d3d/d3d_platform.h"
namespace dawn::native { namespace dawn::native {
struct CopyTextureToTextureCmd; struct CopyTextureToTextureCmd;
} // namespace dawn::native } // namespace dawn::native
namespace dawn::native::d3d {
class Fence;
} // namespace dawn::native::d3d
namespace dawn::native::d3d11 { namespace dawn::native::d3d11 {
class CommandRecordingContext; class CommandRecordingContext;
class Device; class Device;
class Texture final : public TextureBase { MaybeError ValidateTextureCanBeWrapped(ID3D11Resource* d3d11Resource,
const TextureDescriptor* descriptor);
MaybeError ValidateVideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat);
class Texture final : public d3d::Texture {
public: public:
static ResultOrError<Ref<Texture>> Create(Device* device, const TextureDescriptor* descriptor); static ResultOrError<Ref<Texture>> Create(Device* device, const TextureDescriptor* descriptor);
static ResultOrError<Ref<Texture>> Create(Device* device, static ResultOrError<Ref<Texture>> Create(Device* device,
const TextureDescriptor* descriptor, const TextureDescriptor* descriptor,
ComPtr<ID3D11Resource> d3d11Texture); ComPtr<ID3D11Resource> d3d11Texture);
static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device,
const TextureDescriptor* descriptor,
ComPtr<IUnknown> d3dTexture,
std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized);
DXGI_FORMAT GetD3D11Format() const; DXGI_FORMAT GetD3D11Format() const;
ID3D11Resource* GetD3D11Resource() const; ID3D11Resource* GetD3D11Resource() const;
@ -67,7 +82,11 @@ class Texture final : public TextureBase {
ReadCallback callback); ReadCallback callback);
static MaybeError Copy(CommandRecordingContext* commandContext, CopyTextureToTextureCmd* copy); static MaybeError Copy(CommandRecordingContext* commandContext, CopyTextureToTextureCmd* copy);
ResultOrError<ExecutionSerial> EndAccess() override;
private: private:
using Base = d3d::Texture;
static ResultOrError<Ref<Texture>> CreateStaging(Device* device, static ResultOrError<Ref<Texture>> CreateStaging(Device* device,
const TextureDescriptor* descriptor); const TextureDescriptor* descriptor);
@ -82,7 +101,9 @@ class Texture final : public TextureBase {
MaybeError InitializeAsInternalTexture(); MaybeError InitializeAsInternalTexture();
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D11Resource> d3d11Texture); MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D11Resource> d3d11Texture);
MaybeError InitializeAsExternalTexture(ComPtr<IUnknown> d3dTexture,
std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture);
void SetLabelHelper(const char* prefix); void SetLabelHelper(const char* prefix);
// Dawn API // Dawn API

View File

@ -28,10 +28,6 @@
namespace dawn::native::d3d12 { namespace dawn::native::d3d12 {
ComPtr<ID3D12Device> GetD3D12Device(WGPUDevice device) {
return ToBackend(FromAPI(device))->GetD3D12Device();
}
uint64_t SetExternalMemoryReservation(WGPUDevice device, uint64_t SetExternalMemoryReservation(WGPUDevice device,
uint64_t requestedReservationSize, uint64_t requestedReservationSize,
MemorySegment memorySegment) { MemorySegment memorySegment) {

View File

@ -24,13 +24,14 @@
#include "dawn/native/DynamicUploader.h" #include "dawn/native/DynamicUploader.h"
#include "dawn/native/Instance.h" #include "dawn/native/Instance.h"
#include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d12/BackendD3D12.h" #include "dawn/native/d3d12/BackendD3D12.h"
#include "dawn/native/d3d12/BindGroupD3D12.h" #include "dawn/native/d3d12/BindGroupD3D12.h"
#include "dawn/native/d3d12/BindGroupLayoutD3D12.h" #include "dawn/native/d3d12/BindGroupLayoutD3D12.h"
#include "dawn/native/d3d12/CommandAllocatorManager.h" #include "dawn/native/d3d12/CommandAllocatorManager.h"
#include "dawn/native/d3d12/CommandBufferD3D12.h" #include "dawn/native/d3d12/CommandBufferD3D12.h"
#include "dawn/native/d3d12/ComputePipelineD3D12.h" #include "dawn/native/d3d12/ComputePipelineD3D12.h"
#include "dawn/native/d3d12/ExternalImageDXGIImplD3D12.h" #include "dawn/native/d3d12/FenceD3D12.h"
#include "dawn/native/d3d12/PhysicalDeviceD3D12.h" #include "dawn/native/d3d12/PhysicalDeviceD3D12.h"
#include "dawn/native/d3d12/PipelineLayoutD3D12.h" #include "dawn/native/d3d12/PipelineLayoutD3D12.h"
#include "dawn/native/d3d12/PlatformFunctionsD3D12.h" #include "dawn/native/d3d12/PlatformFunctionsD3D12.h"
@ -191,16 +192,7 @@ Device::Device(AdapterBase* adapter,
const TogglesState& deviceToggles) const TogglesState& deviceToggles)
: Base(adapter, descriptor, deviceToggles) {} : Base(adapter, descriptor, deviceToggles) {}
Device::~Device() { Device::~Device() = default;
Destroy();
// Close the handle here instead of in DestroyImpl. The handle is returned from
// ExternalImageDXGI, so it needs to live as long as the Device ref does, even if the device
// state is destroyed.
if (mFenceHandle != nullptr) {
::CloseHandle(mFenceHandle);
}
}
ID3D12Device* Device::GetD3D12Device() const { ID3D12Device* Device::GetD3D12Device() const {
return mD3d12Device.Get(); return mD3d12Device.Get();
@ -214,10 +206,6 @@ ID3D12SharingContract* Device::GetSharingContract() const {
return mD3d12SharingContract.Get(); return mD3d12SharingContract.Get();
} }
HANDLE Device::GetFenceHandle() const {
return mFenceHandle;
}
ComPtr<ID3D12CommandSignature> Device::GetDispatchIndirectSignature() const { ComPtr<ID3D12CommandSignature> Device::GetDispatchIndirectSignature() const {
return mDispatchIndirectSignature; return mDispatchIndirectSignature;
} }
@ -545,61 +533,54 @@ ResultOrError<ResourceHeapAllocation> Device::AllocateMemory(
forceAllocateAsCommittedResource); forceAllocateAsCommittedResource);
} }
std::unique_ptr<d3d::ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl( ResultOrError<Ref<d3d::Fence>> Device::CreateFence(
const d3d::ExternalImageDXGIFenceDescriptor* descriptor) {
return Fence::CreateFromHandle(mD3d12Device.Get(), descriptor->fenceHandle,
descriptor->fenceValue);
}
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> Device::CreateExternalImageDXGIImplImpl(
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) { const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) {
// ExternalImageDXGIImpl holds a weak reference to the device. If the device is destroyed before // ExternalImageDXGIImpl holds a weak reference to the device. If the device is destroyed before
// the image is created, the image will have a dangling reference to the device which can cause // the image is created, the image will have a dangling reference to the device which can cause
// a use-after-free. // a use-after-free.
if (ConsumedError(ValidateIsAlive())) { DAWN_TRY(ValidateIsAlive());
return nullptr;
}
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource; Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource;
if (FAILED(GetD3D12Device()->OpenSharedHandle(descriptor->sharedHandle, DAWN_TRY(CheckHRESULT(
IID_PPV_ARGS(&d3d12Resource)))) { GetD3D12Device()->OpenSharedHandle(descriptor->sharedHandle, IID_PPV_ARGS(&d3d12Resource)),
return nullptr; "D3D12 opening shared handle"));
}
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor); const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) { DAWN_TRY(ValidateTextureDescriptor(this, textureDescriptor));
return nullptr;
}
if (ConsumedError(ValidateTextureDescriptorCanBeWrapped(textureDescriptor), DAWN_TRY_CONTEXT(d3d::ValidateTextureDescriptorCanBeWrapped(textureDescriptor),
"validating that a D3D12 external image can be wrapped with %s", "validating that a D3D12 external image can be wrapped with %s",
textureDescriptor)) { textureDescriptor);
return nullptr;
}
if (ConsumedError(ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), textureDescriptor))) { DAWN_TRY(ValidateTextureCanBeWrapped(d3d12Resource.Get(), textureDescriptor));
return nullptr;
}
// Shared handle is assumed to support resource sharing capability. The resource // Shared handle is assumed to support resource sharing capability. The resource
// shared capability tier must agree to share resources between D3D devices. // shared capability tier must agree to share resources between D3D devices.
const Format* format = GetInternalFormat(textureDescriptor->format).AcquireSuccess(); const Format* format = GetInternalFormat(textureDescriptor->format).AcquireSuccess();
if (format->IsMultiPlanar()) { if (format->IsMultiPlanar()) {
if (ConsumedError(ValidateD3D12VideoTextureCanBeShared( DAWN_TRY(ValidateVideoTextureCanBeShared(
this, d3d::DXGITextureFormat(textureDescriptor->format)))) { this, d3d::DXGITextureFormat(textureDescriptor->format)));
return nullptr;
}
} }
auto impl = return std::make_unique<d3d::ExternalImageDXGIImpl>(this, std::move(d3d12Resource),
std::make_unique<ExternalImageDXGIImpl>(this, std::move(d3d12Resource), textureDescriptor); textureDescriptor);
mExternalImageList.Append(impl.get());
return impl;
} }
Ref<TextureBase> Device::CreateD3D12ExternalTexture(const TextureDescriptor* descriptor, Ref<TextureBase> Device::CreateD3DExternalTexture(const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture, ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture, bool isSwapChainTexture,
bool isInitialized) { bool isInitialized) {
Ref<Texture> dawnTexture; Ref<Texture> dawnTexture;
if (ConsumedError( if (ConsumedError(
Texture::CreateExternalImage(this, descriptor, std::move(d3d12Texture), Texture::CreateExternalImage(this, descriptor, std::move(d3dTexture),
std::move(waitFences), isSwapChainTexture, isInitialized), std::move(waitFences), isSwapChainTexture, isInitialized),
&dawnTexture)) { &dawnTexture)) {
return nullptr; return nullptr;
@ -706,11 +687,7 @@ void Device::AppendDebugLayerMessages(ErrorData* error) {
void Device::DestroyImpl() { void Device::DestroyImpl() {
ASSERT(GetState() == State::Disconnected); ASSERT(GetState() == State::Disconnected);
while (!mExternalImageList.empty()) { Base::DestroyImpl();
d3d::ExternalImageDXGIImpl* externalImage = mExternalImageList.head()->value();
// ExternalImageDXGIImpl::DestroyInternal() calls RemoveFromList().
externalImage->DestroyInternal();
}
mZeroBuffer = nullptr; mZeroBuffer = nullptr;

View File

@ -26,7 +26,6 @@
#include "dawn/native/d3d12/TextureD3D12.h" #include "dawn/native/d3d12/TextureD3D12.h"
namespace dawn::native::d3d { namespace dawn::native::d3d {
struct ExternalImageDescriptorDXGISharedHandle;
class ExternalImageDXGIImpl; class ExternalImageDXGIImpl;
} // namespace dawn::native::d3d } // namespace dawn::native::d3d
@ -65,7 +64,6 @@ class Device final : public d3d::Device {
ID3D12Device* GetD3D12Device() const; ID3D12Device* GetD3D12Device() const;
ComPtr<ID3D12CommandQueue> GetCommandQueue() const; ComPtr<ID3D12CommandQueue> GetCommandQueue() const;
ID3D12SharingContract* GetSharingContract() const; ID3D12SharingContract* GetSharingContract() const;
HANDLE GetFenceHandle() const;
ComPtr<ID3D12CommandSignature> GetDispatchIndirectSignature() const; ComPtr<ID3D12CommandSignature> GetDispatchIndirectSignature() const;
ComPtr<ID3D12CommandSignature> GetDrawIndirectSignature() const; ComPtr<ID3D12CommandSignature> GetDrawIndirectSignature() const;
@ -137,14 +135,16 @@ class Device final : public d3d::Device {
StagingDescriptorAllocator* GetDepthStencilViewAllocator() const; StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
std::unique_ptr<d3d::ExternalImageDXGIImpl> CreateExternalImageDXGIImpl( ResultOrError<Ref<d3d::Fence>> CreateFence(
const d3d::ExternalImageDXGIFenceDescriptor* descriptor) override;
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl(
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override; const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override;
Ref<TextureBase> CreateD3D12ExternalTexture(const TextureDescriptor* descriptor, Ref<TextureBase> CreateD3DExternalTexture(const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture, ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture, bool isSwapChainTexture,
bool isInitialized); bool isInitialized) override;
uint32_t GetOptimalBytesPerRowAlignment() const override; uint32_t GetOptimalBytesPerRowAlignment() const override;
uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override; uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
@ -218,7 +218,6 @@ class Device final : public d3d::Device {
ComPtr<ID3D12Fence> mFence; ComPtr<ID3D12Fence> mFence;
HANDLE mFenceEvent = nullptr; HANDLE mFenceEvent = nullptr;
HANDLE mFenceHandle = nullptr;
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override; ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
ComPtr<ID3D12Device> mD3d12Device; // Device is owned by adapter and will not be outlived. ComPtr<ID3D12Device> mD3d12Device; // Device is owned by adapter and will not be outlived.
@ -274,9 +273,6 @@ class Device final : public d3d::Device {
// The number of nanoseconds required for a timestamp query to be incremented by 1 // The number of nanoseconds required for a timestamp query to be incremented by 1
float mTimestampPeriod = 1.0f; float mTimestampPeriod = 1.0f;
// List of external image resources opened using this device.
LinkedList<d3d::ExternalImageDXGIImpl> mExternalImageList;
}; };
} // namespace dawn::native::d3d12 } // namespace dawn::native::d3d12

View File

@ -1,126 +0,0 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/d3d12/ExternalImageDXGIImplD3D12.h"
#include <utility>
#include <vector>
#include "dawn/common/Log.h"
#include "dawn/native/D3D12Backend.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
#include "dawn/native/d3d12/Forward.h"
namespace dawn::native::d3d12 {
ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
const TextureDescriptor* textureDescriptor)
: Base(backendDevice, textureDescriptor), mD3D12Resource(std::move(d3d12Resource)) {
ASSERT(mD3D12Resource != nullptr);
}
ExternalImageDXGIImpl::~ExternalImageDXGIImpl() = default;
void ExternalImageDXGIImpl::DestroyInternal() {
if (IsInList()) {
mD3D12Resource = nullptr;
}
Base::DestroyInternal();
}
WGPUTexture ExternalImageDXGIImpl::BeginAccess(
const d3d::ExternalImageDXGIBeginAccessDescriptor* descriptor) {
ASSERT(descriptor != nullptr);
auto deviceLock(GetScopedDeviceLock());
if (!IsInList()) {
dawn::ErrorLog() << "Cannot use external image after device destruction";
return nullptr;
}
// Ensure the texture usage is allowed
if (!IsSubset(descriptor->usage, static_cast<WGPUTextureUsageFlags>(mUsage))) {
dawn::ErrorLog() << "Texture usage is not valid for external image";
return nullptr;
}
ASSERT(mBackendDevice != nullptr);
TextureDescriptor textureDescriptor = {};
textureDescriptor.usage = static_cast<wgpu::TextureUsage>(descriptor->usage);
textureDescriptor.dimension = mDimension;
textureDescriptor.size = {mSize.width, mSize.height, mSize.depthOrArrayLayers};
textureDescriptor.format = mFormat;
textureDescriptor.mipLevelCount = mMipLevelCount;
textureDescriptor.sampleCount = mSampleCount;
textureDescriptor.viewFormats = mViewFormats.data();
textureDescriptor.viewFormatCount = static_cast<uint32_t>(mViewFormats.size());
DawnTextureInternalUsageDescriptor internalDesc = {};
if (mUsageInternal != wgpu::TextureUsage::None) {
textureDescriptor.nextInChain = &internalDesc;
internalDesc.internalUsage = mUsageInternal;
internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor;
}
std::vector<Ref<Fence>> waitFences;
for (const d3d::ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) {
ASSERT(fenceDescriptor.fenceHandle != nullptr);
// TODO(sunnyps): Use a fence cache instead of re-importing fences on each BeginAccess.
Ref<Fence> fence;
if (mBackendDevice->ConsumedError(
Fence::CreateFromHandle(ToBackend(mBackendDevice.Get())->GetD3D12Device(),
fenceDescriptor.fenceHandle, fenceDescriptor.fenceValue),
&fence)) {
dawn::ErrorLog() << "Unable to create D3D12 fence for external image";
return nullptr;
}
waitFences.push_back(std::move(fence));
}
Ref<TextureBase> texture =
ToBackend(mBackendDevice.Get())
->CreateD3D12ExternalTexture(&textureDescriptor, mD3D12Resource, std::move(waitFences),
descriptor->isSwapChainTexture, descriptor->isInitialized);
return ToAPI(texture.Detach());
}
void ExternalImageDXGIImpl::EndAccess(WGPUTexture texture,
d3d::ExternalImageDXGIFenceDescriptor* signalFence) {
auto deviceLock(GetScopedDeviceLock());
if (!IsInList()) {
dawn::ErrorLog() << "Cannot use external image after device destruction";
return;
}
ASSERT(mBackendDevice != nullptr);
ASSERT(signalFence != nullptr);
Texture* backendTexture = ToBackend(FromAPI(texture));
ASSERT(backendTexture != nullptr);
ExecutionSerial fenceValue;
if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) {
dawn::ErrorLog() << "D3D12 fence end access failed";
return;
}
signalFence->fenceHandle = ToBackend(mBackendDevice.Get())->GetFenceHandle();
signalFence->fenceValue = static_cast<uint64_t>(fenceValue);
}
} // namespace dawn::native::d3d12

View File

@ -1,74 +0,0 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_D3D12_EXTERNALIMAGEDXGIIMPLD3D12_H_
#define SRC_DAWN_NATIVE_D3D12_EXTERNALIMAGEDXGIIMPLD3D12_H_
#include <wrl/client.h>
#include <memory>
#include <vector>
#include "dawn/common/LinkedList.h"
#include "dawn/common/Mutex.h"
#include "dawn/native/D3D12Backend.h"
#include "dawn/native/Error.h"
#include "dawn/native/Forward.h"
#include "dawn/native/IntegerTypes.h"
#include "dawn/native/d3d/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d12/FenceD3D12.h"
#include "dawn/webgpu_cpp.h"
struct ID3D12Resource;
struct ID3D12Fence;
namespace dawn::native::d3d {
struct ExternalImageDXGIBeginAccessDescriptor;
struct ExternalImageDescriptorDXGISharedHandle;
} // namespace dawn::native::d3d
namespace dawn::native::d3d12 {
class Device;
class ExternalImageDXGIImpl : public d3d::ExternalImageDXGIImpl {
public:
ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
const TextureDescriptor* textureDescriptor);
~ExternalImageDXGIImpl() override;
ExternalImageDXGIImpl(const ExternalImageDXGIImpl&) = delete;
ExternalImageDXGIImpl& operator=(const ExternalImageDXGIImpl&) = delete;
bool IsValid() const;
WGPUTexture BeginAccess(const d3d::ExternalImageDXGIBeginAccessDescriptor* descriptor) override;
void EndAccess(WGPUTexture texture,
d3d::ExternalImageDXGIFenceDescriptor* signalFence) override;
// This method should only be called by internal code. Don't call this from D3D12Backend side,
// or without locking.
void DestroyInternal() override;
private:
using Base = d3d::ExternalImageDXGIImpl;
Microsoft::WRL::ComPtr<ID3D12Resource> mD3D12Resource;
};
} // namespace dawn::native::d3d12
#endif // SRC_DAWN_NATIVE_D3D12_EXTERNALIMAGEDXGIIMPLD3D12_H_

View File

@ -42,20 +42,12 @@ ResultOrError<Ref<Fence>> Fence::CreateFromHandle(ID3D12Device* device,
} }
Fence::Fence(ComPtr<ID3D12Fence> d3d12Fence, UINT64 fenceValue, HANDLE sharedHandle) Fence::Fence(ComPtr<ID3D12Fence> d3d12Fence, UINT64 fenceValue, HANDLE sharedHandle)
: mD3D12Fence(std::move(d3d12Fence)), mFenceValue(fenceValue), mSharedHandle(sharedHandle) {} : Base(fenceValue, sharedHandle), mD3D12Fence(std::move(d3d12Fence)) {}
Fence::~Fence() { Fence::~Fence() = default;
if (mSharedHandle != nullptr) {
::CloseHandle(mSharedHandle);
}
}
ID3D12Fence* Fence::GetD3D12Fence() const { ID3D12Fence* Fence::GetD3D12Fence() const {
return mD3D12Fence.Get(); return mD3D12Fence.Get();
} }
UINT64 Fence::GetFenceValue() const {
return mFenceValue;
}
} // namespace dawn::native::d3d12 } // namespace dawn::native::d3d12

View File

@ -18,26 +18,26 @@
#include "dawn/common/RefCounted.h" #include "dawn/common/RefCounted.h"
#include "dawn/native/DawnNative.h" #include "dawn/native/DawnNative.h"
#include "dawn/native/Error.h" #include "dawn/native/Error.h"
#include "dawn/native/d3d/Fence.h"
#include "dawn/native/d3d12/d3d12_platform.h" #include "dawn/native/d3d12/d3d12_platform.h"
namespace dawn::native::d3d12 { namespace dawn::native::d3d12 {
class Fence : public RefCounted { class Fence : public d3d::Fence {
public: public:
static ResultOrError<Ref<Fence>> CreateFromHandle(ID3D12Device* device, static ResultOrError<Ref<Fence>> CreateFromHandle(ID3D12Device* device,
HANDLE unownedHandle, HANDLE unownedHandle,
UINT64 fenceValue); UINT64 fenceValue);
ID3D12Fence* GetD3D12Fence() const; ID3D12Fence* GetD3D12Fence() const;
UINT64 GetFenceValue() const;
private: private:
using Base = d3d::Fence;
Fence(ComPtr<ID3D12Fence> d3d12Fence, UINT64 fenceValue, HANDLE sharedHandle); Fence(ComPtr<ID3D12Fence> d3d12Fence, UINT64 fenceValue, HANDLE sharedHandle);
~Fence() override; ~Fence() override;
ComPtr<ID3D12Fence> mD3D12Fence; ComPtr<ID3D12Fence> mD3D12Fence;
const UINT64 mFenceValue;
const HANDLE mSharedHandle;
}; };
} // namespace dawn::native::d3d12 } // namespace dawn::native::d3d12

View File

@ -112,24 +112,7 @@ D3D12_RESOURCE_DIMENSION D3D12TextureDimension(wgpu::TextureDimension dimension)
} // namespace } // namespace
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) { MaybeError ValidateTextureCanBeWrapped(ID3D12Resource* d3d12Resource,
DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
"Texture dimension (%s) is not %s.", descriptor->dimension,
wgpu::TextureDimension::e2D);
DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.",
descriptor->mipLevelCount);
DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1, "Array layer count (%u) is not 1.",
descriptor->size.depthOrArrayLayers);
DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
descriptor->sampleCount);
return {};
}
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
const TextureDescriptor* dawnDescriptor) { const TextureDescriptor* dawnDescriptor) {
const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc(); const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc();
DAWN_INVALID_IF( DAWN_INVALID_IF(
@ -160,7 +143,7 @@ MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
} }
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_shared_resource_compatibility_tier // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_shared_resource_compatibility_tier
MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat) { MaybeError ValidateVideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat) {
const bool supportsSharedResourceCapabilityTier1 = const bool supportsSharedResourceCapabilityTier1 =
device->GetDeviceInfo().supportsSharedResourceCapabilityTier1; device->GetDeviceInfo().supportsSharedResourceCapabilityTier1;
switch (textureFormat) { switch (textureFormat) {
@ -192,15 +175,15 @@ ResultOrError<Ref<Texture>> Texture::Create(Device* device, const TextureDescrip
// static // static
ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device, ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device,
const TextureDescriptor* descriptor, const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture, ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture, bool isSwapChainTexture,
bool isInitialized) { bool isInitialized) {
Ref<Texture> dawnTexture = Ref<Texture> dawnTexture =
AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal)); AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal));
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(std::move(d3d12Texture), DAWN_TRY(dawnTexture->InitializeAsExternalTexture(std::move(d3dTexture), std::move(waitFences),
std::move(waitFences), isSwapChainTexture)); 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.
@ -224,9 +207,12 @@ ResultOrError<Ref<Texture>> Texture::Create(Device* device,
return std::move(dawnTexture); return std::move(dawnTexture);
} }
MaybeError Texture::InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture, MaybeError Texture::InitializeAsExternalTexture(ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture) { bool isSwapChainTexture) {
ComPtr<ID3D12Resource> d3d12Texture;
DAWN_TRY(CheckHRESULT(d3dTexture.As(&d3d12Texture), "texture is not a valid ID3D12Resource"));
D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc(); D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc();
mD3D12ResourceFlags = desc.Flags; mD3D12ResourceFlags = desc.Flags;
@ -330,14 +316,14 @@ MaybeError Texture::InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Tex
} }
Texture::Texture(Device* device, const TextureDescriptor* descriptor, TextureState state) Texture::Texture(Device* device, const TextureDescriptor* descriptor, TextureState state)
: TextureBase(device, descriptor, state), : Base(device, descriptor, state),
mSubresourceStateAndDecay( mSubresourceStateAndDecay(
GetFormat().aspects, GetFormat().aspects,
GetArrayLayers(), GetArrayLayers(),
GetNumMipLevels(), GetNumMipLevels(),
{D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON, kMaxExecutionSerial, false}) {} {D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON, kMaxExecutionSerial, false}) {}
Texture::~Texture() {} Texture::~Texture() = default;
void Texture::DestroyImpl() { void Texture::DestroyImpl() {
TextureBase::DestroyImpl(); TextureBase::DestroyImpl();
@ -405,12 +391,13 @@ DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const {
MaybeError Texture::SynchronizeImportedTextureBeforeUse() { MaybeError Texture::SynchronizeImportedTextureBeforeUse() {
// Perform the wait only on the first call. // Perform the wait only on the first call.
Device* device = ToBackend(GetDevice()); Device* device = ToBackend(GetDevice());
for (Ref<Fence>& fence : mWaitFences) { for (Ref<d3d::Fence>& fence : mWaitFences) {
DAWN_TRY(CheckHRESULT(device->GetCommandQueue()->Wait(fence->GetD3D12Fence(), DAWN_TRY(CheckHRESULT(
fence->GetFenceValue()), device->GetCommandQueue()->Wait(
static_cast<Fence*>(fence.Get())->GetD3D12Fence(), fence->GetFenceValue()),
"D3D12 fence wait");); "D3D12 fence wait"););
// Keep D3D12 fence alive since we'll clear the waitFences list below. // Keep D3D12 fence alive since we'll clear the waitFences list below.
device->ReferenceUntilUnused(fence->GetD3D12Fence()); device->ReferenceUntilUnused(static_cast<Fence*>(fence.Get())->GetD3D12Fence());
} }
mWaitFences.clear(); mWaitFences.clear();
return {}; return {};

View File

@ -19,7 +19,7 @@
#include <vector> #include <vector>
#include "dawn/native/Error.h" #include "dawn/native/Error.h"
#include "dawn/native/Texture.h" #include "dawn/native/d3d/TextureD3D.h"
#include "dawn/native/DawnNative.h" #include "dawn/native/DawnNative.h"
#include "dawn/native/IntegerTypes.h" #include "dawn/native/IntegerTypes.h"
@ -34,18 +34,17 @@ namespace dawn::native::d3d12 {
class CommandRecordingContext; class CommandRecordingContext;
class Device; class Device;
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, MaybeError ValidateTextureCanBeWrapped(ID3D12Resource* d3d12Resource,
const TextureDescriptor* descriptor); const TextureDescriptor* descriptor);
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor); MaybeError ValidateVideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat);
MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat);
class Texture final : public TextureBase { class Texture final : public d3d::Texture {
public: public:
static ResultOrError<Ref<Texture>> Create(Device* device, const TextureDescriptor* descriptor); static ResultOrError<Ref<Texture>> Create(Device* device, const TextureDescriptor* descriptor);
static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device, static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device,
const TextureDescriptor* descriptor, const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture, ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture, bool isSwapChainTexture,
bool isInitialized); bool isInitialized);
static ResultOrError<Ref<Texture>> Create(Device* device, static ResultOrError<Ref<Texture>> Create(Device* device,
@ -54,7 +53,7 @@ class Texture final : public TextureBase {
// For external textures, returns the Device internal fence's value associated with the last // For external textures, returns the Device internal fence's value associated with the last
// ExecuteCommandLists that used this texture. If nullopt is returned, the texture wasn't used. // ExecuteCommandLists that used this texture. If nullopt is returned, the texture wasn't used.
ResultOrError<ExecutionSerial> EndAccess(); ResultOrError<ExecutionSerial> EndAccess() override;
DXGI_FORMAT GetD3D12Format() const; DXGI_FORMAT GetD3D12Format() const;
ID3D12Resource* GetD3D12Resource() const; ID3D12Resource* GetD3D12Resource() const;
@ -97,13 +96,14 @@ class Texture final : public TextureBase {
D3D12_RESOURCE_STATES newState); D3D12_RESOURCE_STATES newState);
private: private:
using Base = d3d::Texture;
Texture(Device* device, const TextureDescriptor* descriptor, TextureState state); Texture(Device* device, const TextureDescriptor* descriptor, TextureState state);
~Texture() override; ~Texture() override;
using TextureBase::TextureBase;
MaybeError InitializeAsInternalTexture(); MaybeError InitializeAsInternalTexture();
MaybeError InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture, MaybeError InitializeAsExternalTexture(ComPtr<IUnknown> d3dTexture,
std::vector<Ref<Fence>> waitFences, std::vector<Ref<d3d::Fence>> waitFences,
bool isSwapChainTexture); bool isSwapChainTexture);
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture); MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
@ -140,7 +140,7 @@ class Texture final : public TextureBase {
ResourceHeapAllocation mResourceAllocation; ResourceHeapAllocation mResourceAllocation;
// TODO(dawn:1460): Encapsulate imported image fields e.g. std::unique_ptr<ExternalImportInfo>. // TODO(dawn:1460): Encapsulate imported image fields e.g. std::unique_ptr<ExternalImportInfo>.
std::vector<Ref<Fence>> mWaitFences; std::vector<Ref<d3d::Fence>> mWaitFences;
std::optional<ExecutionSerial> mSignalFenceValue; std::optional<ExecutionSerial> mSignalFenceValue;
bool mSwapChainTexture = false; bool mSwapChainTexture = false;

View File

@ -576,12 +576,13 @@ source_set("end2end_tests_sources") {
"d3d11.lib", "d3d11.lib",
"dxgi.lib", "dxgi.lib",
] ]
sources += [ "end2end/D3DResourceWrappingTests.cpp" ]
} }
if (dawn_enable_d3d12) { if (dawn_enable_d3d12) {
sources += [ sources += [
"end2end/D3D12CachingTests.cpp", "end2end/D3D12CachingTests.cpp",
"end2end/D3D12ResourceWrappingTests.cpp",
"end2end/VideoViewsTests_win.cpp", "end2end/VideoViewsTests_win.cpp",
] ]
} }

View File

@ -24,6 +24,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "dawn/native/D3D11Backend.h"
#include "dawn/native/D3D12Backend.h" #include "dawn/native/D3D12Backend.h"
#include "dawn/tests/DawnTest.h" #include "dawn/tests/DawnTest.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h" #include "dawn/utils/ComboRenderPipelineDescriptor.h"
@ -33,7 +34,7 @@ using Microsoft::WRL::ComPtr;
namespace { namespace {
class D3D12ResourceTestBase : public DawnTest { class D3DResourceTestBase : public DawnTest {
protected: protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override { std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
return {wgpu::FeatureName::DawnInternalUsages}; return {wgpu::FeatureName::DawnInternalUsages};
@ -47,16 +48,19 @@ class D3D12ResourceTestBase : public DawnTest {
} }
// Create the D3D11 device/contexts that will be used in subsequent tests // Create the D3D11 device/contexts that will be used in subsequent tests
ComPtr<ID3D12Device> d3d12Device = dawn::native::d3d12::GetD3D12Device(device.Get()); ComPtr<IDXGIAdapter> dxgiAdapter =
dawn::native::d3d::GetDXGIAdapter(device.GetAdapter().Get());
DXGI_ADAPTER_DESC adapterDesc;
const LUID adapterLuid = d3d12Device->GetAdapterLuid(); HRESULT hr = dxgiAdapter->GetDesc(&adapterDesc);
ComPtr<IDXGIFactory4> dxgiFactory;
HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
ASSERT_EQ(hr, S_OK); ASSERT_EQ(hr, S_OK);
ComPtr<IDXGIAdapter> dxgiAdapter; ComPtr<IDXGIFactory4> dxgiFactory;
hr = dxgiFactory->EnumAdapterByLuid(adapterLuid, IID_PPV_ARGS(&dxgiAdapter)); hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
ASSERT_EQ(hr, S_OK);
dxgiAdapter = nullptr;
hr = dxgiFactory->EnumAdapterByLuid(adapterDesc.AdapterLuid, IID_PPV_ARGS(&dxgiAdapter));
ASSERT_EQ(hr, S_OK); ASSERT_EQ(hr, S_OK);
ComPtr<ID3D11Device> d3d11Device; ComPtr<ID3D11Device> d3d11Device;
@ -163,12 +167,12 @@ class D3D12ResourceTestBase : public DawnTest {
} // anonymous namespace } // anonymous namespace
// A small fixture used to initialize default data for the D3D12Resource validation tests. // A small fixture used to initialize default data for the D3DResource validation tests.
// These tests are skipped if the harness is using the wire. // These tests are skipped if the harness is using the wire.
class D3D12SharedHandleValidation : public D3D12ResourceTestBase {}; class D3DSharedHandleValidation : public D3DResourceTestBase {};
// Test a successful wrapping of an D3D12Resource in a texture // Test a successful wrapping of an D3DResource in a texture
TEST_P(D3D12SharedHandleValidation, Success) { TEST_P(D3DSharedHandleValidation, Success) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -184,8 +188,8 @@ TEST_P(D3D12SharedHandleValidation, Success) {
texture.Destroy(); texture.Destroy();
} }
// Test a successful wrapping of an D3D12Resource with DawnTextureInternalUsageDescriptor // Test a successful wrapping of an D3DResource with DawnTextureInternalUsageDescriptor
TEST_P(D3D12SharedHandleValidation, SuccessWithInternalUsageDescriptor) { TEST_P(D3DSharedHandleValidation, SuccessWithInternalUsageDescriptor) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
@ -207,7 +211,7 @@ TEST_P(D3D12SharedHandleValidation, SuccessWithInternalUsageDescriptor) {
} }
// Test an error occurs if an invalid sType is the nextInChain // Test an error occurs if an invalid sType is the nextInChain
TEST_P(D3D12SharedHandleValidation, InvalidTextureDescriptor) { TEST_P(D3DSharedHandleValidation, InvalidTextureDescriptor) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::ChainedStruct chainedDescriptor; wgpu::ChainedStruct chainedDescriptor;
@ -224,7 +228,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidTextureDescriptor) {
} }
// Test an error occurs if the descriptor mip level count isn't 1 // Test an error occurs if the descriptor mip level count isn't 1
TEST_P(D3D12SharedHandleValidation, InvalidMipLevelCount) { TEST_P(D3DSharedHandleValidation, InvalidMipLevelCount) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.mipLevelCount = 2; baseDawnDescriptor.mipLevelCount = 2;
@ -238,7 +242,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidMipLevelCount) {
} }
// Test an error occurs if the descriptor depth isn't 1 // Test an error occurs if the descriptor depth isn't 1
TEST_P(D3D12SharedHandleValidation, InvalidDepth) { TEST_P(D3DSharedHandleValidation, InvalidDepth) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.size.depthOrArrayLayers = 2; baseDawnDescriptor.size.depthOrArrayLayers = 2;
@ -252,7 +256,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidDepth) {
} }
// Test an error occurs if the descriptor sample count isn't 1 // Test an error occurs if the descriptor sample count isn't 1
TEST_P(D3D12SharedHandleValidation, InvalidSampleCount) { TEST_P(D3DSharedHandleValidation, InvalidSampleCount) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.sampleCount = 4; baseDawnDescriptor.sampleCount = 4;
@ -266,7 +270,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidSampleCount) {
} }
// Test an error occurs if the descriptor width doesn't match the texture's // Test an error occurs if the descriptor width doesn't match the texture's
TEST_P(D3D12SharedHandleValidation, InvalidWidth) { TEST_P(D3DSharedHandleValidation, InvalidWidth) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.size.width = kTestWidth + 1; baseDawnDescriptor.size.width = kTestWidth + 1;
@ -280,7 +284,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidWidth) {
} }
// Test an error occurs if the descriptor height doesn't match the texture's // Test an error occurs if the descriptor height doesn't match the texture's
TEST_P(D3D12SharedHandleValidation, InvalidHeight) { TEST_P(D3DSharedHandleValidation, InvalidHeight) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.size.height = kTestHeight + 1; baseDawnDescriptor.size.height = kTestHeight + 1;
@ -293,8 +297,8 @@ TEST_P(D3D12SharedHandleValidation, InvalidHeight) {
ASSERT_EQ(texture.Get(), nullptr); ASSERT_EQ(texture.Get(), nullptr);
} }
// Test an error occurs if the descriptor format isn't compatible with the D3D12 Resource // Test an error occurs if the descriptor format isn't compatible with the D3D Resource
TEST_P(D3D12SharedHandleValidation, InvalidFormat) { TEST_P(D3DSharedHandleValidation, InvalidFormat) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseDawnDescriptor.format = wgpu::TextureFormat::R8Unorm; baseDawnDescriptor.format = wgpu::TextureFormat::R8Unorm;
@ -308,7 +312,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidFormat) {
} }
// Test an error occurs if the number of D3D mip levels is greater than 1. // Test an error occurs if the number of D3D mip levels is greater than 1.
TEST_P(D3D12SharedHandleValidation, InvalidNumD3DMipLevels) { TEST_P(D3DSharedHandleValidation, InvalidNumD3DMipLevels) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseD3dDescriptor.MipLevels = 2; baseD3dDescriptor.MipLevels = 2;
@ -322,7 +326,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidNumD3DMipLevels) {
} }
// Test an error occurs if the number of array levels is greater than 1. // Test an error occurs if the number of array levels is greater than 1.
TEST_P(D3D12SharedHandleValidation, InvalidD3DArraySize) { TEST_P(D3DSharedHandleValidation, InvalidD3DArraySize) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
baseD3dDescriptor.ArraySize = 2; baseD3dDescriptor.ArraySize = 2;
@ -335,7 +339,7 @@ TEST_P(D3D12SharedHandleValidation, InvalidD3DArraySize) {
ASSERT_EQ(texture.Get(), nullptr); ASSERT_EQ(texture.Get(), nullptr);
} }
class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase { class D3DSharedHandleUsageTests : public D3DResourceTestBase {
protected: protected:
// Submits a 1x1x1 copy from source to destination // Submits a 1x1x1 copy from source to destination
void SimpleCopyTextureToTexture(wgpu::Texture source, wgpu::Texture destination) { void SimpleCopyTextureToTexture(wgpu::Texture source, wgpu::Texture destination) {
@ -563,7 +567,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
// 1. Create and clear a D3D11 texture // 1. Create and clear a D3D11 texture
// 2. Copy the wrapped texture to another dawn texture // 2. Copy the wrapped texture to another dawn texture
// 3. Readback the copied texture and ensure the color matches the original clear color. // 3. Readback the copied texture and ensure the color matches the original clear color.
TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11CopyAndReadbackInD3D12) { TEST_P(D3DSharedHandleUsageTests, ClearInD3D11CopyAndReadbackInD3D) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f}; const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f};
@ -591,7 +595,7 @@ TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11CopyAndReadbackInD3D12) {
// 1. Create and clear a D3D11 texture // 1. Create and clear a D3D11 texture
// 2. Readback the wrapped texture and ensure the color matches the original clear color. // 2. Readback the wrapped texture and ensure the color matches the original clear color.
TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11ReadbackInD3D12) { TEST_P(D3DSharedHandleUsageTests, ClearInD3D11ReadbackInD3D) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f}; const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f};
@ -616,7 +620,7 @@ TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11ReadbackInD3D12) {
// 1. Create and clear a D3D11 texture // 1. Create and clear a D3D11 texture
// 2. Wrap it in a Dawn texture and clear it to a different color // 2. Wrap it in a Dawn texture and clear it to a different color
// 3. Readback the texture with D3D11 and ensure we receive the color we cleared with Dawn. // 3. Readback the texture with D3D11 and ensure we receive the color we cleared with Dawn.
TEST_P(D3D12SharedHandleUsageTests, ClearInD3D12ReadbackInD3D11) { TEST_P(D3DSharedHandleUsageTests, ClearInD3DReadbackInD3D11) {
// TODO(crbug.com/dawn/735): This test appears to hang for // TODO(crbug.com/dawn/735): This test appears to hang for
// D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled.
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled());
@ -631,24 +635,24 @@ TEST_P(D3D12SharedHandleUsageTests, ClearInD3D12ReadbackInD3D11) {
&d3d11Texture, &externalImage, /*isInitialized=*/true); &d3d11Texture, &externalImage, /*isInitialized=*/true);
ASSERT_NE(dawnTexture.Get(), nullptr); ASSERT_NE(dawnTexture.Get(), nullptr);
const wgpu::Color d3d12ClearColor{0.0f, 0.0f, 1.0f, 1.0f}; const wgpu::Color d3dClearColor{0.0f, 0.0f, 1.0f, 1.0f};
ClearImage(dawnTexture, d3d12ClearColor, device); ClearImage(dawnTexture, d3dClearColor, device);
dawn::native::d3d::ExternalImageDXGIFenceDescriptor signalFence; dawn::native::d3d::ExternalImageDXGIFenceDescriptor signalFence;
externalImage->EndAccess(dawnTexture.Get(), &signalFence); externalImage->EndAccess(dawnTexture.Get(), &signalFence);
dawnTexture.Destroy(); dawnTexture.Destroy();
// Now that Dawn (via D3D12) has finished writing to the texture, we should be // Now that Dawn (via D3D) has finished writing to the texture, we should be
// able to read it back by copying it to a staging texture and verifying the // able to read it back by copying it to a staging texture and verifying the
// color matches the D3D12 clear color. // color matches the D3D12 clear color.
ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3d12ClearColor, &signalFence); ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor, &signalFence);
} }
// 1. Create and clear a D3D11 texture // 1. Create and clear a D3D11 texture
// 2. Wrap it in a Dawn texture and clear the texture to two different colors. // 2. Wrap it in a Dawn texture and clear the texture to two different colors.
// 3. Readback the texture with D3D11. // 3. Readback the texture with D3D11.
// 4. Verify the readback color was the final color cleared. // 4. Verify the readback color was the final color cleared.
TEST_P(D3D12SharedHandleUsageTests, ClearTwiceInD3D12ReadbackInD3D11) { TEST_P(D3DSharedHandleUsageTests, ClearTwiceInD3DReadbackInD3D11) {
// TODO(crbug.com/dawn/735): This test appears to hang for // TODO(crbug.com/dawn/735): This test appears to hang for
// D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled.
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled());
@ -663,26 +667,26 @@ TEST_P(D3D12SharedHandleUsageTests, ClearTwiceInD3D12ReadbackInD3D11) {
&d3d11Texture, &externalImage, /*isInitialized=*/true); &d3d11Texture, &externalImage, /*isInitialized=*/true);
ASSERT_NE(dawnTexture.Get(), nullptr); ASSERT_NE(dawnTexture.Get(), nullptr);
const wgpu::Color d3d12ClearColor1{0.0f, 0.0f, 1.0f, 1.0f}; const wgpu::Color d3dClearColor1{0.0f, 0.0f, 1.0f, 1.0f};
ClearImage(dawnTexture, d3d12ClearColor1, device); ClearImage(dawnTexture, d3dClearColor1, device);
const wgpu::Color d3d12ClearColor2{0.0f, 1.0f, 1.0f, 1.0f}; const wgpu::Color d3dClearColor2{0.0f, 1.0f, 1.0f, 1.0f};
ClearImage(dawnTexture, d3d12ClearColor2, device); ClearImage(dawnTexture, d3dClearColor2, device);
dawn::native::d3d::ExternalImageDXGIFenceDescriptor signalFence; dawn::native::d3d::ExternalImageDXGIFenceDescriptor signalFence;
externalImage->EndAccess(dawnTexture.Get(), &signalFence); externalImage->EndAccess(dawnTexture.Get(), &signalFence);
dawnTexture.Destroy(); dawnTexture.Destroy();
// Now that Dawn (via D3D12) has finished writing to the texture, we should be // Now that Dawn (via D3D) has finished writing to the texture, we should be
// able to read it back by copying it to a staging texture and verifying the // able to read it back by copying it to a staging texture and verifying the
// color matches the last D3D12 clear color. // color matches the last D3D12 clear color.
ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3d12ClearColor2, &signalFence); ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor2, &signalFence);
} }
// 1. Create and clear a D3D11 texture with clearColor // 1. Create and clear a D3D11 texture with clearColor
// 2. Import the texture with isInitialized = false // 2. Import the texture with isInitialized = false
// 3. Verify clearColor is not visible in wrapped texture // 3. Verify clearColor is not visible in wrapped texture
TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) { TEST_P(D3DSharedHandleUsageTests, UninitializedTextureIsCleared) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
const wgpu::Color clearColor{1.0f, 0.0f, 0.0f, 1.0f}; const wgpu::Color clearColor{1.0f, 0.0f, 0.0f, 1.0f};
@ -705,7 +709,7 @@ TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) {
// 1. Create an external image from the DX11 texture. // 1. Create an external image from the DX11 texture.
// 2. Produce two Dawn textures from the external image. // 2. Produce two Dawn textures from the external image.
// 3. Clear each Dawn texture and verify the texture was cleared to a unique color. // 3. Clear each Dawn texture and verify the texture was cleared to a unique color.
TEST_P(D3D12SharedHandleUsageTests, ReuseExternalImage) { TEST_P(D3DSharedHandleUsageTests, ReuseExternalImage) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
// Create the first Dawn texture then clear it to red. // Create the first Dawn texture then clear it to red.
@ -752,7 +756,7 @@ TEST_P(D3D12SharedHandleUsageTests, ReuseExternalImage) {
texture.Destroy(); texture.Destroy();
} }
TEST_P(D3D12SharedHandleUsageTests, ConcurrentExternalImageReadAccess) { TEST_P(D3DSharedHandleUsageTests, ConcurrentExternalImageReadAccess) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Device device2 = CreateDevice(); wgpu::Device device2 = CreateDevice();
@ -905,7 +909,7 @@ TEST_P(D3D12SharedHandleUsageTests, ConcurrentExternalImageReadAccess) {
} }
// Produce a new texture with a usage not specified in the external image. // Produce a new texture with a usage not specified in the external image.
TEST_P(D3D12SharedHandleUsageTests, ExternalImageUsage) { TEST_P(D3DSharedHandleUsageTests, ExternalImageUsage) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -934,7 +938,7 @@ TEST_P(D3D12SharedHandleUsageTests, ExternalImageUsage) {
} }
// Verify external image cannot be used after its creating device is destroyed. // Verify external image cannot be used after its creating device is destroyed.
TEST_P(D3D12SharedHandleUsageTests, InvalidateExternalImageOnDestroyDevice) { TEST_P(D3DSharedHandleUsageTests, InvalidateExternalImageOnDestroyDevice) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -963,7 +967,7 @@ TEST_P(D3D12SharedHandleUsageTests, InvalidateExternalImageOnDestroyDevice) {
} }
// Verify external image cannot be created after the target device is destroyed. // Verify external image cannot be created after the target device is destroyed.
TEST_P(D3D12SharedHandleUsageTests, DisallowExternalImageAfterDestroyDevice) { TEST_P(D3DSharedHandleUsageTests, DisallowExternalImageAfterDestroyDevice) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -981,7 +985,7 @@ TEST_P(D3D12SharedHandleUsageTests, DisallowExternalImageAfterDestroyDevice) {
// Verify there is no error generated when we destroy an external image with CommandRecordingContext // Verify there is no error generated when we destroy an external image with CommandRecordingContext
// open. // open.
TEST_P(D3D12SharedHandleUsageTests, CallWriteBufferBeforeDestroyingExternalImage) { TEST_P(D3DSharedHandleUsageTests, CallWriteBufferBeforeDestroyingExternalImage) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -1006,7 +1010,7 @@ TEST_P(D3D12SharedHandleUsageTests, CallWriteBufferBeforeDestroyingExternalImage
// Test that texture descriptor view formats are passed to the backend for wrapped external // Test that texture descriptor view formats are passed to the backend for wrapped external
// textures, and that contents may be reinterpreted as sRGB. // textures, and that contents may be reinterpreted as sRGB.
TEST_P(D3D12SharedHandleUsageTests, SRGBReinterpretation) { TEST_P(D3DSharedHandleUsageTests, SRGBReinterpretation) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::Texture texture; wgpu::Texture texture;
@ -1045,7 +1049,7 @@ TEST_P(D3D12SharedHandleUsageTests, SRGBReinterpretation) {
utils::RGBA8(247, 125, 105, 255), texture, 0, 0); utils::RGBA8(247, 125, 105, 255), texture, 0, 0);
} }
class D3D12SharedHandleMultithreadTests : public D3D12SharedHandleUsageTests { class D3DSharedHandleMultithreadTests : public D3DSharedHandleUsageTests {
protected: protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override { std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
std::vector<wgpu::FeatureName> features; std::vector<wgpu::FeatureName> features;
@ -1057,14 +1061,14 @@ class D3D12SharedHandleMultithreadTests : public D3D12SharedHandleUsageTests {
} }
void SetUp() override { void SetUp() override {
D3D12SharedHandleUsageTests::SetUp(); D3DSharedHandleUsageTests::SetUp();
// TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet. // TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet.
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
} }
}; };
// Test the destroy device before destroying the external image won't cause deadlock. // Test the destroy device before destroying the external image won't cause deadlock.
TEST_P(D3D12SharedHandleMultithreadTests, DestroyDeviceBeforeImageNoDeadLock) { TEST_P(D3DSharedHandleMultithreadTests, DestroyDeviceBeforeImageNoDeadLock) {
wgpu::Texture texture; wgpu::Texture texture;
ComPtr<ID3D11Texture2D> d3d11Texture; ComPtr<ID3D11Texture2D> d3d11Texture;
std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage; std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage;
@ -1084,7 +1088,7 @@ TEST_P(D3D12SharedHandleMultithreadTests, DestroyDeviceBeforeImageNoDeadLock) {
// Test that using the external image and destroying the device simultaneously on different threads // Test that using the external image and destroying the device simultaneously on different threads
// won't race. // won't race.
TEST_P(D3D12SharedHandleMultithreadTests, DestroyDeviceAndUseImageInParallel) { TEST_P(D3DSharedHandleMultithreadTests, DestroyDeviceAndUseImageInParallel) {
wgpu::Texture texture; wgpu::Texture texture;
ComPtr<ID3D11Texture2D> d3d11Texture; ComPtr<ID3D11Texture2D> d3d11Texture;
std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage; std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage;
@ -1112,13 +1116,13 @@ TEST_P(D3D12SharedHandleMultithreadTests, DestroyDeviceAndUseImageInParallel) {
// 1. Create and clear a D3D11 texture // 1. Create and clear a D3D11 texture
// 2. On 2nd thread: Wrap it in a Dawn texture and clear it to a different color // 2. On 2nd thread: Wrap it in a Dawn texture and clear it to a different color
// 3. Readback the texture with D3D11 and ensure we receive the color we cleared with Dawn. // 3. Readback the texture with D3D11 and ensure we receive the color we cleared with Dawn.
TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads) { TEST_P(D3DSharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads) {
// TODO(crbug.com/dawn/735): This test appears to hang for // TODO(crbug.com/dawn/735): This test appears to hang for
// D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled.
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled());
const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f}; const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f};
const wgpu::Color d3d12ClearColor{0.0f, 0.0f, 1.0f, 1.0f}; const wgpu::Color d3dClearColor{0.0f, 0.0f, 1.0f, 1.0f};
constexpr uint64_t kD3D11FenceSignalValue = 1; constexpr uint64_t kD3D11FenceSignalValue = 1;
@ -1129,9 +1133,9 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
CreateSharedD3D11Texture(baseD3dDescriptor, &d3d11Texture, &d3d11Fence, &sharedHandle, CreateSharedD3D11Texture(baseD3dDescriptor, &d3d11Texture, &d3d11Fence, &sharedHandle,
&fenceSharedHandle); &fenceSharedHandle);
dawn::native::d3d::ExternalImageDXGIFenceDescriptor d3d12SignalFence; dawn::native::d3d::ExternalImageDXGIFenceDescriptor d3dSignalFence;
std::thread d3d12Thread([=, &d3d12SignalFence] { std::thread d3dThread([=, &d3dSignalFence] {
wgpu::Texture dawnTexture; wgpu::Texture dawnTexture;
std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage; std::unique_ptr<dawn::native::d3d::ExternalImageDXGI> externalImage;
WaitAndWrapD3D11Texture(baseDawnDescriptor, sharedHandle, fenceSharedHandle, WaitAndWrapD3D11Texture(baseDawnDescriptor, sharedHandle, fenceSharedHandle,
@ -1144,9 +1148,9 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
d3d11ClearColor.b * 255, d3d11ClearColor.a * 255), d3d11ClearColor.b * 255, d3d11ClearColor.a * 255),
dawnTexture, 0, 0); dawnTexture, 0, 0);
ClearImage(dawnTexture, d3d12ClearColor, device); ClearImage(dawnTexture, d3dClearColor, device);
externalImage->EndAccess(dawnTexture.Get(), &d3d12SignalFence); externalImage->EndAccess(dawnTexture.Get(), &d3dSignalFence);
dawnTexture.Destroy(); dawnTexture.Destroy();
}); });
@ -1154,11 +1158,11 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
ClearD3D11Texture(d3d11ClearColor, d3d11Texture.Get(), d3d11Fence.Get(), ClearD3D11Texture(d3d11ClearColor, d3d11Texture.Get(), d3d11Fence.Get(),
/*fenceSignalValue=*/kD3D11FenceSignalValue); /*fenceSignalValue=*/kD3D11FenceSignalValue);
d3d12Thread.join(); d3dThread.join();
// Now that Dawn (via D3D12) has finished writing to the texture, we should be // Now that Dawn (via D3D12) has finished writing to the texture, we should be
// able to read it back by copying it to a staging texture and verifying the // able to read it back by copying it to a staging texture and verifying the
// color matches the D3D12 clear color. // color matches the D3D12 clear color.
ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3d12ClearColor, &d3d12SignalFence); ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor, &d3dSignalFence);
if (sharedHandle != nullptr) { if (sharedHandle != nullptr) {
::CloseHandle(sharedHandle); ::CloseHandle(sharedHandle);
@ -1169,6 +1173,6 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
} }
} }
DAWN_INSTANTIATE_TEST(D3D12SharedHandleValidation, D3D12Backend()); DAWN_INSTANTIATE_TEST(D3DSharedHandleValidation, D3D11Backend(), D3D12Backend());
DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend()); DAWN_INSTANTIATE_TEST(D3DSharedHandleUsageTests, D3D11Backend(), D3D12Backend());
DAWN_INSTANTIATE_TEST(D3D12SharedHandleMultithreadTests, D3D12Backend()); DAWN_INSTANTIATE_TEST(D3DSharedHandleMultithreadTests, D3D11Backend(), D3D12Backend());

View File

@ -44,21 +44,13 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
mWGPUDevice = device; mWGPUDevice = device;
// Create the D3D11 device/contexts that will be used in subsequent tests // Create the D3D11 device/contexts that will be used in subsequent tests
ComPtr<ID3D12Device> d3d12Device = dawn::native::d3d12::GetD3D12Device(device); ComPtr<IDXGIAdapter> dxgiAdapter =
dawn::native::d3d::GetDXGIAdapter(wgpuDeviceGetAdapter(device));
const LUID adapterLuid = d3d12Device->GetAdapterLuid();
ComPtr<IDXGIFactory4> dxgiFactory;
HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
ASSERT_EQ(hr, S_OK);
ComPtr<IDXGIAdapter> dxgiAdapter;
hr = dxgiFactory->EnumAdapterByLuid(adapterLuid, IID_PPV_ARGS(&dxgiAdapter));
ASSERT_EQ(hr, S_OK);
ComPtr<ID3D11Device> d3d11Device; ComPtr<ID3D11Device> d3d11Device;
D3D_FEATURE_LEVEL d3dFeatureLevel; D3D_FEATURE_LEVEL d3dFeatureLevel;
ComPtr<ID3D11DeviceContext> d3d11DeviceContext; ComPtr<ID3D11DeviceContext> d3d11DeviceContext;
HRESULT hr;
hr = ::D3D11CreateDevice(dxgiAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0, hr = ::D3D11CreateDevice(dxgiAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0,
D3D11_SDK_VERSION, &d3d11Device, &d3dFeatureLevel, D3D11_SDK_VERSION, &d3d11Device, &d3dFeatureLevel,
&d3d11DeviceContext); &d3d11DeviceContext);