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