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_dom_object_with_cx;
16use script_bindings::script_runtime::CanGc;
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 GPUAdapterMethods, 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_dom_object_with_cx(
172 Box::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 cx,
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| wgpu_pipe::VertexBufferLayout {
294 array_stride: buffer.arrayStride,
295 step_mode: match buffer.stepMode {
296 GPUVertexStepMode::Vertex => wgpu_types::VertexStepMode::Vertex,
297 GPUVertexStepMode::Instance => wgpu_types::VertexStepMode::Instance,
298 },
299 attributes: Cow::Owned(
300 buffer
301 .attributes
302 .iter()
303 .map(|att| wgpu_types::VertexAttribute {
304 format: att.format.convert(),
305 offset: att.offset,
306 shader_location: att.shaderLocation,
307 })
308 .collect::<Vec<_>>(),
309 ),
310 })
311 .collect::<Vec<_>>(),
312 ),
313 },
314 fragment: descriptor
315 .fragment
316 .as_ref()
317 .map(|stage| -> Fallible<wgpu_pipe::FragmentState> {
318 Ok(wgpu_pipe::FragmentState {
319 stage: (&stage.parent).convert(),
320 targets: Cow::Owned(
321 stage
322 .targets
323 .iter()
324 .map(|state| {
325 self.validate_texture_format_required_features(&state.format)
326 .map(|format| {
327 Some(wgpu_types::ColorTargetState {
328 format,
329 write_mask:
330 wgpu_types::ColorWrites::from_bits_retain(
331 state.writeMask,
332 ),
333 blend: state.blend.as_ref().map(|blend| {
334 wgpu_types::BlendState {
335 color: (&blend.color).convert(),
336 alpha: (&blend.alpha).convert(),
337 }
338 }),
339 })
340 })
341 })
342 .collect::<Result<Vec<_>, _>>()?,
343 ),
344 })
345 })
346 .transpose()?,
347 primitive: (&descriptor.primitive).convert(),
348 depth_stencil: descriptor
349 .depthStencil
350 .as_ref()
351 .map(|dss_desc| {
352 self.validate_texture_format_required_features(&dss_desc.format)
353 .map(|format| wgpu_types::DepthStencilState {
354 format,
355 depth_write_enabled: dss_desc.depthWriteEnabled,
356 depth_compare: dss_desc.depthCompare.map(|dc| dc.convert()),
357 stencil: wgpu_types::StencilState {
358 front: wgpu_types::StencilFaceState {
359 compare: dss_desc.stencilFront.compare.convert(),
360
361 fail_op: dss_desc.stencilFront.failOp.convert(),
362 depth_fail_op: dss_desc.stencilFront.depthFailOp.convert(),
363 pass_op: dss_desc.stencilFront.passOp.convert(),
364 },
365 back: wgpu_types::StencilFaceState {
366 compare: dss_desc.stencilBack.compare.convert(),
367 fail_op: dss_desc.stencilBack.failOp.convert(),
368 depth_fail_op: dss_desc.stencilBack.depthFailOp.convert(),
369 pass_op: dss_desc.stencilBack.passOp.convert(),
370 },
371 read_mask: dss_desc.stencilReadMask,
372 write_mask: dss_desc.stencilWriteMask,
373 },
374 bias: wgpu_types::DepthBiasState {
375 constant: dss_desc.depthBias,
376 slope_scale: *dss_desc.depthBiasSlopeScale,
377 clamp: *dss_desc.depthBiasClamp,
378 },
379 })
380 })
381 .transpose()?,
382 multisample: wgpu_types::MultisampleState {
383 count: descriptor.multisample.count,
384 mask: descriptor.multisample.mask as u64,
385 alpha_to_coverage_enabled: descriptor.multisample.alphaToCoverageEnabled,
386 },
387 multiview_mask: None,
388 };
389 Ok(desc)
390 }
391
392 pub(crate) fn lose(&self, reason: GPUDeviceLostReason, msg: String) {
394 let this = Trusted::new(self);
395
396 self.global().task_manager().webgpu_task_source().queue(
399 task!(resolve_device_lost: move |cx| {
400 let this = this.root();
401
402 let lost_promise = &(*this.lost_promise.borrow());
403 let lost = GPUDeviceLostInfo::new(&this.global(), msg.into(), reason, CanGc::deprecated_note());
404 lost_promise.resolve_native(cx, &*lost);
405 }),
406 );
407 }
408}
409
410impl GPUDeviceMethods<crate::DomTypeHolder> for GPUDevice {
411 fn Features(&self) -> DomRoot<GPUSupportedFeatures> {
413 DomRoot::from_ref(&self.features)
414 }
415
416 fn Limits(&self) -> DomRoot<GPUSupportedLimits> {
418 DomRoot::from_ref(&self.limits)
419 }
420
421 fn AdapterInfo(&self) -> DomRoot<GPUAdapterInfo> {
423 DomRoot::from_ref(&self.adapter_info)
424 }
425
426 fn GetQueue(&self) -> DomRoot<GPUQueue> {
428 DomRoot::from_ref(&self.default_queue)
429 }
430
431 fn Label(&self) -> USVString {
433 self.label.borrow().clone()
434 }
435
436 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
438 *self.label.safe_borrow_mut(no_gc) = value;
439 }
440
441 fn Lost(&self) -> Rc<Promise> {
443 self.lost_promise.borrow().clone()
444 }
445
446 fn CreateBuffer(
448 &self,
449 cx: &mut JSContext,
450 descriptor: &GPUBufferDescriptor,
451 ) -> Fallible<DomRoot<GPUBuffer>> {
452 GPUBuffer::create(cx, self, descriptor)
453 }
454
455 fn CreateBindGroupLayout(
457 &self,
458 cx: &mut JSContext,
459 descriptor: &GPUBindGroupLayoutDescriptor,
460 ) -> Fallible<DomRoot<GPUBindGroupLayout>> {
461 GPUBindGroupLayout::create(cx, self, descriptor)
462 }
463
464 fn CreatePipelineLayout(
466 &self,
467 cx: &mut JSContext,
468 descriptor: &GPUPipelineLayoutDescriptor,
469 ) -> DomRoot<GPUPipelineLayout> {
470 GPUPipelineLayout::create(cx, self, descriptor)
471 }
472
473 fn CreateBindGroup(
475 &self,
476 cx: &mut JSContext,
477 descriptor: &GPUBindGroupDescriptor,
478 ) -> DomRoot<GPUBindGroup> {
479 GPUBindGroup::create(cx, self, descriptor)
480 }
481
482 fn CreateShaderModule(
484 &self,
485 cx: &mut CurrentRealm<'_>,
486 descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
487 ) -> DomRoot<GPUShaderModule> {
488 GPUShaderModule::create(cx, self, descriptor)
489 }
490
491 fn CreateComputePipeline(
493 &self,
494 cx: &mut JSContext,
495 descriptor: &GPUComputePipelineDescriptor,
496 ) -> DomRoot<GPUComputePipeline> {
497 let compute_pipeline = GPUComputePipeline::create(self, descriptor, None);
498 GPUComputePipeline::new(
499 cx,
500 &self.global(),
501 compute_pipeline,
502 descriptor.parent.parent.label.clone(),
503 self,
504 )
505 }
506
507 fn CreateComputePipelineAsync(
509 &self,
510 cx: &mut CurrentRealm<'_>,
511 descriptor: &GPUComputePipelineDescriptor,
512 ) -> Rc<Promise> {
513 let promise = Promise::new_in_realm(cx);
514 let callback = callback_promise(
515 &promise,
516 self,
517 self.global().task_manager().dom_manipulation_task_source(),
518 );
519 GPUComputePipeline::create(self, descriptor, Some(callback));
520 promise
521 }
522
523 fn CreateCommandEncoder(
525 &self,
526 cx: &mut JSContext,
527 descriptor: &GPUCommandEncoderDescriptor,
528 ) -> DomRoot<GPUCommandEncoder> {
529 GPUCommandEncoder::create(cx, self, descriptor)
530 }
531
532 fn CreateTexture(
534 &self,
535 cx: &mut JSContext,
536 descriptor: &GPUTextureDescriptor,
537 ) -> Fallible<DomRoot<GPUTexture>> {
538 GPUTexture::create(cx, self, descriptor)
539 }
540
541 fn CreateSampler(
543 &self,
544 cx: &mut JSContext,
545 descriptor: &GPUSamplerDescriptor,
546 ) -> DomRoot<GPUSampler> {
547 GPUSampler::create(cx, self, descriptor)
548 }
549
550 fn CreateRenderPipeline(
552 &self,
553 cx: &mut JSContext,
554 descriptor: &GPURenderPipelineDescriptor,
555 ) -> Fallible<DomRoot<GPURenderPipeline>> {
556 let desc = self.parse_render_pipeline(descriptor)?;
557 let render_pipeline = GPURenderPipeline::create(self, desc, None)?;
558 Ok(GPURenderPipeline::new(
559 cx,
560 &self.global(),
561 render_pipeline,
562 descriptor.parent.parent.label.clone(),
563 self,
564 ))
565 }
566
567 fn CreateRenderPipelineAsync(
569 &self,
570 cx: &mut CurrentRealm<'_>,
571 descriptor: &GPURenderPipelineDescriptor,
572 ) -> Fallible<Rc<Promise>> {
573 let desc = self.parse_render_pipeline(descriptor)?;
574 let promise = Promise::new_in_realm(cx);
575 let callback = callback_promise(
576 &promise,
577 self,
578 self.global().task_manager().dom_manipulation_task_source(),
579 );
580 GPURenderPipeline::create(self, desc, Some(callback))?;
581 Ok(promise)
582 }
583
584 fn CreateRenderBundleEncoder(
586 &self,
587 cx: &mut JSContext,
588 descriptor: &GPURenderBundleEncoderDescriptor,
589 ) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
590 GPURenderBundleEncoder::create(cx, self, descriptor)
591 }
592
593 fn CreateQuerySet(
595 &self,
596 cx: &mut JSContext,
597 descriptor: &GPUQuerySetDescriptor,
598 ) -> Fallible<DomRoot<GPUQuerySet>> {
599 GPUQuerySet::create(cx, self, descriptor)
600 }
601
602 fn ImportExternalTexture(
604 &self,
605 cx: &mut JSContext,
606 descriptor: &GPUExternalTextureDescriptor,
607 ) -> Fallible<DomRoot<GPUExternalTexture>> {
608 GPUExternalTexture::create(cx, self, descriptor)
609 }
610
611 fn PushErrorScope(&self, filter: GPUErrorFilter) {
613 if self
614 .droppable
615 .channel
616 .0
617 .send(WebGPURequest::PushErrorScope {
618 device_id: self.id().0,
619 filter: filter.as_webgpu(),
620 })
621 .is_err()
622 {
623 warn!("Failed sending WebGPURequest::PushErrorScope");
624 }
625 }
626
627 fn PopErrorScope(&self, cx: &mut CurrentRealm<'_>) -> Rc<Promise> {
629 let promise = Promise::new_in_realm(cx);
630 let callback = callback_promise(
631 &promise,
632 self,
633 self.global().task_manager().dom_manipulation_task_source(),
634 );
635 if self
636 .droppable
637 .channel
638 .0
639 .send(WebGPURequest::PopErrorScope {
640 device_id: self.id().0,
641 callback,
642 })
643 .is_err()
644 {
645 warn!("Error when sending WebGPURequest::PopErrorScope");
646 }
647 promise
648 }
649
650 event_handler!(uncapturederror, GetOnuncapturederror, SetOnuncapturederror);
652
653 fn Destroy(&self) {
655 if self.valid.get() {
656 self.valid.set(false);
657
658 if let Err(e) = self
659 .droppable
660 .channel
661 .0
662 .send(WebGPURequest::DestroyDevice(self.id().0))
663 {
664 warn!("Failed to send DestroyDevice ({:?}) ({})", self.id().0, e);
665 }
666 }
667 }
668}
669
670impl RoutedPromiseListener<WebGPUPoppedErrorScopeResponse> for GPUDevice {
671 fn handle_response(
672 &self,
673 cx: &mut js::context::JSContext,
674 response: WebGPUPoppedErrorScopeResponse,
675 promise: &Rc<Promise>,
676 ) {
677 match response {
678 Ok(None) | Err(PopError::Lost) => promise.resolve_native(cx, &None::<Option<GPUError>>),
679 Err(PopError::Empty) => promise.reject_error(cx, Error::Operation(None)),
680 Ok(Some(error)) => {
681 let error = GPUError::from_error(cx, &self.global(), error);
682 promise.resolve_native(cx, &error);
683 },
684 }
685 }
686}
687
688impl RoutedPromiseListener<WebGPUComputePipelineResponse> for GPUDevice {
689 fn handle_response(
690 &self,
691 cx: &mut js::context::JSContext,
692 response: WebGPUComputePipelineResponse,
693 promise: &Rc<Promise>,
694 ) {
695 match response {
696 Ok(pipeline) => {
697 let gpu_compute_pipeline = GPUComputePipeline::new(
698 cx,
699 &self.global(),
700 WebGPUComputePipeline(pipeline.id),
701 pipeline.label.into(),
702 self,
703 );
704 promise.resolve_native(cx, &gpu_compute_pipeline)
705 },
706 Err(webgpu_traits::Error::Validation(msg)) => {
707 let gpu_pipeline_error = GPUPipelineError::new(
708 cx,
709 &self.global(),
710 msg.into(),
711 GPUPipelineErrorReason::Validation,
712 );
713 promise.reject_native(cx, &gpu_pipeline_error)
714 },
715 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
716 let gpu_pipeline_error = GPUPipelineError::new(
717 cx,
718 &self.global(),
719 msg.into(),
720 GPUPipelineErrorReason::Internal,
721 );
722 promise.reject_native(cx, &gpu_pipeline_error)
723 },
724 }
725 }
726}
727
728impl RoutedPromiseListener<WebGPURenderPipelineResponse> for GPUDevice {
729 fn handle_response(
730 &self,
731 cx: &mut js::context::JSContext,
732 response: WebGPURenderPipelineResponse,
733 promise: &Rc<Promise>,
734 ) {
735 match response {
736 Ok(pipeline) => {
737 let gpu_pipeline = GPURenderPipeline::new(
738 cx,
739 &self.global(),
740 WebGPURenderPipeline(pipeline.id),
741 pipeline.label.into(),
742 self,
743 );
744 promise.resolve_native(cx, &gpu_pipeline)
745 },
746 Err(webgpu_traits::Error::Validation(msg)) => {
747 let pipeline_error = GPUPipelineError::new(
748 cx,
749 &self.global(),
750 msg.into(),
751 GPUPipelineErrorReason::Validation,
752 );
753
754 promise.reject_native(cx, &pipeline_error)
755 },
756 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
757 let pipeline_error = GPUPipelineError::new(
758 cx,
759 &self.global(),
760 msg.into(),
761 GPUPipelineErrorReason::Internal,
762 );
763 promise.reject_native(cx, &pipeline_error)
764 },
765 }
766 }
767}