[WebGPU backend] Implement queue.WriteBuffer
Add BufferWGPU, CommandBufferWGPU.
Enable related end2end tests.
Implement webgpu::Queue::WriteBufferImpl,
SubmitImpl, Buffer::MapAsync and Command::CopyBufferToBuffer
to be able to run certain writeBuffer tests.
Bug: 413053623
Change-Id: I94c7e100fc2e54c0c951485129501426b7b1e469
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243114
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index c8468eb..1d6a81f 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -706,6 +706,10 @@
sources += [
"webgpu/BackendWGPU.cpp",
"webgpu/BackendWGPU.h",
+ "webgpu/BufferWGPU.cpp",
+ "webgpu/BufferWGPU.h",
+ "webgpu/CommandBufferWGPU.cpp",
+ "webgpu/CommandBufferWGPU.h",
"webgpu/DeviceWGPU.cpp",
"webgpu/DeviceWGPU.h",
"webgpu/Forward.h",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 2871791..d86d06b 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -571,6 +571,8 @@
)
list(APPEND private_headers
"webgpu/BackendWGPU.h"
+ "webgpu/BufferWGPU.h"
+ "webgpu/CommandBufferWGPU.h"
"webgpu/DeviceWGPU.h"
"webgpu/Forward.h"
"webgpu/PhysicalDeviceWGPU.h"
@@ -578,6 +580,8 @@
)
list(APPEND sources
"webgpu/BackendWGPU.cpp"
+ "webgpu/BufferWGPU.cpp"
+ "webgpu/CommandBufferWGPU.cpp"
"webgpu/DeviceWGPU.cpp"
"webgpu/PhysicalDeviceWGPU.cpp"
"webgpu/QueueWGPU.cpp"
diff --git a/src/dawn/native/webgpu/BufferWGPU.cpp b/src/dawn/native/webgpu/BufferWGPU.cpp
new file mode 100644
index 0000000..623520a
--- /dev/null
+++ b/src/dawn/native/webgpu/BufferWGPU.cpp
@@ -0,0 +1,142 @@
+// 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/webgpu/BufferWGPU.h"
+
+#include <string>
+#include <utility>
+
+#include "dawn/common/StringViewUtils.h"
+#include "dawn/native/Buffer.h"
+#include "dawn/native/webgpu/DeviceWGPU.h"
+#include "dawn/native/webgpu/QueueWGPU.h"
+
+namespace dawn::native::webgpu {
+
+// static
+ResultOrError<Ref<Buffer>> Buffer::Create(Device* device,
+ const UnpackedPtr<BufferDescriptor>& descriptor) {
+ auto desc = ToAPI(*descriptor);
+ WGPUBuffer innerBuffer = device->wgpu.deviceCreateBuffer(device->GetInnerHandle(), desc);
+ if (innerBuffer == nullptr) {
+ // innerBuffer can be nullptr when mappedAtCreation == true and fails.
+ // Return an error buffer.
+ const BufferDescriptor* rawDescriptor = *descriptor;
+ return ToBackend(BufferBase::MakeError(device, rawDescriptor));
+ }
+
+ Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor, innerBuffer));
+ return std::move(buffer);
+}
+
+Buffer::Buffer(Device* device,
+ const UnpackedPtr<BufferDescriptor>& descriptor,
+ WGPUBuffer innerBuffer)
+ : BufferBase(device, descriptor), mInnerBuffer(innerBuffer) {
+ mAllocatedSize = GetSize();
+}
+
+WGPUBuffer Buffer::GetInnerHandle() const {
+ return mInnerBuffer;
+}
+
+bool Buffer::IsCPUWritableAtCreation() const {
+ return ToBackend(GetDevice())->wgpu.bufferGetMapState(mInnerBuffer) ==
+ WGPUBufferMapState_Mapped;
+}
+
+MaybeError Buffer::MapAtCreationImpl() {
+ return DAWN_UNIMPLEMENTED_ERROR("Not implemented");
+}
+
+MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
+ struct MapAsyncResult {
+ WGPUMapAsyncStatus status;
+ std::string message;
+ } mapAsyncResult = {};
+
+ WGPUBufferMapCallbackInfo innerCallbackInfo = {};
+ innerCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly;
+ innerCallbackInfo.callback = [](WGPUMapAsyncStatus status, WGPUStringView message,
+ void* result_param, void* userdata_param) {
+ MapAsyncResult* result = reinterpret_cast<MapAsyncResult*>(result_param);
+ result->status = status;
+ result->message = ToString(message);
+ };
+ innerCallbackInfo.userdata1 = &mapAsyncResult;
+ innerCallbackInfo.userdata2 = this;
+
+ auto& wgpu = ToBackend(GetDevice())->wgpu;
+
+ // TODO(crbug.com/413053623): We do not have a way to efficiently process the async event
+ // on the inner webgpu layer. For now we simply wait on the future.
+ WGPUFutureWaitInfo waitInfo = {};
+ waitInfo.future = wgpu.bufferMapAsync(mInnerBuffer, static_cast<WGPUMapMode>(mode), offset,
+ size, innerCallbackInfo);
+ wgpu.instanceWaitAny(ToBackend(GetDevice())->GetInnerInstance(), 1, &waitInfo, UINT64_MAX);
+
+ if (mapAsyncResult.status != WGPUMapAsyncStatus_Success) {
+ return DAWN_INTERNAL_ERROR(mapAsyncResult.message);
+ }
+
+ // The frontend asks that the pointer returned by GetMappedPointer is from the start of
+ // the resource but WGPU gives us the pointer at offset. Remove the offset.
+ if (bool{mode & wgpu::MapMode::Write}) {
+ mMappedData =
+ static_cast<uint8_t*>(wgpu.bufferGetMappedRange(mInnerBuffer, offset, size)) - offset;
+ } else if (bool{mode & wgpu::MapMode::Read}) {
+ mMappedData = static_cast<uint8_t*>(const_cast<void*>(
+ wgpu.bufferGetConstMappedRange(mInnerBuffer, offset, size))) -
+ offset;
+ } else {
+ DAWN_UNREACHABLE();
+ }
+ return {};
+}
+
+void* Buffer::GetMappedPointer() {
+ // The mapping offset has already been removed.
+ return mMappedData;
+}
+
+void Buffer::UnmapImpl() {
+ if (mInnerBuffer) {
+ ToBackend(GetDevice())->wgpu.bufferUnmap(mInnerBuffer);
+ }
+ mMappedData = nullptr;
+}
+
+void Buffer::DestroyImpl() {
+ BufferBase::DestroyImpl();
+
+ if (mInnerBuffer) {
+ ToBackend(GetDevice())->wgpu.bufferRelease(mInnerBuffer);
+ mInnerBuffer = nullptr;
+ }
+}
+
+} // namespace dawn::native::webgpu
diff --git a/src/dawn/native/webgpu/BufferWGPU.h b/src/dawn/native/webgpu/BufferWGPU.h
new file mode 100644
index 0000000..b171b4b
--- /dev/null
+++ b/src/dawn/native/webgpu/BufferWGPU.h
@@ -0,0 +1,62 @@
+// 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_WEBGPU_BUFFERWGPU_H_
+#define SRC_DAWN_NATIVE_WEBGPU_BUFFERWGPU_H_
+
+#include "dawn/native/Buffer.h"
+
+#include "dawn/native/webgpu/Forward.h"
+
+namespace dawn::native::webgpu {
+
+class Device;
+
+class Buffer final : public BufferBase {
+ public:
+ static ResultOrError<Ref<Buffer>> Create(Device* device,
+ const UnpackedPtr<BufferDescriptor>& descriptor);
+ Buffer(Device* device, const UnpackedPtr<BufferDescriptor>& descriptor, WGPUBuffer innerBuffer);
+
+ WGPUBuffer GetInnerHandle() const;
+
+ private:
+ MaybeError MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) override;
+ void UnmapImpl() override;
+ void DestroyImpl() override;
+ bool IsCPUWritableAtCreation() const override;
+ MaybeError MapAtCreationImpl() override;
+ void* GetMappedPointer() override;
+
+ WGPUBuffer mInnerBuffer = nullptr;
+
+ raw_ptr<void> mMappedData = nullptr;
+};
+
+} // namespace dawn::native::webgpu
+
+#endif // SRC_DAWN_NATIVE_WEBGPU_BUFFERWGPU_H_
diff --git a/src/dawn/native/webgpu/CommandBufferWGPU.cpp b/src/dawn/native/webgpu/CommandBufferWGPU.cpp
new file mode 100644
index 0000000..0ff5213
--- /dev/null
+++ b/src/dawn/native/webgpu/CommandBufferWGPU.cpp
@@ -0,0 +1,73 @@
+// 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/webgpu/CommandBufferWGPU.h"
+
+#include "dawn/native/webgpu/BufferWGPU.h"
+#include "dawn/native/webgpu/DeviceWGPU.h"
+
+namespace dawn::native::webgpu {
+
+// static
+Ref<CommandBuffer> CommandBuffer::Create(CommandEncoder* encoder,
+ const CommandBufferDescriptor* descriptor) {
+ return AcquireRef(new CommandBuffer(encoder, descriptor));
+}
+
+CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)
+ : CommandBufferBase(encoder, descriptor) {}
+
+WGPUCommandBuffer CommandBuffer::Encode() {
+ auto& wgpu = ToBackend(GetDevice())->wgpu;
+
+ // TODO(crbug.com/413053623): Use stored command encoder descriptor
+ WGPUCommandEncoder innerEncoder =
+ wgpu.deviceCreateCommandEncoder(ToBackend(GetDevice())->GetInnerHandle(), nullptr);
+
+ Command type;
+ while (mCommands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::CopyBufferToBuffer: {
+ CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
+ wgpu.commandEncoderCopyBufferToBuffer(
+ innerEncoder, ToBackend(copy->source)->GetInnerHandle(), copy->sourceOffset,
+ ToBackend(copy->destination)->GetInnerHandle(), copy->destinationOffset,
+ copy->size);
+ break;
+ }
+ default:
+ DAWN_UNREACHABLE();
+ }
+ }
+
+ // TODO(crbug.com/413053623): Store WGPUCommandBufferDescriptor and assign here.
+ WGPUCommandBuffer result = wgpu.commandEncoderFinish(innerEncoder, nullptr);
+ wgpu.commandEncoderRelease(innerEncoder);
+ return result;
+}
+
+} // namespace dawn::native::webgpu
diff --git a/src/dawn/native/webgpu/CommandBufferWGPU.h b/src/dawn/native/webgpu/CommandBufferWGPU.h
new file mode 100644
index 0000000..678a30b
--- /dev/null
+++ b/src/dawn/native/webgpu/CommandBufferWGPU.h
@@ -0,0 +1,50 @@
+// 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_WEBGPU_COMMANDBUFFERWGPU_H_
+#define SRC_DAWN_NATIVE_WEBGPU_COMMANDBUFFERWGPU_H_
+
+#include "dawn/native/CommandBuffer.h"
+
+#include "dawn/native/webgpu/Forward.h"
+
+namespace dawn::native::webgpu {
+
+class CommandBuffer final : public CommandBufferBase {
+ public:
+ static Ref<CommandBuffer> Create(CommandEncoder* encoder,
+ const CommandBufferDescriptor* descriptor);
+
+ WGPUCommandBuffer Encode();
+
+ private:
+ CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
+};
+
+} // namespace dawn::native::webgpu
+
+#endif // SRC_DAWN_NATIVE_WEBGPU_COMMANDBUFFERWGPU_H_
diff --git a/src/dawn/native/webgpu/DeviceWGPU.cpp b/src/dawn/native/webgpu/DeviceWGPU.cpp
index 911a272..aceb775 100644
--- a/src/dawn/native/webgpu/DeviceWGPU.cpp
+++ b/src/dawn/native/webgpu/DeviceWGPU.cpp
@@ -50,6 +50,9 @@
#include "dawn/native/Surface.h"
#include "dawn/native/SwapChain.h"
#include "dawn/native/Texture.h"
+#include "dawn/native/webgpu/BackendWGPU.h"
+#include "dawn/native/webgpu/BufferWGPU.h"
+#include "dawn/native/webgpu/CommandBufferWGPU.h"
#include "dawn/native/webgpu/PhysicalDeviceWGPU.h"
#include "dawn/native/webgpu/QueueWGPU.h"
@@ -115,6 +118,10 @@
return mInnerDevice;
}
+WGPUInstance Device::GetInnerInstance() const {
+ return ToBackend(GetPhysicalDevice())->GetBackend()->GetInnerInstance();
+}
+
MaybeError Device::Initialize(const UnpackedPtr<DeviceDescriptor>& descriptor) {
Ref<Queue> queue;
DAWN_TRY_ASSIGN(queue, Queue::Create(this, &descriptor->defaultQueue));
@@ -134,12 +141,14 @@
}
ResultOrError<Ref<BufferBase>> Device::CreateBufferImpl(
const UnpackedPtr<BufferDescriptor>& descriptor) {
- return Ref<BufferBase>{nullptr};
+ return Buffer::Create(this, descriptor);
}
ResultOrError<Ref<CommandBufferBase>> Device::CreateCommandBuffer(
CommandEncoder* encoder,
const CommandBufferDescriptor* descriptor) {
- return Ref<CommandBufferBase>{nullptr};
+ // This is called by CommandEncoder::Finish
+ // TODO(crbug.com/413053623): Store CommandEncoderDescriptor and assign here.
+ return CommandBuffer::Create(encoder, descriptor);
}
Ref<ComputePipelineBase> Device::CreateUninitializedComputePipelineImpl(
const UnpackedPtr<ComputePipelineDescriptor>& descriptor) {
diff --git a/src/dawn/native/webgpu/DeviceWGPU.h b/src/dawn/native/webgpu/DeviceWGPU.h
index 16c9ee9..714ebdd 100644
--- a/src/dawn/native/webgpu/DeviceWGPU.h
+++ b/src/dawn/native/webgpu/DeviceWGPU.h
@@ -56,6 +56,8 @@
WGPUDevice GetInnerHandle() const;
+ WGPUInstance GetInnerInstance() const;
+
const DawnProcTable& wgpu;
private:
diff --git a/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp b/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
index ab76b96..96ae1f3 100644
--- a/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
+++ b/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
@@ -79,6 +79,10 @@
return mBackend->GetFunctions();
}
+Backend* PhysicalDevice::GetBackend() const {
+ return mBackend;
+}
+
bool PhysicalDevice::SupportsExternalImages() const {
return false;
}
diff --git a/src/dawn/native/webgpu/PhysicalDeviceWGPU.h b/src/dawn/native/webgpu/PhysicalDeviceWGPU.h
index 48273e3..5d99e07 100644
--- a/src/dawn/native/webgpu/PhysicalDeviceWGPU.h
+++ b/src/dawn/native/webgpu/PhysicalDeviceWGPU.h
@@ -50,6 +50,7 @@
const Surface* surface) const override;
const DawnProcTable& GetFunctions() const;
+ Backend* GetBackend() const;
private:
explicit PhysicalDevice(Backend* backend, WGPUAdapter innerAdapter);
diff --git a/src/dawn/native/webgpu/QueueWGPU.cpp b/src/dawn/native/webgpu/QueueWGPU.cpp
index 76bb6b7..691a96c 100644
--- a/src/dawn/native/webgpu/QueueWGPU.cpp
+++ b/src/dawn/native/webgpu/QueueWGPU.cpp
@@ -27,7 +27,11 @@
#include "dawn/native/webgpu/QueueWGPU.h"
+#include <vector>
+
#include "dawn/native/Queue.h"
+#include "dawn/native/webgpu/BufferWGPU.h"
+#include "dawn/native/webgpu/CommandBufferWGPU.h"
#include "dawn/native/webgpu/DeviceWGPU.h"
namespace dawn::native::webgpu {
@@ -37,12 +41,35 @@
return AcquireRef(new Queue(device, descriptor));
}
-Queue::Queue(Device* device, const QueueDescriptor* descriptor) : QueueBase(device, descriptor) {}
+Queue::Queue(Device* device, const QueueDescriptor* descriptor)
+ : QueueBase(device, descriptor),
+ mInnerQueue(device->wgpu.deviceGetQueue(device->GetInnerHandle())) {}
-Queue::~Queue() = default;
+Queue::~Queue() {
+ if (mInnerQueue) {
+ ToBackend(GetDevice())->wgpu.queueRelease(mInnerQueue);
+ mInnerQueue = nullptr;
+ }
+}
MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) {
- // TODO(crbug.com/413053623): finish implementing WebGPU backend.
+ if (commandCount == 0 || commands == nullptr) {
+ return {};
+ }
+
+ auto& wgpu = ToBackend(GetDevice())->wgpu;
+
+ std::vector<WGPUCommandBuffer> innerCommandBuffers(commandCount);
+ for (uint32_t i = 0; i < commandCount; ++i) {
+ innerCommandBuffers[i] = ToBackend(commands[i])->Encode();
+ }
+
+ wgpu.queueSubmit(mInnerQueue, commandCount, innerCommandBuffers.data());
+
+ for (uint32_t i = 0; i < commandCount; ++i) {
+ wgpu.commandBufferRelease(innerCommandBuffers[i]);
+ }
+
return {};
}
@@ -50,7 +77,9 @@
uint64_t bufferOffset,
const void* data,
size_t size) {
- // TODO(crbug.com/413053623): finish implementing WebGPU backend.
+ auto innerBuffer = ToBackend(buffer)->GetInnerHandle();
+ ToBackend(GetDevice())
+ ->wgpu.queueWriteBuffer(mInnerQueue, innerBuffer, bufferOffset, data, size);
return {};
}
diff --git a/src/dawn/native/webgpu/QueueWGPU.h b/src/dawn/native/webgpu/QueueWGPU.h
index ae7ec98..27b9786 100644
--- a/src/dawn/native/webgpu/QueueWGPU.h
+++ b/src/dawn/native/webgpu/QueueWGPU.h
@@ -54,6 +54,8 @@
MaybeError SubmitPendingCommands() override;
ResultOrError<bool> WaitForQueueSerial(ExecutionSerial serial, Nanoseconds timeout) override;
MaybeError WaitForIdleForDestruction() override;
+
+ WGPUQueue mInnerQueue = nullptr;
};
} // namespace dawn::native::webgpu
diff --git a/src/dawn/tests/end2end/BasicTests.cpp b/src/dawn/tests/end2end/BasicTests.cpp
index f82bc4f..a89d305 100644
--- a/src/dawn/tests/end2end/BasicTests.cpp
+++ b/src/dawn/tests/end2end/BasicTests.cpp
@@ -94,7 +94,8 @@
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
- VulkanBackend());
+ VulkanBackend(),
+ WebGPUBackend());
} // anonymous namespace
} // namespace dawn
diff --git a/src/dawn/tests/end2end/BufferTests.cpp b/src/dawn/tests/end2end/BufferTests.cpp
index 8b51d9b..34342f0 100644
--- a/src/dawn/tests/end2end/BufferTests.cpp
+++ b/src/dawn/tests/end2end/BufferTests.cpp
@@ -642,8 +642,8 @@
}
DAWN_INSTANTIATE_TEST_P(BufferMappingTests,
- {D3D11Backend(), D3D12Backend(), MetalBackend(), VulkanBackend(),
- OpenGLBackend(), OpenGLESBackend()},
+ {D3D11Backend(), D3D12Backend(), MetalBackend(), OpenGLBackend(),
+ OpenGLESBackend(), VulkanBackend(), WebGPUBackend()},
std::initializer_list<wgpu::CallbackMode>{
wgpu::CallbackMode::WaitAnyOnly, wgpu::CallbackMode::AllowProcessEvents,
wgpu::CallbackMode::AllowSpontaneous});
diff --git a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
index d8087ce..7b32557 100644
--- a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
@@ -53,9 +53,6 @@
// Test that the device can be dropped while an onSubmittedWorkDone callback is in flight.
TEST_P(DeviceLifetimeTests, DroppedWhileQueueOnSubmittedWorkDone) {
- // TODO(crbug.com/413053623): implement webgpu::CommandBuffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
// Submit some work.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(nullptr);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
@@ -72,9 +69,6 @@
// Test that the device can be dropped inside an onSubmittedWorkDone callback.
TEST_P(DeviceLifetimeTests, DroppedInsideQueueOnSubmittedWorkDone) {
- // TODO(crbug.com/413053623): implement webgpu::CommandBuffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
// Submit some work.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(nullptr);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
@@ -148,9 +142,6 @@
// Test that the device can be dropped while a buffer created from it is being mapped.
TEST_P(DeviceLifetimeTests, DroppedWhileMappingBuffer) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -168,9 +159,6 @@
// Test that the device can be dropped before a mapped buffer created from it.
TEST_P(DeviceLifetimeTests, DroppedBeforeMappedBuffer) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -183,7 +171,7 @@
// Test that the device can be dropped before a mapped at creation buffer created from it.
TEST_P(DeviceLifetimeTests, DroppedBeforeMappedAtCreationBuffer) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
+ // TODO(crbug.com/413053623): implement webgpu::Buffer::MapAtCreationImpl
DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
wgpu::BufferDescriptor desc = {};
@@ -198,9 +186,6 @@
// Test that the device can be dropped before a buffer created from it, then mapping the buffer
// fails.
TEST_P(DeviceLifetimeTests, DroppedThenMapBuffer) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -219,9 +204,6 @@
// Test that the device can be dropped before a buffer created from it, then mapping the buffer
// twice (one inside callback) will both fail.
TEST_P(DeviceLifetimeTests, Dropped_ThenMapBuffer_ThenMapBufferInCallback) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -250,9 +232,6 @@
// Test that the device can be dropped inside a buffer map callback.
TEST_P(DeviceLifetimeTests, DroppedInsideBufferMapCallback) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -285,9 +264,6 @@
// Test that the device can be dropped while a write buffer operation is enqueued.
TEST_P(DeviceLifetimeTests, DroppedWhileWriteBuffer) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
@@ -302,9 +278,6 @@
// a queue submit occurs. This is slightly different from the former test since it ensures
// that pending work is flushed.
TEST_P(DeviceLifetimeTests, DroppedWhileWriteBufferAndSubmit) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc = {};
desc.size = 4;
desc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp
index d59d67e..301d73e 100644
--- a/src/dawn/tests/end2end/DeviceLostTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLostTests.cpp
@@ -259,9 +259,6 @@
// Test that buffer.MapAsync for writing fails after device is lost
TEST_P(DeviceLostTest, BufferMapAsyncFailsForWriting) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = 4;
bufferDescriptor.usage = wgpu::BufferUsage::MapWrite;
@@ -279,9 +276,6 @@
// Test that BufferMapAsync for writing calls back with success when device lost after
// mapping
TEST_P(DeviceLostTest, BufferMapAsyncBeforeLossFailsForWriting) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = 4;
bufferDescriptor.usage = wgpu::BufferUsage::MapWrite;
@@ -297,7 +291,7 @@
// Test that buffer.Unmap after device is lost
TEST_P(DeviceLostTest, BufferUnmapAfterDeviceLost) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
+ // TODO(crbug.com/413053623): implement webgpu::Buffer::MapAtCreationImpl
DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
wgpu::BufferDescriptor bufferDescriptor;
@@ -367,9 +361,6 @@
// Test that BufferMapAsync for reading fails after device is lost
TEST_P(DeviceLostTest, BufferMapAsyncFailsForReading) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = 4;
bufferDescriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -388,9 +379,6 @@
// Test that BufferMapAsync for reading calls back with success when device lost after
// mapping
TEST_P(DeviceLostTest, BufferMapAsyncBeforeLossFailsForReading) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = sizeof(float);
bufferDescriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -420,7 +408,7 @@
// Test it's possible to GetMappedRange on a buffer created mapped after device loss
TEST_P(DeviceLostTest, GetMappedRange_CreateBufferMappedAtCreationAfterLoss) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
+ // TODO(crbug.com/413053623): implement webgpu::Buffer::MapAtCreationImpl
DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
LoseDeviceForTesting();
@@ -437,7 +425,7 @@
// Test that device loss doesn't change the result of GetMappedRange, mappedAtCreation version.
TEST_P(DeviceLostTest, GetMappedRange_CreateBufferMappedAtCreationBeforeLoss) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
+ // TODO(crbug.com/413053623): implement webgpu::Buffer::MapAtCreationImpl
DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
wgpu::BufferDescriptor desc;
@@ -455,9 +443,6 @@
// Test that device loss doesn't change the result of GetMappedRange, mapping for reading version.
TEST_P(DeviceLostTest, GetMappedRange_MapAsyncReading) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc;
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -475,9 +460,6 @@
// Test that device loss doesn't change the result of GetMappedRange, mapping for writing version.
TEST_P(DeviceLostTest, GetMappedRange_MapAsyncWriting) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
wgpu::BufferDescriptor desc;
desc.size = 4;
desc.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
@@ -642,9 +624,6 @@
// Attempting to set an object label after device loss should not cause an error.
TEST_P(DeviceLostTest, SetLabelAfterDeviceLoss) {
- // TODO(crbug.com/413053623): implement webgpu::Buffer
- DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
-
std::string label = "test";
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
diff --git a/src/dawn/tests/end2end/QueueTests.cpp b/src/dawn/tests/end2end/QueueTests.cpp
index ae1c93e..b352728 100644
--- a/src/dawn/tests/end2end/QueueTests.cpp
+++ b/src/dawn/tests/end2end/QueueTests.cpp
@@ -53,7 +53,8 @@
NullBackend(),
OpenGLBackend(),
OpenGLESBackend(),
- VulkanBackend());
+ VulkanBackend(),
+ WebGPUBackend());
class QueueWriteBufferTests : public DawnTest {};
@@ -204,6 +205,9 @@
// Test a special code path: writing when dynamic uploader already contatins some unaligned
// data, it might be necessary to use a ring buffer with properly aligned offset.
TEST_P(QueueWriteBufferTests, UnalignedDynamicUploader) {
+ // TODO(crbug.com/413053623): implement webgpu::Texture
+ DAWN_SUPPRESS_TEST_IF(IsWebGPUOnWebGPU());
+
utils::UnalignDynamicUploader(device);
wgpu::BufferDescriptor descriptor;
@@ -272,7 +276,8 @@
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
- VulkanBackend());
+ VulkanBackend(),
+ WebGPUBackend());
// For MinimumDataSpec bytesPerRow and rowsPerImage, compute a default from the copy extent.
constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul;