[dawn][emscripten] Implements onSubmittedWorkDone future entry point.

Bug: 372077545
Change-Id: I7748fc294a4d8d2e659902307742d89c7f3e4533
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/209895
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/third_party/emdawnwebgpu/library_webgpu.js b/third_party/emdawnwebgpu/library_webgpu.js
index 3e81bab..b4d9f3d 100644
--- a/third_party/emdawnwebgpu/library_webgpu.js
+++ b/third_party/emdawnwebgpu/library_webgpu.js
@@ -137,8 +137,8 @@
     importJsDevice__deps: ['emwgpuCreateDevice', 'emwgpuCreateQueue'],
     importJsDevice: (device, parentPtr = 0) => {
       var queuePtr = _emwgpuCreateQueue(parentPtr);
-      WebGPU.Internals.jsObjectInsert(queuePtr, device.queue);
       var devicePtr = _emwgpuCreateDevice(parentPtr, queuePtr);
+      WebGPU.Internals.jsObjectInsert(queuePtr, device.queue);
       WebGPU.Internals.jsObjectInsert(devicePtr, device);
       return devicePtr;
     },
@@ -1491,7 +1491,7 @@
     return ptr;
   },
 
-  emwgpuDeviceCreateComputePipelineAsync__i53abi:false,
+  emwgpuDeviceCreateComputePipelineAsync__i53abi: false,
   emwgpuDeviceCreateComputePipelineAsync__deps: ['emwgpuCreateComputePipeline', 'emwgpuOnCreateComputePipelineCompleted'],
   emwgpuDeviceCreateComputePipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
     var desc = WebGPU.makeComputePipelineDesc(descriptor);
@@ -1601,7 +1601,7 @@
     return ptr;
   },
 
-  emwgpuDeviceCreateRenderPipelineAsync__i53abi:false,
+  emwgpuDeviceCreateRenderPipelineAsync__i53abi: false,
   emwgpuDeviceCreateRenderPipelineAsync__deps: ['emwgpuCreateRenderPipeline', 'emwgpuOnCreateRenderPipelineCompleted'],
   emwgpuDeviceCreateRenderPipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
     var desc = WebGPU.makeRenderPipelineDesc(descriptor);
@@ -1956,22 +1956,19 @@
   // Methods of Queue
   // --------------------------------------------------------------------------
 
-  wgpuQueueOnSubmittedWorkDone__deps: ['$callUserCallback'],
-  wgpuQueueOnSubmittedWorkDone: (queuePtr, callback, userdata) => {
+  emwgpuQueueOnSubmittedWorkDone__i53abi: false,
+  emwgpuQueueOnSubmittedWorkDone__deps: ['emwgpuOnWorkDoneCompleted'],
+  emwgpuQueueOnSubmittedWorkDone: (queuePtr, futureIdL, futureIdH) => {
     var queue = WebGPU.getJsObject(queuePtr);
 
     {{{ runtimeKeepalivePush() }}}
-    queue.onSubmittedWorkDone().then(() => {
+    WebGPU.Internals.futureInsert(futureIdL, futureIdH, queue.onSubmittedWorkDone().then(() => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Success }}}, userdata);
-      });
+      _emwgpuOnWorkDoneCompleted(futureIdL, futureIdH, {{{ gpu.QueueWorkDoneStatus.Success }}});
     }, () => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Error }}}, userdata);
-      });
-    });
+      _emwgpuOnWorkDoneCompleted(futureIdL, futureIdH, {{{ gpu.QueueWorkDoneStatus.Error }}});
+    }));
   },
 
   wgpuQueueSetLabel: (queuePtr, labelPtr) => {
diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp
index 2e72892..f2ba66b 100644
--- a/third_party/emdawnwebgpu/webgpu.cpp
+++ b/third_party/emdawnwebgpu/webgpu.cpp
@@ -78,6 +78,7 @@
 void emwgpuInstanceRequestAdapter(WGPUInstance instance,
                                   FutureID futureId,
                                   const WGPURequestAdapterOptions* options);
+void emwgpuQueueOnSubmittedWorkDone(WGPUQueue queue, FutureID futureId);
 }  // extern "C"
 
 // ----------------------------------------------------------------------------
@@ -286,7 +287,6 @@
   X(ComputePipeline)     \
   X(PipelineLayout)      \
   X(QuerySet)            \
-  X(Queue)               \
   X(RenderBundle)        \
   X(RenderBundleEncoder) \
   X(RenderPassEncoder)   \
@@ -313,6 +313,7 @@
   MapAsync,
   RequestAdapter,
   RequestDevice,
