From d253fe70f1481974868ee1017ad37c2041a29145 Mon Sep 17 00:00:00 2001 From: Andrei Volykhin Date: Fri, 29 Aug 2025 23:09:03 +0300 Subject: [PATCH] webgpu: Add the dedicated WebGPU task source (#39020) According to the WebGPU specification there are the dedicated task source which is used to queue a global task for a GPUDevice on content timeline. https://gpuweb.github.io/gpuweb/#-webgpu-task-source Tasks on content timeline: - to fire "uncaptureevent" event - to resolve GPUDevice.lost promise Also fixed the "isTrusted" attribute status (false -> true) of the "uncaptureevent" event by using non JS version of event dispatching. Testing: No changes in WebGPU CTS expectations - webgpu:api,operation,uncapturederror:* - webgpu:api,operation,device,lost:* - webgpu:api,validation,state,device_lost,destroy:* Signed-off-by: Andrei Volykhin Co-authored-by: Andrei Volykhin --- components/script/dom/globalscope.rs | 6 +- components/script/dom/webgpu/gpuadapter.rs | 2 +- components/script/dom/webgpu/gpudevice.rs | 57 +++++++++++++------ .../dom/webgpu/gpuuncapturederrorevent.rs | 4 -- components/script/script_thread.rs | 8 +-- components/script/task_manager.rs | 1 + components/script/task_source.rs | 3 + 7 files changed, 51 insertions(+), 30 deletions(-) diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index a5ddceeee38..5a91bba7046 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -3191,7 +3191,6 @@ impl GlobalScope { device: WebGPUDevice, reason: DeviceLostReason, msg: String, - can_gc: CanGc, ) { let reason = match reason { DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown, @@ -3205,7 +3204,7 @@ impl GlobalScope { .expect("GPUDevice should still be in devices hashmap") .root() { - device.lose(reason, msg, can_gc); + device.lose(reason, msg); } } @@ -3214,7 +3213,6 @@ impl GlobalScope { &self, device: WebGPUDevice, error: webgpu_traits::Error, - can_gc: CanGc, ) { if let Some(gpu_device) = self .gpu_devices @@ -3222,7 +3220,7 @@ impl GlobalScope { .get(&device) .and_then(|device| device.root()) { - gpu_device.fire_uncaptured_error(error, can_gc); + gpu_device.fire_uncaptured_error(error); } else { warn!("Recived error for lost GPUDevice!") } diff --git a/components/script/dom/webgpu/gpuadapter.rs b/components/script/dom/webgpu/gpuadapter.rs index 38c0bbd8224..35e6a9d8f34 100644 --- a/components/script/dom/webgpu/gpuadapter.rs +++ b/components/script/dom/webgpu/gpuadapter.rs @@ -269,7 +269,7 @@ impl RoutedPromiseListener for GPUAdapter { can_gc, ); // 2. Lose the device(device, "unknown"). - device.lose(GPUDeviceLostReason::Unknown, e, can_gc); + device.lose(GPUDeviceLostReason::Unknown, e); promise.resolve_native(&device, can_gc); }, } diff --git a/components/script/dom/webgpu/gpudevice.rs b/components/script/dom/webgpu/gpudevice.rs index e4c0673b634..dc4657cb718 100644 --- a/components/script/dom/webgpu/gpudevice.rs +++ b/components/script/dom/webgpu/gpudevice.rs @@ -27,7 +27,6 @@ use super::gpusupportedlimits::GPUSupportedLimits; use crate::conversions::Convert; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit; -use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBufferDescriptor, GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason, @@ -38,10 +37,13 @@ use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ }; use crate::dom::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode; use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::trace::RootedTraceableBox; +use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; @@ -195,18 +197,30 @@ impl GPUDevice { } } - pub(crate) fn fire_uncaptured_error(&self, error: webgpu_traits::Error, can_gc: CanGc) { - let error = GPUError::from_error(&self.global(), error, can_gc); - let ev = GPUUncapturedErrorEvent::new( - &self.global(), - DOMString::from("uncapturederror"), - &GPUUncapturedErrorEventInit { - error, - parent: EventInit::empty(), - }, - can_gc, + /// + pub(crate) fn fire_uncaptured_error(&self, error: webgpu_traits::Error) { + let this = Trusted::new(self); + + // Queue a global task, using the webgpu task source, to fire an event named + // uncapturederror at a GPUDevice using GPUUncapturedErrorEvent. + self.global().task_manager().webgpu_task_source().queue( + task!(fire_uncaptured_error: move || { + let this = this.root(); + let error = GPUError::from_error(&this.global(), error, CanGc::note()); + + let event = GPUUncapturedErrorEvent::new( + &this.global(), + DOMString::from("uncapturederror"), + &GPUUncapturedErrorEventInit { + error, + parent: EventInit::empty(), + }, + CanGc::note(), + ); + + event.upcast::().fire(this.upcast(), CanGc::note()); + }), ); - let _ = self.eventtarget.DispatchEvent(ev.event(), can_gc); } /// @@ -370,11 +384,20 @@ impl GPUDevice { } /// - pub(crate) fn lose(&self, reason: GPUDeviceLostReason, msg: String, can_gc: CanGc) { - let lost_promise = &(*self.lost_promise.borrow()); - let global = &self.global(); - let lost = GPUDeviceLostInfo::new(global, msg.into(), reason, can_gc); - lost_promise.resolve_native(&*lost, can_gc); + pub(crate) fn lose(&self, reason: GPUDeviceLostReason, msg: String) { + let this = Trusted::new(self); + + // Queue a global task, using the webgpu task source, to resolve device.lost + // promise with a new GPUDeviceLostInfo with reason and message. + self.global().task_manager().webgpu_task_source().queue( + task!(resolve_device_lost: move || { + let this = this.root(); + + let lost_promise = &(*this.lost_promise.borrow()); + let lost = GPUDeviceLostInfo::new(&this.global(), msg.into(), reason, CanGc::note()); + lost_promise.resolve_native(&*lost, CanGc::note()); + }), + ); } } diff --git a/components/script/dom/webgpu/gpuuncapturederrorevent.rs b/components/script/dom/webgpu/gpuuncapturederrorevent.rs index af9722c2ca3..5abecf8051f 100644 --- a/components/script/dom/webgpu/gpuuncapturederrorevent.rs +++ b/components/script/dom/webgpu/gpuuncapturederrorevent.rs @@ -62,10 +62,6 @@ impl GPUUncapturedErrorEvent { ); ev } - - pub(crate) fn event(&self) -> &Event { - &self.event - } } impl GPUUncapturedErrorEventMethods for GPUUncapturedErrorEvent { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 6972163bc5e..48195fa56fe 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1523,7 +1523,7 @@ impl ScriptThread { }, #[cfg(feature = "webgpu")] MixedMessage::FromWebGPUServer(inner_msg) => { - self.handle_msg_from_webgpu_server(inner_msg, can_gc) + self.handle_msg_from_webgpu_server(inner_msg) }, MixedMessage::TimerFired => {}, } @@ -1959,7 +1959,7 @@ impl ScriptThread { } #[cfg(feature = "webgpu")] - fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg, can_gc: CanGc) { + fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg) { match msg { WebGPUMsg::FreeAdapter(id) => self.gpu_id_hub.free_adapter_id(id), WebGPUMsg::FreeDevice { @@ -1997,7 +1997,7 @@ impl ScriptThread { msg, } => { let global = self.documents.borrow().find_global(pipeline_id).unwrap(); - global.gpu_device_lost(device, reason, msg, can_gc); + global.gpu_device_lost(device, reason, msg); }, WebGPUMsg::UncapturedError { device, @@ -2006,7 +2006,7 @@ impl ScriptThread { } => { let global = self.documents.borrow().find_global(pipeline_id).unwrap(); let _ac = enter_realm(&*global); - global.handle_uncaptured_gpu_error(device, error, can_gc); + global.handle_uncaptured_gpu_error(device, error); }, _ => {}, } diff --git a/components/script/task_manager.rs b/components/script/task_manager.rs index 7535f3a8bc8..36601efc2c3 100644 --- a/components/script/task_manager.rs +++ b/components/script/task_manager.rs @@ -153,4 +153,5 @@ impl TaskManager { intersection_observer_task_source, IntersectionObserver ); + task_source_functions!(self, webgpu_task_source, WebGPU); } diff --git a/components/script/task_source.rs b/components/script/task_source.rs index d8e63c6ea07..23999c70ade 100644 --- a/components/script/task_source.rs +++ b/components/script/task_source.rs @@ -46,6 +46,8 @@ pub(crate) enum TaskSourceName { Gamepad, /// IntersectionObserver, + /// + WebGPU, } impl From for ScriptThreadEventCategory { @@ -72,6 +74,7 @@ impl From for ScriptThreadEventCategory { TaskSourceName::Timer => ScriptThreadEventCategory::TimerEvent, TaskSourceName::Gamepad => ScriptThreadEventCategory::InputEvent, TaskSourceName::IntersectionObserver => ScriptThreadEventCategory::ScriptEvent, + TaskSourceName::WebGPU => ScriptThreadEventCategory::ScriptEvent, } } }