tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebGPUChild.cpp (22986B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "WebGPUChild.h"
      7 
      8 #include <utility>
      9 
     10 #include "Adapter.h"
     11 #include "CompilationInfo.h"
     12 #include "DeviceLostInfo.h"
     13 #include "PipelineLayout.h"
     14 #include "Sampler.h"
     15 #include "Utility.h"
     16 #include "js/RootingAPI.h"
     17 #include "js/String.h"
     18 #include "js/TypeDecls.h"
     19 #include "js/Value.h"
     20 #include "js/Warnings.h"  // JS::WarnUTF8
     21 #include "mozilla/Assertions.h"
     22 #include "mozilla/ProfilerMarkers.h"
     23 #include "mozilla/dom/GPUUncapturedErrorEvent.h"
     24 #include "mozilla/dom/Promise.h"
     25 #include "mozilla/dom/ScriptSettings.h"
     26 #include "mozilla/dom/WebGPUBinding.h"
     27 #include "mozilla/webgpu/ComputePipeline.h"
     28 #include "mozilla/webgpu/InternalError.h"
     29 #include "mozilla/webgpu/OutOfMemoryError.h"
     30 #include "mozilla/webgpu/PipelineError.h"
     31 #include "mozilla/webgpu/RenderPipeline.h"
     32 #include "mozilla/webgpu/ValidationError.h"
     33 #include "mozilla/webgpu/WebGPUTypes.h"
     34 #include "mozilla/webgpu/ffi/wgpu.h"
     35 
     36 namespace mozilla::webgpu {
     37 
     38 void WebGPUChild::JsWarning(nsIGlobalObject* aGlobal,
     39                            const nsACString& aMessage) {
     40  const auto& flatString = PromiseFlatCString(aMessage);
     41  if (aGlobal) {
     42    dom::AutoJSAPI api;
     43    if (api.Init(aGlobal)) {
     44      JS::WarnUTF8(api.cx(), "Uncaptured WebGPU error: %s", flatString.get());
     45    }
     46  } else {
     47    printf_stderr("Uncaptured WebGPU error without device target: %s\n",
     48                  flatString.get());
     49  }
     50 }
     51 
     52 void on_message_queued(ffi::WGPUWebGPUChildPtr child) {
     53  auto* c = static_cast<WebGPUChild*>(child);
     54  c->ScheduleFlushQueuedMessages();
     55 }
     56 
     57 WebGPUChild::WebGPUChild()
     58    : mClient(ffi::wgpu_client_new(this, on_message_queued)) {}
     59 
     60 WebGPUChild::~WebGPUChild() = default;
     61 
     62 RawId WebGPUChild::RenderBundleEncoderFinish(
     63    ffi::WGPURenderBundleEncoder& aEncoder, RawId aDeviceId,
     64    const dom::GPURenderBundleDescriptor& aDesc) {
     65  ffi::WGPURenderBundleDescriptor desc = {};
     66 
     67  webgpu::StringHelper label(aDesc.mLabel);
     68  desc.label = label.Get();
     69 
     70  RawId id = ffi::wgpu_client_create_render_bundle(GetClient(), aDeviceId,
     71                                                   &aEncoder, &desc);
     72 
     73  return id;
     74 }
     75 
     76 RawId WebGPUChild::RenderBundleEncoderFinishError(RawId aDeviceId,
     77                                                  const nsString& aLabel) {
     78  webgpu::StringHelper label(aLabel);
     79 
     80  RawId id = ffi::wgpu_client_create_render_bundle_error(GetClient(), aDeviceId,
     81                                                         label.Get());
     82 
     83  return id;
     84 }
     85 
     86 namespace ffi {
     87 void wgpu_child_send_messages(WGPUWebGPUChildPtr aChild, uint32_t aNrOfMessages,
     88                              struct WGPUByteBuf aSerializedMessages) {
     89  auto* c = static_cast<WebGPUChild*>(aChild);
     90  auto messages =
     91      ipc::ByteBuf(aSerializedMessages.data, aSerializedMessages.len,
     92                   aSerializedMessages.capacity);
     93  c->SendSerializedMessages(aNrOfMessages, std::move(messages));
     94 }
     95 
     96 void wgpu_child_resolve_request_adapter_promise(
     97    WGPUWebGPUChildPtr aChild, RawId aAdapterId,
     98    const struct WGPUAdapterInformation* aAdapterInfo) {
     99  auto* c = static_cast<WebGPUChild*>(aChild);
    100  auto& pending_promises = c->mPendingRequestAdapterPromises;
    101  auto pending_promise = std::move(pending_promises.front());
    102  pending_promises.pop_front();
    103 
    104  MOZ_RELEASE_ASSERT(pending_promise.adapter_id == aAdapterId);
    105 
    106  if (aAdapterInfo == nullptr) {
    107    pending_promise.promise->MaybeResolve(JS::NullHandleValue);
    108  } else {
    109    auto info = std::make_shared<WGPUAdapterInformation>(*aAdapterInfo);
    110    RefPtr<Adapter> adapter = new Adapter(pending_promise.instance, c, info);
    111    pending_promise.promise->MaybeResolve(adapter);
    112  }
    113 }
    114 
    115 void wgpu_child_resolve_request_device_promise(WGPUWebGPUChildPtr aChild,
    116                                               RawId aDeviceId, RawId aQueueId,
    117                                               const nsCString* aError) {
    118  auto* c = static_cast<WebGPUChild*>(aChild);
    119  auto& pending_promises = c->mPendingRequestDevicePromises;
    120  auto pending_promise = std::move(pending_promises.front());
    121  pending_promises.pop_front();
    122 
    123  MOZ_RELEASE_ASSERT(pending_promise.device_id == aDeviceId);
    124  MOZ_RELEASE_ASSERT(pending_promise.queue_id == aQueueId);
    125 
    126  if (aError == nullptr) {
    127    RefPtr<Device> device =
    128        new Device(pending_promise.adapter, pending_promise.device_id,
    129                   pending_promise.queue_id, pending_promise.features,
    130                   pending_promise.limits, pending_promise.adapter_info,
    131                   pending_promise.lost_promise);
    132    device->SetLabel(pending_promise.label);
    133    pending_promise.promise->MaybeResolve(device);
    134  } else {
    135    pending_promise.promise->MaybeRejectWithOperationError(*aError);
    136  }
    137 }
    138 
    139 void wgpu_child_resolve_pop_error_scope_promise(WGPUWebGPUChildPtr aChild,
    140                                                RawId aDeviceId, uint8_t aTy,
    141                                                const nsCString* aMessage) {
    142  auto* c = static_cast<WebGPUChild*>(aChild);
    143  auto& pending_promises = c->mPendingPopErrorScopePromises;
    144  auto pending_promise = std::move(pending_promises.front());
    145  pending_promises.pop_front();
    146 
    147  MOZ_RELEASE_ASSERT(pending_promise.device->GetId() == aDeviceId);
    148 
    149  RefPtr<Error> error;
    150 
    151  switch ((PopErrorScopeResultType)aTy) {
    152    case PopErrorScopeResultType::NoError:
    153      pending_promise.promise->MaybeResolve(JS::NullHandleValue);
    154      return;
    155 
    156    case PopErrorScopeResultType::DeviceLost:
    157      pending_promise.promise->MaybeResolve(JS::NullHandleValue);
    158      return;
    159 
    160    case PopErrorScopeResultType::ThrowOperationError:
    161      pending_promise.promise->MaybeRejectWithOperationError(*aMessage);
    162      return;
    163 
    164    case PopErrorScopeResultType::OutOfMemory:
    165      error = new OutOfMemoryError(pending_promise.device->GetParentObject(),
    166                                   *aMessage);
    167      break;
    168 
    169    case PopErrorScopeResultType::ValidationError:
    170      error = new ValidationError(pending_promise.device->GetParentObject(),
    171                                  *aMessage);
    172      break;
    173 
    174    case PopErrorScopeResultType::InternalError:
    175      error = new InternalError(pending_promise.device->GetParentObject(),
    176                                *aMessage);
    177      break;
    178  }
    179  pending_promise.promise->MaybeResolve(std::move(error));
    180 }
    181 
    182 void wgpu_child_resolve_create_pipeline_promise(WGPUWebGPUChildPtr aChild,
    183                                                RawId aPipelineId,
    184                                                bool aIsRenderPipeline,
    185                                                bool aIsValidationError,
    186                                                const nsCString* aError) {
    187  auto* c = static_cast<WebGPUChild*>(aChild);
    188  auto& pending_promises = c->mPendingCreatePipelinePromises;
    189  auto pending_promise = std::move(pending_promises.front());
    190  pending_promises.pop_front();
    191 
    192  MOZ_RELEASE_ASSERT(pending_promise.pipeline_id == aPipelineId);
    193  MOZ_RELEASE_ASSERT(pending_promise.is_render_pipeline == aIsRenderPipeline);
    194 
    195  if (aError == nullptr) {
    196    if (pending_promise.is_render_pipeline) {
    197      RefPtr<RenderPipeline> object = new RenderPipeline(
    198          pending_promise.device, pending_promise.pipeline_id);
    199      object->SetLabel(pending_promise.label);
    200      pending_promise.promise->MaybeResolve(object);
    201    } else {
    202      RefPtr<ComputePipeline> object = new ComputePipeline(
    203          pending_promise.device, pending_promise.pipeline_id);
    204      object->SetLabel(pending_promise.label);
    205      pending_promise.promise->MaybeResolve(object);
    206    }
    207  } else {
    208    dom::GPUPipelineErrorReason reason;
    209    if (aIsValidationError) {
    210      reason = dom::GPUPipelineErrorReason::Validation;
    211    } else {
    212      reason = dom::GPUPipelineErrorReason::Internal;
    213    }
    214    RefPtr<PipelineError> e = new PipelineError(*aError, reason);
    215    pending_promise.promise->MaybeReject(e);
    216  }
    217 }
    218 
    219 void wgpu_child_resolve_create_shader_module_promise(
    220    WGPUWebGPUChildPtr aChild, RawId aShaderModuleId,
    221    struct WGPUFfiSlice_FfiShaderModuleCompilationMessage aMessages) {
    222  auto* c = static_cast<WebGPUChild*>(aChild);
    223  auto& pending_promises = c->mPendingCreateShaderModulePromises;
    224  auto pending_promise = std::move(pending_promises.front());
    225  pending_promises.pop_front();
    226 
    227  MOZ_RELEASE_ASSERT(pending_promise.shader_module->GetId() == aShaderModuleId);
    228 
    229  auto ffi_messages = Span(aMessages.data, aMessages.length);
    230 
    231  auto messages = nsTArray<WebGPUCompilationMessage>(aMessages.length);
    232  for (const auto& message : ffi_messages) {
    233    WebGPUCompilationMessage msg;
    234    msg.lineNum = message.line_number;
    235    msg.linePos = message.line_pos;
    236    msg.offset = message.utf16_offset;
    237    msg.length = message.utf16_length;
    238    msg.message = message.message;
    239    // wgpu currently only returns errors.
    240    msg.messageType = WebGPUCompilationMessageType::Error;
    241    messages.AppendElement(std::move(msg));
    242  }
    243 
    244  if (!messages.IsEmpty()) {
    245    auto shader_module = pending_promise.shader_module;
    246    reportCompilationMessagesToConsole(shader_module, std::cref(messages));
    247  }
    248  RefPtr<CompilationInfo> infoObject(
    249      new CompilationInfo(pending_promise.device));
    250  infoObject->SetMessages(messages);
    251  pending_promise.promise->MaybeResolve(infoObject);
    252 };
    253 
    254 void wgpu_child_resolve_buffer_map_promise(WGPUWebGPUChildPtr aChild,
    255                                           WGPUBufferId aBufferId,
    256                                           bool aIsWritable, uint64_t aOffset,
    257                                           uint64_t aSize,
    258                                           const nsCString* aError) {
    259  auto* c = static_cast<WebGPUChild*>(aChild);
    260  auto& pending_promises = c->mPendingBufferMapPromises;
    261 
    262  WebGPUChild::PendingBufferMapPromise pending_promise;
    263  if (auto search = pending_promises.find(aBufferId);
    264      search != pending_promises.end()) {
    265    pending_promise = std::move(search->second.front());
    266    search->second.pop_front();
    267 
    268    if (search->second.empty()) {
    269      pending_promises.erase(aBufferId);
    270    }
    271  } else {
    272    NS_ERROR("Missing pending promise for buffer map");
    273  }
    274 
    275  // Unmap might have been called while the result was on the way back.
    276  if (pending_promise.promise->State() != dom::Promise::PromiseState::Pending) {
    277    return;
    278  }
    279 
    280  if (aError == nullptr) {
    281    pending_promise.buffer->ResolveMapRequest(pending_promise.promise, aOffset,
    282                                              aSize, aIsWritable);
    283  } else {
    284    pending_promise.buffer->RejectMapRequest(pending_promise.promise, *aError);
    285  }
    286 }
    287 
    288 void wgpu_child_resolve_on_submitted_work_done_promise(
    289    WGPUWebGPUChildPtr aChild, WGPUQueueId aQueueId) {
    290  auto* c = static_cast<WebGPUChild*>(aChild);
    291  const auto& it = c->mPendingOnSubmittedWorkDonePromises.find(aQueueId);
    292  MOZ_RELEASE_ASSERT(it != c->mPendingOnSubmittedWorkDonePromises.end());
    293  auto& pending_promises = it->second;
    294  auto pending_promise = std::move(pending_promises.front());
    295  pending_promises.pop_front();
    296 
    297  if (pending_promises.empty()) {
    298    c->mPendingOnSubmittedWorkDonePromises.erase(it);
    299  }
    300 
    301  pending_promise->MaybeResolveWithUndefined();
    302 };
    303 }  // namespace ffi
    304 
    305 ipc::IPCResult WebGPUChild::RecvServerMessage(const ipc::ByteBuf& aByteBuf) {
    306  ffi::wgpu_client_receive_server_message(GetClient(), ToFFI(&aByteBuf));
    307  return IPC_OK();
    308 }
    309 
    310 void WebGPUChild::ScheduleFlushQueuedMessages() {
    311  if (mScheduledFlushQueuedMessages) {
    312    return;
    313  }
    314  mScheduledFlushQueuedMessages = true;
    315 
    316  nsContentUtils::RunInStableState(
    317      NewRunnableMethod("dom::WebGPUChild::ScheduledFlushQueuedMessages", this,
    318                        &WebGPUChild::ScheduledFlushQueuedMessages));
    319 }
    320 
    321 size_t WebGPUChild::QueueDataBuffer(ipc::ByteBuf&& bb) {
    322  auto buffer_index = mQueuedDataBuffers.Length();
    323  mQueuedDataBuffers.AppendElement(std::move(bb));
    324  return buffer_index;
    325 }
    326 
    327 size_t WebGPUChild::QueueShmemHandle(ipc::MutableSharedMemoryHandle&& handle) {
    328  auto shmem_handle_index = mQueuedHandles.Length();
    329  mQueuedHandles.AppendElement(std::move(handle));
    330  return shmem_handle_index;
    331 }
    332 
    333 void WebGPUChild::ScheduledFlushQueuedMessages() {
    334  MOZ_ASSERT(mScheduledFlushQueuedMessages);
    335  mScheduledFlushQueuedMessages = false;
    336 
    337  PROFILER_MARKER_UNTYPED("WebGPU: ScheduledFlushQueuedMessages",
    338                          GRAPHICS_WebGPU);
    339  FlushQueuedMessages();
    340 }
    341 
    342 void WebGPUChild::FlushQueuedMessages() {
    343  ipc::ByteBuf serialized_messages;
    344  auto nr_of_messages = ffi::wgpu_client_get_queued_messages(
    345      GetClient(), ToFFI(&serialized_messages));
    346  if (nr_of_messages == 0) {
    347    return;
    348  }
    349 
    350  SendSerializedMessages(nr_of_messages, std::move(serialized_messages));
    351 }
    352 
    353 void WebGPUChild::SendSerializedMessages(uint32_t aNrOfMessages,
    354                                         ipc::ByteBuf aSerializedMessages) {
    355  PROFILER_MARKER_FMT("WebGPU: SendSerializedMessages", GRAPHICS_WebGPU, {},
    356                      "messages: {}", aNrOfMessages);
    357 
    358  bool sent =
    359      SendMessages(aNrOfMessages, std::move(aSerializedMessages),
    360                   std::move(mQueuedDataBuffers), std::move(mQueuedHandles));
    361  mQueuedDataBuffers.Clear();
    362  mQueuedHandles.Clear();
    363 
    364  if (!sent) {
    365    ClearActorState();
    366  }
    367 }
    368 
    369 ipc::IPCResult WebGPUChild::RecvUncapturedError(RawId aDeviceId,
    370                                                const nsACString& aMessage) {
    371  MOZ_RELEASE_ASSERT(aDeviceId);
    372 
    373  RefPtr<Device> device;
    374  const auto itr = mDeviceMap.find(aDeviceId);
    375  if (itr != mDeviceMap.end()) {
    376    device = itr->second.get();
    377  }
    378 
    379  if (!device) {
    380    return IPC_OK();
    381  }
    382 
    383  // We don't want to spam the errors to the console indefinitely
    384  if (device->CheckNewWarning(aMessage)) {
    385    JsWarning(device->GetOwnerGlobal(), aMessage);
    386 
    387    dom::GPUUncapturedErrorEventInit init;
    388    init.mError = new ValidationError(device->GetParentObject(), aMessage);
    389    RefPtr<mozilla::dom::GPUUncapturedErrorEvent> event =
    390        dom::GPUUncapturedErrorEvent::Constructor(device, u"uncapturederror"_ns,
    391                                                  init);
    392    device->DispatchEvent(*event);
    393  }
    394  return IPC_OK();
    395 }
    396 
    397 ipc::IPCResult WebGPUChild::RecvDeviceLost(RawId aDeviceId, uint8_t aReason,
    398                                           const nsACString& aMessage) {
    399  // There might have been a race between getting back the response to a
    400  // `device.destroy()` call and actual device loss. If that was the case,
    401  // set the lost reason to "destroyed".
    402  auto device_lost_promise_entry =
    403      mPendingDeviceLostPromises.extract(aDeviceId);
    404  if (!device_lost_promise_entry.empty()) {
    405    auto promise = std::move(device_lost_promise_entry.mapped());
    406    RefPtr<DeviceLostInfo> info = new DeviceLostInfo(
    407        promise->GetParentObject(), dom::GPUDeviceLostReason::Destroyed,
    408        u"Device destroyed"_ns);
    409    promise->MaybeResolve(info);
    410  } else {
    411    auto message = NS_ConvertUTF8toUTF16(aMessage);
    412 
    413    const auto itr = mDeviceMap.find(aDeviceId);
    414    if (itr != mDeviceMap.end()) {
    415      RefPtr<Device> device = itr->second.get();
    416 
    417      if (!device) {
    418        return IPC_OK();
    419      }
    420 
    421      dom::GPUDeviceLostReason reason =
    422          static_cast<dom::GPUDeviceLostReason>(aReason);
    423      device->ResolveLost(reason, message);
    424    }
    425  }
    426 
    427  return IPC_OK();
    428 }
    429 
    430 void WebGPUChild::SwapChainPresent(RawId aTextureId,
    431                                   const RemoteTextureId& aRemoteTextureId,
    432                                   const RemoteTextureOwnerId& aOwnerId) {
    433  // The parent side needs to create a command encoder which will be submitted
    434  // and dropped right away so we create and release an encoder ID here.
    435  RawId commandEncoderId =
    436      ffi::wgpu_client_make_command_encoder_id(GetClient());
    437  RawId commandBufferId = ffi::wgpu_client_make_command_buffer_id(GetClient());
    438  ffi::wgpu_client_swap_chain_present(GetClient(), aTextureId, commandEncoderId,
    439                                      commandBufferId, aRemoteTextureId.mId,
    440                                      aOwnerId.mId);
    441  ffi::wgpu_client_free_command_encoder_id(GetClient(), commandEncoderId);
    442  ffi::wgpu_client_free_command_buffer_id(GetClient(), commandBufferId);
    443 }
    444 
    445 void WebGPUChild::RegisterDevice(Device* const aDevice) {
    446  mDeviceMap.insert({aDevice->GetId(), aDevice});
    447 }
    448 
    449 void WebGPUChild::UnregisterDevice(RawId aDeviceId) {
    450  mDeviceMap.erase(aDeviceId);
    451 }
    452 
    453 void WebGPUChild::ActorDestroy(ActorDestroyReason) { ClearActorState(); }
    454 
    455 void WebGPUChild::ClearActorState() {
    456  // All following code sections resolve/reject promises immediately. JS code
    457  // can perform further calls that add more promises to data structures, so
    458  // all code sections below should not use iterators!
    459 
    460  // Make sure we resolve/reject all pending promises; even the ones that get
    461  // enqueued immediately by JS code that gets to run as a result of a promise
    462  // we just resolved/rejected.
    463  while (true) {
    464    // Resolve the promise with null since the WebGPUChild has been destroyed.
    465    if (!mPendingRequestAdapterPromises.empty()) {
    466      auto pending_promise = std::move(mPendingRequestAdapterPromises.front());
    467      mPendingRequestAdapterPromises.pop_front();
    468 
    469      pending_promise.promise->MaybeResolve(JS::NullHandleValue);
    470    }
    471    // Pretend this worked but return a lost device, per spec.
    472    else if (!mPendingRequestDevicePromises.empty()) {
    473      auto pending_promise = std::move(mPendingRequestDevicePromises.front());
    474      mPendingRequestDevicePromises.pop_front();
    475 
    476      RefPtr<Device> device =
    477          new Device(pending_promise.adapter, pending_promise.device_id,
    478                     pending_promise.queue_id, pending_promise.features,
    479                     pending_promise.limits, pending_promise.adapter_info,
    480                     pending_promise.lost_promise);
    481      device->SetLabel(pending_promise.label);
    482      device->ResolveLost(dom::GPUDeviceLostReason::Unknown,
    483                          u"WebGPUChild destroyed"_ns);
    484      pending_promise.promise->MaybeResolve(device);
    485    }
    486    // Resolve all promises that were pending due to `device.destroy()` being
    487    // called.
    488    else if (!mPendingDeviceLostPromises.empty()) {
    489      auto pending_promise_entry = mPendingDeviceLostPromises.begin();
    490      auto pending_promise = std::move(pending_promise_entry->second);
    491      mPendingDeviceLostPromises.erase(pending_promise_entry->first);
    492 
    493      RefPtr<DeviceLostInfo> info = new DeviceLostInfo(
    494          pending_promise->GetParentObject(),
    495          dom::GPUDeviceLostReason::Destroyed, u"Device destroyed"_ns);
    496      pending_promise->MaybeResolve(info);
    497    }
    498    // Empty device map and resolve all lost promises with an "unknown" reason.
    499    else if (!mDeviceMap.empty()) {
    500      auto device_map_entry = mDeviceMap.begin();
    501      RefPtr<Device> device = device_map_entry->second.get();
    502      mDeviceMap.erase(device_map_entry->first);
    503 
    504      if (device) {
    505        device->ResolveLost(dom::GPUDeviceLostReason::Unknown,
    506                            u"WebGPUChild destroyed"_ns);
    507      }
    508    }
    509    // Pretend this worked and there is no error, per spec.
    510    else if (!mPendingPopErrorScopePromises.empty()) {
    511      auto pending_promise = std::move(mPendingPopErrorScopePromises.front());
    512      mPendingPopErrorScopePromises.pop_front();
    513 
    514      pending_promise.promise->MaybeResolve(JS::NullHandleValue);
    515    }
    516    // Pretend this worked, per spec; see "Listen for timeline event".
    517    else if (!mPendingCreatePipelinePromises.empty()) {
    518      auto pending_promise = std::move(mPendingCreatePipelinePromises.front());
    519      mPendingCreatePipelinePromises.pop_front();
    520 
    521      if (pending_promise.is_render_pipeline) {
    522        RefPtr<RenderPipeline> object = new RenderPipeline(
    523            pending_promise.device, pending_promise.pipeline_id);
    524        object->SetLabel(pending_promise.label);
    525        pending_promise.promise->MaybeResolve(object);
    526      } else {
    527        RefPtr<ComputePipeline> object = new ComputePipeline(
    528            pending_promise.device, pending_promise.pipeline_id);
    529        object->SetLabel(pending_promise.label);
    530        pending_promise.promise->MaybeResolve(object);
    531      }
    532    }
    533    // Pretend this worked, per spec; see "Listen for timeline event".
    534    else if (!mPendingCreateShaderModulePromises.empty()) {
    535      auto pending_promise =
    536          std::move(mPendingCreateShaderModulePromises.front());
    537      mPendingCreateShaderModulePromises.pop_front();
    538 
    539      nsTArray<WebGPUCompilationMessage> messages;
    540      RefPtr<CompilationInfo> infoObject(
    541          new CompilationInfo(pending_promise.device));
    542      infoObject->SetMessages(messages);
    543      pending_promise.promise->MaybeResolve(infoObject);
    544    }
    545    // Reject the promise as if unmap() has been called, per spec.
    546    else if (!mPendingBufferMapPromises.empty()) {
    547      auto pending_promises = mPendingBufferMapPromises.begin();
    548      auto pending_promise = std::move(pending_promises->second.front());
    549      pending_promises->second.pop_front();
    550      if (pending_promises->second.empty()) {
    551        mPendingBufferMapPromises.erase(pending_promises->first);
    552      }
    553 
    554      // Unmap might have been called.
    555      if (pending_promise.promise->State() !=
    556          dom::Promise::PromiseState::Pending) {
    557        continue;
    558      }
    559      pending_promise.buffer->RejectMapRequestWithAbortError(
    560          pending_promise.promise);
    561    }
    562    // Pretend this worked, per spec; see "Listen for timeline event".
    563    else if (auto it = mPendingOnSubmittedWorkDonePromises.begin();
    564             it != mPendingOnSubmittedWorkDonePromises.end()) {
    565      auto& pending_promises = it->second;
    566      MOZ_ASSERT(!pending_promises.empty(),
    567                 "Empty queues should have been removed from the map");
    568 
    569      auto pending_promise = std::move(pending_promises.front());
    570      pending_promises.pop_front();
    571 
    572      if (pending_promises.empty()) {
    573        mPendingOnSubmittedWorkDonePromises.erase(it);
    574      }
    575 
    576      pending_promise->MaybeResolveWithUndefined();
    577    } else {
    578      break;
    579    }
    580  }
    581 }
    582 
    583 void WebGPUChild::QueueSubmit(
    584    RawId aSelfId, RawId aDeviceId, nsTArray<RawId>& aCommandBuffers,
    585    const nsTArray<RawId>& aUsedExternalTextureSources) {
    586  ffi::wgpu_client_queue_submit(
    587      GetClient(), aDeviceId, aSelfId,
    588      {aCommandBuffers.Elements(), aCommandBuffers.Length()},
    589      {mSwapChainTexturesWaitingForSubmit.Elements(),
    590       mSwapChainTexturesWaitingForSubmit.Length()},
    591      {aUsedExternalTextureSources.Elements(),
    592       aUsedExternalTextureSources.Length()});
    593  mSwapChainTexturesWaitingForSubmit.Clear();
    594 
    595  PROFILER_MARKER_UNTYPED("WebGPU: QueueSubmit", GRAPHICS_WebGPU);
    596  FlushQueuedMessages();
    597 }
    598 
    599 void WebGPUChild::NotifyWaitForSubmit(RawId aTextureId) {
    600  mSwapChainTexturesWaitingForSubmit.AppendElement(aTextureId);
    601 }
    602 
    603 }  // namespace mozilla::webgpu