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