[dawn][emscripten] Implements create*PipelineAsync future entry points

- Also some minor re-ordering of the file to keep alphabetical order.

Bug: 369443752
Change-Id: I6fe252228a93abd1bd4f4639b91f2f6d41e46d27
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/207614
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/third_party/emdawnwebgpu/library_webgpu.js b/third_party/emdawnwebgpu/library_webgpu.js
index 0165702..2fc6219 100644
--- a/third_party/emdawnwebgpu/library_webgpu.js
+++ b/third_party/emdawnwebgpu/library_webgpu.js
@@ -1449,33 +1449,28 @@
     return ptr;
   },
 
-  wgpuDeviceCreateComputePipelineAsync__deps: ['$callUserCallback', '$stringToUTF8OnStack', 'emwgpuCreateComputePipeline'],
-  wgpuDeviceCreateComputePipelineAsync: (devicePtr, descriptor, callback, userdata) => {
+  emwgpuDeviceCreateComputePipelineAsync__i53abi:false,
+  emwgpuDeviceCreateComputePipelineAsync__deps: ['$stringToUTF8OnStack', 'emwgpuCreateComputePipeline', 'emwgpuOnDeviceCreateComputePipelineCompleted'],
+  emwgpuDeviceCreateComputePipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
     var desc = WebGPU.makeComputePipelineDesc(descriptor);
     var device = WebGPU._tableGet(devicePtr);
     {{{ runtimeKeepalivePush() }}}
-    device.createComputePipelineAsync(desc).then((pipeline) => {
+    WebGPU._futureInsert(futureIdL, futureIdH, device.createComputePipelineAsync(desc).then((pipeline) => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        var ptr = _emwgpuCreateComputePipeline();
-        WebGPU._tableInsert(ptr, pipeline);
-        {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Success }}}, ptr, 0, userdata);
-      });
+      var pipelinePtr = _emwgpuCreateComputePipeline();
+      WebGPU._tableInsert(pipelinePtr, pipeline);
+      _emwgpuOnDeviceCreateComputePipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
     }, (pipelineError) => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        var sp = stackSave();
-        var messagePtr = stringToUTF8OnStack(pipelineError.message);
-        if (pipelineError.reason === 'validation') {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.ValidationError }}}, 0, messagePtr, userdata);
-        } else if (pipelineError.reason === 'internal') {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.InternalError }}}, 0, messagePtr, userdata);
-        } else {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Unknown }}}, 0, messagePtr, userdata);
-        }
-        stackRestore(sp);
-      });
-    });
+      var sp = stackSave();
+      var messagePtr = stringToUTF8OnStack(pipelineError.message);
+      var status =
+        pipeline.reason === 'validation' ? {{{ gpu.CreatePipelineAsyncStatus.ValidationError }}} :
+        pipeline.reason === 'internal' ? {{{ gpu.CreatePipelineAsyncStatus.InternalError }}} :
+        {{{ gpu.CreatePipelineAsyncStatus.Unknown }}};
+      _emwgpuOnDeviceCreateComputePipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
+      stackRestore(sp);
+    }));
   },
 
   wgpuDeviceCreatePipelineLayout__deps: ['emwgpuCreatePipelineLayout'],
@@ -1564,33 +1559,28 @@
     return ptr;
   },
 
-  wgpuDeviceCreateRenderPipelineAsync__deps: ['$callUserCallback', '$stringToUTF8OnStack', 'emwgpuCreateRenderPipeline'],
-  wgpuDeviceCreateRenderPipelineAsync: (devicePtr, descriptor, callback, userdata) => {
+  emwgpuDeviceCreateRenderPipelineAsync__i53abi:false,
+  emwgpuDeviceCreateRenderPipelineAsync__deps: ['$stringToUTF8OnStack', 'emwgpuCreateRenderPipeline', 'emwgpuOnDeviceCreateRenderPipelineCompleted'],
+  emwgpuDeviceCreateRenderPipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
     var desc = WebGPU.makeRenderPipelineDesc(descriptor);
     var device = WebGPU._tableGet(devicePtr);
     {{{ runtimeKeepalivePush() }}}
-    device.createRenderPipelineAsync(desc).then((pipeline) => {
+    WebGPU._futureInsert(futureIdL, futureIdH, device.createRenderPipelineAsync(desc).then((pipeline) => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        var ptr = _emwgpuCreateRenderPipeline();
-        WebGPU._tableInsert(ptr, pipeline);
-        {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Success }}}, ptr, 0, userdata);
-      });
+      var pipelinePtr = _emwgpuCreateRenderPipeline();
+      WebGPU._tableInsert(pipelinePtr, pipeline);
+      _emwgpuOnDeviceCreateRenderPipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
     }, (pipelineError) => {
       {{{ runtimeKeepalivePop() }}}
-      callUserCallback(() => {
-        var sp = stackSave();
-        var messagePtr = stringToUTF8OnStack(pipelineError.message);
-        if (pipelineError.reason === 'validation') {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.ValidationError }}}, 0, messagePtr, userdata);
-        } else if (pipelineError.reason === 'internal') {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.InternalError }}}, 0, messagePtr, userdata);
-        } else {
-          {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Unknown }}}, 0, messagePtr, userdata);
-        }
-        stackRestore(sp);
-      });
-    });
+      var sp = stackSave();
+      var messagePtr = stringToUTF8OnStack(pipelineError.message);
+      var status =
+        pipeline.reason === 'validation' ? {{{ gpu.CreatePipelineAsyncStatus.ValidationError }}} :
+        pipeline.reason === 'internal' ? {{{ gpu.CreatePipelineAsyncStatus.InternalError }}} :
+        {{{ gpu.CreatePipelineAsyncStatus.Unknown }}};
+        _emwgpuOnDeviceCreateRenderPipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
+      stackRestore(sp);
+    }));
   },
 
   wgpuDeviceCreateSampler__deps: ['emwgpuCreateSampler'],