+  WorkDone,
 };
 
 class EventManager;
@@ -641,6 +642,11 @@
   WGPUBufferMapState mMapState;
 };
 
+struct WGPUQueueImpl final : public EventSource, public RefCounted {
+ public:
+  WGPUQueueImpl(const EventSource* source);
+};
+
 // Device is specially implemented in order to handle refcounting the Queue.
 struct WGPUDeviceImpl final : public EventSource,
                               public RefCountedWithExternalCount {
@@ -943,6 +949,38 @@
   std::optional<std::string> mMessage = std::nullopt;
 };
 
+class WorkDoneEvent final : public TrackedEvent {
+ public:
+  static constexpr EventType kType = EventType::WorkDone;
+
+  WorkDoneEvent(InstanceID instance,
+                const WGPUQueueWorkDoneCallbackInfo2& callbackInfo)
+      : TrackedEvent(instance, callbackInfo.mode),
+        mCallback(callbackInfo.callback),
+        mUserdata1(callbackInfo.userdata1),
+        mUserdata2(callbackInfo.userdata2) {}
+
+  EventType GetType() override { return kType; }
+
+  void ReadyHook(WGPUQueueWorkDoneStatus status) { mStatus = status; }
+
+  void Complete(FutureID, EventCompletionType type) override {
+    if (type == EventCompletionType::Shutdown) {
+      mStatus = WGPUQueueWorkDoneStatus_InstanceDropped;
+    }
+    if (mCallback) {
+      mCallback(mStatus, mUserdata1, mUserdata2);
+    }
+  }
+
+ private:
+  WGPUQueueWorkDoneCallback2 mCallback = nullptr;
+  void* mUserdata1 = nullptr;
+  void* mUserdata2 = nullptr;
+
+  WGPUQueueWorkDoneStatus mStatus;
+};
+
 // ----------------------------------------------------------------------------
 // WGPU struct implementations.
 // ----------------------------------------------------------------------------
@@ -1128,6 +1166,12 @@
 }
 
 // ----------------------------------------------------------------------------
+// WGPUQueueImpl implementations.
+// ----------------------------------------------------------------------------
+
+WGPUQueueImpl::WGPUQueueImpl(const EventSource* source) : EventSource(source) {}
+
+// ----------------------------------------------------------------------------
 // Definitions for C++ emwgpu functions (callable from library_webgpu.js)
 // ----------------------------------------------------------------------------
 extern "C" {
@@ -1153,6 +1197,10 @@
   return new WGPUDeviceImpl(source, queue);
 }
 
+WGPUQueue emwgpuCreateQueue(const EventSource* source) {
+  return new WGPUQueueImpl(source);
+}
+
 // Future event callbacks.
 void emwgpuOnCreateComputePipelineCompleted(
     FutureID futureId,
@@ -1204,6 +1252,10 @@
                                                          nullptr, message);
   }
 }
+void emwgpuOnWorkDoneCompleted(FutureID futureId,
+                               WGPUQueueWorkDoneStatus status) {
+  GetEventManager().SetFutureReady<WorkDoneEvent>(futureId, status);
+}
 
 // Uncaptured error handler is similar to the Future event callbacks, but it
 // doesn't go through the EventManager and just calls the callback on the Device
@@ -1299,7 +1351,7 @@
 
   // For RequestDevice, we always create a Device and Queue up front. The
   // Device is also immediately associated with the DeviceLostEvent.
-  WGPUQueue queue = new WGPUQueueImpl();
+  WGPUQueue queue = new WGPUQueueImpl(adapter);
   WGPUDevice device = new WGPUDeviceImpl(adapter, descriptor, queue);
 
   auto [deviceLostFutureId, _] = GetEventManager().TrackEvent(
@@ -1510,6 +1562,19 @@
 // Methods of Queue
 // ----------------------------------------------------------------------------
 
+WGPUFuture wgpuQueueOnSubmittedWorkDone2(
+    WGPUQueue queue,
+    WGPUQueueWorkDoneCallbackInfo2 callbackInfo) {
+  auto [futureId, tracked] = GetEventManager().TrackEvent(
+      std::make_unique<WorkDoneEvent>(queue->GetInstanceId(), callbackInfo));
+  if (!tracked) {
+    return WGPUFuture{kNullFutureId};
+  }
+
+  emwgpuQueueOnSubmittedWorkDone(queue, futureId);
+  return WGPUFuture{futureId};
+}
+
 // ----------------------------------------------------------------------------
 // Methods of RenderBundle
 // ----------------------------------------------------------------------------