Remove ExternalImageDXGI This CL removes ExternalImageDXGI as we have switched to using SharedTextureMemory. Bug: chromium:335003893 Change-Id: I8ecdcdfa03a780f6fc7ece8846368bc736f696b1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/187426 Reviewed-by: Peng Huang <penghuang@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
diff --git a/include/dawn/native/D3DBackend.h b/include/dawn/native/D3DBackend.h index d6bf080..cafbdf7 100644 --- a/include/dawn/native/D3DBackend.h +++ b/include/dawn/native/D3DBackend.h
@@ -54,73 +54,6 @@ // Chrome uses 0 as acquire key. static constexpr UINT64 kDXGIKeyedMutexAcquireKey = 0; -struct DAWN_NATIVE_EXPORT ExternalImageDescriptorDXGISharedHandle : ExternalImageDescriptor { - public: - ExternalImageDescriptorDXGISharedHandle(); - - // Note: SharedHandle must be a handle to a texture object. - HANDLE sharedHandle = nullptr; - - // Whether the underlying texture has a keyed mutex which should be used for synchronization. - bool useKeyedMutex = false; -}; - -struct DAWN_NATIVE_EXPORT ExternalImageDescriptorD3D11Texture : ExternalImageDescriptor { - public: - ExternalImageDescriptorD3D11Texture(); - - // Texture is used for creating ExternalImageDXGI with d3d11 backend. It must be an - // ID3D11Texture2D object and created from the same ID3D11Device used in the WGPUDevice. - Microsoft::WRL::ComPtr<IUnknown> texture; -}; - -struct DAWN_NATIVE_EXPORT ExternalImageDXGIFenceDescriptor { - // Shared handle for the fence. This never passes ownership to the callee (when used as an input - // parameter) or to the caller (when used as a return value or output parameter). - HANDLE fenceHandle = nullptr; - - // The value that was previously signaled on this fence and should be waited on. - uint64_t fenceValue = 0; -}; - -struct DAWN_NATIVE_EXPORT ExternalImageDXGIBeginAccessDescriptor { - bool isInitialized = false; // Whether the texture is initialized on import - WGPUTextureUsageFlags usage = WGPUTextureUsage_None; - - // A list of fences to wait on before accessing the texture. - std::vector<ExternalImageDXGIFenceDescriptor> waitFences; - - // Whether the texture is for a WebGPU swap chain. - bool isSwapChainTexture = false; -}; - -class DAWN_NATIVE_EXPORT ExternalImageDXGI { - public: - ~ExternalImageDXGI(); - - static std::unique_ptr<ExternalImageDXGI> Create(WGPUDevice device, - const ExternalImageDescriptor* descriptor); - - // Returns true if the external image resources are still valid, otherwise BeginAccess() is - // guaranteed to fail e.g. after device destruction. - bool IsValid() const; - - // Creates WGPUTexture wrapping the DXGI shared handle. The provided wait fences will be - // synchronized before using the texture in any command lists. Empty fences (nullptr handle) are - // ignored for convenience (EndAccess can return such fences). - WGPUTexture BeginAccess(const ExternalImageDXGIBeginAccessDescriptor* descriptor); - - // Returns the signalFence that the client must wait on for correct synchronization. Can return - // an empty fence (nullptr handle) if the texture wasn't accessed by Dawn. - // Note that merely calling Destroy() on the WGPUTexture does not ensure synchronization. - void EndAccess(WGPUTexture texture, ExternalImageDXGIFenceDescriptor* signalFence); - - private: - explicit ExternalImageDXGI(std::unique_ptr<ExternalImageDXGIImpl> impl); - - std::unique_ptr<ExternalImageDXGIImpl> mImpl; -}; - } // namespace dawn::native::d3d #endif // INCLUDE_DAWN_NATIVE_D3DBACKEND_H_
diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h index f0a9ffe..4b5e9e3 100644 --- a/include/dawn/native/DawnNative.h +++ b/include/dawn/native/DawnNative.h
@@ -234,8 +234,6 @@ OpaqueFD, DmaBuf, IOSurface, - DXGISharedHandle, - D3D11Texture, EGLImage, GLTexture, AHardwareBuffer,
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index 450a056..80d6bae 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn
@@ -454,8 +454,6 @@ "d3d/D3DError.h", "d3d/DeviceD3D.cpp", "d3d/DeviceD3D.h", - "d3d/ExternalImageDXGIImpl.cpp", - "d3d/ExternalImageDXGIImpl.h", "d3d/Forward.h", "d3d/KeyedMutex.cpp", "d3d/KeyedMutex.h",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index a2f4274..427f338 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt
@@ -313,8 +313,6 @@ "d3d/D3DError.h" "d3d/DeviceD3D.cpp" "d3d/DeviceD3D.h" - "d3d/ExternalImageDXGIImpl.cpp" - "d3d/ExternalImageDXGIImpl.h" "d3d/Forward.h" "d3d/KeyedMutex.cpp" "d3d/KeyedMutex.h"
diff --git a/src/dawn/native/d3d/D3DBackend.cpp b/src/dawn/native/d3d/D3DBackend.cpp index ceb30b9..4947317 100644 --- a/src/dawn/native/d3d/D3DBackend.cpp +++ b/src/dawn/native/d3d/D3DBackend.cpp
@@ -36,7 +36,6 @@ #include "dawn/common/Log.h" #include "dawn/native/Adapter.h" #include "dawn/native/d3d/DeviceD3D.h" -#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/Forward.h" #include "dawn/native/d3d/PhysicalDeviceD3D.h" @@ -50,53 +49,4 @@ return ToBackend(FromAPI(adapter)->GetPhysicalDevice())->GetHardwareAdapter(); } -ExternalImageDescriptorDXGISharedHandle::ExternalImageDescriptorDXGISharedHandle() - : ExternalImageDescriptor(ExternalImageType::DXGISharedHandle) {} - -ExternalImageDescriptorD3D11Texture::ExternalImageDescriptorD3D11Texture() - : ExternalImageDescriptor(ExternalImageType::D3D11Texture) {} - -ExternalImageDXGI::ExternalImageDXGI(std::unique_ptr<ExternalImageDXGIImpl> impl) - : mImpl(std::move(impl)) { - DAWN_ASSERT(mImpl != nullptr); -} - -ExternalImageDXGI::~ExternalImageDXGI() { - auto deviceLock = mImpl->GetScopedDeviceLock(); - mImpl = nullptr; -} - -bool ExternalImageDXGI::IsValid() const { - auto deviceLock = mImpl->GetScopedDeviceLock(); - return mImpl->IsValid(); -} - -WGPUTexture ExternalImageDXGI::BeginAccess( - const ExternalImageDXGIBeginAccessDescriptor* descriptor) { - auto deviceLock = mImpl->GetScopedDeviceLock(); - return mImpl->BeginAccess(descriptor); -} - -void ExternalImageDXGI::EndAccess(WGPUTexture texture, - ExternalImageDXGIFenceDescriptor* signalFence) { - auto deviceLock = mImpl->GetScopedDeviceLock(); - mImpl->EndAccess(texture, signalFence); -} - -// static -std::unique_ptr<ExternalImageDXGI> ExternalImageDXGI::Create( - WGPUDevice device, - const ExternalImageDescriptor* descriptor) { - Device* backendDevice = ToBackend(FromAPI(device)); - auto deviceLock = backendDevice->GetScopedLock(); - - std::unique_ptr<ExternalImageDXGIImpl> impl = - backendDevice->CreateExternalImageDXGIImpl(descriptor); - if (!impl) { - dawn::ErrorLog() << "Failed to create DXGI external image"; - return nullptr; - } - return std::unique_ptr<ExternalImageDXGI>(new ExternalImageDXGI(std::move(impl))); -} - } // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d/DeviceD3D.cpp b/src/dawn/native/d3d/DeviceD3D.cpp index 02d0621..bc5608e 100644 --- a/src/dawn/native/d3d/DeviceD3D.cpp +++ b/src/dawn/native/d3d/DeviceD3D.cpp
@@ -30,7 +30,6 @@ #include <utility> #include "dawn/native/d3d/BackendD3D.h" -#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/Forward.h" #include "dawn/native/d3d/PhysicalDeviceD3D.h" #include "dawn/native/d3d/SharedFenceD3D.h" @@ -47,20 +46,7 @@ Destroy(); } -void Device::DestroyImpl() { - // TODO(crbug.com/dawn/831): DestroyImpl is called from two places. - // - It may be called if the device is explicitly destroyed with APIDestroy. - // This case is NOT thread-safe and needs proper synchronization with other - // simultaneous uses of the device. - // - It may be called when the last ref to the device is dropped and the device - // is implicitly destroyed. This case is thread-safe because there are no - // other threads using the device since there are no other live refs. - while (!mExternalImageList.empty()) { - d3d::ExternalImageDXGIImpl* externalImage = mExternalImageList.head()->value(); - // ExternalImageDXGIImpl::DestroyInternal() calls RemoveFromList(). - externalImage->DestroyInternal(); - } -} +void Device::DestroyImpl() {} ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl( const Surface* surface) const { @@ -78,14 +64,4 @@ return ToBackend(GetPhysicalDevice())->GetBackend()->GetFactory(); } -std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl( - const ExternalImageDescriptor* descriptor) { - std::unique_ptr<ExternalImageDXGIImpl> externalImage; - if (!ConsumedError(CreateExternalImageDXGIImplImpl(descriptor), &externalImage)) { - mExternalImageList.Append(externalImage.get()); - return externalImage; - } - return {}; -} - } // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d/DeviceD3D.h b/src/dawn/native/d3d/DeviceD3D.h index 272abd9..a752cd2 100644 --- a/src/dawn/native/d3d/DeviceD3D.h +++ b/src/dawn/native/d3d/DeviceD3D.h
@@ -36,11 +36,6 @@ namespace dawn::native::d3d { -struct ExternalImageDescriptorDXGISharedHandle; -struct ExternalImageDXGIFenceDescriptor; -class ExternalImageDXGIImpl; -class Fence; -class KeyedMutex; class PlatformFunctions; class Device : public DeviceBase { @@ -57,31 +52,10 @@ const PlatformFunctions* GetFunctions() const; ComPtr<IDXGIFactory4> GetFactory() const; - std::unique_ptr<ExternalImageDXGIImpl> CreateExternalImageDXGIImpl( - const ExternalImageDescriptor* descriptor); - - virtual ResultOrError<FenceAndSignalValue> CreateFence( - const ExternalImageDXGIFenceDescriptor* descriptor) = 0; - - virtual Ref<TextureBase> CreateD3DExternalTexture( - const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) = 0; - virtual void DisposeKeyedMutex(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex) = 0; protected: void DestroyImpl() override; - - virtual ResultOrError<std::unique_ptr<ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl( - const ExternalImageDescriptor* descriptor) = 0; - - private: - // List of external image resources opened using this device. - LinkedList<d3d::ExternalImageDXGIImpl> mExternalImageList; }; } // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d/ExternalImageDXGIImpl.cpp b/src/dawn/native/d3d/ExternalImageDXGIImpl.cpp deleted file mode 100644 index 531b331..0000000 --- a/src/dawn/native/d3d/ExternalImageDXGIImpl.cpp +++ /dev/null
@@ -1,208 +0,0 @@ -// Copyright 2022 The Dawn & Tint Authors -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "dawn/native/d3d/ExternalImageDXGIImpl.h" - -#include <utility> -#include <vector> - -#include "dawn/common/Log.h" -#include "dawn/native/ChainUtils.h" -#include "dawn/native/D3D12Backend.h" -#include "dawn/native/DawnNative.h" -#include "dawn/native/d3d/DeviceD3D.h" -#include "dawn/native/d3d/Forward.h" -#include "dawn/native/d3d/KeyedMutex.h" -#include "dawn/native/d3d/QueueD3D.h" -#include "dawn/native/d3d/SharedFenceD3D.h" -#include "dawn/native/d3d/TextureD3D.h" - -namespace dawn::native::d3d { - -MaybeError ValidateTextureDescriptorCanBeWrapped(const UnpackedPtr<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, - ComPtr<IUnknown> d3dResource, - Ref<d3d::KeyedMutex> keyedMutex, - const UnpackedPtr<TextureDescriptor>& textureDescriptor) - : mBackendDevice(backendDevice), - mD3DResource(std::move(d3dResource)), - mKeyedMutex(std::move(keyedMutex)), - mUsage(textureDescriptor->usage), - mDimension(textureDescriptor->dimension), - mSize(textureDescriptor->size), - mFormat(textureDescriptor->format), - mMipLevelCount(textureDescriptor->mipLevelCount), - mSampleCount(textureDescriptor->sampleCount), - mViewFormats(textureDescriptor->viewFormats, - textureDescriptor->viewFormats + textureDescriptor->viewFormatCount) { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - DAWN_ASSERT(mBackendDevice != nullptr); - DAWN_ASSERT(!textureDescriptor->nextInChain || - textureDescriptor->nextInChain->sType == - wgpu::SType::DawnTextureInternalUsageDescriptor); - if (textureDescriptor->nextInChain) { - mUsageInternal = reinterpret_cast<const wgpu::DawnTextureInternalUsageDescriptor*>( - textureDescriptor->nextInChain) - ->internalUsage; - } -} - -ExternalImageDXGIImpl::~ExternalImageDXGIImpl() { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - DestroyInternal(); -} - -Mutex::AutoLock ExternalImageDXGIImpl::GetScopedDeviceLock() const { - return mBackendDevice->GetScopedLock(); -} - -bool ExternalImageDXGIImpl::IsValid() const { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - return IsInList(); -} - -void ExternalImageDXGIImpl::DestroyInternal() { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - if (IsInList()) { - mKeyedMutex = nullptr; - mD3DResource = nullptr; - } - - if (IsInList()) { - RemoveFromList(); - } -} - -WGPUTexture ExternalImageDXGIImpl::BeginAccess( - const d3d::ExternalImageDXGIBeginAccessDescriptor* descriptor) { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - DAWN_ASSERT(descriptor != nullptr); - - 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; - } - - DAWN_ASSERT(mBackendDevice != nullptr); - if (mBackendDevice->GetValidInternalFormat(mFormat).IsMultiPlanar() && - !descriptor->isInitialized) { - [[maybe_unused]] bool consumed = mBackendDevice->ConsumedError(DAWN_VALIDATION_ERROR( - "External textures with multiplanar formats must be initialized.")); - return 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 = mViewFormats.size(); - - DawnTextureInternalUsageDescriptor internalDesc = {}; - if (mUsageInternal != wgpu::TextureUsage::None) { - textureDescriptor.nextInChain = &internalDesc; - internalDesc.internalUsage = mUsageInternal; - } - - std::vector<FenceAndSignalValue> waitFences; - for (const d3d::ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) { - FenceAndSignalValue 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(Unpack(&textureDescriptor), mD3DResource, mKeyedMutex, - std::move(waitFences), descriptor->isSwapChainTexture, - descriptor->isInitialized); - return ToAPI(ReturnToAPI(std::move(texture))); -} - -void ExternalImageDXGIImpl::EndAccess(WGPUTexture texture, - d3d::ExternalImageDXGIFenceDescriptor* signalFence) { - DAWN_ASSERT(mBackendDevice->IsLockedByCurrentThreadIfNeeded()); - - if (!IsInList()) { - dawn::ErrorLog() << "Cannot use external image after device destruction"; - return; - } - - DAWN_ASSERT(mBackendDevice != nullptr); - DAWN_ASSERT(signalFence != nullptr); - - Texture* backendTexture = ToBackend(FromAPI(texture)); - DAWN_ASSERT(backendTexture != nullptr); - - Ref<SharedFence> sharedFence; - if (mBackendDevice->ConsumedError( - ToBackend(mBackendDevice->GetQueue())->GetOrCreateSharedFence(), &sharedFence)) { - dawn::ErrorLog() << "Could not retrieve device shared fence"; - return; - } - - ExecutionSerial fenceValue; - if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) { - dawn::ErrorLog() << "D3D texture end access failed"; - return; - } - - signalFence->fenceHandle = sharedFence->GetFenceHandle(); - signalFence->fenceValue = static_cast<uint64_t>(fenceValue); -} - -} // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d/ExternalImageDXGIImpl.h b/src/dawn/native/d3d/ExternalImageDXGIImpl.h deleted file mode 100644 index ae73715..0000000 --- a/src/dawn/native/d3d/ExternalImageDXGIImpl.h +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2023 The Dawn & Tint Authors -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef SRC_DAWN_NATIVE_D3D_EXTERNALIMAGEDXGIIMPL_H_ -#define SRC_DAWN_NATIVE_D3D_EXTERNALIMAGEDXGIIMPL_H_ - -#include <wrl/client.h> - -#include <memory> -#include <optional> -#include <utility> -#include <vector> - -#include "dawn/common/LinkedList.h" -#include "dawn/common/Mutex.h" -#include "dawn/common/NonCopyable.h" -#include "dawn/native/Error.h" -#include "dawn/native/Forward.h" -#include "dawn/native/IntegerTypes.h" -#include "dawn/native/d3d/d3d_platform.h" -#include "dawn/webgpu_cpp.h" - -namespace dawn::native::d3d { - -class Device; -class KeyedMutex; -struct ExternalImageDXGIBeginAccessDescriptor; -struct ExternalImageDXGIFenceDescriptor; -struct ExternalImageDescriptorDXGISharedHandle; - -MaybeError ValidateTextureDescriptorCanBeWrapped(const UnpackedPtr<TextureDescriptor>& descriptor); - -class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> { - public: - ExternalImageDXGIImpl(Device* backendDevice, - ComPtr<IUnknown> d3dResource, - Ref<d3d::KeyedMutex> keyedMutex, - const UnpackedPtr<TextureDescriptor>& textureDescriptor); - ~ExternalImageDXGIImpl(); - - ExternalImageDXGIImpl(const ExternalImageDXGIImpl&) = delete; - ExternalImageDXGIImpl& operator=(const ExternalImageDXGIImpl&) = delete; - - bool IsValid() const; - - WGPUTexture BeginAccess(const ExternalImageDXGIBeginAccessDescriptor* descriptor); - void EndAccess(WGPUTexture texture, ExternalImageDXGIFenceDescriptor* signalFence); - - // This method should only be called by internal code. Don't call this from D3D12Backend side, - // or without locking. - void DestroyInternal(); - - [[nodiscard]] Mutex::AutoLock GetScopedDeviceLock() const; - - protected: - Ref<DeviceBase> mBackendDevice; - ComPtr<IUnknown> mD3DResource; - Ref<d3d::KeyedMutex> mKeyedMutex; - wgpu::TextureUsage mUsage; - wgpu::TextureUsage mUsageInternal = wgpu::TextureUsage::None; - wgpu::TextureDimension mDimension; - Extent3D mSize; - wgpu::TextureFormat mFormat; - uint32_t mMipLevelCount; - uint32_t mSampleCount; - std::vector<wgpu::TextureFormat> mViewFormats; -}; - -} // namespace dawn::native::d3d - -#endif // SRC_DAWN_NATIVE_D3D_EXTERNALIMAGEDXGIIMPL_H_
diff --git a/src/dawn/native/d3d11/DeviceD3D11.cpp b/src/dawn/native/d3d11/DeviceD3D11.cpp index 896245e..f9907eb 100644 --- a/src/dawn/native/d3d11/DeviceD3D11.cpp +++ b/src/dawn/native/d3d11/DeviceD3D11.cpp
@@ -38,7 +38,6 @@ #include "dawn/native/DynamicUploader.h" #include "dawn/native/Instance.h" #include "dawn/native/d3d/D3DError.h" -#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/KeyedMutex.h" #include "dawn/native/d3d/UtilsD3D.h" #include "dawn/native/d3d11/BackendD3D11.h" @@ -394,89 +393,6 @@ void Device::SetLabelImpl() {} -ResultOrError<FenceAndSignalValue> Device::CreateFence( - const d3d::ExternalImageDXGIFenceDescriptor* externalImageFenceDesc) { - SharedFenceDXGISharedHandleDescriptor sharedFenceDesc; - sharedFenceDesc.handle = externalImageFenceDesc->fenceHandle; - - Ref<SharedFence> fence; - DAWN_TRY_ASSIGN(fence, SharedFence::Create(this, "Imported DXGI fence", &sharedFenceDesc)); - - return FenceAndSignalValue{std::move(fence), externalImageFenceDesc->fenceValue}; -} - -ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> Device::CreateExternalImageDXGIImplImpl( - const ExternalImageDescriptor* descriptor) { - // 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 - // a use-after-free. - DAWN_TRY(ValidateIsAlive()); - - ComPtr<ID3D11Resource> d3d11Resource; - ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex; - switch (descriptor->GetType()) { - case ExternalImageType::DXGISharedHandle: { - const auto* sharedHandleDescriptor = - static_cast<const d3d::ExternalImageDescriptorDXGISharedHandle*>(descriptor); - DAWN_TRY(CheckHRESULT( - mD3d11Device5->OpenSharedResource1(sharedHandleDescriptor->sharedHandle, - IID_PPV_ARGS(&d3d11Resource)), - "D3D11 OpenSharedResource1")); - if (sharedHandleDescriptor->useKeyedMutex) { - d3d11Resource.As(&dxgiKeyedMutex); - DAWN_INVALID_IF(!dxgiKeyedMutex, - "Failed to retrieve DXGI keyed mutex when expected"); - } - break; - } - case ExternalImageType::D3D11Texture: { - const auto* d3d11TextureDescriptor = - static_cast<const d3d::ExternalImageDescriptorD3D11Texture*>(descriptor); - DAWN_TRY(CheckHRESULT(d3d11TextureDescriptor->texture.As(&d3d11Resource), - "Cannot get ID3D11Resource from texture")); - ComPtr<ID3D11Device> textureDevice; - d3d11Resource->GetDevice(textureDevice.GetAddressOf()); - DAWN_INVALID_IF( - textureDevice.Get() != mD3d11Device.Get(), - "The D3D11 device of the texture and the D3D11 device of the WebGPU device " - "must be same."); - d3d11Resource.As(&dxgiKeyedMutex); - break; - } - default: { - return DAWN_VALIDATION_ERROR("descriptor type (%d) is not supported", - static_cast<int>(descriptor->GetType())); - } - } - - UnpackedPtr<TextureDescriptor> textureDescriptor; - DAWN_TRY_ASSIGN(textureDescriptor, ValidateAndUnpack(FromAPI(descriptor->cTextureDescriptor))); - DAWN_TRY( - ValidateTextureDescriptor(this, textureDescriptor, AllowMultiPlanarTextureFormat::Yes)); - - 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() && descriptor->GetType() == ExternalImageType::DXGISharedHandle) { - DAWN_TRY(ValidateVideoTextureCanBeShared( - this, d3d::DXGITextureFormat(textureDescriptor->format))); - } - - Ref<d3d::KeyedMutex> keyedMutex; - if (dxgiKeyedMutex) { - keyedMutex = AcquireRef(new d3d::KeyedMutex(this, std::move(dxgiKeyedMutex))); - } - - return std::make_unique<d3d::ExternalImageDXGIImpl>(this, std::move(d3d11Resource), - std::move(keyedMutex), textureDescriptor); -} - void Device::DisposeKeyedMutex(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex) { // Nothing to do, the ComPtr will release the keyed mutex. } @@ -493,22 +409,6 @@ return true; } -Ref<TextureBase> Device::CreateD3DExternalTexture(const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) { - Ref<Texture> dawnTexture; - if (ConsumedError(Texture::CreateExternalImage(this, descriptor, std::move(d3dTexture), - std::move(keyedMutex), std::move(waitFences), - isSwapChainTexture, isInitialized), - &dawnTexture)) { - return nullptr; - } - return {dawnTexture}; -} - uint32_t Device::GetUAVSlotCount() const { return ToBackend(GetPhysicalDevice())->GetUAVSlotCount(); }
diff --git a/src/dawn/native/d3d11/DeviceD3D11.h b/src/dawn/native/d3d11/DeviceD3D11.h index 8d8b80e..c13f12b 100644 --- a/src/dawn/native/d3d11/DeviceD3D11.h +++ b/src/dawn/native/d3d11/DeviceD3D11.h
@@ -56,12 +56,6 @@ const DeviceInfo& GetDeviceInfo() const; void ReferenceUntilUnused(ComPtr<IUnknown> object); - Ref<TextureBase> CreateD3DExternalTexture(const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) override; ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer( CommandEncoder* encoder, @@ -84,12 +78,6 @@ bool IsResolveTextureBlitWithDrawSupported() const override; void SetLabelImpl() override; - ResultOrError<FenceAndSignalValue> CreateFence( - const d3d::ExternalImageDXGIFenceDescriptor* descriptor) override; - - ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl( - const ExternalImageDescriptor* descriptor) override; - void DisposeKeyedMutex(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex) override; uint32_t GetUAVSlotCount() const;
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp index 5ef307f..d052901 100644 --- a/src/dawn/native/d3d11/TextureD3D11.cpp +++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -226,40 +226,6 @@ } // static -ResultOrError<Ref<Texture>> Texture::CreateExternalImage( - Device* device, - const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) { - Ref<Texture> dawnTexture = AcquireRef(new Texture(device, descriptor, Kind::Normal)); - DAWN_TRY( - dawnTexture->InitializeAsExternalTexture(std::move(d3dTexture), std::move(keyedMutex))); - - auto commandContext = - ToBackend(device->GetQueue()) - ->GetScopedPendingCommandContext(ExecutionQueueBase::SubmitMode::Normal); - for (const auto& fence : waitFences) { - DAWN_TRY(CheckHRESULT( - commandContext.Wait(ToBackend(fence.object)->GetD3DFence(), fence.signaledValue), - "ID3D11DeviceContext4::Wait")); - } - - // 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); -} - -// static ResultOrError<Ref<Texture>> Texture::CreateFromSharedTextureMemory( SharedTextureMemory* memory, const UnpackedPtr<TextureDescriptor>& descriptor) {
diff --git a/src/dawn/native/d3d11/TextureD3D11.h b/src/dawn/native/d3d11/TextureD3D11.h index 7afca35..58cf57c 100644 --- a/src/dawn/native/d3d11/TextureD3D11.h +++ b/src/dawn/native/d3d11/TextureD3D11.h
@@ -64,14 +64,6 @@ static ResultOrError<Ref<Texture>> Create(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, ComPtr<ID3D11Resource> d3d11Texture); - static ResultOrError<Ref<Texture>> CreateExternalImage( - Device* device, - const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized); static ResultOrError<Ref<Texture>> CreateFromSharedTextureMemory( SharedTextureMemory* memory, const UnpackedPtr<TextureDescriptor>& descriptor);
diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp index a8e9231..3fc0cc4 100644 --- a/src/dawn/native/d3d12/DeviceD3D12.cpp +++ b/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -38,7 +38,6 @@ #include "dawn/native/DynamicUploader.h" #include "dawn/native/Instance.h" #include "dawn/native/d3d/D3DError.h" -#include "dawn/native/d3d/ExternalImageDXGIImpl.h" #include "dawn/native/d3d/KeyedMutex.h" #include "dawn/native/d3d12/BackendD3D12.h" #include "dawn/native/d3d12/BindGroupD3D12.h" @@ -562,76 +561,6 @@ forceAllocateAsCommittedResource); } -ResultOrError<FenceAndSignalValue> Device::CreateFence( - const d3d::ExternalImageDXGIFenceDescriptor* externalImageFenceDesc) { - SharedFenceDXGISharedHandleDescriptor sharedFenceDesc; - sharedFenceDesc.handle = externalImageFenceDesc->fenceHandle; - - Ref<SharedFence> fence; - DAWN_TRY_ASSIGN(fence, SharedFence::Create(this, "Imported DXGI fence", &sharedFenceDesc)); - - return FenceAndSignalValue{std::move(fence), externalImageFenceDesc->fenceValue}; -} - -ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> Device::CreateExternalImageDXGIImplImpl( - const ExternalImageDescriptor* descriptor) { - // 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 - // a use-after-free. - DAWN_TRY(ValidateIsAlive()); - - DAWN_INVALID_IF(descriptor->GetType() != ExternalImageType::DXGISharedHandle, - "descriptor is not an ExternalImageDescriptorDXGISharedHandle"); - - const d3d::ExternalImageDescriptorDXGISharedHandle* sharedHandleDescriptor = - static_cast<const d3d::ExternalImageDescriptorDXGISharedHandle*>(descriptor); - - Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource; - Ref<d3d::KeyedMutex> keyedMutex; - DAWN_TRY(ImportSharedHandleResource(sharedHandleDescriptor->sharedHandle, - sharedHandleDescriptor->useKeyedMutex, d3d12Resource, - keyedMutex)); - - UnpackedPtr<TextureDescriptor> textureDescriptor; - DAWN_TRY_ASSIGN(textureDescriptor, - ValidateAndUnpack(FromAPI(sharedHandleDescriptor->cTextureDescriptor))); - DAWN_TRY( - ValidateTextureDescriptor(this, textureDescriptor, AllowMultiPlanarTextureFormat::Yes)); - - DAWN_TRY_CONTEXT(d3d::ValidateTextureDescriptorCanBeWrapped(textureDescriptor), - "validating that a D3D12 external image can be wrapped with %s", - textureDescriptor); - - DAWN_TRY(ValidateTextureCanBeWrapped(d3d12Resource.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(d3d12Resource), - std::move(keyedMutex), textureDescriptor); -} - -Ref<TextureBase> Device::CreateD3DExternalTexture(const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) { - Ref<Texture> dawnTexture; - if (ConsumedError(Texture::CreateExternalImage(this, descriptor, std::move(d3dTexture), - std::move(keyedMutex), std::move(waitFences), - isSwapChainTexture, isInitialized), - &dawnTexture)) { - return nullptr; - } - return {dawnTexture}; -} - MaybeError Device::ImportSharedHandleResource(HANDLE handle, bool useKeyedMutex, ComPtr<ID3D12Resource>& d3d12Resource,
diff --git a/src/dawn/native/d3d12/DeviceD3D12.h b/src/dawn/native/d3d12/DeviceD3D12.h index 9ac8aa3..a46bf8f 100644 --- a/src/dawn/native/d3d12/DeviceD3D12.h +++ b/src/dawn/native/d3d12/DeviceD3D12.h
@@ -139,19 +139,6 @@ MutexProtected<StagingDescriptorAllocator>& GetDepthStencilViewAllocator() const; - ResultOrError<FenceAndSignalValue> CreateFence( - const d3d::ExternalImageDXGIFenceDescriptor* descriptor) override; - - ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl( - const ExternalImageDescriptor* descriptor) override; - - Ref<TextureBase> CreateD3DExternalTexture(const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) override; - void DisposeKeyedMutex(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex) override; MaybeError ImportSharedHandleResource(HANDLE handle,
diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp index 9a6fd16..530f257 100644 --- a/src/dawn/native/d3d12/TextureD3D12.cpp +++ b/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -196,31 +196,6 @@ } // static -ResultOrError<Ref<Texture>> Texture::CreateExternalImage( - Device* device, - const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized) { - Ref<Texture> dawnTexture = AcquireRef(new Texture(device, descriptor)); - DAWN_TRY(dawnTexture->InitializeAsExternalTexture(std::move(d3dTexture), std::move(keyedMutex), - 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); -} - -// static ResultOrError<Ref<Texture>> Texture::Create(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, ComPtr<ID3D12Resource> d3d12Texture) {
diff --git a/src/dawn/native/d3d12/TextureD3D12.h b/src/dawn/native/d3d12/TextureD3D12.h index 4dc1dce..476e51b 100644 --- a/src/dawn/native/d3d12/TextureD3D12.h +++ b/src/dawn/native/d3d12/TextureD3D12.h
@@ -59,14 +59,6 @@ public: static ResultOrError<Ref<Texture>> Create(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor); - static ResultOrError<Ref<Texture>> CreateExternalImage( - Device* device, - const UnpackedPtr<TextureDescriptor>& descriptor, - ComPtr<IUnknown> d3dTexture, - Ref<d3d::KeyedMutex> keyedMutex, - std::vector<FenceAndSignalValue> waitFences, - bool isSwapChainTexture, - bool isInitialized); static ResultOrError<Ref<Texture>> Create(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, ComPtr<ID3D12Resource> d3d12Texture);
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn index de09e9c..37963f1 100644 --- a/src/dawn/tests/BUILD.gn +++ b/src/dawn/tests/BUILD.gn
@@ -682,10 +682,7 @@ "dxgi.lib", ] - sources += [ - "end2end/D3DResourceWrappingTests.cpp", - "end2end/VideoViewsTests_win.cpp", - ] + sources += [ "end2end/VideoViewsTests_win.cpp" ] } if (dawn_enable_d3d12) {
diff --git a/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp b/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp deleted file mode 100644 index b45a1d9..0000000 --- a/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp +++ /dev/null
@@ -1,1300 +0,0 @@ -// Copyright 2019 The Dawn & Tint Authors -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <d3d11.h> -#include <d3d11_4.h> -#include <d3d12.h> -#include <dxgi1_4.h> -#include <wrl/client.h> - -#include <memory> -#include <mutex> -#include <thread> -#include <utility> -#include <vector> - -#include "dawn/native/D3D11Backend.h" -#include "dawn/native/D3D12Backend.h" -#include "dawn/tests/DawnTest.h" -#include "dawn/utils/ComboRenderPipelineDescriptor.h" -#include "dawn/utils/WGPUHelpers.h" - -using Microsoft::WRL::ComPtr; - -namespace dawn { -namespace { - -enum class ExternalImageType { - kSharedHandle, - kD3D11Texture, -}; - -std::ostream& operator<<(std::ostream& o, const ExternalImageType& t) { - switch (t) { - case ExternalImageType::kSharedHandle: - o << "SharedHandle"; - break; - case ExternalImageType::kD3D11Texture: - o << "D3D11Texture"; - break; - } - return o; -} - -DAWN_TEST_PARAM_STRUCT(D3D12ResourceTestParams, ExternalImageType); - -class D3DResourceTestBase : public DawnTestWithParams<D3D12ResourceTestParams> { - protected: - std::vector<wgpu::FeatureName> GetRequiredFeatures() override { - return {wgpu::FeatureName::DawnInternalUsages}; - } - - public: - void SetUp() override { - DawnTestWithParams<D3D12ResourceTestParams>::SetUp(); - - DAWN_TEST_UNSUPPORTED_IF(UsesWire()); - - // D3D11Texture external image type is only supported on D3D11 - DAWN_TEST_UNSUPPORTED_IF(IsD3D11Texture() && !IsD3D11()); - - mD3d11Device = IsD3D11Texture() ? dawn::native::d3d11::GetD3D11Device(device.Get()) - : CreateD3D11Device(); - mD3d11Device->GetImmediateContext(&mD3d11DeviceContext); - - baseDawnDescriptor.dimension = wgpu::TextureDimension::e2D; - baseDawnDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; - baseDawnDescriptor.size = {kTestWidth, kTestHeight, 1}; - baseDawnDescriptor.sampleCount = 1; - baseDawnDescriptor.mipLevelCount = 1; - baseDawnDescriptor.usage = - wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopyDst; - - baseD3dDescriptor.Width = kTestWidth; - baseD3dDescriptor.Height = kTestHeight; - baseD3dDescriptor.MipLevels = 1; - baseD3dDescriptor.ArraySize = 1; - baseD3dDescriptor.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - baseD3dDescriptor.SampleDesc.Count = 1; - baseD3dDescriptor.SampleDesc.Quality = 0; - baseD3dDescriptor.Usage = D3D11_USAGE_DEFAULT; - baseD3dDescriptor.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - baseD3dDescriptor.CPUAccessFlags = 0; - baseD3dDescriptor.MiscFlags = - D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; - } - - protected: - bool IsSharedHandle() const { - return GetParam().mExternalImageType == ExternalImageType::kSharedHandle; - } - - bool IsD3D11Texture() const { - return GetParam().mExternalImageType == ExternalImageType::kD3D11Texture; - } - - ComPtr<ID3D11Device> CreateD3D11Device() { - // Create the D3D11 device/contexts that will be used in subsequent tests - ComPtr<IDXGIAdapter> dxgiAdapter = native::d3d::GetDXGIAdapter(device.GetAdapter().Get()); - DXGI_ADAPTER_DESC adapterDesc; - - HRESULT hr = dxgiAdapter->GetDesc(&adapterDesc); - DAWN_ASSERT(hr == S_OK); - - ComPtr<IDXGIFactory4> dxgiFactory; - hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory)); - DAWN_ASSERT(hr == S_OK); - - dxgiAdapter = nullptr; - hr = dxgiFactory->EnumAdapterByLuid(adapterDesc.AdapterLuid, IID_PPV_ARGS(&dxgiAdapter)); - DAWN_ASSERT(hr == S_OK); - - ComPtr<ID3D11Device> d3d11Device; - D3D_FEATURE_LEVEL d3dFeatureLevel; - hr = ::D3D11CreateDevice(dxgiAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0, - D3D11_SDK_VERSION, &d3d11Device, &d3dFeatureLevel, nullptr); - DAWN_ASSERT(hr == S_OK); - return d3d11Device; - } - - std::unique_ptr<native::d3d::ExternalImageDXGI> CreateExternalImage( - WGPUDevice targetDevice, - ID3D11Texture2D* d3d11Texture, - const wgpu::TextureDescriptor* dawnDesc, - bool usingSharedHandle) const { - if (usingSharedHandle) { - ComPtr<IDXGIResource1> dxgiResource; - EXPECT_EQ(d3d11Texture->QueryInterface(IID_PPV_ARGS(&dxgiResource)), S_OK); - - HANDLE textureSharedHandle = nullptr; - EXPECT_EQ(dxgiResource->CreateSharedHandle( - nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, - &textureSharedHandle), - S_OK); - - native::d3d::ExternalImageDescriptorDXGISharedHandle externalImageDesc; - externalImageDesc.cTextureDescriptor = - reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc); - externalImageDesc.sharedHandle = textureSharedHandle; - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = - native::d3d::ExternalImageDXGI::Create(targetDevice, &externalImageDesc); - - // Now that we've created all of our resources, we can close the handle - // since we no longer need it. - ::CloseHandle(textureSharedHandle); - - return externalImage; - } else { - native::d3d::ExternalImageDescriptorD3D11Texture externalImageDesc; - externalImageDesc.cTextureDescriptor = - reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc); - externalImageDesc.texture = d3d11Texture; - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = - native::d3d::ExternalImageDXGI::Create(targetDevice, &externalImageDesc); - - return externalImage; - } - } - - void Wrap(const wgpu::TextureDescriptor* dawnDesc, - const D3D11_TEXTURE2D_DESC* d3dDesc, - wgpu::Texture* dawnTexture, - ID3D11Texture2D** d3d11TextureOut, - std::unique_ptr<native::d3d::ExternalImageDXGI>* externalImageOut) const { - if (IsSharedHandle()) { - WrapSharedHandle(dawnDesc, d3dDesc, dawnTexture, d3d11TextureOut, externalImageOut); - } else { - WrapD3D11Texture(dawnDesc, d3dDesc, dawnTexture, d3d11TextureOut, externalImageOut); - } - } - - void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc, - const D3D11_TEXTURE2D_DESC* d3dDesc, - wgpu::Texture* dawnTexture, - ID3D11Texture2D** d3d11TextureOut, - std::unique_ptr<native::d3d::ExternalImageDXGI>* externalImageOut) const { - ComPtr<ID3D11Texture2D> d3d11Texture; - HRESULT hr = mD3d11Device->CreateTexture2D(d3dDesc, nullptr, &d3d11Texture); - ASSERT_EQ(hr, S_OK); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = CreateExternalImage( - device.Get(), d3d11Texture.Get(), dawnDesc, /*usingSharedHandle=*/true); - - // Cannot access a non-existent external image (ex. validation error). - if (externalImage == nullptr) { - return; - } - - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(dawnDesc->usage); - - *dawnTexture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - *d3d11TextureOut = d3d11Texture.Detach(); - - if (externalImageOut != nullptr) { - *externalImageOut = std::move(externalImage); - } - } - - void WrapD3D11Texture(const wgpu::TextureDescriptor* dawnDesc, - const D3D11_TEXTURE2D_DESC* d3dDesc, - wgpu::Texture* dawnTexture, - ID3D11Texture2D** d3d11TextureOut, - std::unique_ptr<native::d3d::ExternalImageDXGI>* externalImageOut) const { - // Use the D3D11Device from WGPUDevice to create a D3D11Texture2D. So the D3D11Texture2D can - // be wrapped. - ComPtr<ID3D11Device> d3d11Device = native::d3d11::GetD3D11Device(device.Get()); - - ComPtr<ID3D11Texture2D> d3d11Texture; - HRESULT hr = d3d11Device->CreateTexture2D(d3dDesc, nullptr, &d3d11Texture); - ASSERT_EQ(hr, S_OK); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = CreateExternalImage( - device.Get(), d3d11Texture.Get(), dawnDesc, /*usingSharedHandle=*/false); - - // Cannot access a non-existent external image (ex. validation error). - if (externalImage == nullptr) { - return; - } - - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(dawnDesc->usage); - - *dawnTexture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - *d3d11TextureOut = d3d11Texture.Detach(); - - if (externalImageOut != nullptr) { - *externalImageOut = std::move(externalImage); - } - } - - static constexpr size_t kTestWidth = 10; - static constexpr size_t kTestHeight = 10; - - ComPtr<ID3D11Device> mD3d11Device; - ComPtr<ID3D11DeviceContext> mD3d11DeviceContext; - - D3D11_TEXTURE2D_DESC baseD3dDescriptor; - wgpu::TextureDescriptor baseDawnDescriptor; -}; - -// A small fixture used to initialize default data for the D3DResource validation tests. -// These tests are skipped if the harness is using the wire. -class D3DExternalImageValidation : public D3DResourceTestBase {}; - -// Test a successful wrapping of an D3DResource in a texture -TEST_P(D3DExternalImageValidation, Success) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage); - - ASSERT_NE(texture.Get(), nullptr); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); -} - -// Test a successful wrapping of an D3DResource with DawnTextureInternalUsageDescriptor -TEST_P(D3DExternalImageValidation, SuccessWithInternalUsageDescriptor) { - wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; - baseDawnDescriptor.nextInChain = &internalDesc; - internalDesc.internalUsage = wgpu::TextureUsage::CopySrc; - internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage); - - ASSERT_NE(texture.Get(), nullptr); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); -} - -// Test an error occurs if an invalid sType is the nextInChain -TEST_P(D3DExternalImageValidation, InvalidTextureDescriptor) { - wgpu::ChainedStruct chainedDescriptor; - chainedDescriptor.sType = wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel; - baseDawnDescriptor.nextInChain = &chainedDescriptor; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor mip level count isn't 1 -TEST_P(D3DExternalImageValidation, InvalidMipLevelCount) { - baseDawnDescriptor.mipLevelCount = 2; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor depth isn't 1 -TEST_P(D3DExternalImageValidation, InvalidDepth) { - baseDawnDescriptor.size.depthOrArrayLayers = 2; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor sample count isn't 1 -TEST_P(D3DExternalImageValidation, InvalidSampleCount) { - baseDawnDescriptor.sampleCount = 4; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor width doesn't match the texture's -TEST_P(D3DExternalImageValidation, InvalidWidth) { - baseDawnDescriptor.size.width = kTestWidth + 1; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor height doesn't match the texture's -TEST_P(D3DExternalImageValidation, InvalidHeight) { - baseDawnDescriptor.size.height = kTestHeight + 1; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the descriptor format isn't compatible with the D3D Resource -TEST_P(D3DExternalImageValidation, InvalidFormat) { - baseDawnDescriptor.format = wgpu::TextureFormat::R8Unorm; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the number of D3D mip levels is greater than 1. -TEST_P(D3DExternalImageValidation, InvalidNumD3DMipLevels) { - baseD3dDescriptor.MipLevels = 2; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -// Test an error occurs if the number of array levels is greater than 1. -TEST_P(D3DExternalImageValidation, InvalidD3DArraySize) { - baseD3dDescriptor.ArraySize = 2; - - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - ASSERT_DEVICE_ERROR( - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage)); - - ASSERT_EQ(texture.Get(), nullptr); -} - -class D3DExternalImageUsageTests : public D3DResourceTestBase { - protected: - // Submits a 1x1x1 copy from source to destination - void SimpleCopyTextureToTexture(wgpu::Texture source, wgpu::Texture destination) { - wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture(source, 0, {0, 0, 0}); - wgpu::ImageCopyTexture copyDst = utils::CreateImageCopyTexture(destination, 0, {0, 0, 0}); - - wgpu::Extent3D copySize = {1, 1, 1}; - - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); - wgpu::CommandBuffer commands = encoder.Finish(); - - queue.Submit(1, &commands); - } - - // Clear a texture on a given device - void ClearImage(wgpu::Texture wrappedTexture, - const wgpu::Color& clearColor, - wgpu::Device wgpuDevice) { - wgpu::TextureView wrappedView = wrappedTexture.CreateView(); - - // Submit a clear operation - utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {}); - renderPassDescriptor.cColorAttachments[0].clearValue = clearColor; - - wgpu::CommandEncoder encoder = wgpuDevice.CreateCommandEncoder(); - wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor); - pass.End(); - - wgpu::CommandBuffer commands = encoder.Finish(); - wgpu::Queue queue = wgpuDevice.GetQueue(); - queue.Submit(1, &commands); - } - - void CreateSharedD3D11Texture(const D3D11_TEXTURE2D_DESC& d3dDescriptor, - ID3D11Texture2D** d3d11TextureOut, - ID3D11Fence** d3d11FenceOut, - HANDLE* sharedHandleOut, - HANDLE* fenceSharedHandleOut) const { - ComPtr<ID3D11Texture2D> d3d11Texture; - HRESULT hr = mD3d11Device->CreateTexture2D(&d3dDescriptor, nullptr, &d3d11Texture); - ASSERT_EQ(hr, S_OK); - - ComPtr<IDXGIResource1> dxgiResource; - hr = d3d11Texture.As(&dxgiResource); - ASSERT_EQ(hr, S_OK); - - HANDLE sharedHandle; - hr = dxgiResource->CreateSharedHandle( - nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, - &sharedHandle); - ASSERT_EQ(hr, S_OK); - - HANDLE fenceSharedHandle = nullptr; - ComPtr<ID3D11Fence> d3d11Fence; - - ComPtr<ID3D11Device5> d3d11Device5; - hr = mD3d11Device.As(&d3d11Device5); - ASSERT_EQ(hr, S_OK); - - hr = d3d11Device5->CreateFence(0, D3D11_FENCE_FLAG_SHARED, IID_PPV_ARGS(&d3d11Fence)); - ASSERT_EQ(hr, S_OK); - - hr = d3d11Fence->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, &fenceSharedHandle); - ASSERT_EQ(hr, S_OK); - - *d3d11TextureOut = d3d11Texture.Detach(); - *d3d11FenceOut = d3d11Fence.Detach(); - *sharedHandleOut = sharedHandle; - *fenceSharedHandleOut = fenceSharedHandle; - } - - void ClearD3D11Texture(const wgpu::Color& clearColor, - ID3D11Texture2D* d3d11TexturePtr, - ID3D11Fence* d3d11Fence, - uint64_t fenceSignalValue) const { - ComPtr<ID3D11Texture2D> d3d11Texture = d3d11TexturePtr; - - ComPtr<IDXGIResource1> dxgiResource; - HRESULT hr = d3d11Texture.As(&dxgiResource); - ASSERT_EQ(hr, S_OK); - - ComPtr<ID3D11RenderTargetView> d3d11RTV; - hr = mD3d11Device->CreateRenderTargetView(d3d11Texture.Get(), nullptr, &d3d11RTV); - ASSERT_EQ(hr, S_OK); - - const float colorRGBA[] = { - static_cast<float>(clearColor.r), static_cast<float>(clearColor.g), - static_cast<float>(clearColor.b), static_cast<float>(clearColor.a)}; - mD3d11DeviceContext->ClearRenderTargetView(d3d11RTV.Get(), colorRGBA); - - ComPtr<ID3D11DeviceContext4> d3d11DeviceContext4; - hr = mD3d11DeviceContext.As(&d3d11DeviceContext4); - ASSERT_EQ(hr, S_OK); - // The fence starts with 0 signaled, but that won't capture the render target view clear - // above, so signal explicitly with 1 and make the next Dawn access wait on 1. - d3d11DeviceContext4->Signal(d3d11Fence, fenceSignalValue); - } - - void WaitAndWrapD3D11Texture(const wgpu::TextureDescriptor& dawnDescriptor, - ID3D11Texture2D* d3d11TexturePtr, - HANDLE sharedHandle, - HANDLE fenceSharedHandle, - uint64_t fenceWaitValue, - wgpu::Texture* dawnTextureOut, - std::unique_ptr<native::d3d::ExternalImageDXGI>* externalImageOut, - bool isInitialized) const { - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - if (IsSharedHandle()) { - native::d3d::ExternalImageDescriptorDXGISharedHandle externalImageDesc = {}; - externalImageDesc.sharedHandle = sharedHandle; - externalImageDesc.cTextureDescriptor = - reinterpret_cast<const WGPUTextureDescriptor*>(&dawnDescriptor); - - externalImage = - native::d3d::ExternalImageDXGI::Create(device.Get(), &externalImageDesc); - } else { - native::d3d::ExternalImageDescriptorD3D11Texture externalImageDesc = {}; - externalImageDesc.texture = d3d11TexturePtr; - externalImageDesc.cTextureDescriptor = - reinterpret_cast<const WGPUTextureDescriptor*>(&dawnDescriptor); - - externalImage = - native::d3d::ExternalImageDXGI::Create(device.Get(), &externalImageDesc); - } - - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = isInitialized; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(dawnDescriptor.usage); - if (fenceSharedHandle != nullptr) { - externalAccessDesc.waitFences.push_back({fenceSharedHandle, fenceWaitValue}); - } - - *dawnTextureOut = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - *externalImageOut = std::move(externalImage); - } - - void WrapAndClearD3D11Texture(const wgpu::TextureDescriptor& dawnDescriptor, - const D3D11_TEXTURE2D_DESC& d3dDescriptor, - const wgpu::Color& clearColor, - wgpu::Texture* dawnTextureOut, - ID3D11Texture2D** d3d11TextureOut, - std::unique_ptr<native::d3d::ExternalImageDXGI>* externalImageOut, - bool isInitialized = true) const { - ComPtr<ID3D11Texture2D> d3d11Texture; - ComPtr<ID3D11Fence> d3d11Fence; - HANDLE sharedHandle = nullptr; - HANDLE fenceSharedHandle = nullptr; - CreateSharedD3D11Texture(d3dDescriptor, &d3d11Texture, &d3d11Fence, &sharedHandle, - &fenceSharedHandle); - - constexpr uint64_t kFenceSignalValue = 1; - ClearD3D11Texture(clearColor, d3d11Texture.Get(), d3d11Fence.Get(), kFenceSignalValue); - - WaitAndWrapD3D11Texture(dawnDescriptor, d3d11Texture.Get(), sharedHandle, fenceSharedHandle, - /*fenceWaitValue=*/kFenceSignalValue, dawnTextureOut, - externalImageOut, isInitialized); - - *d3d11TextureOut = d3d11Texture.Detach(); - - if (fenceSharedHandle != nullptr) { - ::CloseHandle(fenceSharedHandle); - } - } - - void ExpectPixelRGBA8EQ(ID3D11Texture2D* d3d11Texture, - const wgpu::Color& color, - const native::d3d::ExternalImageDXGIFenceDescriptor* waitFence) { - D3D11_TEXTURE2D_DESC texture2DDesc; - d3d11Texture->GetDesc(&texture2DDesc); - - const CD3D11_TEXTURE2D_DESC texture2DStagingDesc( - texture2DDesc.Format, // Format - texture2DDesc.Width, // Width - texture2DDesc.Height, // Height - 1, // ArraySize - 1, // MipLevels - 0, // BindFlags - D3D11_USAGE_STAGING, // Usage - D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); // CPUAccessFlags - - ComPtr<ID3D11Texture2D> spD3DTextureStaging; - HRESULT hr = - mD3d11Device->CreateTexture2D(&texture2DStagingDesc, nullptr, &spD3DTextureStaging); - ASSERT_EQ(hr, S_OK); - - D3D11_BOX d3dRc; - d3dRc.back = 1; - d3dRc.front = 0; - d3dRc.top = 0; - d3dRc.left = 0; - d3dRc.bottom = texture2DDesc.Height; - d3dRc.right = texture2DDesc.Width; - - if (waitFence->fenceHandle != nullptr) { - ComPtr<ID3D11Device5> d3d11Device5; - mD3d11Device.As(&d3d11Device5); - ASSERT_EQ(hr, S_OK); - - ComPtr<ID3D11Fence> d3d11Fence; - hr = d3d11Device5->OpenSharedFence(waitFence->fenceHandle, IID_PPV_ARGS(&d3d11Fence)); - ASSERT_EQ(hr, S_OK); - - ComPtr<ID3D11DeviceContext4> d3d11DeviceContext4; - hr = mD3d11DeviceContext.As(&d3d11DeviceContext4); - ASSERT_EQ(hr, S_OK); - - hr = d3d11DeviceContext4->Wait(d3d11Fence.Get(), waitFence->fenceValue); - ASSERT_EQ(hr, S_OK); - } - - mD3d11DeviceContext->CopySubresourceRegion(spD3DTextureStaging.Get(), // pDstResource - 0, // DstSubresource - 0, // DstX - 0, // DstY - 0, // DstZ - d3d11Texture, // pSrcResource - 0, // SrcSubresource - &d3dRc); // pSrcBox - - D3D11_MAPPED_SUBRESOURCE mappedResource; - hr = mD3d11DeviceContext->Map(spD3DTextureStaging.Get(), 0, D3D11_MAP_READ_WRITE, 0, - &mappedResource); - ASSERT_EQ(hr, S_OK); - - const uint8_t* colorData = static_cast<uint8_t*>(mappedResource.pData); - EXPECT_EQ(colorData[0], color.r * 255u); - EXPECT_EQ(colorData[1], color.g * 255u); - EXPECT_EQ(colorData[2], color.b * 255u); - EXPECT_EQ(colorData[3], color.a * 255u); - - mD3d11DeviceContext->Unmap(spD3DTextureStaging.Get(), 0); - } -}; - -// 1. Create and clear a D3D11 texture -// 2. Copy the wrapped texture to another dawn texture -// 3. Readback the copied texture and ensure the color matches the original clear color. -TEST_P(D3DExternalImageUsageTests, ClearInD3D11CopyAndReadbackInD3D) { - const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f}; - wgpu::Texture dawnSrcTexture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, clearColor, &dawnSrcTexture, - &d3d11Texture, &externalImage); - ASSERT_NE(dawnSrcTexture.Get(), nullptr); - - // Create a texture on the device and copy the source texture to it. - wgpu::Texture dawnCopyDestTexture = device.CreateTexture(&baseDawnDescriptor); - SimpleCopyTextureToTexture(dawnSrcTexture, dawnCopyDestTexture); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(dawnSrcTexture.Get(), &signalFence); - dawnSrcTexture.Destroy(); - - // Readback the destination texture and ensure it contains the colors we used - // to clear the source texture on the D3D device. - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(clearColor.r * 255u, clearColor.g * 255u, - clearColor.b * 255u, clearColor.a * 255u), - dawnCopyDestTexture, 0, 0); -} - -// 1. Create and clear a D3D11 texture -// 2. Readback the wrapped texture and ensure the color matches the original clear color. -TEST_P(D3DExternalImageUsageTests, ClearInD3D11ReadbackInD3D) { - const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f}; - wgpu::Texture dawnTexture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, clearColor, &dawnTexture, - &d3d11Texture, &externalImage); - ASSERT_NE(dawnTexture.Get(), nullptr); - - // Readback the destination texture and ensure it contains the colors we used - // to clear the source texture on the D3D device. - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(clearColor.r * 255, clearColor.g * 255, clearColor.b * 255, - clearColor.a * 255), - dawnTexture, 0, 0); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(dawnTexture.Get(), &signalFence); - dawnTexture.Destroy(); -} - -// 1. Create and clear a D3D11 texture -// 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. -TEST_P(D3DExternalImageUsageTests, ClearInD3DReadbackInD3D11) { - // TODO(crbug.com/dawn/735): This test appears to hang for - // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. - DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); - - const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f}; - wgpu::Texture dawnTexture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, d3d11ClearColor, &dawnTexture, - &d3d11Texture, &externalImage, /*isInitialized=*/true); - ASSERT_NE(dawnTexture.Get(), nullptr); - - const wgpu::Color d3dClearColor{0.0f, 0.0f, 1.0f, 1.0f}; - ClearImage(dawnTexture, d3dClearColor, device); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(dawnTexture.Get(), &signalFence); - dawnTexture.Destroy(); - - // 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 - // color matches the D3D12 clear color. - ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor, &signalFence); -} - -// 1. Create and clear a D3D11 texture -// 2. Wrap it in a Dawn texture and clear the texture to two different colors. -// 3. Readback the texture with D3D11. -// 4. Verify the readback color was the final color cleared. -TEST_P(D3DExternalImageUsageTests, ClearTwiceInD3DReadbackInD3D11) { - // TODO(crbug.com/dawn/735): This test appears to hang for - // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. - DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); - - const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f}; - wgpu::Texture dawnTexture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, d3d11ClearColor, &dawnTexture, - &d3d11Texture, &externalImage, /*isInitialized=*/true); - ASSERT_NE(dawnTexture.Get(), nullptr); - - const wgpu::Color d3dClearColor1{0.0f, 0.0f, 1.0f, 1.0f}; - ClearImage(dawnTexture, d3dClearColor1, device); - - const wgpu::Color d3dClearColor2{0.0f, 1.0f, 1.0f, 1.0f}; - ClearImage(dawnTexture, d3dClearColor2, device); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(dawnTexture.Get(), &signalFence); - dawnTexture.Destroy(); - - // 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 - // color matches the last D3D12 clear color. - ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor2, &signalFence); -} - -// 1. Create and clear a D3D11 texture with clearColor -// 2. Import the texture with isInitialized = false -// 3. Verify clearColor is not visible in wrapped texture -TEST_P(D3DExternalImageUsageTests, UninitializedTextureIsCleared) { - const wgpu::Color clearColor{1.0f, 0.0f, 0.0f, 1.0f}; - wgpu::Texture dawnTexture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, clearColor, &dawnTexture, - &d3d11Texture, &externalImage, /*isInitialized=*/false); - ASSERT_NE(dawnTexture.Get(), nullptr); - - // Readback the destination texture and ensure it contains the colors we used - // to clear the source texture on the D3D device. - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(0, 0, 0, 0), dawnTexture, 0, 0); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(dawnTexture.Get(), &signalFence); - dawnTexture.Destroy(); -} - -// 1. Create an external image from the DX11 texture. -// 2. Produce two Dawn textures from the external image. -// 3. Clear each Dawn texture and verify the texture was cleared to a unique color. -TEST_P(D3DExternalImageUsageTests, ReuseExternalImage) { - // Create the first Dawn texture then clear it to red. - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - { - const wgpu::Color solidRed{1.0f, 0.0f, 0.0f, 1.0f}; - ASSERT_NE(texture.Get(), nullptr); - ClearImage(texture.Get(), solidRed, device); - - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(0xFF, 0, 0, 0xFF), texture.Get(), 0, 0); - } - - // Once finished with the first texture, destroy it so we may re-acquire the external image - // again. - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - - // Create another Dawn texture then clear it with another color. - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = true; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(baseDawnDescriptor.usage); - externalAccessDesc.waitFences.push_back(signalFence); - - texture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - - // Check again that the new texture is still red - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(0xFF, 0, 0, 0xFF), texture.Get(), 0, 0); - - // Clear the new texture to blue - { - const wgpu::Color solidBlue{0.0f, 0.0f, 1.0f, 1.0f}; - ASSERT_NE(texture.Get(), nullptr); - ClearImage(texture.Get(), solidBlue, device); - - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(0, 0, 0xFF, 0xFF), texture.Get(), 0, 0); - } - - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); -} - -TEST_P(D3DExternalImageUsageTests, ConcurrentExternalImageReadAccess) { - wgpu::Device device2 = CreateDevice(); - EXPECT_NE(device2, nullptr); - - wgpu::Device device3 = CreateDevice(); - EXPECT_NE(device3, nullptr); - - wgpu::Device device4 = CreateDevice(); - EXPECT_NE(device4, nullptr); - - wgpu::Device device5 = CreateDevice(); - EXPECT_NE(device5, nullptr); - - // Create Dawn texture with write access, then clear it to red. - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - - // Clear to red. - { - const wgpu::Color solidRed{1.0f, 0.0f, 0.0f, 1.0f}; - ASSERT_NE(texture.Get(), nullptr); - ClearImage(texture.Get(), solidRed, device); - } - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage2 = CreateExternalImage( - device2.Get(), d3d11Texture.Get(), &baseDawnDescriptor, /*usingSharedHandle=*/true); - EXPECT_NE(externalImage2, nullptr); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage3 = CreateExternalImage( - device3.Get(), d3d11Texture.Get(), &baseDawnDescriptor, /*usingSharedHandle=*/true); - EXPECT_NE(externalImage3, nullptr); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage4 = CreateExternalImage( - device4.Get(), d3d11Texture.Get(), &baseDawnDescriptor, /*usingSharedHandle=*/true); - EXPECT_NE(externalImage4, nullptr); - - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage5 = CreateExternalImage( - device5.Get(), d3d11Texture.Get(), &baseDawnDescriptor, /*usingSharedHandle=*/true); - EXPECT_NE(externalImage5, nullptr); - - // Create two Dawn textures for concurrent read on second device. - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = true; - externalAccessDesc.usage = WGPUTextureUsage_CopySrc; - externalAccessDesc.waitFences = {signalFence}; - - // Concurrent read access on device 2 and 3. - native::d3d::ExternalImageDXGIFenceDescriptor signalFence2; - native::d3d::ExternalImageDXGIFenceDescriptor signalFence3; - { - wgpu::Texture texture2 = - wgpu::Texture::Acquire(externalImage2->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture2, nullptr); - - wgpu::Texture texture3 = - wgpu::Texture::Acquire(externalImage3->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture3, nullptr); - - // Check again that the new textures are also red. - const utils::RGBA8 solidRed(0xFF, 0, 0, 0xFF); - EXPECT_TEXTURE_EQ(device2, solidRed, texture2.Get(), {0, 0}); - EXPECT_TEXTURE_EQ(device3, solidRed, texture3.Get(), {0, 0}); - - externalImage2->EndAccess(texture2.Get(), &signalFence2); - texture2.Destroy(); - - externalImage3->EndAccess(texture3.Get(), &signalFence3); - texture3.Destroy(); - } - - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(baseDawnDescriptor.usage); - externalAccessDesc.waitFences = {signalFence2, signalFence3}; - - // Exclusive read-write access on device 4. - native::d3d::ExternalImageDXGIFenceDescriptor signalFence4; - { - wgpu::Texture texture4 = - wgpu::Texture::Acquire(externalImage4->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture4, nullptr); - - const utils::RGBA8 solidRed(0xFF, 0, 0, 0xFF); - EXPECT_TEXTURE_EQ(device4, solidRed, texture4.Get(), {0, 0}); - - // Clear to blue. - const wgpu::Color solidBlue{0.0f, 0.0f, 1.0f, 1.0f}; - ASSERT_NE(texture4.Get(), nullptr); - ClearImage(texture4.Get(), solidBlue, device4); - - externalImage4->EndAccess(texture4.Get(), &signalFence4); - texture4.Destroy(); - } - - externalAccessDesc.waitFences = {signalFence4}; - - // Import texture on device 5, but do nothing with it. - native::d3d::ExternalImageDXGIFenceDescriptor signalFence5; - { - wgpu::Texture texture5 = - wgpu::Texture::Acquire(externalImage5->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture5, nullptr); - externalImage5->EndAccess(texture5.Get(), &signalFence5); - texture5.Destroy(); - } - - externalAccessDesc.usage = WGPUTextureUsage_CopySrc; - externalAccessDesc.waitFences = {signalFence5}; - - // Concurrent read access on device 1 (twice), 2 and 3. - { - texture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture, nullptr); - - wgpu::Texture texture1 = - wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture1, nullptr); - - wgpu::Texture texture2 = - wgpu::Texture::Acquire(externalImage2->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture2, nullptr); - - wgpu::Texture texture3 = - wgpu::Texture::Acquire(externalImage3->BeginAccess(&externalAccessDesc)); - EXPECT_NE(texture3, nullptr); - - // Check again that the new textures are now blue. - const utils::RGBA8 solidBlue(0, 0, 0xFF, 0xFF); - EXPECT_TEXTURE_EQ(device, solidBlue, texture.Get(), {0, 0}); - EXPECT_TEXTURE_EQ(device, solidBlue, texture1.Get(), {0, 0}); - EXPECT_TEXTURE_EQ(device2, solidBlue, texture2.Get(), {0, 0}); - EXPECT_TEXTURE_EQ(device3, solidBlue, texture3.Get(), {0, 0}); - - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - - externalImage->EndAccess(texture1.Get(), &signalFence); - texture1.Destroy(); - - externalImage2->EndAccess(texture2.Get(), &signalFence2); - texture2.Destroy(); - - externalImage3->EndAccess(texture3.Get(), &signalFence3); - texture3.Destroy(); - } -} - -// Produce a new texture with a usage not specified in the external image. -TEST_P(D3DExternalImageUsageTests, ExternalImageUsage) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - ASSERT_NE(texture.Get(), nullptr); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = true; - externalAccessDesc.usage = WGPUTextureUsage_StorageBinding; - externalAccessDesc.waitFences.push_back(signalFence); - texture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - ASSERT_EQ(texture.Get(), nullptr); - - externalAccessDesc.usage = WGPUTextureUsage_TextureBinding; - texture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - ASSERT_NE(texture.Get(), nullptr); - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); -} - -// Verify external image cannot be used after its creating device is destroyed. -TEST_P(D3DExternalImageUsageTests, InvalidateExternalImageOnDestroyDevice) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - - // Create the Dawn texture then clear it to red. - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - const wgpu::Color solidRed{1.0f, 0.0f, 0.0f, 1.0f}; - ASSERT_NE(texture.Get(), nullptr); - ClearImage(texture.Get(), solidRed, device); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - - // Do not readback pixels since that requires device to be alive during DawnTest::TearDown(). - DestroyDevice(); - - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = true; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(baseDawnDescriptor.usage); - - EXPECT_EQ(wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)), nullptr); -} - -// Verify external image cannot be created after the target device is destroyed. -TEST_P(D3DExternalImageUsageTests, DisallowExternalImageAfterDestroyDevice) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - - DestroyDevice(); - - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - - EXPECT_EQ(externalImage, nullptr); - EXPECT_EQ(texture, nullptr); -} - -// Verify there is no error generated when we destroy an external image with CommandRecordingContext -// open. -TEST_P(D3DExternalImageUsageTests, CallWriteBufferBeforeDestroyingExternalImage) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - - // In utils::CreateBufferFromData() we will call queue.WriteBuffer(), which will make a - // recording context pending. - constexpr uint32_t kExpected = 1u; - wgpu::Buffer buffer = utils::CreateBufferFromData( - device, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst, {kExpected}); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); - externalImage = nullptr; - - EXPECT_BUFFER_U32_EQ(kExpected, buffer, 0); -} - -// Test that texture descriptor view formats are passed to the backend for wrapped external -// textures, and that contents may be reinterpreted as sRGB. -TEST_P(D3DExternalImageUsageTests, SRGBReinterpretation) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - - // The texture will be reinterpreted as sRGB. - wgpu::TextureViewDescriptor viewDesc = {}; - viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; - - wgpu::TextureDescriptor textureDesc = baseDawnDescriptor; - textureDesc.viewFormatCount = 1; - textureDesc.viewFormats = &viewDesc.format; - // Check that the base format is not sRGB. - ASSERT_EQ(textureDesc.format, wgpu::TextureFormat::RGBA8Unorm); - - // Wrap a shared handle as a Dawn texture. - WrapSharedHandle(&textureDesc, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage); - ASSERT_NE(texture.Get(), nullptr); - - // Submit a clear operation to sRGB value rgb(234, 51, 35). - { - utils::ComboRenderPassDescriptor renderPassDescriptor({texture.CreateView(&viewDesc)}, {}); - renderPassDescriptor.cColorAttachments[0].clearValue = {234.0 / 255.0, 51.0 / 255.0, - 35.0 / 255.0, 1.0}; - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - encoder.BeginRenderPass(&renderPassDescriptor).End(); - - wgpu::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); - } - - // Expect the contents to be approximately rgb(246 124 104) - EXPECT_PIXEL_RGBA8_BETWEEN( // - utils::RGBA8(245, 123, 103, 255), // - utils::RGBA8(247, 125, 105, 255), texture, 0, 0); -} - -class D3DExternalImageMultithreadTests : public D3DExternalImageUsageTests { - protected: - std::vector<wgpu::FeatureName> GetRequiredFeatures() override { - std::vector<wgpu::FeatureName> features; - // TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet. - if (!UsesWire()) { - features.push_back(wgpu::FeatureName::ImplicitDeviceSynchronization); - } - return features; - } - - void SetUp() override { - D3DExternalImageUsageTests::SetUp(); - // TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet. - DAWN_TEST_UNSUPPORTED_IF(UsesWire()); - - if (IsD3D11() && IsD3D11Texture()) { - // For this configuration, the d3d1Device will be used from more than one thread. - auto d3d11Device = dawn::native::d3d11::GetD3D11Device(device.Get()); - ComPtr<ID3D11Multithread> multithread; - d3d11Device.As(&multithread); - multithread->SetMultithreadProtected(TRUE); - } - } -}; - -// Test the destroy device before destroying the external image won't cause deadlock. -TEST_P(D3DExternalImageMultithreadTests, DestroyDeviceBeforeImageNoDeadLock) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage); - - ASSERT_NE(texture.Get(), nullptr); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - EXPECT_TRUE(externalImage->IsValid()); - - // Destroy device, it should destroy image internally. - device.Destroy(); - EXPECT_FALSE(externalImage->IsValid()); -} - -// Test that using the external image and destroying the device simultaneously on different threads -// won't race. -TEST_P(D3DExternalImageMultithreadTests, DestroyDeviceAndUseImageInParallel) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - Wrap(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, &externalImage); - - ASSERT_NE(texture.Get(), nullptr); - EXPECT_TRUE(externalImage->IsValid()); - - std::thread thread1([&] { - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - }); - - std::thread thread2([&] { - // Destroy device, it should destroy image internally. - device.Destroy(); - EXPECT_FALSE(externalImage->IsValid()); - }); - - thread1.join(); - thread2.join(); -} - -// 1. Create and clear a D3D11 texture -// 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. -TEST_P(D3DExternalImageMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads) { - // TODO(crbug.com/dawn/735): This test appears to hang for - // D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled. - DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled()); - - const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f}; - const wgpu::Color d3dClearColor{0.0f, 0.0f, 1.0f, 1.0f}; - - constexpr uint64_t kD3D11FenceSignalValue = 1; - - ComPtr<ID3D11Texture2D> d3d11Texture; - ComPtr<ID3D11Fence> d3d11Fence; - HANDLE sharedHandle = nullptr; - HANDLE fenceSharedHandle = nullptr; - CreateSharedD3D11Texture(baseD3dDescriptor, &d3d11Texture, &d3d11Fence, &sharedHandle, - &fenceSharedHandle); - - native::d3d::ExternalImageDXGIFenceDescriptor d3dSignalFence; - - std::thread d3dThread([=, &d3dSignalFence] { - wgpu::Texture dawnTexture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WaitAndWrapD3D11Texture(baseDawnDescriptor, d3d11Texture.Get(), sharedHandle, - fenceSharedHandle, - /*fenceWaitValue=*/kD3D11FenceSignalValue, &dawnTexture, - &externalImage, /*isInitialized=*/true); - - ASSERT_NE(dawnTexture.Get(), nullptr); - - EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(d3d11ClearColor.r * 255, d3d11ClearColor.g * 255, - d3d11ClearColor.b * 255, d3d11ClearColor.a * 255), - dawnTexture, 0, 0); - - ClearImage(dawnTexture, d3dClearColor, device); - - externalImage->EndAccess(dawnTexture.Get(), &d3dSignalFence); - - dawnTexture.Destroy(); - }); - - ClearD3D11Texture(d3d11ClearColor, d3d11Texture.Get(), d3d11Fence.Get(), - /*fenceSignalValue=*/kD3D11FenceSignalValue); - - d3dThread.join(); - // 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 - // color matches the D3D12 clear color. - ExpectPixelRGBA8EQ(d3d11Texture.Get(), d3dClearColor, &d3dSignalFence); - - if (sharedHandle != nullptr) { - ::CloseHandle(sharedHandle); - } - - if (fenceSharedHandle != nullptr) { - ::CloseHandle(fenceSharedHandle); - } -} - -class D3DExternalImageD3D11TextureValidation : public D3DResourceTestBase {}; - -// Test a successful wrapping of an D3D11Texture2D in a texture -TEST_P(D3DExternalImageD3D11TextureValidation, Success) { - wgpu::Texture texture; - ComPtr<ID3D11Texture2D> d3d11Texture; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage; - WrapD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture, - &externalImage); - - ASSERT_NE(texture.Get(), nullptr); - - native::d3d::ExternalImageDXGIFenceDescriptor signalFence; - externalImage->EndAccess(texture.Get(), &signalFence); - texture.Destroy(); -} - -TEST_P(D3DExternalImageD3D11TextureValidation, InvalidD3D11Texture) { - ComPtr<ID3D11Device> d3d11Device = CreateD3D11Device(); - ComPtr<ID3D11Texture2D> d3d11Texture; - HRESULT hr = d3d11Device->CreateTexture2D(&baseD3dDescriptor, nullptr, &d3d11Texture); - ASSERT_EQ(hr, S_OK); - - // Import texture created from other device will fail. - ASSERT_DEVICE_ERROR({ - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = CreateExternalImage( - device.Get(), d3d11Texture.Get(), &baseDawnDescriptor, /*usingSharedHandle=*/false); - - ASSERT_EQ(externalImage.get(), nullptr); - }); -} - -DAWN_INSTANTIATE_TEST_P(D3DExternalImageValidation, - {D3D11Backend(), D3D12Backend()}, - {ExternalImageType::kSharedHandle, ExternalImageType::kD3D11Texture}); -DAWN_INSTANTIATE_TEST_P(D3DExternalImageUsageTests, - {D3D11Backend(), D3D12Backend()}, - {ExternalImageType::kSharedHandle, ExternalImageType::kD3D11Texture}); -DAWN_INSTANTIATE_TEST_P(D3DExternalImageMultithreadTests, - {D3D11Backend(), D3D12Backend()}, - {ExternalImageType::kSharedHandle, ExternalImageType::kD3D11Texture}); -DAWN_INSTANTIATE_TEST_P(D3DExternalImageD3D11TextureValidation, - {D3D11Backend()}, - {ExternalImageType::kD3D11Texture}); - -} // anonymous namespace -} // namespace dawn
diff --git a/src/dawn/tests/end2end/VideoViewsTests.cpp b/src/dawn/tests/end2end/VideoViewsTests.cpp index 71bad9e..20f6af9 100644 --- a/src/dawn/tests/end2end/VideoViewsTests.cpp +++ b/src/dawn/tests/end2end/VideoViewsTests.cpp
@@ -75,6 +75,17 @@ requiredFeatures.push_back(wgpu::FeatureName::SharedFenceMTLSharedEvent); } + // Required for the Win tests. + if (SupportsFeatures({wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D})) { + requiredFeatures.push_back(wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D); + } + if (SupportsFeatures({wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle})) { + requiredFeatures.push_back(wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle); + } + if (SupportsFeatures({wgpu::FeatureName::SharedFenceDXGISharedHandle})) { + requiredFeatures.push_back(wgpu::FeatureName::SharedFenceDXGISharedHandle); + } + mIsMultiPlanarFormatP010Supported = SupportsFeatures({wgpu::FeatureName::MultiPlanarFormatP010}); if (mIsMultiPlanarFormatP010Supported) { @@ -513,7 +524,7 @@ DAWN_TEST_UNSUPPORTED_IF(!IsFormatSupported()); mBackend = VideoViewsTestBackend::Create(); - mBackend->OnSetUp(device.Get()); + mBackend->OnSetUp(device); } void TearDown() override { @@ -1465,12 +1476,19 @@ // Tests creating a texture with a multi-plane format. TEST_P(VideoViewsValidationTests, RenderAttachmentInvalid) { + // "Invalid Texture" error is expected if failed to create the video texture. + EXPECT_CALL(mDeviceErrorCallback, Call(testing::Ne(WGPUErrorType_NoError), + testing::HasSubstr("Invalid Texture"), device.Get())) + .Times(testing::AnyNumber()); + // multi-planar formats are NOT allowed to be renderable by default and require // Feature::MultiPlanarRenderTargets. - ASSERT_DEVICE_ERROR(auto platformTexture = mBackend->CreateVideoTextureForTest( - GetFormat(), wgpu::TextureUsage::RenderAttachment, - /*isCheckerboard*/ true, - /*initialized*/ true)); + // "RenderAttachment is incompatible with the non-renderable format" error is expected. + ASSERT_DEVICE_ERROR_MSG(auto platformTexture = mBackend->CreateVideoTextureForTest( + GetFormat(), wgpu::TextureUsage::RenderAttachment, + /*isCheckerboard*/ true, + /*initialized*/ true), + testing::HasSubstr("is incompatible")); mBackend->DestroyVideoTextureForTest(std::move(platformTexture)); }
diff --git a/src/dawn/tests/end2end/VideoViewsTests.h b/src/dawn/tests/end2end/VideoViewsTests.h index 7afa002..f498443 100644 --- a/src/dawn/tests/end2end/VideoViewsTests.h +++ b/src/dawn/tests/end2end/VideoViewsTests.h
@@ -47,7 +47,7 @@ virtual ~VideoViewsTestBackend(); - virtual void OnSetUp(WGPUDevice device) = 0; + virtual void OnSetUp(const wgpu::Device& device) = 0; virtual void OnTearDown() {} class PlatformTexture {
diff --git a/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp b/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp index 7538390..a290726 100644 --- a/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp +++ b/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp
@@ -79,8 +79,8 @@ class VideoViewsTestBackendGbm : public VideoViewsTestBackend { public: - void OnSetUp(WGPUDevice device) override { - mWGPUDevice = device; + void OnSetUp(const wgpu::Device& device) override { + mWGPUDevice = device.Get(); mGbmDevice = CreateGbmDevice(); }
diff --git a/src/dawn/tests/end2end/VideoViewsTests_mac.cpp b/src/dawn/tests/end2end/VideoViewsTests_mac.cpp index 135bd76..1d5ca65 100644 --- a/src/dawn/tests/end2end/VideoViewsTests_mac.cpp +++ b/src/dawn/tests/end2end/VideoViewsTests_mac.cpp
@@ -56,7 +56,7 @@ class VideoViewsTestBackendIOSurface : public VideoViewsTestBackend { public: - void OnSetUp(WGPUDevice device) override { mWGPUDevice = device; } + void OnSetUp(const wgpu::Device& device) override { mWGPUDevice = device; } private: std::unique_ptr<VideoViewsTestBackend::PlatformTexture> CreateVideoTextureForTest( @@ -110,19 +110,9 @@ wgpu::SharedTextureMemoryDescriptor desc; desc.nextInChain = &ioSurfaceDesc; - auto device = wgpu::Device(mWGPUDevice); - auto sharedTextureMemory = device.ImportSharedTextureMemory(&desc); + auto sharedTextureMemory = mWGPUDevice.ImportSharedTextureMemory(&desc); - // Some tests create a texture that is invalid in some way and verify - // that an error is seen. These tests fail if multiple errors are seen, - // so swallow any error that is generated by creating the texture in - // favor of surfacing errors generated by the BeginAccess() call below. - // Any error generated when creating the texture will be resurfaced when - // calling BeginAccess() as the texture will be invalid, but there are - // also errors that surface only on the BeginAccess() call. - device.PushErrorScope(wgpu::ErrorFilter::Validation); auto texture = sharedTextureMemory.CreateTexture(&textureDesc); - device.PopErrorScope([](WGPUErrorType type, const char*, void* userdataPtr) {}, nullptr); // Invoke BeginAccess() on the texture to ensure that it can be used by // the test. We will end the access when the texture is destroyed @@ -130,31 +120,17 @@ wgpu::SharedTextureMemoryBeginAccessDescriptor beginAccessDesc; beginAccessDesc.initialized = initialized; beginAccessDesc.fenceCount = 0; - sharedTextureMemory.BeginAccess(texture, &beginAccessDesc); + bool success = sharedTextureMemory.BeginAccess(texture, &beginAccessDesc); - return std::make_unique<PlatformTextureIOSurface>(std::move(texture), - std::move(sharedTextureMemory)); + return success ? std::make_unique<PlatformTextureIOSurface>(std::move(texture), + std::move(sharedTextureMemory)) + : nullptr; } void DestroyVideoTextureForTest( - std::unique_ptr<VideoViewsTestBackend::PlatformTexture>&& platformTexture) override { - auto device = wgpu::Device(mWGPUDevice); - auto platformTextureIOSurface = - static_cast<PlatformTextureIOSurface*>(platformTexture.get()); - wgpu::SharedTextureMemoryEndAccessState endAccessState; + std::unique_ptr<VideoViewsTestBackend::PlatformTexture>&& platformTexture) override {} - // Tests of error cases will pass invalid textures here, for which the - // below EndAccess() call will generate an error. However, the tests do - // not listen for an error happening in this call (and errors are not - // generated on other platforms that are not using SharedTextureMemory). - // Hence, we swallow the error here to avoid spurious test failures. - device.PushErrorScope(wgpu::ErrorFilter::Validation); - platformTextureIOSurface->mSharedTextureMemory.EndAccess(platformTexture->wgpuTexture, - &endAccessState); - device.PopErrorScope([](WGPUErrorType type, const char*, void* userdataPtr) {}, nullptr); - } - - WGPUDevice mWGPUDevice = nullptr; + wgpu::Device mWGPUDevice = nullptr; }; } // anonymous namespace
diff --git a/src/dawn/tests/end2end/VideoViewsTests_win.cpp b/src/dawn/tests/end2end/VideoViewsTests_win.cpp index 03ad4a0..4f2054e 100644 --- a/src/dawn/tests/end2end/VideoViewsTests_win.cpp +++ b/src/dawn/tests/end2end/VideoViewsTests_win.cpp
@@ -38,7 +38,7 @@ #include "VideoViewsTests.h" #include "dawn/common/Assert.h" -#include "dawn/native/D3D12Backend.h" +#include "dawn/native/D3DBackend.h" #include "dawn/utils/TextureUtils.h" namespace dawn { @@ -58,12 +58,12 @@ public: ~VideoViewsTestBackendWin() override = default; - void OnSetUp(WGPUDevice device) override { + void OnSetUp(const wgpu::Device& device) override { mWGPUDevice = device; // Create the D3D11 device/contexts that will be used in subsequent tests ComPtr<IDXGIAdapter> dxgiAdapter = - native::d3d::GetDXGIAdapter(wgpuDeviceGetAdapter(device)); + native::d3d::GetDXGIAdapter(wgpuDeviceGetAdapter(device.Get())); ComPtr<ID3D11Device> d3d11Device; D3D_FEATURE_LEVEL d3dFeatureLevel; @@ -203,45 +203,42 @@ DAWN_ASSERT(hr == S_OK); // Open the DX11 texture in Dawn from the shared handle and return it as a WebGPU texture. - native::d3d::ExternalImageDescriptorDXGISharedHandle externalImageDesc; - externalImageDesc.cTextureDescriptor = - reinterpret_cast<const WGPUTextureDescriptor*>(&textureDesc); - externalImageDesc.sharedHandle = sharedHandle; + wgpu::SharedTextureMemoryDXGISharedHandleDescriptor sharedHandleDesc{}; + sharedHandleDesc.handle = sharedHandle; - std::unique_ptr<native::d3d::ExternalImageDXGI> externalImage = - native::d3d::ExternalImageDXGI::Create(mWGPUDevice, &externalImageDesc); + wgpu::SharedTextureMemoryDescriptor desc; + desc.nextInChain = &sharedHandleDesc; + auto sharedTextureMemory = mWGPUDevice.ImportSharedTextureMemory(&desc); // Handle is no longer needed once resources are created. ::CloseHandle(sharedHandle); - if (!externalImage) { - // Failed to create external image. Return early and close outstanding handles. - // Otherwise we'll dereference a nullptr below. - ::CloseHandle(fenceSharedHandle); - return nullptr; - } + wgpu::SharedFenceDXGISharedHandleDescriptor dxgiFenceDesc{}; + dxgiFenceDesc.handle = fenceSharedHandle; + wgpu::SharedFenceDescriptor fenceDesc{}; + fenceDesc.nextInChain = &dxgiFenceDesc; + auto wgpuFence = mWGPUDevice.ImportSharedFence(&fenceDesc); + uint64_t signaled_value = 1; - native::d3d::ExternalImageDXGIFenceDescriptor fenceDesc; - fenceDesc.fenceHandle = fenceSharedHandle; - fenceDesc.fenceValue = 1; + wgpu::SharedTextureMemoryBeginAccessDescriptor beginDesc{}; + beginDesc.initialized = initialized; + beginDesc.concurrentRead = false; + beginDesc.fenceCount = 1; + beginDesc.fences = &wgpuFence; + beginDesc.signaledValues = &signaled_value; - native::d3d::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc; - externalAccessDesc.isInitialized = initialized; - externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(textureDesc.usage); - externalAccessDesc.waitFences = {}; - - auto wgpuTexture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc)); - + auto wgpuTexture = sharedTextureMemory.CreateTexture(&textureDesc); + bool success = sharedTextureMemory.BeginAccess(wgpuTexture, &beginDesc); // Fence handle is no longer needed after begin access. ::CloseHandle(fenceSharedHandle); - return std::make_unique<PlatformTextureWin>(std::move(wgpuTexture)); + return success ? std::make_unique<PlatformTextureWin>(std::move(wgpuTexture)) : nullptr; } void DestroyVideoTextureForTest( - std::unique_ptr<VideoViewsTestBackend::PlatformTexture>&& PlatformTexture) override {} + std::unique_ptr<VideoViewsTestBackend::PlatformTexture>&& platformTexture) override {} - WGPUDevice mWGPUDevice = nullptr; + wgpu::Device mWGPUDevice = nullptr; ComPtr<ID3D11Device> mD3d11Device; };