@@ -1917,14 +1907,12 @@
         _emwgpuOnRequestAdapterCompleted(futureIdL, futureIdH, {{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr);
         stackRestore(sp);
       }
-      return;
     }, (ex) => {
       {{{ runtimeKeepalivePop() }}}
       var sp = stackSave();
       var messagePtr = stringToUTF8OnStack(ex.message);
       _emwgpuOnRequestAdapterCompleted(futureIdL, futureIdH, {{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr);
       stackRestore(sp);
-      return;
     }));
   },
 
diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp
index 9933fe7..850b4a6 100644
--- a/third_party/emdawnwebgpu/webgpu.cpp
+++ b/third_party/emdawnwebgpu/webgpu.cpp
@@ -47,6 +47,14 @@
                                 WGPUDevice device,
                                 WGPUQueue queue,
                                 const WGPUDeviceDescriptor* descriptor);
+void emwgpuDeviceCreateComputePipelineAsync(
+    WGPUDevice device,
+    FutureID futureId,
+    const WGPUComputePipelineDescriptor* descriptor);
+void emwgpuDeviceCreateRenderPipelineAsync(
+    WGPUDevice device,
+    FutureID futureId,
+    const WGPURenderPipelineDescriptor* descriptor);
 void emwgpuInstanceRequestAdapter(WGPUInstance instance,
                                   FutureID futureId,
                                   const WGPURequestAdapterOptions* options);
