1use std::borrow::Cow;
6use std::cell::Cell;
7use std::rc::Rc;
8
9use dom_struct::dom_struct;
10use js::context::{JSContext, NoGC};
11use js::jsapi::{HandleObject, Heap, JSObject};
12use js::realm::CurrentRealm;
13use jstraceable_derive::JSTraceable;
14use log::warn;
15use malloc_size_of_derive::MallocSizeOf;
16use script_bindings::callback::CallbackContainer;
17use script_bindings::cell::DomRefCell;
18use script_bindings::codegen::GenericBindings::EventBinding::EventInit;
19use script_bindings::codegen::GenericBindings::EventHandlerBinding::EventHandlerNonNull;
20use script_bindings::codegen::GenericBindings::WebGPUBinding::{
21 GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBufferDescriptor,
22 GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason,
23 GPUDeviceMethods, GPUDeviceWrap, GPUErrorFilter, GPUExternalTextureDescriptor,
24 GPUPipelineErrorReason, GPUPipelineLayoutDescriptor, GPUQuerySetDescriptor,
25 GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerDescriptor,
26 GPUShaderModuleDescriptor, GPUTextureDescriptor, GPUTextureFormat, GPUUncapturedErrorEventInit,
27 GPUVertexStepMode,
28};
29use script_bindings::codegen::GenericUnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
30use script_bindings::conversions::DerivedFrom;
31use script_bindings::error::Error;
32use script_bindings::inheritance::Castable;
33use script_bindings::interfaces::{
34 HeapTracedPromiseHelpers, PromiseHelpers, StackRootPromiseHelpers,
35};
36use script_bindings::reflector::{
37 DomGlobalGeneric, reflect_weak_referenceable_dom_object_with_wrap,
38};
39use script_bindings::routed_promise::RoutedPromiseListener;
40use script_bindings::traits::{DomEventTrait, DomExceptionTrait};
41use script_bindings::{DomTypes, cformat, task};
42use stylo_atoms::atom;
43use webgpu_traits::{
44 BlendState, ColorTargetState, ColorWrites, DepthBiasState, DepthStencilState, Features,
45 FragmentState, Limits, MultisampleState, PopError, RenderPipelineDescriptor, StencilFaceState,
46 StencilState, TextureFormat, VertexAttribute, VertexBufferLayout, VertexState, VertexStepMode,
47 WebGPU, WebGPUComputePipeline, WebGPUComputePipelineResponse, WebGPUDevice,
48 WebGPUPoppedErrorScopeResponse, WebGPUQueue, WebGPURenderPipeline,
49 WebGPURenderPipelineResponse, WebGPURequest,
50};
51
52use super::gpudevicelostinfo::GPUDeviceLostInfo;
53use crate::PipelineLayout;
54use crate::dom::bindings::error::Fallible;
55use crate::dom::bindings::refcounted::Trusted;
56use crate::dom::bindings::root::{Dom, DomRoot};
57use crate::dom::bindings::str::USVString;
58use crate::gpuadapter::GPUAdapter;
59use crate::gpuadapterinfo::GPUAdapterInfo;
60use crate::gpubindgroup::GPUBindGroup;
61use crate::gpubindgrouplayout::GPUBindGroupLayout;
62use crate::gpubuffer::GPUBuffer;
63use crate::gpucommandencoder::GPUCommandEncoder;
64use crate::gpucomputepipeline::GPUComputePipeline;
65use crate::gpuconvert::WebGPUConvert;
66use crate::gpuerror::{AsWebGpu, GPUError};
67use crate::gpuexternaltexture::GPUExternalTexture;
68use crate::gpupipelineerror::GPUPipelineError;
69use crate::gpupipelinelayout::GPUPipelineLayout;
70use crate::gpuqueryset::GPUQuerySet;
71use crate::gpurenderbundleencoder::GPURenderBundleEncoder;
72use crate::gpurenderpipeline::GPURenderPipeline;
73use crate::gpusampler::GPUSampler;
74use crate::gpushadermodule::GPUShaderModule;
75use crate::gpusupportedfeatures::GPUSupportedFeatures;
76use crate::gpusupportedlimits::GPUSupportedLimits;
77use crate::gputexture::GPUTexture;
78use crate::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
79use crate::traits::{
80 Equivalence, EventTargetTrait, WebGPUGlobalTrait, WebGPUPromise, WebGPUPromiseCallbackTrait,
81};
82
83macro_rules! event_handler(
84 ($event_type: ident, $getter: ident, $setter: ident) => (
85 define_event_handler!(
86 script_bindings::codegen::GenericBindings::EventHandlerBinding::EventHandlerNonNull<D>,
87 $event_type,
88 $getter,
89 $setter,
90 set_event_handler_common
91 );
92 )
93);
94
95macro_rules! define_event_handler(
97 ($handler: ty, $event_type: ident, $getter: ident, $setter: ident, $setter_fn: ident) => (
98 fn $getter(&self, cx: &mut js::context::JSContext) -> Option<script_bindings::callback::RootedCallback<$handler>> {
99 use crate::dom::bindings::inheritance::Castable;
100 let eventtarget = self.upcast::<D::EventTarget>();
101 D::EventTarget::get_event_handler_common(eventtarget, cx, stringify!($event_type))
102 }
103
104 fn $setter(&self, cx: &mut js::context::JSContext, listener: Option<script_bindings::callback::RootedCallback<$handler>>) {
105 use crate::dom::bindings::inheritance::Castable;
106 let eventtarget = self.upcast::<D::EventTarget>();
107 eventtarget.$setter_fn(cx, stringify!($event_type), listener)
108 }
109 )
110);
111
112#[derive(JSTraceable, MallocSizeOf)]
113struct DroppableGPUDevice {
114 #[no_trace]
115 channel: WebGPU,
116 #[no_trace]
117 device: WebGPUDevice,
118}
119
120impl Drop for DroppableGPUDevice {
121 fn drop(&mut self) {
122 if let Err(e) = self
123 .channel
124 .0
125 .send(WebGPURequest::DropDevice(self.device.0))
126 {
127 warn!("Failed to send DropDevice ({:?}) ({})", self.device.0, e);
128 }
129 }
130}
131
132#[dom_struct]
133pub struct GPUDevice<D: DomTypes> {
134 eventtarget: D::EventTarget,
135 adapter: Dom<GPUAdapter<D>>,
136 #[ignore_malloc_size_of = "mozjs"]
137 extensions: Heap<*mut JSObject>,
138 features: Dom<GPUSupportedFeatures<D>>,
139 limits: Dom<GPUSupportedLimits<D>>,
140 adapter_info: Dom<GPUAdapterInfo<D>>,
141 label: DomRefCell<USVString>,
142 default_queue: Dom<D::GPUQueue>,
143 lost_promise: DomRefCell<<D::Promise as PromiseHelpers<D>>::HeapTraced>,
145 valid: Cell<bool>,
146 droppable: DroppableGPUDevice,
147}
148
149impl<D> GPUDevice<D>
150where
151 D: Equivalence,
152 EventHandlerNonNull<D>: CallbackContainer,
153{
154 #[expect(clippy::too_many_arguments)]
155 fn new_inherited(
156 channel: WebGPU,
157 adapter: &GPUAdapter<D>,
158 features: &GPUSupportedFeatures<D>,
159 limits: &GPUSupportedLimits<D>,
160 adapter_info: &GPUAdapterInfo<D>,
161 device: WebGPUDevice,
162 queue: &D::GPUQueue,
163 label: String,
164 lost_promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
165 ) -> Self {
166 Self {
167 eventtarget: D::EventTarget::new_inherited(),
168 adapter: Dom::from_ref(adapter),
169 extensions: Heap::default(),
170 features: Dom::from_ref(features),
171 limits: Dom::from_ref(limits),
172 adapter_info: Dom::from_ref(adapter_info),
173 label: DomRefCell::new(USVString::from(label)),
174 default_queue: Dom::from_ref(queue),
175 lost_promise: DomRefCell::new(lost_promise.to_traced()),
176 valid: Cell::new(true),
177 droppable: DroppableGPUDevice { channel, device },
178 }
179 }
180
181 #[allow(clippy::too_many_arguments)]
182 pub fn new(
183 cx: &mut JSContext,
184 global: &D::GlobalScope,
185 channel: WebGPU,
186 adapter: &GPUAdapter<D>,
187 extensions: HandleObject,
188 features: Features,
189 limits: Limits,
190 device: WebGPUDevice,
191 queue: WebGPUQueue,
192 label: String,
193 ) -> DomRoot<Self> {
194 let queue = D::GPUQueue::new(cx, global, channel.clone(), queue);
195 let limits = GPUSupportedLimits::new(cx, global, limits);
196 let features = GPUSupportedFeatures::Constructor(cx, global, None, features).unwrap();
197 let adapter_info = GPUAdapterInfo::clone_from(cx, global, &adapter.info());
198 let lost_promise = D::Promise::new(cx, global);
199 let device = reflect_weak_referenceable_dom_object_with_wrap::<D, _, _>(
200 cx,
201 Rc::new(GPUDevice::new_inherited(
202 channel,
203 adapter,
204 &features,
205 &limits,
206 &adapter_info,
207 device,
208 &queue,
209 label,
210 &lost_promise,
211 )),
212 global,
213 GPUDeviceWrap::<D>,
214 );
215 queue.set_device(&device);
216 device.extensions.set(*extensions);
217 device
218 }
219}
220
221impl<D> GPUDevice<D>
222where
223 D: Equivalence,
224 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
225 EventHandlerNonNull<D>: CallbackContainer,
226{
227 pub fn id(&self) -> WebGPUDevice {
228 self.droppable.device
229 }
230
231 pub fn queue_id(&self) -> WebGPUQueue {
232 self.default_queue.id()
233 }
234
235 pub(crate) fn dispatch_error(&self, error: webgpu_traits::Error) {
236 if let Err(e) = self.droppable.channel.0.send(WebGPURequest::DispatchError {
237 device_id: self.id().0,
238 error,
239 }) {
240 warn!("Failed to send WebGPURequest::DispatchError due to {e:?}");
241 }
242 }
243
244 pub fn fire_uncaptured_error(&self, error: webgpu_traits::Error) {
246 let this = Trusted::new(self);
247
248 self.global_from_reflector().queue_webgpu_task_source(task!(
251 fire_uncaptured_error: move |cx| {
252 let this = this.root();
253 let error = GPUError::from_error(cx, &*this.global_from_reflector(), error);
254
255 let event = GPUUncapturedErrorEvent::new(
256 cx,
257 &*this.global_from_reflector(),
258 atom!("uncapturederror"),
259 &GPUUncapturedErrorEventInit::<D> {
260 error,
261 parent: EventInit::empty(),
262 },
263 );
264
265 event.upcast::<D::Event>().fire(cx, this.upcast());
266 }
267 ));
268 }
269
270 pub(crate) fn validate_texture_format_required_features(
275 &self,
276 format: &GPUTextureFormat,
277 ) -> Fallible<TextureFormat> {
278 let texture_format: TextureFormat = (*format).convert();
279 if self
280 .features
281 .wgpu_features()
282 .contains(texture_format.required_features())
283 {
284 Ok(texture_format)
285 } else {
286 Err(Error::Type(cformat!(
287 "{texture_format:?} is not supported by this GPUDevice"
288 )))
289 }
290 }
291
292 pub(crate) fn get_pipeline_layout_data(
293 &self,
294 layout: &GPUPipelineLayoutOrGPUAutoLayoutMode<D>,
295 ) -> PipelineLayout {
296 if let GPUPipelineLayoutOrGPUAutoLayoutMode::GPUPipelineLayout(layout) = layout {
297 PipelineLayout::Explicit(layout.id().0)
298 } else {
299 PipelineLayout::Implicit
300 }
301 }
302
303 pub(crate) fn parse_render_pipeline<'a>(
304 &self,
305 descriptor: &GPURenderPipelineDescriptor<D>,
306 ) -> Fallible<RenderPipelineDescriptor<'a>> {
307 let pipeline_layout = self.get_pipeline_layout_data(&descriptor.parent.layout);
308 let desc = RenderPipelineDescriptor {
309 label: (&descriptor.parent.parent).convert(),
310 layout: pipeline_layout.explicit(),
311 cache: None,
312 vertex: VertexState {
313 stage: (&descriptor.vertex.parent).convert(),
314 buffers: Cow::Owned(
315 descriptor
316 .vertex
317 .buffers
318 .iter()
319 .map(|buffer| {
322 Some(VertexBufferLayout {
323 array_stride: buffer.arrayStride,
324 step_mode: match buffer.stepMode {
325 GPUVertexStepMode::Vertex => VertexStepMode::Vertex,
326 GPUVertexStepMode::Instance => VertexStepMode::Instance,
327 },
328 attributes: Cow::Owned(
329 buffer
330 .attributes
331 .iter()
332 .map(|att| VertexAttribute {
333 format: att.format.convert(),
334 offset: att.offset,
335 shader_location: att.shaderLocation,
336 })
337 .collect::<Vec<_>>(),
338 ),
339 })
340 })
341 .collect::<Vec<_>>(),
342 ),
343 },
344 fragment: descriptor
345 .fragment
346 .as_ref()
347 .map(|stage| -> Fallible<FragmentState> {
348 Ok(FragmentState {
349 stage: (&stage.parent).convert(),
350 targets: Cow::Owned(
351 stage
352 .targets
353 .iter()
354 .map(|state| {
355 self.validate_texture_format_required_features(&state.format)
356 .map(|format| {
357 Some(ColorTargetState {
358 format,
359 write_mask: ColorWrites::from_bits_retain(
360 state.writeMask,
361 ),
362 blend: state.blend.as_ref().map(|blend| {
363 BlendState {
364 color: (&blend.color).convert(),
365 alpha: (&blend.alpha).convert(),
366 }
367 }),
368 })
369 })
370 })
371 .collect::<Result<Vec<_>, _>>()?,
372 ),
373 })
374 })
375 .transpose()?,
376 primitive: (&descriptor.primitive).convert(),
377 depth_stencil: descriptor
378 .depthStencil
379 .as_ref()
380 .map(|dss_desc| {
381 self.validate_texture_format_required_features(&dss_desc.format)
382 .map(|format| DepthStencilState {
383 format,
384 depth_write_enabled: dss_desc.depthWriteEnabled,
385 depth_compare: dss_desc.depthCompare.map(|dc| dc.convert()),
386 stencil: StencilState {
387 front: StencilFaceState {
388 compare: dss_desc.stencilFront.compare.convert(),
389
390 fail_op: dss_desc.stencilFront.failOp.convert(),
391 depth_fail_op: dss_desc.stencilFront.depthFailOp.convert(),
392 pass_op: dss_desc.stencilFront.passOp.convert(),
393 },
394 back: StencilFaceState {
395 compare: dss_desc.stencilBack.compare.convert(),
396 fail_op: dss_desc.stencilBack.failOp.convert(),
397 depth_fail_op: dss_desc.stencilBack.depthFailOp.convert(),
398 pass_op: dss_desc.stencilBack.passOp.convert(),
399 },
400 read_mask: dss_desc.stencilReadMask,
401 write_mask: dss_desc.stencilWriteMask,
402 },
403 bias: DepthBiasState {
404 constant: dss_desc.depthBias,
405 slope_scale: *dss_desc.depthBiasSlopeScale,
406 clamp: *dss_desc.depthBiasClamp,
407 },
408 })
409 })
410 .transpose()?,
411 multisample: MultisampleState {
412 count: descriptor.multisample.count,
413 mask: descriptor.multisample.mask as u64,
414 alpha_to_coverage_enabled: descriptor.multisample.alphaToCoverageEnabled,
415 },
416 multiview_mask: None,
417 };
418 Ok(desc)
419 }
420}
421
422impl<D> GPUDevice<D>
423where
424 D: Equivalence,
425{
426 pub fn channel(&self) -> WebGPU {
427 self.droppable.channel.clone()
428 }
429
430 pub fn lose(&self, reason: GPUDeviceLostReason, msg: String) {
432 let this = Trusted::new(self);
433
434 let global: DomRoot<D::GlobalScope> = self.global_from_reflector();
437 global.queue_webgpu_task_source(task!(resolve_device_lost: move |cx| {
438 let this = this.root();
439
440 let lost_promise = &(*this.lost_promise.borrow());
441 let lost =
442 GPUDeviceLostInfo::<D>::new(cx, &*this.global_from_reflector(), msg.into(), reason);
443 lost_promise.resolve_native(cx, &*lost);
444 }));
445 }
446
447 pub(crate) fn is_lost(&self) -> bool {
448 self.lost_promise.borrow().is_fulfilled()
449 }
450}
451
452impl<D> GPUDeviceMethods<D> for GPUDevice<D>
453where
454 D: Equivalence,
455 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
456 <D::Promise as PromiseHelpers<D>>::HeapTraced: HeapTracedPromiseHelpers<D>,
457{
458 fn Features(&self) -> DomRoot<GPUSupportedFeatures<D>> {
460 DomRoot::from_ref(&self.features)
461 }
462
463 fn Limits(&self) -> DomRoot<GPUSupportedLimits<D>> {
465 DomRoot::from_ref(&*self.limits)
466 }
467
468 fn AdapterInfo(&self) -> DomRoot<GPUAdapterInfo<D>> {
470 DomRoot::from_ref(&self.adapter_info)
471 }
472
473 fn GetQueue(&self) -> DomRoot<D::GPUQueue> {
475 DomRoot::from_ref(&self.default_queue)
476 }
477
478 fn Label(&self) -> USVString {
480 self.label.borrow().clone()
481 }
482
483 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
485 *self.label.safe_borrow_mut(no_gc) = value;
486 }
487
488 fn Lost(&self, cx: &JSContext) -> <<D as script_bindings::DomTypes>::Promise as script_bindings::interfaces::PromiseHelpers<D>>::StackRoot{
490 self.lost_promise.borrow().root(cx)
491 }
492
493 fn CreateBuffer(
495 &self,
496 cx: &mut JSContext,
497 descriptor: &GPUBufferDescriptor,
498 ) -> Fallible<DomRoot<GPUBuffer<D>>> {
499 GPUBuffer::create(cx, self, descriptor)
500 }
501
502 fn CreateBindGroupLayout(
504 &self,
505 cx: &mut JSContext,
506 descriptor: &GPUBindGroupLayoutDescriptor,
507 ) -> Fallible<DomRoot<GPUBindGroupLayout<D>>> {
508 GPUBindGroupLayout::create(cx, self, descriptor)
509 }
510
511 fn CreatePipelineLayout(
513 &self,
514 cx: &mut JSContext,
515 descriptor: &GPUPipelineLayoutDescriptor<D>,
516 ) -> DomRoot<GPUPipelineLayout<D>> {
517 GPUPipelineLayout::create(cx, self, descriptor)
518 }
519
520 fn CreateBindGroup(
522 &self,
523 cx: &mut JSContext,
524 descriptor: &GPUBindGroupDescriptor<D>,
525 ) -> DomRoot<GPUBindGroup<D>> {
526 GPUBindGroup::create(cx, self, descriptor)
527 }
528
529 fn CreateShaderModule(
531 &self,
532 cx: &mut CurrentRealm<'_>,
533 descriptor: &GPUShaderModuleDescriptor,
534 ) -> DomRoot<GPUShaderModule<D>> {
535 GPUShaderModule::create(cx, self, descriptor)
536 }
537
538 fn CreateComputePipeline(
540 &self,
541 cx: &mut JSContext,
542 descriptor: &GPUComputePipelineDescriptor<D>,
543 ) -> DomRoot<GPUComputePipeline<D>> {
544 let compute_pipeline = GPUComputePipeline::create(self, descriptor, None);
545 GPUComputePipeline::new(
546 cx,
547 &*self.global_from_reflector(),
548 compute_pipeline,
549 descriptor.parent.parent.label.clone(),
550 self,
551 )
552 }
553
554 fn CreateComputePipelineAsync(
556 &self,
557 cx: &mut CurrentRealm<'_>,
558 descriptor: &GPUComputePipelineDescriptor<D>,
559 ) -> <<D as script_bindings::DomTypes>::Promise as script_bindings::interfaces::PromiseHelpers<D>>::StackRoot{
560 let promise = D::Promise::new_in_realm(cx);
561 let callback =
562 <D::Promise as PromiseHelpers<D>>::StackRoot::callback_promise_dom_manipulation_task_source(&promise, self);
563 GPUComputePipeline::create(self, descriptor, Some(callback));
564 promise
565 }
566
567 fn CreateCommandEncoder(
569 &self,
570 cx: &mut JSContext,
571 descriptor: &GPUCommandEncoderDescriptor,
572 ) -> DomRoot<GPUCommandEncoder<D>> {
573 GPUCommandEncoder::create(cx, self, descriptor)
574 }
575
576 fn CreateTexture(
578 &self,
579 cx: &mut JSContext,
580 descriptor: &GPUTextureDescriptor,
581 ) -> Fallible<DomRoot<GPUTexture<D>>> {
582 GPUTexture::create(cx, self, descriptor)
583 }
584
585 fn CreateSampler(
587 &self,
588 cx: &mut JSContext,
589 descriptor: &GPUSamplerDescriptor,
590 ) -> DomRoot<GPUSampler<D>> {
591 GPUSampler::create(cx, self, descriptor)
592 }
593
594 fn CreateRenderPipeline(
596 &self,
597 cx: &mut JSContext,
598 descriptor: &GPURenderPipelineDescriptor<D>,
599 ) -> Fallible<DomRoot<GPURenderPipeline<D>>> {
600 let desc = self.parse_render_pipeline(descriptor)?;
601 let render_pipeline = GPURenderPipeline::create(self, desc, None)?;
602 Ok(GPURenderPipeline::new(
603 cx,
604 &*self.global_from_reflector(),
605 render_pipeline,
606 descriptor.parent.parent.label.clone(),
607 self,
608 ))
609 }
610
611 fn CreateRenderPipelineAsync(
613 &self,
614 cx: &mut CurrentRealm<'_>,
615 descriptor: &GPURenderPipelineDescriptor<D>,
616 ) -> Fallible<<<D as script_bindings::DomTypes>::Promise as script_bindings::interfaces::PromiseHelpers<D>>::StackRoot>{
617 let desc = self.parse_render_pipeline(descriptor)?;
618 let promise = D::Promise::new_in_realm(cx);
619 let callback = <D::Promise as PromiseHelpers<D>>::StackRoot::callback_promise_dom_manipulation_task_source(
620 &promise, self,
621 );
622 GPURenderPipeline::create(self, desc, Some(callback))?;
623 Ok(promise)
624 }
625
626 fn CreateRenderBundleEncoder(
628 &self,
629 cx: &mut JSContext,
630 descriptor: &GPURenderBundleEncoderDescriptor,
631 ) -> Fallible<DomRoot<GPURenderBundleEncoder<D>>> {
632 GPURenderBundleEncoder::create(cx, self, descriptor)
633 }
634
635 fn CreateQuerySet(
637 &self,
638 cx: &mut JSContext,
639 descriptor: &GPUQuerySetDescriptor,
640 ) -> Fallible<DomRoot<GPUQuerySet<D>>> {
641 GPUQuerySet::create(cx, self, descriptor)
642 }
643
644 fn ImportExternalTexture(
646 &self,
647 cx: &mut JSContext,
648 descriptor: &GPUExternalTextureDescriptor<D>,
649 ) -> Fallible<DomRoot<GPUExternalTexture<D>>> {
650 GPUExternalTexture::create(cx, self, descriptor)
651 }
652
653 fn PushErrorScope(&self, filter: GPUErrorFilter) {
655 if self
656 .droppable
657 .channel
658 .0
659 .send(WebGPURequest::PushErrorScope {
660 device_id: self.id().0,
661 filter: filter.as_webgpu(),
662 })
663 .is_err()
664 {
665 warn!("Failed sending WebGPURequest::PushErrorScope");
666 }
667 }
668
669 fn PopErrorScope(&self, cx: &mut CurrentRealm<'_>) -> <<D as script_bindings::DomTypes>::Promise as script_bindings::interfaces::PromiseHelpers<D>>::StackRoot{
671 let promise = D::Promise::new_in_realm(cx);
672 let callback = <D::Promise as PromiseHelpers<D>>::StackRoot::callback_promise_dom_manipulation_task_source(
673 &promise, self,
674 );
675 if self
676 .droppable
677 .channel
678 .0
679 .send(WebGPURequest::PopErrorScope {
680 device_id: self.id().0,
681 callback,
682 })
683 .is_err()
684 {
685 warn!("Error when sending WebGPURequest::PopErrorScope");
686 }
687 promise
688 }
689
690 event_handler!(uncapturederror, GetOnuncapturederror, SetOnuncapturederror);
692
693 fn Destroy(&self) {
695 if self.valid.get() {
696 self.valid.set(false);
697
698 if let Err(e) = self
699 .droppable
700 .channel
701 .0
702 .send(WebGPURequest::DestroyDevice(self.id().0))
703 {
704 warn!("Failed to send DestroyDevice ({:?}) ({})", self.id().0, e);
705 }
706 }
707 }
708}
709
710impl<D: Equivalence> RoutedPromiseListener<D, WebGPUPoppedErrorScopeResponse> for GPUDevice<D>
711where
712 Self: DomGlobalGeneric<D>,
713 D::GPUError: Castable,
714 D::GPUValidationError: DerivedFrom<GPUError<D>>,
715 D::GPUOutOfMemoryError: DerivedFrom<GPUError<D>>,
716 D::GPUInternalError: DerivedFrom<GPUError<D>>,
717 D::DOMException: DomExceptionTrait,
718{
719 fn handle_response(
720 &self,
721 cx: &mut js::context::JSContext,
722 response: WebGPUPoppedErrorScopeResponse,
723 promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
724 ) {
725 match response {
726 Ok(None) | Err(PopError::Lost) => {
727 promise.resolve_native(cx, &None::<Option<GPUError<D>>>)
728 },
729 Err(PopError::Empty) => promise.reject_error(
730 cx,
731 Error::Operation(Some("Error scope stack is empty".into())),
732 ),
733 Ok(Some(error)) => {
734 let error = GPUError::<D>::from_error(cx, &self.global_from_reflector(), error);
735 promise.resolve_native(cx, &error);
736 },
737 }
738 }
739}
740
741impl<D: Equivalence> RoutedPromiseListener<D, WebGPUComputePipelineResponse> for GPUDevice<D>
742where
743 Self: DomGlobalGeneric<D>,
744 D::GPUError: Castable,
745 D::GPUValidationError: DerivedFrom<GPUError<D>>,
746 D::GPUOutOfMemoryError: DerivedFrom<GPUError<D>>,
747 D::GPUInternalError: DerivedFrom<GPUError<D>>,
748 D::DOMException: DomExceptionTrait,
749{
750 fn handle_response(
751 &self,
752 cx: &mut js::context::JSContext,
753 response: WebGPUComputePipelineResponse,
754 promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
755 ) {
756 match response {
757 Ok(pipeline) => {
758 let gpu_compute_pipeline = GPUComputePipeline::<D>::new(
759 cx,
760 &self.global_from_reflector(),
761 WebGPUComputePipeline(pipeline.id),
762 pipeline.label.into(),
763 self,
764 );
765 promise.resolve_native(cx, &gpu_compute_pipeline)
766 },
767 Err(webgpu_traits::Error::Validation(msg)) => {
768 let gpu_pipeline_error = GPUPipelineError::<D>::new(
769 cx,
770 &self.global_from_reflector(),
771 msg.into(),
772 GPUPipelineErrorReason::Validation,
773 );
774 promise.reject_native(cx, &gpu_pipeline_error)
775 },
776 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
777 let gpu_pipeline_error = GPUPipelineError::<D>::new(
778 cx,
779 &self.global_from_reflector(),
780 msg.into(),
781 GPUPipelineErrorReason::Internal,
782 );
783 promise.reject_native(cx, &gpu_pipeline_error)
784 },
785 }
786 }
787}
788
789impl<D: Equivalence> RoutedPromiseListener<D, WebGPURenderPipelineResponse> for GPUDevice<D>
790where
791 Self: DomGlobalGeneric<D>,
792 D::GPUError: Castable,
793 D::GPUValidationError: DerivedFrom<GPUError<D>>,
794 D::GPUOutOfMemoryError: DerivedFrom<GPUError<D>>,
795 D::GPUInternalError: DerivedFrom<GPUError<D>>,
796 D::DOMException: DomExceptionTrait,
797{
798 fn handle_response(
799 &self,
800 cx: &mut js::context::JSContext,
801 response: WebGPURenderPipelineResponse,
802 promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
803 ) {
804 match response {
805 Ok(pipeline) => {
806 let gpu_pipeline = GPURenderPipeline::<D>::new(
807 cx,
808 &self.global_from_reflector(),
809 WebGPURenderPipeline(pipeline.id),
810 pipeline.label.into(),
811 self,
812 );
813 promise.resolve_native(cx, &gpu_pipeline)
814 },
815 Err(webgpu_traits::Error::Validation(msg)) => {
816 let pipeline_error = GPUPipelineError::<D>::new(
817 cx,
818 &self.global_from_reflector(),
819 msg.into(),
820 GPUPipelineErrorReason::Validation,
821 );
822
823 promise.reject_native(cx, &pipeline_error)
824 },
825 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
826 let pipeline_error = GPUPipelineError::<D>::new(
827 cx,
828 &self.global_from_reflector(),
829 msg.into(),
830 GPUPipelineErrorReason::Internal,
831 );
832 promise.reject_native(cx, &pipeline_error)
833 },
834 }
835 }
836}