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