@@ -281,6 +289,8 @@
   Shutdown,
 };
 enum class EventType {
+  CreateComputePipeline,
+  CreateRenderPipeline,
   DeviceLost,
   RequestAdapter,
   RequestDevice,
@@ -569,21 +579,6 @@
   struct WGPU##Name##Impl final : public RefCounted {};
 WGPU_PASSTHROUGH_OBJECTS(DEFINE_WGPU_DEFAULT_STRUCT)
 
-// Instance is specially implemented in order to handle Futures implementation.
-struct WGPUInstanceImpl final : public RefCounted, public EventSource {
- public:
-  WGPUInstanceImpl();
-  ~WGPUInstanceImpl();
-
-  void ProcessEvents();
-  WGPUWaitStatus WaitAny(size_t count,
-                         WGPUFutureWaitInfo* infos,
-                         uint64_t timeoutNS);
-
- private:
-  static InstanceID GetNextInstanceId();
-};
-
 struct WGPUAdapterImpl final : public RefCounted, public EventSource {
  public:
   WGPUAdapterImpl(const EventSource* source);
@@ -614,10 +609,81 @@
   FutureID mDeviceLostFutureId = kNullFutureId;
 };
 
+// Instance is specially implemented in order to handle Futures implementation.
+struct WGPUInstanceImpl final : public RefCounted, public EventSource {
+ public:
+  WGPUInstanceImpl();
+  ~WGPUInstanceImpl();
+
+  void ProcessEvents();
+  WGPUWaitStatus WaitAny(size_t count,
+                         WGPUFutureWaitInfo* infos,
+                         uint64_t timeoutNS);
+
+ private:
+  static InstanceID GetNextInstanceId();
+};
+
 // ----------------------------------------------------------------------------
 // Future events.
 // ----------------------------------------------------------------------------
 
+template <typename Pipeline, EventType Type, typename CallbackInfo>
+class CreatePipelineEventBase final : public TrackedEvent {
+ public:
+  static constexpr EventType kType = Type;
+
+  CreatePipelineEventBase(InstanceID instance, const CallbackInfo& callbackInfo)
+      : TrackedEvent(instance, callbackInfo.mode),
+        mCallback(callbackInfo.callback),
+        mUserdata1(callbackInfo.userdata1),
+        mUserdata2(callbackInfo.userdata2) {}
+
+  EventType GetType() override { return kType; }
+
+  void ReadyHook(WGPUCreatePipelineAsyncStatus status,
+                 Pipeline pipeline,
+                 const char* message) {
+    mStatus = status;
+    mPipeline.Acquire(pipeline);
+    if (message) {
+      mMessage = message;
+    }
+  }
+
+  void Complete(FutureID, EventCompletionType type) override {
+    if (type == EventCompletionType::Shutdown) {
+      mStatus = WGPUCreatePipelineAsyncStatus_InstanceDropped;
+      mMessage = "A valid external Instance reference no longer exists.";
+    }
+    if (mCallback) {
+      mCallback(mStatus,
+                mStatus == WGPUCreatePipelineAsyncStatus_Success
+                    ? ReturnToAPI(std::move(mPipeline))
+                    : nullptr,
+                mMessage ? mMessage->c_str() : nullptr, mUserdata1, mUserdata2);
+    }
+  }
+
+ private:
+  using Callback = decltype(std::declval<CallbackInfo>().callback);
+  Callback mCallback = nullptr;
+  void* mUserdata1 = nullptr;
+  void* mUserdata2 = nullptr;
+
+  WGPUCreatePipelineAsyncStatus mStatus = WGPUCreatePipelineAsyncStatus_Success;
+  Ref<Pipeline> mPipeline;
+  std::optional<std::string> mMessage = std::nullopt;
+};
+using CreateComputePipelineEvent =
+    CreatePipelineEventBase<WGPUComputePipeline,
+                            EventType::CreateComputePipeline,
+                            WGPUCreateComputePipelineAsyncCallbackInfo2>;
+using CreateRenderPipelineEvent =
+    CreatePipelineEventBase<WGPURenderPipeline,
+                            EventType::CreateRenderPipeline,
+                            WGPUCreateRenderPipelineAsyncCallbackInfo2>;
+
 class DeviceLostEvent final : public TrackedEvent {
  public:
   static constexpr EventType kType = EventType::DeviceLost;
@@ -773,32 +839,6 @@
     : EventSource(source->GetInstanceId()) {}
 
 // ----------------------------------------------------------------------------
-// WGPUInstanceImpl implementations.
-// ----------------------------------------------------------------------------
-
-WGPUInstanceImpl::WGPUInstanceImpl() : EventSource(GetNextInstanceId()) {
-  GetEventManager().RegisterInstance(GetInstanceId());
-}
-WGPUInstanceImpl::~WGPUInstanceImpl() {
-  GetEventManager().UnregisterInstance(GetInstanceId());
-}
-
-void WGPUInstanceImpl::ProcessEvents() {
-  GetEventManager().ProcessEvents(GetInstanceId());
-}
-
-WGPUWaitStatus WGPUInstanceImpl::WaitAny(size_t count,
-                                         WGPUFutureWaitInfo* infos,
-                                         uint64_t timeoutNS) {
-  return GetEventManager().WaitAny(GetInstanceId(), count, infos, timeoutNS);
-}
-
-InstanceID WGPUInstanceImpl::GetNextInstanceId() {
-  static std::atomic<InstanceID> kNextInstanceId = 1;
-  return kNextInstanceId++;
-}
-
-// ----------------------------------------------------------------------------
 // WGPUDeviceImpl implementations.
 // ----------------------------------------------------------------------------
 
@@ -848,6 +888,32 @@
 }
 
 // ----------------------------------------------------------------------------
+// WGPUInstanceImpl implementations.
+// ----------------------------------------------------------------------------
+
+WGPUInstanceImpl::WGPUInstanceImpl() : EventSource(GetNextInstanceId()) {
+  GetEventManager().RegisterInstance(GetInstanceId());
+}
+WGPUInstanceImpl::~WGPUInstanceImpl() {
+  GetEventManager().UnregisterInstance(GetInstanceId());
+}
+
+void WGPUInstanceImpl::ProcessEvents() {
+  GetEventManager().ProcessEvents(GetInstanceId());
+}
+
+WGPUWaitStatus WGPUInstanceImpl::WaitAny(size_t count,
+                                         WGPUFutureWaitInfo* infos,
+                                         uint64_t timeoutNS) {
+  return GetEventManager().WaitAny(GetInstanceId(), count, infos, timeoutNS);
+}
+
+InstanceID WGPUInstanceImpl::GetNextInstanceId() {
+  static std::atomic<InstanceID> kNextInstanceId = 1;
+  return kNextInstanceId++;
+}
+
+// ----------------------------------------------------------------------------
 // Definitions for C++ emwgpu functions (callable from library_webgpu.js)
 // ----------------------------------------------------------------------------
 extern "C" {
@@ -869,6 +935,22 @@
 }
 
 // Future event callbacks.
+void emwgpuOnDeviceCreateComputePipelineCompleted(
+    FutureID futureId,
+    WGPUCreatePipelineAsyncStatus status,
+    WGPUComputePipeline pipeline,
+    const char* message) {
+  GetEventManager().SetFutureReady<CreateComputePipelineEvent>(
+      futureId, status, pipeline, message);
+}
+void emwgpuOnDeviceCreateRenderPipelineCompleted(
+    FutureID futureId,
+    WGPUCreatePipelineAsyncStatus status,
+    WGPURenderPipeline pipeline,
+    const char* message) {
+  GetEventManager().SetFutureReady<CreateRenderPipelineEvent>(
+      futureId, status, pipeline, message);
+}
 void emwgpuOnDeviceLostCompleted(FutureID futureId,
                                  WGPUDeviceLostReason reason,
                                  const char* message) {
@@ -1037,6 +1119,73 @@
 // Methods of Device
 // ----------------------------------------------------------------------------
 
+void wgpuDeviceCreateComputePipelineAsync(
+    WGPUDevice device,
+    const WGPUComputePipelineDescriptor* descriptor,
+    WGPUCreateComputePipelineAsyncCallback callback,
+    void* userdata) {
+  WGPUCreateComputePipelineAsyncCallbackInfo2 callbackInfo = {};
+  callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+  callbackInfo.callback = [](WGPUCreatePipelineAsyncStatus status,
+                             WGPUComputePipeline pipeline, char const* message,
+                             void* callback, void* userdata) {
+    auto cb =
+        reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+    cb(status, pipeline, message, userdata);
+  };
+  callbackInfo.userdata1 = reinterpret_cast<void*>(callback);
+  callbackInfo.userdata2 = userdata;
+  wgpuDeviceCreateComputePipelineAsync2(device, descriptor, callbackInfo);
+}
+
+WGPUFuture wgpuDeviceCreateComputePipelineAsync2(
+    WGPUDevice device,
+    const WGPUComputePipelineDescriptor* descriptor,
+    WGPUCreateComputePipelineAsyncCallbackInfo2 callbackInfo) {
+  auto [futureId, tracked] =
+      GetEventManager().TrackEvent(std::make_unique<CreateComputePipelineEvent>(
+          device->GetInstanceId(), callbackInfo));
+  if (!tracked) {
+    return WGPUFuture{kNullFutureId};
+  }
+
+  emwgpuDeviceCreateComputePipelineAsync(device, futureId, descriptor);
+  return WGPUFuture{futureId};
+}
+
+void wgpuDeviceCreateRenderPipelineAsync(
+    WGPUDevice device,
+    const WGPURenderPipelineDescriptor* descriptor,
+    WGPUCreateRenderPipelineAsyncCallback callback,
+    void* userdata) {
+  WGPUCreateRenderPipelineAsyncCallbackInfo2 callbackInfo = {};
+  callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+  callbackInfo.callback = [](WGPUCreatePipelineAsyncStatus status,
+                             WGPURenderPipeline pipeline, char const* message,
+                             void* callback, void* userdata) {
+    auto cb = reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+    cb(status, pipeline, message, userdata);
+  };
+  callbackInfo.userdata1 = reinterpret_cast<void*>(callback);
+  callbackInfo.userdata2 = userdata;
+  wgpuDeviceCreateRenderPipelineAsync2(device, descriptor, callbackInfo);
+}
+
+WGPUFuture wgpuDeviceCreateRenderPipelineAsync2(
+    WGPUDevice device,
+    const WGPURenderPipelineDescriptor* descriptor,
+    WGPUCreateRenderPipelineAsyncCallbackInfo2 callbackInfo) {
+  auto [futureId, tracked] =
+      GetEventManager().TrackEvent(std::make_unique<CreateRenderPipelineEvent>(
+          device->GetInstanceId(), callbackInfo));
+  if (!tracked) {
+    return WGPUFuture{kNullFutureId};
+  }
+
+  emwgpuDeviceCreateRenderPipelineAsync(device, futureId, descriptor);
+  return WGPUFuture{futureId};
+}
+
 WGPUQueue wgpuDeviceGetQueue(WGPUDevice device) {
   return device->GetQueue();
 }