D3D11: Allow dynamically skipping fence signals in BeginAccess
Previously, fence signaling for a Shared Texture Manager (STM) was
configured only at creation. This change adds a new option to
BeginAccessDescriptor to control fence signaling dynamically at the time
of access.
This enables use cases where a shared image can initially have fence
signaling disabled and then enforce it after the first WebGPU access.
The older creation-time option will be removed once clients adopt this
new descriptor.
Bug: chromium:429093435
Change-Id: If6bab8749d96bd667a88a3e661b1ffa066481102
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/250434
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
diff --git a/include/dawn/native/D3D11Backend.h b/include/dawn/native/D3D11Backend.h
index 0fd8ba0..415b97e 100644
--- a/include/dawn/native/D3D11Backend.h
+++ b/include/dawn/native/D3D11Backend.h
@@ -32,6 +32,7 @@
#include <wrl/client.h>
#include <memory>
+#include <optional>
#include "dawn/native/D3DBackend.h"
@@ -61,9 +62,14 @@
// If this flag is true, Dawn is required to signal a fence before EndAccess() and return it in
// SharedTextureMemoryEndAccessState's fences list.
// If it's false, no fence signaling is needed and EndAccess() might return empty fence list.
- // Note: this flag is not relevant if the feature SharedFenceDXGISharedHandle is disabled/not
+ // Notes:
+ // - This flag is not relevant if the feature SharedFenceDXGISharedHandle is disabled/not
// supported.
- bool requiresEndAccessFence = true;
+ // - This flag if present will override the requiresEndAccessFence flag in
+ // SharedTextureMemoryD3D11BeginState
+ // TODO(chromium:335003893): This flag is deprecated. Remove it once clients are updated to use
+ // SharedTextureMemoryD3D11BeginState's requiresEndAccessFence.
+ std::optional<bool> requiresEndAccessFence;
};
} // namespace dawn::native::d3d11
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 377e1d6..c082644 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -2066,6 +2066,15 @@
{"name": "is swapchain", "type": "bool", "default": "false"}
]
},
+ "shared texture memory D3D11 begin state": {
+ "category": "structure",
+ "chained": "in",
+ "chain roots": ["shared texture memory begin access descriptor"],
+ "tags": ["dawn", "native"],
+ "members": [
+ {"name": "requires end access fence", "type": "bool", "default": "true"}
+ ]
+ },
"shared fence": {
"category": "object",
"tags": ["dawn", "native"],
@@ -3880,7 +3889,8 @@
{"value": 68, "name": "render pass descriptor resolve rect", "tags": ["dawn"]},
{"value": 69, "name": "request adapter WebGPU backend options", "tags": ["dawn", "native"]},
{"value": 70, "name": "dawn fake device initialize error for testing", "tags": ["dawn"]},
- {"value": 71, "name": "texture component swizzle descriptor", "tags": ["dawn"]}
+ {"value": 71, "name": "texture component swizzle descriptor", "tags": ["dawn"]},
+ {"value": 72, "name": "shared texture memory D3D11 begin state", "tags": ["dawn", "native"]}
]
},
"texture": {
diff --git a/src/dawn/native/SharedResourceMemory.cpp b/src/dawn/native/SharedResourceMemory.cpp
index cf8f69d..679bc32 100644
--- a/src/dawn/native/SharedResourceMemory.cpp
+++ b/src/dawn/native/SharedResourceMemory.cpp
@@ -66,6 +66,10 @@
return mReadAccessCount;
}
+bool SharedResourceMemoryContents::HasAccess() const {
+ return mSharedResourceAccessState != SharedResourceAccessState::NotAccessed;
+}
+
void SharedResourceMemory::Initialize() {
DAWN_ASSERT(!IsError());
mContents = CreateContents();
diff --git a/src/dawn/native/SharedResourceMemory.h b/src/dawn/native/SharedResourceMemory.h
index c552299..0b0a00e 100644
--- a/src/dawn/native/SharedResourceMemory.h
+++ b/src/dawn/native/SharedResourceMemory.h
@@ -163,6 +163,7 @@
bool HasWriteAccess() const;
bool HasExclusiveReadAccess() const;
int GetReadAccessCount() const;
+ bool HasAccess() const;
private:
friend class SharedResourceMemory;
diff --git a/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp b/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
index 59ad1e5..2f3dbac 100644
--- a/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
+++ b/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
@@ -46,7 +46,8 @@
MaybeError SharedTextureMemory::BeginAccessImpl(
TextureBase* texture,
const UnpackedPtr<BeginAccessDescriptor>& descriptor) {
- DAWN_TRY(descriptor.ValidateSubset<SharedTextureMemoryD3DSwapchainBeginState>());
+ DAWN_TRY((descriptor.ValidateSubset<SharedTextureMemoryD3DSwapchainBeginState,
+ SharedTextureMemoryD3D11BeginState>()));
for (size_t i = 0; i < descriptor->fenceCount; ++i) {
SharedFenceBase* fence = descriptor->fences[i];
diff --git a/src/dawn/native/d3d11/SharedTextureMemoryD3D11.cpp b/src/dawn/native/d3d11/SharedTextureMemoryD3D11.cpp
index 6f6b04a..4c7f775 100644
--- a/src/dawn/native/d3d11/SharedTextureMemoryD3D11.cpp
+++ b/src/dawn/native/d3d11/SharedTextureMemoryD3D11.cpp
@@ -134,8 +134,9 @@
DAWN_TRY_ASSIGN(properties, PropertiesFromD3D11Texture(device, d3d11Texture,
/*isSharedWithHandle=*/true));
- auto result = AcquireRef(new SharedTextureMemory(
- device, label, properties, std::move(d3d11Resource), /*requiresFenceSignal=*/true));
+ auto result =
+ AcquireRef(new SharedTextureMemory(device, label, properties, std::move(d3d11Resource),
+ /*requiresFenceSignalOverride=*/std::nullopt));
result->Initialize();
return result;
}
@@ -161,9 +162,9 @@
DAWN_TRY_ASSIGN(properties, PropertiesFromD3D11Texture(device, descriptor->texture,
/*isSharedWithHandle=*/false));
- auto result = AcquireRef(
- new SharedTextureMemory(device, label, properties, std::move(d3d11Resource),
- /*requiresFenceSignal=*/descriptor->requiresEndAccessFence));
+ auto result = AcquireRef(new SharedTextureMemory(
+ device, label, properties, std::move(d3d11Resource),
+ /*requiresFenceSignalOverride=*/descriptor->requiresEndAccessFence));
result->Initialize();
return result;
}
@@ -172,10 +173,10 @@
StringView label,
SharedTextureMemoryProperties properties,
ComPtr<ID3D11Resource> resource,
- bool requiresFenceSignal)
+ std::optional<bool> requiresFenceSignalOverride)
: d3d::SharedTextureMemory(device, label, properties),
mResource(std::move(resource)),
- mRequiresFenceSignal(requiresFenceSignal) {
+ mRequiresFenceSignalOverride(std::move(requiresFenceSignalOverride)) {
ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
mResource.As(&dxgiKeyedMutex);
if (dxgiKeyedMutex) {
@@ -198,7 +199,48 @@
ResultOrError<Ref<TextureBase>> SharedTextureMemory::CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) {
- return Texture::CreateFromSharedTextureMemory(this, descriptor, mRequiresFenceSignal);
+ return Texture::CreateFromSharedTextureMemory(this, descriptor);
+}
+
+Ref<SharedResourceMemoryContents> SharedTextureMemory::CreateContents() {
+ return AcquireRef(new SharedTextureMemoryContentsD3D11(GetWeakRef(this)));
+}
+
+MaybeError SharedTextureMemory::BeginAccessImpl(
+ TextureBase* texture,
+ const UnpackedPtr<SharedTextureMemoryBeginAccessDescriptor>& descriptor) {
+ DAWN_TRY(d3d::SharedTextureMemory::BeginAccessImpl(texture, descriptor));
+
+ auto* contents = static_cast<SharedTextureMemoryContentsD3D11*>(GetContents());
+
+ if (mRequiresFenceSignalOverride) {
+ contents->mRequiresFenceSignal = *mRequiresFenceSignalOverride;
+ } else if (auto* d3d11beginState = descriptor.Get<SharedTextureMemoryD3D11BeginState>()) {
+ contents->mRequiresFenceSignal |= d3d11beginState->requiresEndAccessFence;
+ } else {
+ // If there is no SharedTextureMemoryD3D11BeginState, default to true
+ contents->mRequiresFenceSignal = true;
+ }
+
+ return {};
+}
+
+ResultOrError<FenceAndSignalValue> SharedTextureMemory::EndAccessImpl(
+ TextureBase* texture,
+ ExecutionSerial lastUsageSerial,
+ UnpackedPtr<SharedTextureMemoryEndAccessState>& descriptor) {
+ FenceAndSignalValue fenceAndSignalValue;
+
+ DAWN_TRY_ASSIGN(fenceAndSignalValue,
+ d3d::SharedTextureMemory::EndAccessImpl(texture, lastUsageSerial, descriptor));
+
+ auto* contents = static_cast<SharedTextureMemoryContentsD3D11*>(GetContents());
+ if (!contents->HasAccess()) {
+ // Reset fence requirement flag.
+ contents->mRequiresFenceSignal = false;
+ }
+
+ return fenceAndSignalValue;
}
} // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/SharedTextureMemoryD3D11.h b/src/dawn/native/d3d11/SharedTextureMemoryD3D11.h
index 49b24ff..da5a37e 100644
--- a/src/dawn/native/d3d11/SharedTextureMemoryD3D11.h
+++ b/src/dawn/native/d3d11/SharedTextureMemoryD3D11.h
@@ -28,6 +28,8 @@
#ifndef SRC_DAWN_NATIVE_D3D11_SHARED_TEXTURE_MEMORY_D3D11_H_
#define SRC_DAWN_NATIVE_D3D11_SHARED_TEXTURE_MEMORY_D3D11_H_
+#include <optional>
+
#include "dawn/native/Error.h"
#include "dawn/native/d3d/SharedTextureMemoryD3D.h"
#include "dawn/native/d3d/d3d_platform.h"
@@ -41,6 +43,20 @@
class Device;
struct SharedTextureMemoryD3D11Texture2DDescriptor;
+class SharedTextureMemoryContentsD3D11 final : public SharedTextureMemoryContents {
+ public:
+ using SharedTextureMemoryContents::SharedTextureMemoryContents;
+
+ bool RequiresFenceSignal() const { return mRequiresFenceSignal; }
+
+ private:
+ friend class SharedTextureMemory;
+
+ // Flag indicates whether we need to signal a fence after accessing this texture or not.
+ // This flag will be updated in BeginAccess() & reset in EndAccess().
+ bool mRequiresFenceSignal = false;
+};
+
class SharedTextureMemory final : public d3d::SharedTextureMemory {
public:
static ResultOrError<Ref<SharedTextureMemory>> Create(
@@ -62,18 +78,29 @@
StringView label,
SharedTextureMemoryProperties properties,
ComPtr<ID3D11Resource> resource,
- bool requiresFenceSignal);
+ std::optional<bool> requiresFenceSignalOverride = std::nullopt);
void DestroyImpl() override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
+ Ref<SharedResourceMemoryContents> CreateContents() override;
+
+ MaybeError BeginAccessImpl(TextureBase* texture,
+ const UnpackedPtr<BeginAccessDescriptor>& descriptor) override;
+ ResultOrError<FenceAndSignalValue> EndAccessImpl(
+ TextureBase* texture,
+ ExecutionSerial lastUsageSerial,
+ UnpackedPtr<EndAccessState>& descriptor) override;
+
ComPtr<ID3D11Resource> mResource;
Ref<d3d::KeyedMutex> mKeyedMutex;
// Flag indicates whether we need to signal a fence after accessing this texture or not.
- const bool mRequiresFenceSignal = true;
+ // TODO(chromium:335003893): This flag is deprecated. Remove it once clients are updated to use
+ // SharedTextureMemoryD3D11BeginState's requiresEndAccessFence.
+ const std::optional<bool> mRequiresFenceSignalOverride;
};
} // namespace d3d11
} // namespace dawn::native
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index bcc01c3..6885a96 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -175,11 +175,9 @@
// static
ResultOrError<Ref<Texture>> Texture::CreateFromSharedTextureMemory(
SharedTextureMemory* memory,
- const UnpackedPtr<TextureDescriptor>& descriptor,
- bool requiresFenceSignal) {
+ const UnpackedPtr<TextureDescriptor>& descriptor) {
Device* device = ToBackend(memory->GetDevice());
- Ref<Texture> texture =
- AcquireRef(new Texture(device, descriptor, Kind::Normal, requiresFenceSignal));
+ Ref<Texture> texture = AcquireRef(new Texture(device, descriptor, Kind::Normal));
DAWN_TRY(
texture->InitializeAsExternalTexture(memory->GetD3DResource(), memory->GetKeyedMutex()));
texture->mSharedResourceMemoryContents = memory->GetContents();
@@ -305,11 +303,8 @@
return {};
}
-Texture::Texture(Device* device,
- const UnpackedPtr<TextureDescriptor>& descriptor,
- Kind kind,
- bool requiresFenceSignal)
- : Base(device, descriptor), mKind(kind), mRequiresFenceSignal(requiresFenceSignal) {}
+Texture::Texture(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, Kind kind)
+ : Base(device, descriptor), mKind(kind) {}
Texture::~Texture() = default;
@@ -424,7 +419,8 @@
MaybeError Texture::SynchronizeTextureBeforeUse(
const ScopedCommandRecordingContext* commandContext) {
- if (auto* contents = GetSharedResourceMemoryContents()) {
+ if (auto* contents =
+ static_cast<SharedTextureMemoryContentsD3D11*>(GetSharedResourceMemoryContents())) {
const auto* device = ToBackend(GetDevice());
const auto& queueFence = ToBackend(device->GetQueue())->GetSharedFence();
@@ -442,7 +438,9 @@
CheckHRESULT(commandContext->Wait(d3dFence->GetD3DFence(), fence.signaledValue),
"ID3D11DeviceContext4::Wait"));
}
- if (mRequiresFenceSignal && !device->IsToggleEnabled(Toggle::D3D11DisableFence)) {
+
+ const bool requiresFenceSignal = contents->RequiresFenceSignal();
+ if (requiresFenceSignal && !device->IsToggleEnabled(Toggle::D3D11DisableFence)) {
commandContext->SetNeedsFence();
}
}
diff --git a/src/dawn/native/d3d11/TextureD3D11.h b/src/dawn/native/d3d11/TextureD3D11.h
index e182bff..e3a5928 100644
--- a/src/dawn/native/d3d11/TextureD3D11.h
+++ b/src/dawn/native/d3d11/TextureD3D11.h
@@ -64,8 +64,7 @@
ComPtr<ID3D11Resource> d3d11Texture);
static ResultOrError<Ref<Texture>> CreateFromSharedTextureMemory(
SharedTextureMemory* memory,
- const UnpackedPtr<TextureDescriptor>& descriptor,
- bool requiresFenceSignal);
+ const UnpackedPtr<TextureDescriptor>& descriptor);
ID3D11Resource* GetD3D11Resource() const;
ResultOrError<ComPtr<ID3D11RenderTargetView1>> CreateD3D11RenderTargetView(
@@ -132,10 +131,7 @@
static ResultOrError<Ref<Texture>>
CreateInternal(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, Kind kind);
- Texture(Device* device,
- const UnpackedPtr<TextureDescriptor>& descriptor,
- Kind kind,
- bool requiresFenceSignal = false);
+ Texture(Device* device, const UnpackedPtr<TextureDescriptor>& descriptor, Kind kind);
~Texture() override;
template <typename T>
@@ -198,7 +194,6 @@
const Kind mKind = Kind::Normal;
ComPtr<ID3D11Resource> mD3d11Resource;
Ref<d3d::KeyedMutex> mKeyedMutex;
- const bool mRequiresFenceSignal = false;
// The internal 'R8Uint' texture for sampling stencil from depth-stencil textures.
Ref<Texture> mTextureForStencilSampling;
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests_win.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests_win.cpp
index d232e0d..07798bf 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests_win.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests_win.cpp
@@ -32,6 +32,7 @@
#include <webgpu/webgpu_cpp.h>
#include <wrl/client.h>
+#include <memory>
#include <sstream>
#include <string>
#include <utility>
@@ -52,6 +53,10 @@
D3D11Texture2D,
};
+struct BeginState : public SharedTextureMemoryTestBackend::BackendBeginState {
+ wgpu::SharedTextureMemoryD3D11BeginState beginState{};
+};
+
class Backend : public SharedTextureMemoryTestBackend {
public:
template <Mode kMode>
@@ -66,34 +71,37 @@
return &b;
}
+ template <Mode kMode>
static Backend* GetInstanceWithoutEndAccessFence() {
- static Backend b(Mode::D3D11Texture2D, /*useKeyedMutex=*/false,
+ static Backend b(kMode, /*useKeyedMutex=*/false,
/*requiresEndAccessFence=*/false);
return &b;
}
std::string Name() const override {
+ std::ostringstream ss;
switch (mMode) {
case Mode::D3D11Texture2D: {
- std::ostringstream ss;
ss << "D3D11Texture2D";
- if (mUseKeyedMutex) {
- ss << " KeyedMutex";
- }
-
- if (!mRequiresEndAccessFence) {
- ss << " NoEndAccessFence";
- }
-
- return ss.str();
- }
+ } break;
case Mode::DXGISharedHandle: {
- return mUseKeyedMutex ? "DXGISharedHandle KeyedMutex" : "DXGISharedHandle";
- }
+ ss << "DXGISharedHandle";
+ } break;
}
+ if (mUseKeyedMutex) {
+ ss << " KeyedMutex";
+ }
+
+ if (!mRequiresEndAccessFence) {
+ ss << " NoEndAccessFence";
+ }
+
+ return ss.str();
}
- bool UseSameDevice() const override { return mMode == Mode::D3D11Texture2D; }
+ bool UseSameDevice() const override {
+ return mMode == Mode::D3D11Texture2D || !mRequiresEndAccessFence;
+ }
bool SupportsConcurrentRead() const override { return true; }
void SetUp(const wgpu::Device& device) override {
@@ -197,7 +205,6 @@
case Mode::D3D11Texture2D: {
native::d3d11::SharedTextureMemoryD3D11Texture2DDescriptor texture2DDesc;
texture2DDesc.texture = std::move(d3d11Texture);
- texture2DDesc.requiresEndAccessFence = mRequiresEndAccessFence;
wgpu::SharedTextureMemoryDescriptor desc;
desc.nextInChain = &texture2DDesc;
@@ -356,6 +363,20 @@
return memories;
}
+ std::unique_ptr<BackendBeginState> ChainInitialBeginState(
+ wgpu::SharedTextureMemoryBeginAccessDescriptor* beginDesc) override {
+ auto state = std::make_unique<BeginState>();
+ state->beginState.requiresEndAccessFence = mRequiresEndAccessFence;
+ beginDesc->nextInChain = &state->beginState;
+ return state;
+ }
+
+ std::unique_ptr<BackendBeginState> ChainBeginState(
+ wgpu::SharedTextureMemoryBeginAccessDescriptor* beginDesc,
+ const wgpu::SharedTextureMemoryEndAccessState& endState) override {
+ return ChainInitialBeginState(beginDesc);
+ }
+
private:
Backend(Mode mode, bool useKeyedMutex, bool requiresEndAccessFence)
: mMode(mode),
@@ -579,30 +600,34 @@
Backend::GetKeyedMutexInstance<Mode::DXGISharedHandle>()},
{1});
-DAWN_INSTANTIATE_PREFIXED_TEST_P(D3D,
- SharedTextureMemoryTests,
- {D3D11Backend(), D3D11Backend({"d3d11_delay_flush_to_gpu"}),
- D3D11Backend({"d3d11_disable_fence"}), D3D12Backend()},
- {Backend::GetInstance<Mode::DXGISharedHandle>(),
- Backend::GetKeyedMutexInstance<Mode::DXGISharedHandle>()},
- {1});
+DAWN_INSTANTIATE_PREFIXED_TEST_P(
+ D3D,
+ SharedTextureMemoryTests,
+ {D3D11Backend(), D3D11Backend({"d3d11_delay_flush_to_gpu"}),
+ D3D11Backend({"d3d11_disable_fence"}), D3D12Backend()},
+ {Backend::GetInstance<Mode::DXGISharedHandle>(),
+ Backend::GetKeyedMutexInstance<Mode::DXGISharedHandle>(),
+ Backend::GetInstanceWithoutEndAccessFence<Mode::DXGISharedHandle>()},
+ {1});
-DAWN_INSTANTIATE_PREFIXED_TEST_P(D3D11,
- SharedTextureMemoryNoFeatureTests,
- {D3D11Backend(), D3D11Backend({"d3d11_disable_fence"})},
- {Backend::GetInstance<Mode::D3D11Texture2D>(),
- Backend::GetKeyedMutexInstance<Mode::D3D11Texture2D>(),
- Backend::GetInstanceWithoutEndAccessFence()},
- {1, 2});
+DAWN_INSTANTIATE_PREFIXED_TEST_P(
+ D3D11,
+ SharedTextureMemoryNoFeatureTests,
+ {D3D11Backend(), D3D11Backend({"d3d11_disable_fence"})},
+ {Backend::GetInstance<Mode::D3D11Texture2D>(),
+ Backend::GetKeyedMutexInstance<Mode::D3D11Texture2D>(),
+ Backend::GetInstanceWithoutEndAccessFence<Mode::D3D11Texture2D>()},
+ {1, 2});
-DAWN_INSTANTIATE_PREFIXED_TEST_P(D3D11,
- SharedTextureMemoryTests,
- {D3D11Backend(), D3D11Backend({"d3d11_delay_flush_to_gpu"}),
- D3D11Backend({"d3d11_disable_fence"})},
- {Backend::GetInstance<Mode::D3D11Texture2D>(),
- Backend::GetKeyedMutexInstance<Mode::D3D11Texture2D>(),
- Backend::GetInstanceWithoutEndAccessFence()},
- {1, 2});
+DAWN_INSTANTIATE_PREFIXED_TEST_P(
+ D3D11,
+ SharedTextureMemoryTests,
+ {D3D11Backend(), D3D11Backend({"d3d11_delay_flush_to_gpu"}),
+ D3D11Backend({"d3d11_disable_fence"})},
+ {Backend::GetInstance<Mode::D3D11Texture2D>(),
+ Backend::GetKeyedMutexInstance<Mode::D3D11Texture2D>(),
+ Backend::GetInstanceWithoutEndAccessFence<Mode::D3D11Texture2D>()},
+ {1, 2});
DAWN_INSTANTIATE_PREFIXED_TEST_P(D3D11,
SharedTextureMemoryWithFenceDisabledTests,