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