1use std::borrow::Cow;
6use std::cell::Cell;
7use std::rc::Rc;
8
9use dom_struct::dom_struct;
10use js::jsapi::{HandleObject, Heap, JSObject};
11use script_bindings::cformat;
12use webgpu_traits::{
13 PopError, WebGPU, WebGPUComputePipeline, WebGPUComputePipelineResponse, WebGPUDevice,
14 WebGPUPoppedErrorScopeResponse, WebGPUQueue, WebGPURenderPipeline,
15 WebGPURenderPipelineResponse, WebGPURequest,
16};
17use wgpu_core::id::{BindGroupLayoutId, PipelineLayoutId};
18use wgpu_core::pipeline as wgpu_pipe;
19use wgpu_core::pipeline::RenderPipelineDescriptor;
20use wgpu_types::{self, TextureFormat};
21
22use super::gpudevicelostinfo::GPUDeviceLostInfo;
23use super::gpuerror::AsWebGpu;
24use super::gpupipelineerror::GPUPipelineError;
25use super::gpusupportedlimits::GPUSupportedLimits;
26use crate::conversions::Convert;
27use crate::dom::bindings::cell::DomRefCell;
28use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit;
29use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
30 GPUAdapterMethods, GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBufferDescriptor,
31 GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason,
32 GPUDeviceMethods, GPUErrorFilter, GPUPipelineErrorReason, GPUPipelineLayoutDescriptor,
33 GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerDescriptor,
34 GPUShaderModuleDescriptor, GPUSupportedLimitsMethods, GPUTextureDescriptor, GPUTextureFormat,
35 GPUUncapturedErrorEventInit, GPUVertexStepMode,
36};
37use crate::dom::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
38use crate::dom::bindings::error::{Error, Fallible};
39use crate::dom::bindings::inheritance::Castable;
40use crate::dom::bindings::refcounted::Trusted;
41use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
42use crate::dom::bindings::root::{Dom, DomRoot};
43use crate::dom::bindings::str::USVString;
44use crate::dom::bindings::trace::RootedTraceableBox;
45use crate::dom::event::Event;
46use crate::dom::eventtarget::EventTarget;
47use crate::dom::globalscope::GlobalScope;
48use crate::dom::promise::Promise;
49use crate::dom::types::GPUError;
50use crate::dom::webgpu::gpuadapter::GPUAdapter;
51use crate::dom::webgpu::gpuadapterinfo::GPUAdapterInfo;
52use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
53use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
54use crate::dom::webgpu::gpubuffer::GPUBuffer;
55use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
56use crate::dom::webgpu::gpucomputepipeline::GPUComputePipeline;
57use crate::dom::webgpu::gpupipelinelayout::GPUPipelineLayout;
58use crate::dom::webgpu::gpuqueue::GPUQueue;
59use crate::dom::webgpu::gpurenderbundleencoder::GPURenderBundleEncoder;
60use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
61use crate::dom::webgpu::gpusampler::GPUSampler;
62use crate::dom::webgpu::gpushadermodule::GPUShaderModule;
63use crate::dom::webgpu::gpusupportedfeatures::GPUSupportedFeatures;
64use crate::dom::webgpu::gputexture::GPUTexture;
65use crate::dom::webgpu::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
66use crate::realms::InRealm;
67use crate::routed_promise::{RoutedPromiseListener, callback_promise};
68use crate::script_runtime::CanGc;
69
70#[derive(JSTraceable, MallocSizeOf)]
71struct DroppableGPUDevice {
72 #[no_trace]
73 channel: WebGPU,
74 #[no_trace]
75 device: WebGPUDevice,
76}
77
78impl Drop for DroppableGPUDevice {
79 fn drop(&mut self) {
80 if let Err(e) = self
81 .channel
82 .0
83 .send(WebGPURequest::DropDevice(self.device.0))
84 {
85 warn!("Failed to send DropDevice ({:?}) ({})", self.device.0, e);
86 }
87 }
88}
89
90#[dom_struct]
91pub(crate) struct GPUDevice {
92 eventtarget: EventTarget,
93 adapter: Dom<GPUAdapter>,
94 #[ignore_malloc_size_of = "mozjs"]
95 extensions: Heap<*mut JSObject>,
96 features: Dom<GPUSupportedFeatures>,
97 limits: Dom<GPUSupportedLimits>,
98 adapter_info: Dom<GPUAdapterInfo>,
99 label: DomRefCell<USVString>,
100 default_queue: Dom<GPUQueue>,
101 #[conditional_malloc_size_of]
103 lost_promise: DomRefCell<Rc<Promise>>,
104 valid: Cell<bool>,
105 droppable: DroppableGPUDevice,
106}
107
108pub(crate) enum PipelineLayout {
109 Implicit(PipelineLayoutId, Vec<BindGroupLayoutId>),
110 Explicit(PipelineLayoutId),
111}
112
113impl PipelineLayout {
114 pub(crate) fn explicit(&self) -> Option<PipelineLayoutId> {
115 match self {
116 PipelineLayout::Explicit(layout_id) => Some(*layout_id),
117 _ => None,
118 }
119 }
120
121 pub(crate) fn implicit(self) -> Option<(PipelineLayoutId, Vec<BindGroupLayoutId>)> {
122 match self {
123 PipelineLayout::Implicit(layout_id, bind_group_layout_ids) => {
124 Some((layout_id, bind_group_layout_ids))
125 },
126 _ => None,
127 }
128 }
129}
130
131impl GPUDevice {
132 #[allow(clippy::too_many_arguments)]
133 fn new_inherited(
134 channel: WebGPU,
135 adapter: &GPUAdapter,
136 features: &GPUSupportedFeatures,
137 limits: &GPUSupportedLimits,
138 adapter_info: &GPUAdapterInfo,
139 device: WebGPUDevice,
140 queue: &GPUQueue,
141 label: String,
142 lost_promise: Rc<Promise>,
143 ) -> Self {
144 Self {
145 eventtarget: EventTarget::new_inherited(),
146 adapter: Dom::from_ref(adapter),
147 extensions: Heap::default(),
148 features: Dom::from_ref(features),
149 limits: Dom::from_ref(limits),
150 adapter_info: Dom::from_ref(adapter_info),
151 label: DomRefCell::new(USVString::from(label)),
152 default_queue: Dom::from_ref(queue),
153 lost_promise: DomRefCell::new(lost_promise),
154 valid: Cell::new(true),
155 droppable: DroppableGPUDevice { channel, device },
156 }
157 }
158
159 #[allow(clippy::too_many_arguments)]
160 pub(crate) fn new(
161 global: &GlobalScope,
162 channel: WebGPU,
163 adapter: &GPUAdapter,
164 extensions: HandleObject,
165 features: wgpu_types::Features,
166 limits: wgpu_types::Limits,
167 device: WebGPUDevice,
168 queue: WebGPUQueue,
169 label: String,
170 can_gc: CanGc,
171 ) -> DomRoot<Self> {
172 let queue = GPUQueue::new(global, channel.clone(), queue, can_gc);
173 let limits = GPUSupportedLimits::new(global, limits, can_gc);
174 let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap();
175 let adapter_info = GPUAdapterInfo::clone_from(global, &adapter.Info(), can_gc);
176 let lost_promise = Promise::new(global, can_gc);
177 let device = reflect_dom_object(
178 Box::new(GPUDevice::new_inherited(
179 channel,
180 adapter,
181 &features,
182 &limits,
183 &adapter_info,
184 device,
185 &queue,
186 label,
187 lost_promise,
188 )),
189 global,
190 can_gc,
191 );
192 queue.set_device(&device);
193 device.extensions.set(*extensions);
194 device
195 }
196}
197
198impl GPUDevice {
199 pub(crate) fn id(&self) -> WebGPUDevice {
200 self.droppable.device
201 }
202
203 pub(crate) fn queue_id(&self) -> WebGPUQueue {
204 self.default_queue.id()
205 }
206
207 pub(crate) fn channel(&self) -> WebGPU {
208 self.droppable.channel.clone()
209 }
210
211 pub(crate) fn dispatch_error(&self, error: webgpu_traits::Error) {
212 if let Err(e) = self.droppable.channel.0.send(WebGPURequest::DispatchError {
213 device_id: self.id().0,
214 error,
215 }) {
216 warn!("Failed to send WebGPURequest::DispatchError due to {e:?}");
217 }
218 }
219
220 pub(crate) fn fire_uncaptured_error(&self, error: webgpu_traits::Error) {
222 let this = Trusted::new(self);
223
224 self.global().task_manager().webgpu_task_source().queue(
227 task!(fire_uncaptured_error: move || {
228 let this = this.root();
229 let error = GPUError::from_error(&this.global(), error, CanGc::note());
230
231 let event = GPUUncapturedErrorEvent::new(
232 &this.global(),
233 atom!("uncapturederror"),
234 &GPUUncapturedErrorEventInit {
235 error,
236 parent: EventInit::empty(),
237 },
238 CanGc::note(),
239 );
240
241 event.upcast::<Event>().fire(this.upcast(), CanGc::note());
242 }),
243 );
244 }
245
246 pub(crate) fn validate_texture_format_required_features(
251 &self,
252 format: &GPUTextureFormat,
253 ) -> Fallible<TextureFormat> {
254 let texture_format: TextureFormat = (*format).convert();
255 if self
256 .features
257 .wgpu_features()
258 .contains(texture_format.required_features())
259 {
260 Ok(texture_format)
261 } else {
262 Err(Error::Type(cformat!(
263 "{texture_format:?} is not supported by this GPUDevice"
264 )))
265 }
266 }
267
268 pub(crate) fn is_lost(&self) -> bool {
269 self.lost_promise.borrow().is_fulfilled()
270 }
271
272 pub(crate) fn get_pipeline_layout_data(
273 &self,
274 layout: &GPUPipelineLayoutOrGPUAutoLayoutMode,
275 ) -> PipelineLayout {
276 if let GPUPipelineLayoutOrGPUAutoLayoutMode::GPUPipelineLayout(layout) = layout {
277 PipelineLayout::Explicit(layout.id().0)
278 } else {
279 let layout_id = self.global().wgpu_id_hub().create_pipeline_layout_id();
280 let max_bind_grps = self.limits.MaxBindGroups();
281 let mut bgl_ids = Vec::with_capacity(max_bind_grps as usize);
282 for _ in 0..max_bind_grps {
283 let bgl = self.global().wgpu_id_hub().create_bind_group_layout_id();
284 bgl_ids.push(bgl);
285 }
286 PipelineLayout::Implicit(layout_id, bgl_ids)
287 }
288 }
289
290 pub(crate) fn parse_render_pipeline<'a>(
291 &self,
292 descriptor: &GPURenderPipelineDescriptor,
293 ) -> Fallible<(PipelineLayout, RenderPipelineDescriptor<'a>)> {
294 let pipeline_layout = self.get_pipeline_layout_data(&descriptor.parent.layout);
295
296 let desc = wgpu_pipe::RenderPipelineDescriptor {
297 label: (&descriptor.parent.parent).convert(),
298 layout: pipeline_layout.explicit(),
299 cache: None,
300 vertex: wgpu_pipe::VertexState {
301 stage: (&descriptor.vertex.parent).convert(),
302 buffers: Cow::Owned(
303 descriptor
304 .vertex
305 .buffers
306 .iter()
307 .map(|buffer| wgpu_pipe::VertexBufferLayout {
308 array_stride: buffer.arrayStride,
309 step_mode: match buffer.stepMode {
310 GPUVertexStepMode::Vertex => wgpu_types::VertexStepMode::Vertex,
311 GPUVertexStepMode::Instance => wgpu_types::VertexStepMode::Instance,
312 },
313 attributes: Cow::Owned(
314 buffer
315 .attributes
316 .iter()
317 .map(|att| wgpu_types::VertexAttribute {
318 format: att.format.convert(),
319 offset: att.offset,
320 shader_location: att.shaderLocation,
321 })
322 .collect::<Vec<_>>(),
323 ),
324 })
325 .collect::<Vec<_>>(),
326 ),
327 },
328 fragment: descriptor
329 .fragment
330 .as_ref()
331 .map(|stage| -> Fallible<wgpu_pipe::FragmentState> {
332 Ok(wgpu_pipe::FragmentState {
333 stage: (&stage.parent).convert(),
334 targets: Cow::Owned(
335 stage
336 .targets
337 .iter()
338 .map(|state| {
339 self.validate_texture_format_required_features(&state.format)
340 .map(|format| {
341 Some(wgpu_types::ColorTargetState {
342 format,
343 write_mask:
344 wgpu_types::ColorWrites::from_bits_retain(
345 state.writeMask,
346 ),
347 blend: state.blend.as_ref().map(|blend| {
348 wgpu_types::BlendState {
349 color: (&blend.color).convert(),
350 alpha: (&blend.alpha).convert(),
351 }
352 }),
353 })
354 })
355 })
356 .collect::<Result<Vec<_>, _>>()?,
357 ),
358 })
359 })
360 .transpose()?,
361 primitive: (&descriptor.primitive).convert(),
362 depth_stencil: descriptor
363 .depthStencil
364 .as_ref()
365 .map(|dss_desc| {
366 self.validate_texture_format_required_features(&dss_desc.format)
367 .map(|format| wgpu_types::DepthStencilState {
368 format,
369 depth_write_enabled: dss_desc.depthWriteEnabled,
370 depth_compare: dss_desc.depthCompare.convert(),
371 stencil: wgpu_types::StencilState {
372 front: wgpu_types::StencilFaceState {
373 compare: dss_desc.stencilFront.compare.convert(),
374
375 fail_op: dss_desc.stencilFront.failOp.convert(),
376 depth_fail_op: dss_desc.stencilFront.depthFailOp.convert(),
377 pass_op: dss_desc.stencilFront.passOp.convert(),
378 },
379 back: wgpu_types::StencilFaceState {
380 compare: dss_desc.stencilBack.compare.convert(),
381 fail_op: dss_desc.stencilBack.failOp.convert(),
382 depth_fail_op: dss_desc.stencilBack.depthFailOp.convert(),
383 pass_op: dss_desc.stencilBack.passOp.convert(),
384 },
385 read_mask: dss_desc.stencilReadMask,
386 write_mask: dss_desc.stencilWriteMask,
387 },
388 bias: wgpu_types::DepthBiasState {
389 constant: dss_desc.depthBias,
390 slope_scale: *dss_desc.depthBiasSlopeScale,
391 clamp: *dss_desc.depthBiasClamp,
392 },
393 })
394 })
395 .transpose()?,
396 multisample: wgpu_types::MultisampleState {
397 count: descriptor.multisample.count,
398 mask: descriptor.multisample.mask as u64,
399 alpha_to_coverage_enabled: descriptor.multisample.alphaToCoverageEnabled,
400 },
401 multiview: None,
402 };
403 Ok((pipeline_layout, desc))
404 }
405
406 pub(crate) fn lose(&self, reason: GPUDeviceLostReason, msg: String) {
408 let this = Trusted::new(self);
409
410 self.global().task_manager().webgpu_task_source().queue(
413 task!(resolve_device_lost: move || {
414 let this = this.root();
415
416 let lost_promise = &(*this.lost_promise.borrow());
417 let lost = GPUDeviceLostInfo::new(&this.global(), msg.into(), reason, CanGc::note());
418 lost_promise.resolve_native(&*lost, CanGc::note());
419 }),
420 );
421 }
422}
423
424impl GPUDeviceMethods<crate::DomTypeHolder> for GPUDevice {
425 fn Features(&self) -> DomRoot<GPUSupportedFeatures> {
427 DomRoot::from_ref(&self.features)
428 }
429
430 fn Limits(&self) -> DomRoot<GPUSupportedLimits> {
432 DomRoot::from_ref(&self.limits)
433 }
434
435 fn AdapterInfo(&self) -> DomRoot<GPUAdapterInfo> {
437 DomRoot::from_ref(&self.adapter_info)
438 }
439
440 fn GetQueue(&self) -> DomRoot<GPUQueue> {
442 DomRoot::from_ref(&self.default_queue)
443 }
444
445 fn Label(&self) -> USVString {
447 self.label.borrow().clone()
448 }
449
450 fn SetLabel(&self, value: USVString) {
452 *self.label.borrow_mut() = value;
453 }
454
455 fn Lost(&self) -> Rc<Promise> {
457 self.lost_promise.borrow().clone()
458 }
459
460 fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> Fallible<DomRoot<GPUBuffer>> {
462 GPUBuffer::create(self, descriptor, CanGc::note())
463 }
464
465 fn CreateBindGroupLayout(
467 &self,
468 descriptor: &GPUBindGroupLayoutDescriptor,
469 ) -> Fallible<DomRoot<GPUBindGroupLayout>> {
470 GPUBindGroupLayout::create(self, descriptor, CanGc::note())
471 }
472
473 fn CreatePipelineLayout(
475 &self,
476 descriptor: &GPUPipelineLayoutDescriptor,
477 ) -> DomRoot<GPUPipelineLayout> {
478 GPUPipelineLayout::create(self, descriptor, CanGc::note())
479 }
480
481 fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
483 GPUBindGroup::create(self, descriptor, CanGc::note())
484 }
485
486 fn CreateShaderModule(
488 &self,
489 descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
490 comp: InRealm,
491 can_gc: CanGc,
492 ) -> DomRoot<GPUShaderModule> {
493 GPUShaderModule::create(self, descriptor, comp, can_gc)
494 }
495
496 fn CreateComputePipeline(
498 &self,
499 descriptor: &GPUComputePipelineDescriptor,
500 ) -> DomRoot<GPUComputePipeline> {
501 let compute_pipeline = GPUComputePipeline::create(self, descriptor, None);
502 GPUComputePipeline::new(
503 &self.global(),
504 compute_pipeline,
505 descriptor.parent.parent.label.clone(),
506 self,
507 CanGc::note(),
508 )
509 }
510
511 fn CreateComputePipelineAsync(
513 &self,
514 descriptor: &GPUComputePipelineDescriptor,
515 comp: InRealm,
516 can_gc: CanGc,
517 ) -> Rc<Promise> {
518 let promise = Promise::new_in_current_realm(comp, can_gc);
519 let callback = callback_promise(
520 &promise,
521 self,
522 self.global().task_manager().dom_manipulation_task_source(),
523 );
524 GPUComputePipeline::create(self, descriptor, Some(callback));
525 promise
526 }
527
528 fn CreateCommandEncoder(
530 &self,
531 descriptor: &GPUCommandEncoderDescriptor,
532 ) -> DomRoot<GPUCommandEncoder> {
533 GPUCommandEncoder::create(self, descriptor, CanGc::note())
534 }
535
536 fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> Fallible<DomRoot<GPUTexture>> {
538 GPUTexture::create(self, descriptor, CanGc::note())
539 }
540
541 fn CreateSampler(&self, descriptor: &GPUSamplerDescriptor) -> DomRoot<GPUSampler> {
543 GPUSampler::create(self, descriptor, CanGc::note())
544 }
545
546 fn CreateRenderPipeline(
548 &self,
549 descriptor: &GPURenderPipelineDescriptor,
550 ) -> Fallible<DomRoot<GPURenderPipeline>> {
551 let (pipeline_layout, desc) = self.parse_render_pipeline(descriptor)?;
552 let render_pipeline = GPURenderPipeline::create(self, pipeline_layout, desc, None)?;
553 Ok(GPURenderPipeline::new(
554 &self.global(),
555 render_pipeline,
556 descriptor.parent.parent.label.clone(),
557 self,
558 CanGc::note(),
559 ))
560 }
561
562 fn CreateRenderPipelineAsync(
564 &self,
565 descriptor: &GPURenderPipelineDescriptor,
566 comp: InRealm,
567 can_gc: CanGc,
568 ) -> Fallible<Rc<Promise>> {
569 let (implicit_ids, desc) = self.parse_render_pipeline(descriptor)?;
570 let promise = Promise::new_in_current_realm(comp, can_gc);
571 let callback = callback_promise(
572 &promise,
573 self,
574 self.global().task_manager().dom_manipulation_task_source(),
575 );
576 GPURenderPipeline::create(self, implicit_ids, desc, Some(callback))?;
577 Ok(promise)
578 }
579
580 fn CreateRenderBundleEncoder(
582 &self,
583 descriptor: &GPURenderBundleEncoderDescriptor,
584 ) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
585 GPURenderBundleEncoder::create(self, descriptor, CanGc::note())
586 }
587
588 fn PushErrorScope(&self, filter: GPUErrorFilter) {
590 if self
591 .droppable
592 .channel
593 .0
594 .send(WebGPURequest::PushErrorScope {
595 device_id: self.id().0,
596 filter: filter.as_webgpu(),
597 })
598 .is_err()
599 {
600 warn!("Failed sending WebGPURequest::PushErrorScope");
601 }
602 }
603
604 fn PopErrorScope(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
606 let promise = Promise::new_in_current_realm(comp, can_gc);
607 let callback = callback_promise(
608 &promise,
609 self,
610 self.global().task_manager().dom_manipulation_task_source(),
611 );
612 if self
613 .droppable
614 .channel
615 .0
616 .send(WebGPURequest::PopErrorScope {
617 device_id: self.id().0,
618 callback,
619 })
620 .is_err()
621 {
622 warn!("Error when sending WebGPURequest::PopErrorScope");
623 }
624 promise
625 }
626
627 event_handler!(uncapturederror, GetOnuncapturederror, SetOnuncapturederror);
629
630 fn Destroy(&self) {
632 if self.valid.get() {
633 self.valid.set(false);
634
635 if let Err(e) = self
636 .droppable
637 .channel
638 .0
639 .send(WebGPURequest::DestroyDevice(self.id().0))
640 {
641 warn!("Failed to send DestroyDevice ({:?}) ({})", self.id().0, e);
642 }
643 }
644 }
645}
646
647impl RoutedPromiseListener<WebGPUPoppedErrorScopeResponse> for GPUDevice {
648 fn handle_response(
649 &self,
650 response: WebGPUPoppedErrorScopeResponse,
651 promise: &Rc<Promise>,
652 can_gc: CanGc,
653 ) {
654 match response {
655 Ok(None) | Err(PopError::Lost) => {
656 promise.resolve_native(&None::<Option<GPUError>>, can_gc)
657 },
658 Err(PopError::Empty) => promise.reject_error(Error::Operation(None), can_gc),
659 Ok(Some(error)) => {
660 let error = GPUError::from_error(&self.global(), error, can_gc);
661 promise.resolve_native(&error, can_gc);
662 },
663 }
664 }
665}
666
667impl RoutedPromiseListener<WebGPUComputePipelineResponse> for GPUDevice {
668 fn handle_response(
669 &self,
670 response: WebGPUComputePipelineResponse,
671 promise: &Rc<Promise>,
672 can_gc: CanGc,
673 ) {
674 match response {
675 Ok(pipeline) => promise.resolve_native(
676 &GPUComputePipeline::new(
677 &self.global(),
678 WebGPUComputePipeline(pipeline.id),
679 pipeline.label.into(),
680 self,
681 can_gc,
682 ),
683 can_gc,
684 ),
685 Err(webgpu_traits::Error::Validation(msg)) => promise.reject_native(
686 &GPUPipelineError::new(
687 &self.global(),
688 msg.into(),
689 GPUPipelineErrorReason::Validation,
690 can_gc,
691 ),
692 can_gc,
693 ),
694 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
695 promise.reject_native(
696 &GPUPipelineError::new(
697 &self.global(),
698 msg.into(),
699 GPUPipelineErrorReason::Internal,
700 can_gc,
701 ),
702 can_gc,
703 )
704 },
705 }
706 }
707}
708
709impl RoutedPromiseListener<WebGPURenderPipelineResponse> for GPUDevice {
710 fn handle_response(
711 &self,
712 response: WebGPURenderPipelineResponse,
713 promise: &Rc<Promise>,
714 can_gc: CanGc,
715 ) {
716 match response {
717 Ok(pipeline) => promise.resolve_native(
718 &GPURenderPipeline::new(
719 &self.global(),
720 WebGPURenderPipeline(pipeline.id),
721 pipeline.label.into(),
722 self,
723 can_gc,
724 ),
725 can_gc,
726 ),
727 Err(webgpu_traits::Error::Validation(msg)) => promise.reject_native(
728 &GPUPipelineError::new(
729 &self.global(),
730 msg.into(),
731 GPUPipelineErrorReason::Validation,
732 can_gc,
733 ),
734 can_gc,
735 ),
736 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
737 promise.reject_native(
738 &GPUPipelineError::new(
739 &self.global(),
740 msg.into(),
741 GPUPipelineErrorReason::Internal,
742 can_gc,
743 ),
744 can_gc,
745 )
746 },
747 }
748 }
749}