d3d12: Remove keyed mutex support

Keyed mutex support was deprecated and the only known client using it,
Chromium, has migrated to fences. Remove all related keyed mutex related
code and tests. The useFenceSynchronization field is still present in
the external image descriptor since it's set by Chromium (to true) -
it'll be removed once Chromium stops setting it.

Bug: dawn:1612
Change-Id: Iaec3c16b18bb8ddbde55a7f54eaf4b944d0f06c6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129300
Reviewed-by: Austin Eng <enga@chromium.org>
Auto-Submit: Sunny Sachanandani <sunnyps@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Sunny Sachanandani 2023-04-27 14:46:56 +00:00 committed by Dawn LUCI CQ
parent df218948ba
commit c820dcc53e
17 changed files with 110 additions and 568 deletions

View File

@ -30,7 +30,6 @@ struct ID3D12Resource;
namespace dawn::native::d3d12 {
class D3D11on12ResourceCache;
class Device;
class ExternalImageDXGIImpl;
@ -52,13 +51,11 @@ struct DAWN_NATIVE_EXPORT ExternalImageDescriptorDXGISharedHandle : ExternalImag
// Note: SharedHandle must be a handle to a texture object.
HANDLE sharedHandle = nullptr;
// Whether fence synchronization should be used instead of texture's keyed mutex.
// Deprecated: Fence synchronization is always used after keyed mutex support was removed.
// TODO(dawn:1612): Remove once Chromium stops setting this.
bool useFenceSynchronization = false;
};
// Keyed mutex acquire/release uses a fixed key of 0 to match Chromium behavior.
constexpr UINT64 kDXGIKeyedMutexAcquireReleaseKey = 0;
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).
@ -79,16 +76,6 @@ struct DAWN_NATIVE_EXPORT ExternalImageDXGIBeginAccessDescriptor {
bool isSwapChainTexture = false;
};
// TODO(dawn:576): Remove after changing Chromium code to use the new struct name.
struct DAWN_NATIVE_EXPORT ExternalImageAccessDescriptorDXGIKeyedMutex
: ExternalImageDXGIBeginAccessDescriptor {
public:
// TODO(chromium:1241533): Remove deprecated keyed mutex params after removing associated
// code from Chromium - we use a fixed key of 0 for acquire and release everywhere now.
uint64_t acquireMutexKey;
uint64_t releaseMutexKey;
};
class DAWN_NATIVE_EXPORT ExternalImageDXGI {
public:
~ExternalImageDXGI();
@ -97,17 +84,13 @@ class DAWN_NATIVE_EXPORT ExternalImageDXGI {
WGPUDevice device,
const ExternalImageDescriptorDXGISharedHandle* descriptor);
// Returns true if the external image resources are still valid, otherwise ProduceTexture() is
// Returns true if the external image resources are still valid, otherwise BeginAccess() is
// guaranteed to fail e.g. after device destruction.
bool IsValid() const;
// TODO(sunnyps): |device| is ignored - remove after Chromium migrates to BeginAccess().
WGPUTexture ProduceTexture(WGPUDevice device,
const ExternalImageDXGIBeginAccessDescriptor* descriptor);
// Creates WGPUTexture wrapping the DXGI shared handle. The provided wait fences or the
// texture's keyed mutex will be synchronized before using the texture in any command lists.
// Empty fences (nullptr handle) are ignored for convenience (EndAccess can return such fences).
// 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

View File

@ -491,8 +491,6 @@ source_set("sources") {
"d3d12/CommandRecordingContext.h",
"d3d12/ComputePipelineD3D12.cpp",
"d3d12/ComputePipelineD3D12.h",
"d3d12/D3D11on12Util.cpp",
"d3d12/D3D11on12Util.h",
"d3d12/D3D12Info.cpp",
"d3d12/D3D12Info.h",
"d3d12/DeviceD3D12.cpp",

View File

@ -348,8 +348,6 @@ if (DAWN_ENABLE_D3D12)
"d3d12/CommandRecordingContext.h"
"d3d12/ComputePipelineD3D12.cpp"
"d3d12/ComputePipelineD3D12.h"
"d3d12/D3D11on12Util.cpp"
"d3d12/D3D11on12Util.h"
"d3d12/D3D12Info.cpp"
"d3d12/D3D12Info.h"
"d3d12/DeviceD3D12.cpp"

View File

@ -1,185 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// D3D12Backend.cpp: contains the definition of symbols exported by D3D12Backend.h so that they
// can be compiled twice: once export (shared library), once not exported (static library)
#include "dawn/native/d3d12/D3D11on12Util.h"
#include <utility>
#include "dawn/common/HashUtils.h"
#include "dawn/common/Log.h"
#include "dawn/native/D3D12Backend.h"
#include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
namespace dawn::native::d3d12 {
void Flush11On12DeviceToAvoidLeaks(ComPtr<ID3D11On12Device> d3d11on12Device) {
if (d3d11on12Device == nullptr) {
return;
}
ComPtr<ID3D11Device> d3d11Device;
if (FAILED(d3d11on12Device.As(&d3d11Device))) {
return;
}
ComPtr<ID3D11DeviceContext> d3d11DeviceContext;
d3d11Device->GetImmediateContext(&d3d11DeviceContext);
ASSERT(d3d11DeviceContext != nullptr);
// 11on12 has a bug where D3D12 resources used only for keyed shared mutexes
// are not released until work is submitted to the device context and flushed.
// The most minimal work we can get away with is issuing a TiledResourceBarrier.
// ID3D11DeviceContext2 is available in Win8.1 and above. This suffices for a
// D3D12 backend since both D3D12 and 11on12 first appeared in Windows 10.
ComPtr<ID3D11DeviceContext2> d3d11DeviceContext2;
if (FAILED(d3d11DeviceContext.As(&d3d11DeviceContext2))) {
return;
}
d3d11DeviceContext2->TiledResourceBarrier(nullptr, nullptr);
d3d11DeviceContext2->Flush();
}
D3D11on12ResourceCacheEntry::D3D11on12ResourceCacheEntry(ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex,
ComPtr<ID3D11On12Device> d3d11On12Device)
: mDXGIKeyedMutex(std::move(dxgiKeyedMutex)), mD3D11on12Device(std::move(d3d11On12Device)) {}
D3D11on12ResourceCacheEntry::D3D11on12ResourceCacheEntry(ComPtr<ID3D11On12Device> d3d11On12Device)
: mD3D11on12Device(std::move(d3d11On12Device)) {}
D3D11on12ResourceCacheEntry::~D3D11on12ResourceCacheEntry() {
if (mDXGIKeyedMutex == nullptr) {
return;
}
if (mAcquireCount > 0) {
mDXGIKeyedMutex->ReleaseSync(kDXGIKeyedMutexAcquireReleaseKey);
}
ComPtr<ID3D11Resource> d3d11Resource;
if (FAILED(mDXGIKeyedMutex.As(&d3d11Resource))) {
return;
}
ASSERT(mD3D11on12Device != nullptr);
ID3D11Resource* d3d11ResourceRaw = d3d11Resource.Get();
mD3D11on12Device->ReleaseWrappedResources(&d3d11ResourceRaw, 1);
d3d11Resource.Reset();
mDXGIKeyedMutex.Reset();
Flush11On12DeviceToAvoidLeaks(std::move(mD3D11on12Device));
}
MaybeError D3D11on12ResourceCacheEntry::AcquireKeyedMutex() {
ASSERT(mDXGIKeyedMutex != nullptr);
ASSERT(mAcquireCount >= 0);
if (mAcquireCount == 0) {
DAWN_TRY(
CheckHRESULT(mDXGIKeyedMutex->AcquireSync(kDXGIKeyedMutexAcquireReleaseKey, INFINITE),
"D3D12 acquiring shared mutex"));
}
mAcquireCount++;
return {};
}
MaybeError D3D11on12ResourceCacheEntry::ReleaseKeyedMutex() {
ASSERT(mDXGIKeyedMutex != nullptr);
ASSERT(mAcquireCount > 0);
mAcquireCount--;
if (mAcquireCount == 0) {
DAWN_TRY(CheckHRESULT(mDXGIKeyedMutex->ReleaseSync(kDXGIKeyedMutexAcquireReleaseKey),
"D3D12 releasing keyed mutex"));
}
return {};
}
size_t D3D11on12ResourceCacheEntry::HashFunc::operator()(
const Ref<D3D11on12ResourceCacheEntry> a) const {
size_t hash = 0;
HashCombine(&hash, a->mD3D11on12Device.Get());
return hash;
}
bool D3D11on12ResourceCacheEntry::EqualityFunc::operator()(
const Ref<D3D11on12ResourceCacheEntry> a,
const Ref<D3D11on12ResourceCacheEntry> b) const {
return a->mD3D11on12Device == b->mD3D11on12Device;
}
D3D11on12ResourceCache::D3D11on12ResourceCache() = default;
D3D11on12ResourceCache::~D3D11on12ResourceCache() = default;
Ref<D3D11on12ResourceCacheEntry> D3D11on12ResourceCache::GetOrCreateD3D11on12Resource(
Device* backendDevice,
ID3D12Resource* d3d12Resource) {
// The Dawn and 11on12 device share the same D3D12 command queue whereas this external image
// could be accessed/produced with multiple Dawn devices. To avoid cross-queue sharing
// restrictions, the 11 wrapped resource is forbidden to be shared between Dawn devices by
// using the 11on12 device as the cache key.
ComPtr<ID3D11On12Device> d3d11on12Device = backendDevice->GetOrCreateD3D11on12Device();
if (d3d11on12Device == nullptr) {
dawn::ErrorLog() << "Unable to create 11on12 device for external image";
return nullptr;
}
D3D11on12ResourceCacheEntry blueprint(d3d11on12Device);
auto iter = mCache.find(&blueprint);
if (iter != mCache.end()) {
return *iter;
}
// We use IDXGIKeyedMutexes to synchronize access between D3D11 and D3D12. D3D11/12 fences
// are a viable alternative but are, unfortunately, not available on all versions of Windows
// 10. Since D3D12 does not directly support keyed mutexes, we need to wrap the D3D12
// resource using 11on12 and QueryInterface the D3D11 representation for the keyed mutex.
ComPtr<ID3D11Texture2D> d3d11Texture;
D3D11_RESOURCE_FLAGS resourceFlags;
resourceFlags.BindFlags = 0;
resourceFlags.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
resourceFlags.CPUAccessFlags = 0;
resourceFlags.StructureByteStride = 0;
if (FAILED(d3d11on12Device->CreateWrappedResource(
d3d12Resource, &resourceFlags, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COMMON,
IID_PPV_ARGS(&d3d11Texture)))) {
return nullptr;
}
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
if (FAILED(d3d11Texture.As(&dxgiKeyedMutex))) {
return nullptr;
}
// Keep this cache from growing unbounded.
// TODO(dawn:625): Consider using a replacement policy based cache.
if (mCache.size() > kMaxD3D11on12ResourceCacheSize) {
mCache.clear();
}
Ref<D3D11on12ResourceCacheEntry> entry =
AcquireRef(new D3D11on12ResourceCacheEntry(dxgiKeyedMutex, std::move(d3d11on12Device)));
mCache.insert(entry);
return entry;
}
} // namespace dawn::native::d3d12

View File

@ -1,93 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_D3D12_D3D11ON12UTIL_H_
#define SRC_DAWN_NATIVE_D3D12_D3D11ON12UTIL_H_
#include <memory>
#include <unordered_set>
#include "dawn/common/RefCounted.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/Error.h"
#include "dawn/native/d3d12/d3d12_platform.h"
struct ID3D11On12Device;
struct IDXGIKeyedMutex;
namespace dawn::native::d3d12 {
class Device;
// Wraps 11 wrapped resources in a cache.
class D3D11on12ResourceCacheEntry : public RefCounted {
public:
explicit D3D11on12ResourceCacheEntry(ComPtr<ID3D11On12Device> d3d11on12Device);
D3D11on12ResourceCacheEntry(ComPtr<IDXGIKeyedMutex> d3d11on12Resource,
ComPtr<ID3D11On12Device> d3d11on12Device);
~D3D11on12ResourceCacheEntry() override;
MaybeError AcquireKeyedMutex();
MaybeError ReleaseKeyedMutex();
// Functors necessary for the
// unordered_set<D3D11on12ResourceCacheEntry&>-based cache.
struct HashFunc {
size_t operator()(const Ref<D3D11on12ResourceCacheEntry> a) const;
};
struct EqualityFunc {
bool operator()(const Ref<D3D11on12ResourceCacheEntry> a,
const Ref<D3D11on12ResourceCacheEntry> b) const;
};
private:
ComPtr<IDXGIKeyedMutex> mDXGIKeyedMutex;
ComPtr<ID3D11On12Device> mD3D11on12Device;
int64_t mAcquireCount = 0;
};
// |D3D11on12ResourceCache| maintains a cache of 11 wrapped resources.
// Each entry represents a 11 resource that is exclusively accessed by Dawn device.
// Since each Dawn device creates and stores a 11on12 device, the 11on12 device
// is used as the key for the cache entry which ensures only the same 11 wrapped
// resource is re-used and also fully released.
//
// The cache is primarily needed to avoid repeatedly calling CreateWrappedResource
// and special release code per ProduceTexture(device).
class D3D11on12ResourceCache {
public:
D3D11on12ResourceCache();
~D3D11on12ResourceCache();
Ref<D3D11on12ResourceCacheEntry> GetOrCreateD3D11on12Resource(Device* backendDevice,
ID3D12Resource* d3d12Resource);
private:
// TODO(dawn:625): Figure out a large enough cache size.
static constexpr uint64_t kMaxD3D11on12ResourceCacheSize = 5;
// 11on12 resource cache entries are refcounted to ensure if the ExternalImage outlives the
// Dawn texture (or vice-versa), we always fully release the 11 wrapped resource without
// waiting until Dawn device to shutdown.
using Cache = std::unordered_set<Ref<D3D11on12ResourceCacheEntry>,
D3D11on12ResourceCacheEntry::HashFunc,
D3D11on12ResourceCacheEntry::EqualityFunc>;
Cache mCache;
};
} // namespace dawn::native::d3d12
#endif // SRC_DAWN_NATIVE_D3D12_D3D11ON12UTIL_H_

View File

@ -22,7 +22,6 @@
#include "dawn/common/Log.h"
#include "dawn/common/Math.h"
#include "dawn/native/d3d12/D3D11on12Util.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
#include "dawn/native/d3d12/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d12/ResidencyManagerD3D12.h"
@ -48,12 +47,6 @@ bool ExternalImageDXGI::IsValid() const {
return mImpl->IsValid();
}
WGPUTexture ExternalImageDXGI::ProduceTexture(
WGPUDevice device,
const ExternalImageDXGIBeginAccessDescriptor* descriptor) {
return BeginAccess(descriptor);
}
WGPUTexture ExternalImageDXGI::BeginAccess(
const ExternalImageDXGIBeginAccessDescriptor* descriptor) {
return mImpl->BeginAccess(descriptor);

View File

@ -31,7 +31,6 @@
#include "dawn/native/d3d12/CommandAllocatorManager.h"
#include "dawn/native/d3d12/CommandBufferD3D12.h"
#include "dawn/native/d3d12/ComputePipelineD3D12.h"
#include "dawn/native/d3d12/D3D11on12Util.h"
#include "dawn/native/d3d12/ExternalImageDXGIImpl.h"
#include "dawn/native/d3d12/PipelineLayoutD3D12.h"
#include "dawn/native/d3d12/PlatformFunctionsD3D12.h"
@ -587,49 +586,27 @@ std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl(
}
}
auto impl = std::make_unique<ExternalImageDXGIImpl>(
this, std::move(d3d12Resource), textureDescriptor, descriptor->useFenceSynchronization);
auto impl =
std::make_unique<ExternalImageDXGIImpl>(this, std::move(d3d12Resource), textureDescriptor);
mExternalImageList.Append(impl.get());
return impl;
}
Ref<TextureBase> Device::CreateD3D12ExternalTexture(
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture,
bool isInitialized) {
Ref<TextureBase> Device::CreateD3D12ExternalTexture(const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture;
if (ConsumedError(Texture::CreateExternalImage(
this, descriptor, std::move(d3d12Texture), std::move(waitFences),
std::move(d3d11on12Resource), isSwapChainTexture, isInitialized),
&dawnTexture)) {
if (ConsumedError(
Texture::CreateExternalImage(this, descriptor, std::move(d3d12Texture),
std::move(waitFences), isSwapChainTexture, isInitialized),
&dawnTexture)) {
return nullptr;
}
return {dawnTexture};
}
ComPtr<ID3D11On12Device> Device::GetOrCreateD3D11on12Device() {
if (mD3d11On12Device == nullptr) {
ComPtr<ID3D11Device> d3d11Device;
D3D_FEATURE_LEVEL d3dFeatureLevel;
IUnknown* const iUnknownQueue = mCommandQueue.Get();
if (FAILED(GetFunctions()->d3d11on12CreateDevice(mD3d12Device.Get(), 0, nullptr, 0,
&iUnknownQueue, 1, 1, &d3d11Device,
nullptr, &d3dFeatureLevel))) {
return nullptr;
}
ComPtr<ID3D11On12Device> d3d11on12Device;
HRESULT hr = d3d11Device.As(&d3d11on12Device);
ASSERT(SUCCEEDED(hr));
mD3d11On12Device = std::move(d3d11on12Device);
}
return mD3d11On12Device;
}
const D3D12DeviceInfo& Device::GetDeviceInfo() const {
return ToBackend(GetAdapter())->GetDeviceInfo();
}

View File

@ -140,12 +140,9 @@ class Device final : public d3d::Device {
Ref<TextureBase> CreateD3D12ExternalTexture(const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture,
bool isInitialized);
ComPtr<ID3D11On12Device> GetOrCreateD3D11on12Device();
uint32_t GetOptimalBytesPerRowAlignment() const override;
uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
@ -225,9 +222,6 @@ class Device final : public d3d::Device {
ComPtr<ID3D12CommandQueue> mCommandQueue;
ComPtr<ID3D12SharingContract> mD3d12SharingContract;
// 11on12 device corresponding to mCommandQueue
ComPtr<ID3D11On12Device> mD3d11On12Device;
ComPtr<ID3D12CommandSignature> mDispatchIndirectSignature;
ComPtr<ID3D12CommandSignature> mDrawIndirectSignature;
ComPtr<ID3D12CommandSignature> mDrawIndexedIndirectSignature;

View File

@ -20,19 +20,15 @@
#include "dawn/common/Log.h"
#include "dawn/native/D3D12Backend.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/d3d12/D3D11on12Util.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
namespace dawn::native::d3d12 {
ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
const TextureDescriptor* textureDescriptor,
bool useFenceSynchronization)
const TextureDescriptor* textureDescriptor)
: mBackendDevice(backendDevice),
mD3D12Resource(std::move(d3d12Resource)),
mUseFenceSynchronization(useFenceSynchronization),
mD3D11on12ResourceCache(std::make_unique<D3D11on12ResourceCache>()),
mUsage(textureDescriptor->usage),
mDimension(textureDescriptor->dimension),
mSize(textureDescriptor->size),
@ -77,8 +73,6 @@ void ExternalImageDXGIImpl::DestroyInternal() {
if (IsInList()) {
RemoveFromList();
mD3D12Resource = nullptr;
mD3D11on12ResourceCache = nullptr;
// We don't set mBackendDevice to null here to let its mutex accessible until dtor. This
// also to avoid data racing with non-null check in GetScopedDeviceLock()
}
@ -121,34 +115,23 @@ WGPUTexture ExternalImageDXGIImpl::BeginAccess(
}
std::vector<Ref<Fence>> waitFences;
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource;
if (mUseFenceSynchronization) {
for (const ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) {
ASSERT(fenceDescriptor.fenceHandle != nullptr);
// TODO(sunnyps): Use a fence cache instead of re-importing fences on each BeginAccess.
Ref<Fence> fence;
if (mBackendDevice->ConsumedError(
Fence::CreateFromHandle(mBackendDevice->GetD3D12Device(),
fenceDescriptor.fenceHandle,
fenceDescriptor.fenceValue),
&fence)) {
dawn::ErrorLog() << "Unable to create D3D12 fence for external image";
return nullptr;
}
waitFences.push_back(std::move(fence));
}
} else {
d3d11on12Resource = mD3D11on12ResourceCache->GetOrCreateD3D11on12Resource(
mBackendDevice.Get(), mD3D12Resource.Get());
if (d3d11on12Resource == nullptr) {
dawn::ErrorLog() << "Unable to create 11on12 resource for external image";
for (const ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) {
ASSERT(fenceDescriptor.fenceHandle != nullptr);
// TODO(sunnyps): Use a fence cache instead of re-importing fences on each BeginAccess.
Ref<Fence> fence;
if (mBackendDevice->ConsumedError(
Fence::CreateFromHandle(mBackendDevice->GetD3D12Device(),
fenceDescriptor.fenceHandle, fenceDescriptor.fenceValue),
&fence)) {
dawn::ErrorLog() << "Unable to create D3D12 fence for external image";
return nullptr;
}
waitFences.push_back(std::move(fence));
}
Ref<TextureBase> texture = mBackendDevice->CreateD3D12ExternalTexture(
&textureDescriptor, mD3D12Resource, std::move(waitFences), std::move(d3d11on12Resource),
descriptor->isSwapChainTexture, descriptor->isInitialized);
&textureDescriptor, mD3D12Resource, std::move(waitFences), descriptor->isSwapChainTexture,
descriptor->isInitialized);
return ToAPI(texture.Detach());
}
@ -167,15 +150,13 @@ void ExternalImageDXGIImpl::EndAccess(WGPUTexture texture,
Texture* backendTexture = ToBackend(FromAPI(texture));
ASSERT(backendTexture != nullptr);
if (mUseFenceSynchronization) {
ExecutionSerial fenceValue;
if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) {
dawn::ErrorLog() << "D3D12 fence end access failed";
return;
}
signalFence->fenceHandle = mBackendDevice->GetFenceHandle();
signalFence->fenceValue = static_cast<uint64_t>(fenceValue);
ExecutionSerial fenceValue;
if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) {
dawn::ErrorLog() << "D3D12 fence end access failed";
return;
}
signalFence->fenceHandle = mBackendDevice->GetFenceHandle();
signalFence->fenceValue = static_cast<uint64_t>(fenceValue);
}
} // namespace dawn::native::d3d12

View File

@ -34,7 +34,6 @@ struct ID3D12Fence;
namespace dawn::native::d3d12 {
class D3D11on12ResourceCache;
class Device;
struct ExternalImageDXGIBeginAccessDescriptor;
struct ExternalImageDescriptorDXGISharedHandle;
@ -43,8 +42,7 @@ class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> {
public:
ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
const TextureDescriptor* textureDescriptor,
bool useFenceSynchronization);
const TextureDescriptor* textureDescriptor);
~ExternalImageDXGIImpl();
ExternalImageDXGIImpl(const ExternalImageDXGIImpl&) = delete;
@ -65,9 +63,6 @@ class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> {
Ref<Device> mBackendDevice;
Microsoft::WRL::ComPtr<ID3D12Resource> mD3D12Resource;
const bool mUseFenceSynchronization;
std::unique_ptr<D3D11on12ResourceCache> mD3D11on12ResourceCache;
wgpu::TextureUsage mUsage;
wgpu::TextureUsage mUsageInternal = wgpu::TextureUsage::None;

View File

@ -23,9 +23,7 @@ PlatformFunctions::~PlatformFunctions() = default;
MaybeError PlatformFunctions::LoadFunctions() {
DAWN_TRY(Base::LoadFunctions());
DAWN_TRY(LoadD3D12());
DAWN_TRY(LoadD3D11());
LoadPIXRuntime();
return {};
}
@ -57,20 +55,6 @@ MaybeError PlatformFunctions::LoadD3D12() {
return {};
}
MaybeError PlatformFunctions::LoadD3D11() {
#if DAWN_PLATFORM_IS(WINUWP)
d3d11on12CreateDevice = &D3D11On12CreateDevice;
#else
std::string error;
if (!mD3D11Lib.Open("d3d11.dll", &error) ||
!mD3D11Lib.GetProc(&d3d11on12CreateDevice, "D3D11On12CreateDevice", &error)) {
return DAWN_INTERNAL_ERROR(error.c_str());
}
#endif
return {};
}
bool PlatformFunctions::IsPIXEventRuntimeLoaded() const {
return mPIXEventRuntimeLib.Valid();
}

View File

@ -57,14 +57,10 @@ class PlatformFunctions final : public d3d::PlatformFunctions {
PFN_SET_MARKER_ON_COMMAND_LIST pixSetMarkerOnCommandList = nullptr;
// Functions from D3D11.dll
PFN_D3D11ON12_CREATE_DEVICE d3d11on12CreateDevice = nullptr;
private:
using Base = d3d::PlatformFunctions;
MaybeError LoadD3D12();
MaybeError LoadD3D11();
void LoadPIXRuntime();
DynamicLib mD3D12Lib;

View File

@ -28,7 +28,6 @@
#include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d12/BufferD3D12.h"
#include "dawn/native/d3d12/CommandRecordingContext.h"
#include "dawn/native/d3d12/D3D11on12Util.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
#include "dawn/native/d3d12/Forward.h"
#include "dawn/native/d3d12/HeapD3D12.h"
@ -191,20 +190,17 @@ ResultOrError<Ref<Texture>> Texture::Create(Device* device, const TextureDescrip
}
// static
ResultOrError<Ref<Texture>> Texture::CreateExternalImage(
Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture,
bool isInitialized) {
ResultOrError<Ref<Texture>> Texture::CreateExternalImage(Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture =
AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal));
DAWN_TRY(
dawnTexture->InitializeAsExternalTexture(std::move(d3d12Texture), std::move(waitFences),
std::move(d3d11on12Resource), isSwapChainTexture));
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(std::move(d3d12Texture),
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.
@ -230,7 +226,6 @@ ResultOrError<Ref<Texture>> Texture::Create(Device* device,
MaybeError Texture::InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture) {
D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc();
mD3D12ResourceFlags = desc.Flags;
@ -243,7 +238,6 @@ MaybeError Texture::InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Text
mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr};
mWaitFences = std::move(waitFences);
mD3D11on12Resource = std::move(d3d11on12Resource);
mSwapChainTexture = isSwapChainTexture;
SetLabelHelper("Dawn_ExternalTexture");
@ -347,21 +341,13 @@ Texture::~Texture() {}
void Texture::DestroyImpl() {
TextureBase::DestroyImpl();
ToBackend(GetDevice())->DeallocateMemory(mResourceAllocation);
// Set mSwapChainTexture to false to prevent ever calling ID3D12SharingContract::Present again.
mSwapChainTexture = false;
// Now that the texture has been destroyed, it should release the d3d11on12 resource refptr.
mD3D11on12Resource = nullptr;
}
ResultOrError<ExecutionSerial> Texture::EndAccess() {
ASSERT(mD3D11on12Resource == nullptr);
Device* device = ToBackend(GetDevice());
// Synchronize if texture access wasn't synchronized already due to ExecuteCommandLists.
if (!mSignalFenceValue.has_value()) {
// Needed to ensure that command allocator doesn't get destroyed before pending commands
@ -376,7 +362,6 @@ ResultOrError<ExecutionSerial> Texture::EndAccess() {
DAWN_TRY(device->NextSerial());
ASSERT(mSignalFenceValue.has_value());
}
ExecutionSerial ret = mSignalFenceValue.value();
ASSERT(ret <= device->GetLastSubmittedCommandSerial());
// Explicitly call reset() since std::move() on optional doesn't make it std::nullopt.
@ -418,9 +403,6 @@ DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const {
}
MaybeError Texture::SynchronizeImportedTextureBeforeUse() {
if (mD3D11on12Resource != nullptr) {
DAWN_TRY(mD3D11on12Resource->AcquireKeyedMutex());
}
// Perform the wait only on the first call.
Device* device = ToBackend(GetDevice());
for (Ref<Fence>& fence : mWaitFences) {
@ -448,12 +430,8 @@ MaybeError Texture::SynchronizeImportedTextureAfterUse() {
d3dSharingContract->Present(mResourceAllocation.GetD3D12Resource(), 0, 0);
}
}
if (mD3D11on12Resource != nullptr) {
DAWN_TRY(mD3D11on12Resource->ReleaseKeyedMutex());
} else {
// NextSerial() will be called after this - this is also checked in EndAccess().
mSignalFenceValue = device->GetPendingCommandSerial();
}
// NextSerial() will be called after this - this is also checked in EndAccess().
mSignalFenceValue = device->GetPendingCommandSerial();
return {};
}

View File

@ -33,7 +33,6 @@ namespace dawn::native::d3d12 {
class CommandRecordingContext;
class Device;
class D3D11on12ResourceCacheEntry;
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
const TextureDescriptor* descriptor);
@ -43,21 +42,18 @@ MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT text
class Texture final : public TextureBase {
public:
static ResultOrError<Ref<Texture>> Create(Device* device, const TextureDescriptor* descriptor);
static ResultOrError<Ref<Texture>> CreateExternalImage(
Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture,
bool isInitialized);
static ResultOrError<Ref<Texture>> CreateExternalImage(Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
bool isSwapChainTexture,
bool isInitialized);
static ResultOrError<Ref<Texture>> Create(Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture);
// For external textures, returns the Device internal fence's value associated with the last
// ExecuteCommandLists that used this texture. If nullopt is returned, the texture wasn't used
// or keyed mutex is used instead of fences for synchronization.
// ExecuteCommandLists that used this texture. If nullopt is returned, the texture wasn't used.
ResultOrError<ExecutionSerial> EndAccess();
DXGI_FORMAT GetD3D12Format() const;
@ -108,7 +104,6 @@ class Texture final : public TextureBase {
MaybeError InitializeAsInternalTexture();
MaybeError InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture,
std::vector<Ref<Fence>> waitFences,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
bool isSwapChainTexture);
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
@ -147,7 +142,6 @@ class Texture final : public TextureBase {
// TODO(dawn:1460): Encapsulate imported image fields e.g. std::unique_ptr<ExternalImportInfo>.
std::vector<Ref<Fence>> mWaitFences;
std::optional<ExecutionSerial> mSignalFenceValue;
Ref<D3D11on12ResourceCacheEntry> mD3D11on12Resource;
bool mSwapChainTexture = false;
SubresourceStorage<StateAndDecay> mSubresourceStateAndDecay;

View File

@ -17,7 +17,6 @@
#include "dawn/native/d3d/d3d_platform.h"
#include <d3d11on12.h> // NOLINT(build/include_order)
#include <d3d12.h> // NOLINT(build/include_order)
#endif // SRC_DAWN_NATIVE_D3D12_D3D12_PLATFORM_H_

View File

@ -33,28 +33,7 @@ using Microsoft::WRL::ComPtr;
namespace {
enum class SyncMode {
kKeyedMutex,
kFence,
};
std::ostream& operator<<(std::ostream& o, const SyncMode& m) {
switch (m) {
case SyncMode::kKeyedMutex:
o << "KeyedMutex";
break;
case SyncMode::kFence:
o << "Fence";
break;
}
return o;
}
DAWN_TEST_PARAM_STRUCT(D3D12ResourceTestParams, SyncMode);
using dawn::native::d3d12::kDXGIKeyedMutexAcquireReleaseKey;
class D3D12ResourceTestBase : public DawnTestWithParams<D3D12ResourceTestParams> {
class D3D12ResourceTestBase : public DawnTest {
protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
return {wgpu::FeatureName::DawnInternalUsages};
@ -62,7 +41,7 @@ class D3D12ResourceTestBase : public DawnTestWithParams<D3D12ResourceTestParams>
public:
void SetUp() override {
DawnTestWithParams<D3D12ResourceTestParams>::SetUp();
DawnTest::SetUp();
if (UsesWire()) {
return;
}
@ -110,12 +89,8 @@ class D3D12ResourceTestBase : public DawnTestWithParams<D3D12ResourceTestParams>
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;
if (GetParam().mSyncMode == SyncMode::kKeyedMutex) {
baseD3dDescriptor.MiscFlags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
} else {
baseD3dDescriptor.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
}
baseD3dDescriptor.MiscFlags =
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
}
protected:
@ -136,7 +111,6 @@ class D3D12ResourceTestBase : public DawnTestWithParams<D3D12ResourceTestParams>
externalImageDesc.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc);
externalImageDesc.sharedHandle = textureSharedHandle;
externalImageDesc.useFenceSynchronization = GetParam().mSyncMode == SyncMode::kFence;
std::unique_ptr<dawn::native::d3d12::ExternalImageDXGI> externalImage =
dawn::native::d3d12::ExternalImageDXGI::Create(targetDevice, &externalImageDesc);
@ -418,17 +392,15 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
HANDLE fenceSharedHandle = nullptr;
ComPtr<ID3D11Fence> d3d11Fence;
if (GetParam().mSyncMode == SyncMode::kFence) {
ComPtr<ID3D11Device5> d3d11Device5;
hr = mD3d11Device.As(&d3d11Device5);
ASSERT_EQ(hr, S_OK);
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 = 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);
}
hr = d3d11Fence->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, &fenceSharedHandle);
ASSERT_EQ(hr, S_OK);
*d3d11TextureOut = d3d11Texture.Detach();
*d3d11FenceOut = d3d11Fence.Detach();
@ -445,18 +417,6 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
HRESULT hr = d3d11Texture.As(&dxgiResource);
ASSERT_EQ(hr, S_OK);
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
ComPtr<ID3D11DeviceContext4> d3d11DeviceContext4;
if (GetParam().mSyncMode == SyncMode::kKeyedMutex) {
hr = d3d11Texture.As(&dxgiKeyedMutex);
ASSERT_EQ(hr, S_OK);
hr = dxgiKeyedMutex->AcquireSync(kDXGIKeyedMutexAcquireReleaseKey, INFINITE);
ASSERT_EQ(hr, S_OK);
}
ComPtr<ID3D11RenderTargetView> d3d11RTV;
hr = mD3d11Device->CreateRenderTargetView(d3d11Texture.Get(), nullptr, &d3d11RTV);
ASSERT_EQ(hr, S_OK);
@ -466,16 +426,12 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
static_cast<float>(clearColor.b), static_cast<float>(clearColor.a)};
mD3d11DeviceContext->ClearRenderTargetView(d3d11RTV.Get(), colorRGBA);
if (dxgiKeyedMutex) {
hr = dxgiKeyedMutex->ReleaseSync(kDXGIKeyedMutexAcquireReleaseKey);
ASSERT_EQ(hr, S_OK);
} else {
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);
}
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(
@ -490,7 +446,6 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
externalImageDesc.sharedHandle = sharedHandle;
externalImageDesc.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(&dawnDescriptor);
externalImageDesc.useFenceSynchronization = GetParam().mSyncMode == SyncMode::kFence;
std::unique_ptr<dawn::native::d3d12::ExternalImageDXGI> externalImage =
dawn::native::d3d12::ExternalImageDXGI::Create(device.Get(), &externalImageDesc);
@ -538,7 +493,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
void ExpectPixelRGBA8EQ(
ID3D11Texture2D* d3d11Texture,
const wgpu::Color& color,
const dawn::native::d3d12::ExternalImageDXGIFenceDescriptor* waitFence = nullptr) {
const dawn::native::d3d12::ExternalImageDXGIFenceDescriptor* waitFence) {
D3D11_TEXTURE2D_DESC texture2DDesc;
d3d11Texture->GetDesc(&texture2DDesc);
@ -565,15 +520,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
d3dRc.bottom = texture2DDesc.Height;
d3dRc.right = texture2DDesc.Width;
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
d3d11Texture->QueryInterface(IID_PPV_ARGS(&dxgiKeyedMutex));
if (dxgiKeyedMutex != nullptr) {
hr = dxgiKeyedMutex->AcquireSync(kDXGIKeyedMutexAcquireReleaseKey, INFINITE);
ASSERT_EQ(hr, S_OK);
}
if (waitFence != nullptr && waitFence->fenceHandle != nullptr) {
if (waitFence->fenceHandle != nullptr) {
ComPtr<ID3D11Device5> d3d11Device5;
mD3d11Device.As(&d3d11Device5);
ASSERT_EQ(hr, S_OK);
@ -611,11 +558,6 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
EXPECT_EQ(colorData[3], color.a * 255u);
mD3d11DeviceContext->Unmap(spD3DTextureStaging.Get(), 0);
if (dxgiKeyedMutex != nullptr) {
hr = dxgiKeyedMutex->ReleaseSync(kDXGIKeyedMutexAcquireReleaseKey);
ASSERT_EQ(hr, S_OK);
}
}
};
@ -686,7 +628,6 @@ TEST_P(D3D12SharedHandleUsageTests, ClearInD3D12ReadbackInD3D11) {
wgpu::Texture dawnTexture;
ComPtr<ID3D11Texture2D> d3d11Texture;
std::unique_ptr<dawn::native::d3d12::ExternalImageDXGI> externalImage;
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
WrapAndClearD3D11Texture(baseDawnDescriptor, baseD3dDescriptor, d3d11ClearColor, &dawnTexture,
&d3d11Texture, &externalImage, /*isInitialized=*/true);
ASSERT_NE(dawnTexture.Get(), nullptr);
@ -814,7 +755,6 @@ TEST_P(D3D12SharedHandleUsageTests, ReuseExternalImage) {
TEST_P(D3D12SharedHandleUsageTests, ConcurrentExternalImageReadAccess) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
DAWN_TEST_UNSUPPORTED_IF(GetParam().mSyncMode == SyncMode::kKeyedMutex);
wgpu::Device device2 = CreateDevice();
EXPECT_NE(device2, nullptr);
@ -1178,9 +1118,6 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
// D3D12_Microsoft_Basic_Render_Driver_CPU when validation is enabled.
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP() && IsBackendValidationEnabled());
// KeyedMutex doesn't guarantee the order of commands so skip it.
DAWN_TEST_UNSUPPORTED_IF(GetParam().mSyncMode != SyncMode::kFence);
const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f};
const wgpu::Color d3d12ClearColor{0.0f, 0.0f, 1.0f, 1.0f};
@ -1233,12 +1170,6 @@ TEST_P(D3D12SharedHandleMultithreadTests, ClearInD3D12ReadbackInD3D11_TwoThreads
}
}
DAWN_INSTANTIATE_TEST_P(D3D12SharedHandleValidation,
{D3D12Backend()},
{SyncMode::kKeyedMutex, SyncMode::kFence});
DAWN_INSTANTIATE_TEST_P(D3D12SharedHandleUsageTests,
{D3D12Backend()},
{SyncMode::kKeyedMutex, SyncMode::kFence});
DAWN_INSTANTIATE_TEST_P(D3D12SharedHandleMultithreadTests,
{D3D12Backend()},
{SyncMode::kKeyedMutex, SyncMode::kFence});
DAWN_INSTANTIATE_TEST(D3D12SharedHandleValidation, D3D12Backend());
DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend());
DAWN_INSTANTIATE_TEST(D3D12SharedHandleMultithreadTests, D3D12Backend());

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include <d3d11.h>
#include <d3d11_4.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <wrl/client.h>
@ -118,8 +119,7 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
d3dDescriptor.Usage = D3D11_USAGE_DEFAULT;
d3dDescriptor.BindFlags = D3D11_BIND_SHADER_RESOURCE;
d3dDescriptor.CPUAccessFlags = 0;
d3dDescriptor.MiscFlags =
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
d3dDescriptor.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
std::vector<uint8_t> initialData =
VideoViewsTests::GetTestTextureData(format, isCheckerboard);
@ -143,22 +143,32 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
&sharedHandle);
ASSERT(hr == S_OK);
// DX11 texture should be initialized upon CreateTexture2D. However, if we do not
// acquire/release the keyed mutex before using the wrapped WebGPU texture, the WebGPU
// texture is left uninitialized. This is required for D3D11 and D3D12 interop.
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
hr = d3d11Texture.As(&dxgiKeyedMutex);
HANDLE fenceSharedHandle = nullptr;
ComPtr<ID3D11Fence> d3d11Fence;
ComPtr<ID3D11Device5> d3d11Device5;
hr = mD3d11Device.As(&d3d11Device5);
ASSERT(hr == S_OK);
using dawn::native::d3d12::kDXGIKeyedMutexAcquireReleaseKey;
hr = dxgiKeyedMutex->AcquireSync(kDXGIKeyedMutexAcquireReleaseKey, INFINITE);
hr = d3d11Device5->CreateFence(0, D3D11_FENCE_FLAG_SHARED, IID_PPV_ARGS(&d3d11Fence));
ASSERT(hr == S_OK);
hr = dxgiKeyedMutex->ReleaseSync(kDXGIKeyedMutexAcquireReleaseKey);
hr = d3d11Fence->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, &fenceSharedHandle);
ASSERT(hr == S_OK);
// Open the DX11 texture in Dawn from the shared handle and return it as a WebGPU
// texture.
ComPtr<ID3D11DeviceContext> d3d11DeviceContext;
mD3d11Device->GetImmediateContext(&d3d11DeviceContext);
ComPtr<ID3D11DeviceContext4> d3d11DeviceContext4;
hr = d3d11DeviceContext.As(&d3d11DeviceContext4);
ASSERT(hr == S_OK);
// D3D11 texture should be initialized upon CreateTexture2D, but we need to make Dawn/D3D12
// wait on the initializtaion. The fence starts with 0 signaled, but that won't capture the
// initialization above, so signal explicitly with 1 and make Dawn wait on it.
hr = d3d11DeviceContext4->Signal(d3d11Fence.Get(), 1);
ASSERT(hr == S_OK);
// Open the DX11 texture in Dawn from the shared handle and return it as a WebGPU texture.
dawn::native::d3d12::ExternalImageDescriptorDXGISharedHandle externalImageDesc;
externalImageDesc.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(&textureDesc);
@ -170,12 +180,21 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
// Handle is no longer needed once resources are created.
::CloseHandle(sharedHandle);
dawn::native::d3d12::ExternalImageAccessDescriptorDXGIKeyedMutex externalAccessDesc;
dawn::native::d3d12::ExternalImageDXGIFenceDescriptor fenceDesc;
fenceDesc.fenceHandle = fenceSharedHandle;
fenceDesc.fenceValue = 1;
dawn::native::d3d12::ExternalImageDXGIBeginAccessDescriptor externalAccessDesc;
externalAccessDesc.isInitialized = true;
externalAccessDesc.usage = static_cast<WGPUTextureUsageFlags>(textureDesc.usage);
externalAccessDesc.waitFences = {};
return std::make_unique<PlatformTextureWin>(wgpu::Texture::Acquire(
externalImage->ProduceTexture(mWGPUDevice, &externalAccessDesc)));
auto wgpuTexture = wgpu::Texture::Acquire(externalImage->BeginAccess(&externalAccessDesc));
// Fence handle is no longer needed after begin access.
::CloseHandle(fenceSharedHandle);
return std::make_unique<PlatformTextureWin>(std::move(wgpuTexture));
}
void DestroyVideoTextureForTest(