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 // 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 // multiple of 4. This function handles cases where the buffer descriptor's size is not a multiple
// of 4 by padding with zeros. // 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, const uint32_t byteOffset, wgpu::Device const& device,
WebGPUQueueManager* const webGPUQueueManager) { WebGPUQueueManager* const webGPUQueueManager) {
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer) FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
@@ -89,24 +89,49 @@ void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor const& bufferDescriptor,
wgpu::BufferDescriptor descriptor{ wgpu::BufferDescriptor descriptor{
.label = "Filament WebGPU Staging Buffer", .label = "Filament WebGPU Staging Buffer",
.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, .usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc,
.size = stagingBufferSize, .size = stagingBufferSize};
.mappedAtCreation = true };
wgpu::Buffer stagingBuffer = device.CreateBuffer(&descriptor); wgpu::Buffer stagingBuffer = device.CreateBuffer(&descriptor);
void* mappedRange = stagingBuffer.GetMappedRange(); struct UserData final {
memcpy(mappedRange, bufferDescriptor.buffer, bufferDescriptor.size); uint32_t byteOffset;
size_t stagingBufferSize;
// Make sure the padded memory is set to 0 to have deterministic behaviors size_t remainder;
if (remainder != 0) { BufferDescriptor srcBufferDescriptor;
uint8_t* paddingStart = static_cast<uint8_t*>(mappedRange) + bufferDescriptor.size; wgpu::Buffer stagingBuffer;
memset(paddingStart, 0, FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS - remainder); WebGPUQueueManager* const webGPUQueueManager;
} wgpu::Buffer dstBuffer;
};
stagingBuffer.Unmap(); auto userData = std::make_unique<UserData>(UserData{
.byteOffset = byteOffset,
// Copy the staging buffer contents to the destination buffer. .stagingBufferSize = stagingBufferSize,
webGPUQueueManager->getCommandEncoder().CopyBufferToBuffer(stagingBuffer, 0, mBuffer, .remainder = remainder,
byteOffset, stagingBufferSize); .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 } // 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 * happen after draw commands encoded in the encoder. Submitting any commands up to this point
* ensures the calls happen in the expected sequence. * 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); WebGPUQueueManager* const webGPUQueueManager);
[[nodiscard]] wgpu::Buffer const& getBuffer() const { return mBuffer; } [[nodiscard]] wgpu::Buffer const& getBuffer() const { return mBuffer; }

View File

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

View File

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

View File

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