Compare commits

...

1 Commits

Author SHA1 Message Date
Run Yu
5f14ebba87 Use MapAsync and AllowProcessEvents for callback 2025-11-19 11:19:27 -05:00
5 changed files with 51 additions and 21 deletions

View File

@@ -63,7 +63,7 @@ WebGPUBufferBase::WebGPUBufferBase(wgpu::Device const& device, const wgpu::Buffe
// WebGPU requires that the size of the data copied from the staging buffer to the GPU buffer is a
// multiple of 4. This function handles cases where the buffer descriptor's size is not a multiple
// of 4 by padding with zeros.
void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor const& bufferDescriptor,
void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor&& bufferDescriptor,
const uint32_t byteOffset, wgpu::Device const& device,
WebGPUQueueManager* const webGPUQueueManager) {
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
@@ -89,24 +89,49 @@ void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor const& bufferDescriptor,
wgpu::BufferDescriptor descriptor{
.label = "Filament WebGPU Staging Buffer",
.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc,
.size = stagingBufferSize,
.mappedAtCreation = true };
.size = stagingBufferSize};
wgpu::Buffer stagingBuffer = device.CreateBuffer(&descriptor);
void* mappedRange = stagingBuffer.GetMappedRange();
memcpy(mappedRange, bufferDescriptor.buffer, bufferDescriptor.size);
// Make sure the padded memory is set to 0 to have deterministic behaviors
if (remainder != 0) {
uint8_t* paddingStart = static_cast<uint8_t*>(mappedRange) + bufferDescriptor.size;
memset(paddingStart, 0, FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS - remainder);
}
stagingBuffer.Unmap();
// Copy the staging buffer contents to the destination buffer.
webGPUQueueManager->getCommandEncoder().CopyBufferToBuffer(stagingBuffer, 0, mBuffer,
byteOffset, stagingBufferSize);
struct UserData final {
uint32_t byteOffset;
size_t stagingBufferSize;
size_t remainder;
BufferDescriptor srcBufferDescriptor;
wgpu::Buffer stagingBuffer;
WebGPUQueueManager* const webGPUQueueManager;
wgpu::Buffer dstBuffer;
};
auto userData = std::make_unique<UserData>(UserData{
.byteOffset = byteOffset,
.stagingBufferSize = stagingBufferSize,
.remainder = remainder,
.srcBufferDescriptor = std::move(bufferDescriptor),
.stagingBuffer = stagingBuffer,
.webGPUQueueManager = webGPUQueueManager,
.dstBuffer = mBuffer});
stagingBuffer.MapAsync(
wgpu::MapMode::Write, 0, stagingBufferSize, wgpu::CallbackMode::AllowProcessEvents,
[](wgpu::MapAsyncStatus status, const char* message, UserData* userdata) {
std::unique_ptr<UserData> data(static_cast<UserData*>(userdata));
if (UTILS_LIKELY(status == wgpu::MapAsyncStatus::Success)) {
void* mappedRange = data->stagingBuffer.GetMappedRange();
memcpy(mappedRange, data->srcBufferDescriptor.buffer,
data->srcBufferDescriptor.size);
if (data->remainder != 0) {
uint8_t* paddingStart =
static_cast<uint8_t*>(mappedRange) + data->srcBufferDescriptor.size;
memset(paddingStart, 0,
FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS - data->remainder);
}
data->stagingBuffer.Unmap();
data->webGPUQueueManager->getCommandEncoder().CopyBufferToBuffer(
data->stagingBuffer, 0, data->dstBuffer, data->byteOffset,
data->stagingBufferSize);
} else {
FWGPU_LOGE << "Failed to map staging buffer for readPixels: " << message;
}
},
userData.release());
}
} // namespace filament::backend

View File

@@ -39,7 +39,7 @@ public:
* happen after draw commands encoded in the encoder. Submitting any commands up to this point
* ensures the calls happen in the expected sequence.
*/
void updateGPUBuffer(BufferDescriptor const&, uint32_t byteOffset, wgpu::Device const& device,
void updateGPUBuffer(BufferDescriptor&&, uint32_t byteOffset, wgpu::Device const& device,
WebGPUQueueManager* const webGPUQueueManager);
[[nodiscard]] wgpu::Buffer const& getBuffer() const { return mBuffer; }

View File

@@ -856,7 +856,7 @@ void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> indexBufferHandle,
// draw calls are made.
flush();
handleCast<WebGPUIndexBuffer>(indexBufferHandle)
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
scheduleDestroy(std::move(bufferDescriptor));
}
@@ -867,14 +867,14 @@ void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> bufferObjectHandle,
// draw calls are made.
flush();
handleCast<WebGPUBufferObject>(bufferObjectHandle)
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
scheduleDestroy(std::move(bufferDescriptor));
}
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> bufferObjectHandle,
BufferDescriptor&& bufferDescriptor, const uint32_t byteOffset) {
handleCast<WebGPUBufferObject>(bufferObjectHandle)
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
scheduleDestroy(std::move(bufferDescriptor));
}

View File

@@ -21,6 +21,7 @@
#include <chrono>
#include <cstdint>
#include <thread>
#include <iostream>
namespace filament::backend {
@@ -58,6 +59,7 @@ WebGPUQueueManager::WebGPUQueueManager(wgpu::Device const& device)
WebGPUQueueManager::~WebGPUQueueManager() = default;
wgpu::CommandEncoder WebGPUQueueManager::getCommandEncoder() {
// std::unique_lock<std::mutex> lock(mLock);
if (!mCommandEncoder) {
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
.label = "Filament Command Encoder",
@@ -90,7 +92,9 @@ std::shared_ptr<WebGPUSubmissionState> WebGPUQueueManager::getLatestSubmissionSt
}
void WebGPUQueueManager::submit() {
// std::unique_lock<std::mutex> lock(mLock);
if (!mCommandEncoder) {
std::cout << "Run Yu: no mCommandEncoder found!\n";
return;
}

View File

@@ -74,6 +74,7 @@ private:
wgpu::Queue mQueue;
wgpu::CommandEncoder mCommandEncoder;
std::shared_ptr<WebGPUSubmissionState> mLatestSubmissionState;
std::mutex mLock;
};
} // namespace filament::backend