[dawn][native] Split DynamicArrayState to its own class. The logic of the dynamic array is very different from the one for static bindings of a BindGroup. Tracking of pinned / unpinned resources and metadata buffer updates will get non-trivial so it is better to separate the classes in different files. Bug: 435317394 Change-Id: I8b4514f56b2eb7a50ed86e5be9623f719ce684f0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/259194 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: dan sinclair <dsinclair@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index ab6ad62..1b1d8a1 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn
@@ -278,6 +278,8 @@ "Device.h", "DeviceGuard.cpp", "DeviceGuard.h", + "DynamicArrayState.cpp", + "DynamicArrayState.h", "DynamicUploader.cpp", "DynamicUploader.h", "EncodingContext.cpp",
diff --git a/src/dawn/native/BindGroup.cpp b/src/dawn/native/BindGroup.cpp index 73bd805..0bd5f3a 100644 --- a/src/dawn/native/BindGroup.cpp +++ b/src/dawn/native/BindGroup.cpp
@@ -42,6 +42,7 @@ #include "dawn/native/Buffer.h" #include "dawn/native/CommandValidation.h" #include "dawn/native/Device.h" +#include "dawn/native/DynamicArrayState.h" #include "dawn/native/ExternalTexture.h" #include "dawn/native/ObjectBase.h" #include "dawn/native/ObjectType_autogen.h" @@ -814,9 +815,9 @@ // Gather dynamic binding entries in a second loop to put the handling off the critical path. if (auto* dynamic = descriptor.Get<BindGroupDynamicBindingArray>()) { - mDynamicArray = std::make_unique<DynamicArrayState>( - GetDevice(), BindingIndex(dynamic->dynamicArraySize)); - DAWN_TRY(mDynamicArray->Initialize()); + mDynamicArray = + std::make_unique<DynamicArrayState>(BindingIndex(dynamic->dynamicArraySize)); + DAWN_TRY(mDynamicArray->Initialize(GetDevice())); for (uint32_t i = 0; i < descriptor->entryCount; ++i) { UnpackedPtr<BindGroupEntry> entry = Unpack(&descriptor->entries[i]); @@ -967,12 +968,6 @@ return mDynamicArray != nullptr; } -BindingIndex BindGroupBase::GetDynamicArraySize() const { - DAWN_ASSERT(!IsError()); - DAWN_ASSERT(HasDynamicArray()); - return mDynamicArray->GetSize(); -} - ityp::span<BindingIndex, const Ref<TextureViewBase>> BindGroupBase::GetDynamicArrayBindings() const { DAWN_ASSERT(!IsError()); @@ -997,61 +992,4 @@ return {}; } -BindGroupBase::DynamicArrayState::DynamicArrayState(DeviceBase* device, BindingIndex size) - : mDevice(device) { - mBindings.resize(size); -} - -MaybeError BindGroupBase::DynamicArrayState::Initialize() { - // Create a storage buffer that will hold the shader-visible metadata for the dynamic array. - BufferDescriptor metadataDesc{ - .label = "binding array metadata", - .usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, - .size = 4, - .mappedAtCreation = true, - }; - DAWN_TRY_ASSIGN(mMetadataBuffer, mDevice->CreateBuffer(&metadataDesc)); - - // TODO(https://crbug.com/439522242): For now it only contains the size but we also need to add - // type information for each entry in the future. - uint32_t* data = static_cast<uint32_t*>(mMetadataBuffer->GetMappedRange(0, metadataDesc.size)); - *data = uint32_t(mBindings.size()); - DAWN_TRY(mMetadataBuffer->Unmap()); - - return {}; -} - -BindingIndex BindGroupBase::DynamicArrayState::GetSize() const { - DAWN_ASSERT(!mDestroyed); - return mBindings.size(); -} - -ityp::span<BindingIndex, const Ref<TextureViewBase>> BindGroupBase::DynamicArrayState::GetBindings() - const { - DAWN_ASSERT(!mDestroyed); - return {mBindings.data(), mBindings.size()}; -} - -BufferBase* BindGroupBase::DynamicArrayState::GetMetadataBuffer() const { - DAWN_ASSERT(!mDestroyed); - return mMetadataBuffer.Get(); -} - -bool BindGroupBase::DynamicArrayState::IsDestroyed() const { - return mDestroyed; -} - -void BindGroupBase::DynamicArrayState::Update(BindingIndex i, TextureViewBase* view) { - DAWN_ASSERT(!mDestroyed); - mBindings[i] = view; -} - -void BindGroupBase::DynamicArrayState::Destroy() { - DAWN_ASSERT(!mDestroyed); - mBindings.clear(); - mMetadataBuffer->Destroy(); - mMetadataBuffer = nullptr; - mDestroyed = true; -} - } // namespace dawn::native
diff --git a/src/dawn/native/BindGroup.h b/src/dawn/native/BindGroup.h index 7fd07cf..77bcafc 100644 --- a/src/dawn/native/BindGroup.h +++ b/src/dawn/native/BindGroup.h
@@ -35,7 +35,6 @@ #include "dawn/common/Constants.h" #include "dawn/common/Math.h" #include "dawn/common/ityp_span.h" -#include "dawn/common/ityp_vector.h" #include "dawn/native/BindGroupLayout.h" #include "dawn/native/ChainUtils.h" #include "dawn/native/Error.h" @@ -48,6 +47,7 @@ namespace dawn::native { class DeviceBase; +class DynamicArrayState; ResultOrError<UnpackedPtr<BindGroupDescriptor>> ValidateBindGroupDescriptor( DeviceBase* device, @@ -86,9 +86,9 @@ void ForEachUnverifiedBufferBindingIndex(std::function<void(BindingIndex, uint32_t)> fn) const; - // Getters and operations on the dynamic array part. + // Getters and operations on the dynamic array part for code that doesn't need to directly + // modify the state. bool HasDynamicArray() const; - BindingIndex GetDynamicArraySize() const; ityp::span<BindingIndex, const Ref<TextureViewBase>> GetDynamicArrayBindings() const; MaybeError ValidateCanUseOnQueueNow() const; @@ -133,26 +133,6 @@ // The dynamic array is separate so as to not bloat the size and destructor of bind groups // without them. - class DynamicArrayState { - public: - explicit DynamicArrayState(DeviceBase* device, BindingIndex size); - - MaybeError Initialize(); - - BindingIndex GetSize() const; - ityp::span<BindingIndex, const Ref<TextureViewBase>> GetBindings() const; - BufferBase* GetMetadataBuffer() const; - bool IsDestroyed() const; - - void Update(BindingIndex i, TextureViewBase* view); - void Destroy(); - - private: - bool mDestroyed = false; - ityp::vector<BindingIndex, Ref<TextureViewBase>> mBindings; - raw_ptr<DeviceBase> mDevice; - Ref<BufferBase> mMetadataBuffer; - }; std::unique_ptr<DynamicArrayState> mDynamicArray; };
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index 62eb7f4..354577a 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt
@@ -80,6 +80,7 @@ "dawn_platform.h" "Device.h" "DeviceGuard.h" + "DynamicArrayState.h" "DynamicUploader.h" "EncodingContext.h" "EnumClassBitmasks.h" @@ -201,6 +202,7 @@ "CreatePipelineAsyncEvent.cpp" "Device.cpp" "DeviceGuard.cpp" + "DynamicArrayState.cpp" "DynamicUploader.cpp" "EncodingContext.cpp" "Error.cpp"
diff --git a/src/dawn/native/DynamicArrayState.cpp b/src/dawn/native/DynamicArrayState.cpp new file mode 100644 index 0000000..d5902d6 --- /dev/null +++ b/src/dawn/native/DynamicArrayState.cpp
@@ -0,0 +1,90 @@ +// Copyright 2025 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/DynamicArrayState.h" + +#include "dawn/native/Buffer.h" +#include "dawn/native/Device.h" + +namespace dawn::native { + +DynamicArrayState::DynamicArrayState(BindingIndex size) { + mBindings.resize(size); +} + +MaybeError DynamicArrayState::Initialize(DeviceBase* device) { + // Create a storage buffer that will hold the shader-visible metadata for the dynamic array. + BufferDescriptor metadataDesc{ + .label = "binding array metadata", + .usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, + .size = 4, + .mappedAtCreation = true, + }; + DAWN_TRY_ASSIGN(mMetadataBuffer, device->CreateBuffer(&metadataDesc)); + + // TODO(https://crbug.com/439522242): For now it only contains the size but we also need to add + // type information for each entry in the future. + uint32_t* data = static_cast<uint32_t*>(mMetadataBuffer->GetMappedRange(0, metadataDesc.size)); + *data = uint32_t(mBindings.size()); + DAWN_TRY(mMetadataBuffer->Unmap()); + + return {}; +} + +BindingIndex DynamicArrayState::GetSize() const { + DAWN_ASSERT(!mDestroyed); + return mBindings.size(); +} + +ityp::span<BindingIndex, const Ref<TextureViewBase>> DynamicArrayState::GetBindings() const { + DAWN_ASSERT(!mDestroyed); + return {mBindings.data(), mBindings.size()}; +} + +BufferBase* DynamicArrayState::GetMetadataBuffer() const { + DAWN_ASSERT(!mDestroyed); + return mMetadataBuffer.Get(); +} + +bool DynamicArrayState::IsDestroyed() const { + return mDestroyed; +} + +void DynamicArrayState::Update(BindingIndex i, TextureViewBase* view) { + DAWN_ASSERT(!mDestroyed); + mBindings[i] = view; +} + +void DynamicArrayState::Destroy() { + DAWN_ASSERT(!mDestroyed); + mBindings.clear(); + mMetadataBuffer->Destroy(); + mMetadataBuffer = nullptr; + mDestroyed = true; +} + +} // namespace dawn::native
diff --git a/src/dawn/native/DynamicArrayState.h b/src/dawn/native/DynamicArrayState.h new file mode 100644 index 0000000..1ddeae7 --- /dev/null +++ b/src/dawn/native/DynamicArrayState.h
@@ -0,0 +1,70 @@ +// Copyright 2025 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_DYNAMICARRAYSTATE_H_ +#define SRC_DAWN_NATIVE_DYNAMICARRAYSTATE_H_ + +#include <vector> + +#include "dawn/common/Ref.h" +#include "dawn/common/ityp_span.h" +#include "dawn/common/ityp_vector.h" +#include "dawn/native/Error.h" +#include "dawn/native/Forward.h" +#include "dawn/native/IntegerTypes.h" +#include "dawn/native/dawn_platform.h" +#include "partition_alloc/pointers/raw_ptr.h" + +namespace dawn::native { + +// An optional component of a BindGroup that's used to track the resources that are in the dynamic +// binding array part. It helps maintain the metadata buffer that's used in shaders to know if it is +// valid to access an entry of the dynamic binding array with a given type (note that the writing of +// the updates to the buffer are done by the backends). +class DynamicArrayState { + public: + explicit DynamicArrayState(BindingIndex size); + + MaybeError Initialize(DeviceBase* device); + + BindingIndex GetSize() const; + ityp::span<BindingIndex, const Ref<TextureViewBase>> GetBindings() const; + BufferBase* GetMetadataBuffer() const; + bool IsDestroyed() const; + + void Update(BindingIndex i, TextureViewBase* view); + void Destroy(); + + private: + bool mDestroyed = false; + ityp::vector<BindingIndex, Ref<TextureViewBase>> mBindings; + Ref<BufferBase> mMetadataBuffer; +}; + +} // namespace dawn::native + +#endif // SRC_DAWN_NATIVE_DYNAMICARRAYSTATE_H_