Implement Queue::OnSubmittedWorkDone
This is the replacement for Fence in the single-queue WebGPU world. To
keep this CL focused, it doesn't deprecate the fences yet.
Bug: chromium:1177476
Change-Id: I09d60732ec67bc1deb49f7a9d57699c049475acf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/41723
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_wire/client/ClientDoers.cpp b/src/dawn_wire/client/ClientDoers.cpp
index a5ef7f6..2c6e23f 100644
--- a/src/dawn_wire/client/ClientDoers.cpp
+++ b/src/dawn_wire/client/ClientDoers.cpp
@@ -66,7 +66,6 @@
if (buffer == nullptr) {
return true;
}
-
return buffer->OnMapAsyncCallback(requestSerial, status, readInitialDataInfoLength,
readInitialDataInfo);
}
@@ -88,9 +87,17 @@
if (fence == nullptr) {
return true;
}
+ return fence->OnCompletionCallback(requestSerial, status);
+ }
- fence->OnCompletionCallback(requestSerial, status);
- return true;
+ bool Client::DoQueueWorkDoneCallback(Queue* queue,
+ uint64_t requestSerial,
+ WGPUQueueWorkDoneStatus status) {
+ // The queue might have been deleted or recreated so this isn't an error.
+ if (queue == nullptr) {
+ return true;
+ }
+ return queue->OnWorkDoneCallback(requestSerial, status);
}
bool Client::DoDeviceCreateComputePipelineAsyncCallback(Device* device,
diff --git a/src/dawn_wire/client/Fence.cpp b/src/dawn_wire/client/Fence.cpp
index d9a858a..563f13f1 100644
--- a/src/dawn_wire/client/Fence.cpp
+++ b/src/dawn_wire/client/Fence.cpp
@@ -46,7 +46,8 @@
WGPUFenceOnCompletionCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
- return callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
+ callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
+ return;
}
uint32_t serial = mOnCompletionRequestSerial++;
diff --git a/src/dawn_wire/client/Queue.cpp b/src/dawn_wire/client/Queue.cpp
index f5f68f7..8c9f78b 100644
--- a/src/dawn_wire/client/Queue.cpp
+++ b/src/dawn_wire/client/Queue.cpp
@@ -19,6 +19,47 @@
namespace dawn_wire { namespace client {
+ Queue::~Queue() {
+ ClearAllCallbacks(WGPUQueueWorkDoneStatus_Unknown);
+ }
+
+ bool Queue::OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus status) {
+ auto requestIt = mOnWorkDoneRequests.find(requestSerial);
+ if (requestIt == mOnWorkDoneRequests.end()) {
+ return false;
+ }
+
+ // Remove the request data so that the callback cannot be called again.
+ // ex.) inside the callback: if the queue is deleted (when there are multiple queues),
+ // all callbacks reject.
+ OnWorkDoneData request = std::move(requestIt->second);
+ mOnWorkDoneRequests.erase(requestIt);
+
+ request.callback(status, request.userdata);
+ return true;
+ }
+
+ void Queue::OnSubmittedWorkDone(uint64_t signalValue,
+ WGPUQueueWorkDoneCallback callback,
+ void* userdata) {
+ if (client->IsDisconnected()) {
+ callback(WGPUQueueWorkDoneStatus_DeviceLost, userdata);
+ return;
+ }
+
+ uint32_t serial = mOnWorkDoneSerial++;
+ ASSERT(mOnWorkDoneRequests.find(serial) == mOnWorkDoneRequests.end());
+
+ QueueOnSubmittedWorkDoneCmd cmd;
+ cmd.queueId = this->id;
+ cmd.signalValue = signalValue;
+ cmd.requestSerial = serial;
+
+ mOnWorkDoneRequests[serial] = {callback, userdata};
+
+ client->SerializeCommand(cmd);
+ }
+
WGPUFence Queue::CreateFence(WGPUFenceDescriptor const* descriptor) {
auto* allocation = client->FenceAllocator().New(client);
@@ -65,4 +106,17 @@
client->SerializeCommand(cmd);
}
+ void Queue::CancelCallbacksForDisconnect() {
+ ClearAllCallbacks(WGPUQueueWorkDoneStatus_DeviceLost);
+ }
+
+ void Queue::ClearAllCallbacks(WGPUQueueWorkDoneStatus status) {
+ for (auto& it : mOnWorkDoneRequests) {
+ if (it.second.callback) {
+ it.second.callback(status, it.second.userdata);
+ }
+ }
+ mOnWorkDoneRequests.clear();
+ }
+
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Queue.h b/src/dawn_wire/client/Queue.h
index 91c9393..f14fae1 100644
--- a/src/dawn_wire/client/Queue.h
+++ b/src/dawn_wire/client/Queue.h
@@ -27,7 +27,14 @@
class Queue final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
+ ~Queue();
+ bool OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus status);
+
+ // Dawn API
+ void OnSubmittedWorkDone(uint64_t signalValue,
+ WGPUQueueWorkDoneCallback callback,
+ void* userdata);
WGPUFence CreateFence(const WGPUFenceDescriptor* descriptor);
void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
void WriteTexture(const WGPUTextureCopyView* destination,
@@ -35,6 +42,18 @@
size_t dataSize,
const WGPUTextureDataLayout* dataLayout,
const WGPUExtent3D* writeSize);
+
+ private:
+ void CancelCallbacksForDisconnect() override;
+
+ void ClearAllCallbacks(WGPUQueueWorkDoneStatus status);
+
+ struct OnWorkDoneData {
+ WGPUQueueWorkDoneCallback callback = nullptr;
+ void* userdata = nullptr;
+ };
+ uint64_t mOnWorkDoneSerial = 0;
+ std::map<uint64_t, OnWorkDoneData> mOnWorkDoneRequests;
};
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h
index bcedeaa..1124cba 100644
--- a/src/dawn_wire/server/Server.h
+++ b/src/dawn_wire/server/Server.h
@@ -141,6 +141,13 @@
uint64_t requestSerial;
};
+ struct QueueWorkDoneUserdata : CallbackUserdata {
+ using CallbackUserdata::CallbackUserdata;
+
+ ObjectHandle queue;
+ uint64_t requestSerial;
+ };
+
struct CreatePipelineAsyncUserData : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
@@ -202,6 +209,7 @@
FenceCompletionUserdata* userdata);
void OnFenceOnCompletion(WGPUFenceCompletionStatus status,
FenceOnCompletionUserdata* userdata);
+ void OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* userdata);
void OnCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,
const char* message,
diff --git a/src/dawn_wire/server/ServerQueue.cpp b/src/dawn_wire/server/ServerQueue.cpp
index d798d41..9ab8bc0 100644
--- a/src/dawn_wire/server/ServerQueue.cpp
+++ b/src/dawn_wire/server/ServerQueue.cpp
@@ -40,6 +40,34 @@
return true;
}
+ void Server::OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* data) {
+ ReturnQueueWorkDoneCallbackCmd cmd;
+ cmd.queue = data->queue;
+ cmd.requestSerial = data->requestSerial;
+ cmd.status = status;
+
+ SerializeCommand(cmd);
+ }
+
+ bool Server::DoQueueOnSubmittedWorkDone(ObjectId queueId,
+ uint64_t signalValue,
+ uint64_t requestSerial) {
+ auto* queue = QueueObjects().Get(queueId);
+ if (queue == nullptr) {
+ return false;
+ }
+
+ auto userdata = MakeUserdata<QueueWorkDoneUserdata>();
+ userdata->queue = ObjectHandle{queueId, queue->generation};
+ userdata->requestSerial = requestSerial;
+
+ mProcs.queueOnSubmittedWorkDone(
+ queue->handle, signalValue,
+ ForwardToServer<decltype(&Server::OnQueueWorkDone)>::Func<&Server::OnQueueWorkDone>(),
+ userdata.release());
+ return true;
+ }
+
bool Server::DoQueueWriteBufferInternal(ObjectId queueId,
ObjectId bufferId,
uint64_t bufferOffset,