1#![allow(unsafe_code)]
6
7use std::borrow::Cow;
8use std::cell::Cell;
9use std::rc::Rc;
10
11use dom_struct::dom_struct;
12use js::jsapi::{HandleObject, Heap, JSObject};
13use webgpu_traits::{
14 PopError, WebGPU, WebGPUComputePipeline, WebGPUComputePipelineResponse, WebGPUDevice,
15 WebGPUPoppedErrorScopeResponse, WebGPUQueue, WebGPURenderPipeline,
16 WebGPURenderPipelineResponse, WebGPURequest,
17};
18use wgpu_core::id::{BindGroupLayoutId, PipelineLayoutId};
19use wgpu_core::pipeline as wgpu_pipe;
20use wgpu_core::pipeline::RenderPipelineDescriptor;
21use wgpu_types::{self, TextureFormat};
22
23use super::gpudevicelostinfo::GPUDeviceLostInfo;
24use super::gpuerror::AsWebGpu;
25use super::gpupipelineerror::GPUPipelineError;
26use super::gpusupportedlimits::GPUSupportedLimits;
27use crate::conversions::Convert;
28use crate::dom::bindings::cell::DomRefCell;
29use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit;
30use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
31 GPUAdapterMethods, GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBufferDescriptor,
32 GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason,
33 GPUDeviceMethods, GPUErrorFilter, GPUPipelineErrorReason, GPUPipelineLayoutDescriptor,
34 GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerDescriptor,
35 GPUShaderModuleDescriptor, GPUSupportedLimitsMethods, GPUTextureDescriptor, GPUTextureFormat,
36 GPUUncapturedErrorEventInit, GPUVertexStepMode,
37};
38use crate::dom::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
39use crate::dom::bindings::error::{Error, Fallible};
40use crate::dom::bindings::inheritance::Castable;
41use crate::dom::bindings::refcounted::Trusted;
42use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
43use crate::dom::bindings::root::{Dom, DomRoot};
44use crate::dom::bindings::str::{DOMString, USVString};
45use crate::dom::bindings::trace::RootedTraceableBox;
46use crate::dom::event::Event;
47use crate::dom::eventtarget::EventTarget;
48use crate::dom::globalscope::GlobalScope;
49use crate::dom::promise::Promise;
50use crate::dom::types::GPUError;
51use crate::dom::webgpu::gpuadapter::GPUAdapter;
52use crate::dom::webgpu::gpuadapterinfo::GPUAdapterInfo;
53use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
54use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
55use crate::dom::webgpu::gpubuffer::GPUBuffer;
56use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
57use crate::dom::webgpu::gpucomputepipeline::GPUComputePipeline;
58use crate::dom::webgpu::gpupipelinelayout::GPUPipelineLayout;
59use crate::dom::webgpu::gpuqueue::GPUQueue;
60use crate::dom::webgpu::gpurenderbundleencoder::GPURenderBundleEncoder;
61use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
62use crate::dom::webgpu::gpusampler::GPUSampler;
63use crate::dom::webgpu::gpushadermodule::GPUShaderModule;
64use crate::dom::webgpu::gpusupportedfeatures::GPUSupportedFeatures;
65use crate::dom::webgpu::gputexture::GPUTexture;
66use crate::dom::webgpu::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
67use crate::realms::InRealm;
68use crate::routed_promise::{RoutedPromiseListener, route_promise};
69use crate::script_runtime::CanGc;
70
71#[dom_struct]
72pub(crate) struct GPUDevice {
73 eventtarget: EventTarget,
74 #[ignore_malloc_size_of = "channels are hard"]
75 #[no_trace]
76 channel: WebGPU,
77 adapter: Dom<GPUAdapter>,
78 #[ignore_malloc_size_of = "mozjs"]
79 extensions: Heap<*mut JSObject>,
80 features: Dom<GPUSupportedFeatures>,
81 limits: Dom<GPUSupportedLimits>,
82 adapter_info: Dom<GPUAdapterInfo>,
83 label: DomRefCell<USVString>,
84 #[no_trace]
85 device: WebGPUDevice,
86 default_queue: Dom<GPUQueue>,
87 #[conditional_malloc_size_of]
89 lost_promise: DomRefCell<Rc<Promise>>,
90 valid: Cell<bool>,
91}
92
93pub(crate) enum PipelineLayout {
94 Implicit(PipelineLayoutId, Vec<BindGroupLayoutId>),
95 Explicit(PipelineLayoutId),
96}
97
98impl PipelineLayout {
99 pub(crate) fn explicit(&self) -> Option<PipelineLayoutId> {
100 match self {
101 PipelineLayout::Explicit(layout_id) => Some(*layout_id),
102 _ => None,
103 }
104 }
105
106 pub(crate) fn implicit(self) -> Option<(PipelineLayoutId, Vec<BindGroupLayoutId>)> {
107 match self {
108 PipelineLayout::Implicit(layout_id, bind_group_layout_ids) => {
109 Some((layout_id, bind_group_layout_ids))
110 },
111 _ => None,
112 }
113 }
114}
115
116impl GPUDevice {
117 #[allow(clippy::too_many_arguments)]
118 fn new_inherited(
119 channel: WebGPU,
120 adapter: &GPUAdapter,
121 features: &GPUSupportedFeatures,
122 limits: &GPUSupportedLimits,
123 adapter_info: &GPUAdapterInfo,
124 device: WebGPUDevice,
125 queue: &GPUQueue,
126 label: String,
127 lost_promise: Rc<Promise>,
128 ) -> Self {
129 Self {
130 eventtarget: EventTarget::new_inherited(),
131 channel,
132 adapter: Dom::from_ref(adapter),
133 extensions: Heap::default(),
134 features: Dom::from_ref(features),
135 limits: Dom::from_ref(limits),
136 adapter_info: Dom::from_ref(adapter_info),
137 label: DomRefCell::new(USVString::from(label)),
138 device,
139 default_queue: Dom::from_ref(queue),
140 lost_promise: DomRefCell::new(lost_promise),
141 valid: Cell::new(true),
142 }
143 }
144
145 #[allow(clippy::too_many_arguments)]
146 pub(crate) fn new(
147 global: &GlobalScope,
148 channel: WebGPU,
149 adapter: &GPUAdapter,
150 extensions: HandleObject,
151 features: wgpu_types::Features,
152 limits: wgpu_types::Limits,
153 device: WebGPUDevice,
154 queue: WebGPUQueue,
155 label: String,
156 can_gc: CanGc,
157 ) -> DomRoot<Self> {
158 let queue = GPUQueue::new(global, channel.clone(), queue, can_gc);
159 let limits = GPUSupportedLimits::new(global, limits, can_gc);
160 let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap();
161 let adapter_info = GPUAdapterInfo::clone_from(global, &adapter.Info(), can_gc);
162 let lost_promise = Promise::new(global, can_gc);
163 let device = reflect_dom_object(
164 Box::new(GPUDevice::new_inherited(
165 channel,
166 adapter,
167 &features,
168 &limits,
169 &adapter_info,
170 device,
171 &queue,
172 label,
173 lost_promise,
174 )),
175 global,
176 can_gc,
177 );
178 queue.set_device(&device);
179 device.extensions.set(*extensions);
180 device
181 }
182}
183
184impl GPUDevice {
185 pub(crate) fn id(&self) -> WebGPUDevice {
186 self.device
187 }
188
189 pub(crate) fn queue_id(&self) -> WebGPUQueue {
190 self.default_queue.id()
191 }
192
193 pub(crate) fn channel(&self) -> WebGPU {
194 self.channel.clone()
195 }
196
197 pub(crate) fn dispatch_error(&self, error: webgpu_traits::Error) {
198 if let Err(e) = self.channel.0.send(WebGPURequest::DispatchError {
199 device_id: self.device.0,
200 error,
201 }) {
202 warn!("Failed to send WebGPURequest::DispatchError due to {e:?}");
203 }
204 }
205
206 pub(crate) fn fire_uncaptured_error(&self, error: webgpu_traits::Error) {
208 let this = Trusted::new(self);
209
210 self.global().task_manager().webgpu_task_source().queue(
213 task!(fire_uncaptured_error: move || {
214 let this = this.root();
215 let error = GPUError::from_error(&this.global(), error, CanGc::note());
216
217 let event = GPUUncapturedErrorEvent::new(
218 &this.global(),
219 DOMString::from("uncapturederror"),
220 &GPUUncapturedErrorEventInit {
221 error,
222 parent: EventInit::empty(),
223 },
224 CanGc::note(),
225 );
226
227 event.upcast::<Event>().fire(this.upcast(), CanGc::note());
228 }),
229 );
230 }
231
232 pub(crate) fn validate_texture_format_required_features(
237 &self,
238 format: &GPUTextureFormat,
239 ) -> Fallible<TextureFormat> {
240 let texture_format: TextureFormat = (*format).convert();
241 if self
242 .features
243 .wgpu_features()
244 .contains(texture_format.required_features())
245 {
246 Ok(texture_format)
247 } else {
248 Err(Error::Type(format!(
249 "{texture_format:?} is not supported by this GPUDevice"
250 )))
251 }
252 }
253
254 pub(crate) fn is_lost(&self) -> bool {
255 self.lost_promise.borrow().is_fulfilled()
256 }
257
258 pub(crate) fn get_pipeline_layout_data(
259 &self,
260 layout: &GPUPipelineLayoutOrGPUAutoLayoutMode,
261 ) -> PipelineLayout {
262 if let GPUPipelineLayoutOrGPUAutoLayoutMode::GPUPipelineLayout(layout) = layout {
263 PipelineLayout::Explicit(layout.id().0)
264 } else {
265 let layout_id = self.global().wgpu_id_hub().create_pipeline_layout_id();
266 let max_bind_grps = self.limits.MaxBindGroups();
267 let mut bgl_ids = Vec::with_capacity(max_bind_grps as usize);
268 for _ in 0..max_bind_grps {
269 let bgl = self.global().wgpu_id_hub().create_bind_group_layout_id();
270 bgl_ids.push(bgl);
271 }
272 PipelineLayout::Implicit(layout_id, bgl_ids)
273 }
274 }
275
276 pub(crate) fn parse_render_pipeline<'a>(
277 &self,
278 descriptor: &GPURenderPipelineDescriptor,
279 ) -> Fallible<(PipelineLayout, RenderPipelineDescriptor<'a>)> {
280 let pipeline_layout = self.get_pipeline_layout_data(&descriptor.parent.layout);
281
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.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: None,
388 };
389 Ok((pipeline_layout, 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 || {
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::note());
404 lost_promise.resolve_native(&*lost, CanGc::note());
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, value: USVString) {
438 *self.label.borrow_mut() = value;
439 }
440
441 fn Lost(&self) -> Rc<Promise> {
443 self.lost_promise.borrow().clone()
444 }
445
446 fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> Fallible<DomRoot<GPUBuffer>> {
448 GPUBuffer::create(self, descriptor, CanGc::note())
449 }
450
451 #[allow(non_snake_case)]
453 fn CreateBindGroupLayout(
454 &self,
455 descriptor: &GPUBindGroupLayoutDescriptor,
456 ) -> Fallible<DomRoot<GPUBindGroupLayout>> {
457 GPUBindGroupLayout::create(self, descriptor, CanGc::note())
458 }
459
460 fn CreatePipelineLayout(
462 &self,
463 descriptor: &GPUPipelineLayoutDescriptor,
464 ) -> DomRoot<GPUPipelineLayout> {
465 GPUPipelineLayout::create(self, descriptor, CanGc::note())
466 }
467
468 fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
470 GPUBindGroup::create(self, descriptor, CanGc::note())
471 }
472
473 fn CreateShaderModule(
475 &self,
476 descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
477 comp: InRealm,
478 can_gc: CanGc,
479 ) -> DomRoot<GPUShaderModule> {
480 GPUShaderModule::create(self, descriptor, comp, can_gc)
481 }
482
483 fn CreateComputePipeline(
485 &self,
486 descriptor: &GPUComputePipelineDescriptor,
487 ) -> DomRoot<GPUComputePipeline> {
488 let compute_pipeline = GPUComputePipeline::create(self, descriptor, None);
489 GPUComputePipeline::new(
490 &self.global(),
491 compute_pipeline,
492 descriptor.parent.parent.label.clone(),
493 self,
494 CanGc::note(),
495 )
496 }
497
498 fn CreateComputePipelineAsync(
500 &self,
501 descriptor: &GPUComputePipelineDescriptor,
502 comp: InRealm,
503 can_gc: CanGc,
504 ) -> Rc<Promise> {
505 let promise = Promise::new_in_current_realm(comp, can_gc);
506 let sender = route_promise(
507 &promise,
508 self,
509 self.global().task_manager().dom_manipulation_task_source(),
510 );
511 GPUComputePipeline::create(self, descriptor, Some(sender));
512 promise
513 }
514
515 fn CreateCommandEncoder(
517 &self,
518 descriptor: &GPUCommandEncoderDescriptor,
519 ) -> DomRoot<GPUCommandEncoder> {
520 GPUCommandEncoder::create(self, descriptor, CanGc::note())
521 }
522
523 fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> Fallible<DomRoot<GPUTexture>> {
525 GPUTexture::create(self, descriptor, CanGc::note())
526 }
527
528 fn CreateSampler(&self, descriptor: &GPUSamplerDescriptor) -> DomRoot<GPUSampler> {
530 GPUSampler::create(self, descriptor, CanGc::note())
531 }
532
533 fn CreateRenderPipeline(
535 &self,
536 descriptor: &GPURenderPipelineDescriptor,
537 ) -> Fallible<DomRoot<GPURenderPipeline>> {
538 let (pipeline_layout, desc) = self.parse_render_pipeline(descriptor)?;
539 let render_pipeline = GPURenderPipeline::create(self, pipeline_layout, desc, None)?;
540 Ok(GPURenderPipeline::new(
541 &self.global(),
542 render_pipeline,
543 descriptor.parent.parent.label.clone(),
544 self,
545 CanGc::note(),
546 ))
547 }
548
549 fn CreateRenderPipelineAsync(
551 &self,
552 descriptor: &GPURenderPipelineDescriptor,
553 comp: InRealm,
554 can_gc: CanGc,
555 ) -> Fallible<Rc<Promise>> {
556 let (implicit_ids, desc) = self.parse_render_pipeline(descriptor)?;
557 let promise = Promise::new_in_current_realm(comp, can_gc);
558 let sender = route_promise(
559 &promise,
560 self,
561 self.global().task_manager().dom_manipulation_task_source(),
562 );
563 GPURenderPipeline::create(self, implicit_ids, desc, Some(sender))?;
564 Ok(promise)
565 }
566
567 fn CreateRenderBundleEncoder(
569 &self,
570 descriptor: &GPURenderBundleEncoderDescriptor,
571 ) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
572 GPURenderBundleEncoder::create(self, descriptor, CanGc::note())
573 }
574
575 fn PushErrorScope(&self, filter: GPUErrorFilter) {
577 if self
578 .channel
579 .0
580 .send(WebGPURequest::PushErrorScope {
581 device_id: self.device.0,
582 filter: filter.as_webgpu(),
583 })
584 .is_err()
585 {
586 warn!("Failed sending WebGPURequest::PushErrorScope");
587 }
588 }
589
590 fn PopErrorScope(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
592 let promise = Promise::new_in_current_realm(comp, can_gc);
593 let sender = route_promise(
594 &promise,
595 self,
596 self.global().task_manager().dom_manipulation_task_source(),
597 );
598 if self
599 .channel
600 .0
601 .send(WebGPURequest::PopErrorScope {
602 device_id: self.device.0,
603 sender,
604 })
605 .is_err()
606 {
607 warn!("Error when sending WebGPURequest::PopErrorScope");
608 }
609 promise
610 }
611
612 event_handler!(uncapturederror, GetOnuncapturederror, SetOnuncapturederror);
614
615 fn Destroy(&self) {
617 if self.valid.get() {
618 self.valid.set(false);
619
620 if let Err(e) = self
621 .channel
622 .0
623 .send(WebGPURequest::DestroyDevice(self.device.0))
624 {
625 warn!("Failed to send DestroyDevice ({:?}) ({})", self.device.0, e);
626 }
627 }
628 }
629}
630
631impl RoutedPromiseListener<WebGPUPoppedErrorScopeResponse> for GPUDevice {
632 fn handle_response(
633 &self,
634 response: WebGPUPoppedErrorScopeResponse,
635 promise: &Rc<Promise>,
636 can_gc: CanGc,
637 ) {
638 match response {
639 Ok(None) | Err(PopError::Lost) => {
640 promise.resolve_native(&None::<Option<GPUError>>, can_gc)
641 },
642 Err(PopError::Empty) => promise.reject_error(Error::Operation, can_gc),
643 Ok(Some(error)) => {
644 let error = GPUError::from_error(&self.global(), error, can_gc);
645 promise.resolve_native(&error, can_gc);
646 },
647 }
648 }
649}
650
651impl RoutedPromiseListener<WebGPUComputePipelineResponse> for GPUDevice {
652 fn handle_response(
653 &self,
654 response: WebGPUComputePipelineResponse,
655 promise: &Rc<Promise>,
656 can_gc: CanGc,
657 ) {
658 match response {
659 Ok(pipeline) => promise.resolve_native(
660 &GPUComputePipeline::new(
661 &self.global(),
662 WebGPUComputePipeline(pipeline.id),
663 pipeline.label.into(),
664 self,
665 can_gc,
666 ),
667 can_gc,
668 ),
669 Err(webgpu_traits::Error::Validation(msg)) => promise.reject_native(
670 &GPUPipelineError::new(
671 &self.global(),
672 msg.into(),
673 GPUPipelineErrorReason::Validation,
674 can_gc,
675 ),
676 can_gc,
677 ),
678 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
679 promise.reject_native(
680 &GPUPipelineError::new(
681 &self.global(),
682 msg.into(),
683 GPUPipelineErrorReason::Internal,
684 can_gc,
685 ),
686 can_gc,
687 )
688 },
689 }
690 }
691}
692
693impl RoutedPromiseListener<WebGPURenderPipelineResponse> for GPUDevice {
694 fn handle_response(
695 &self,
696 response: WebGPURenderPipelineResponse,
697 promise: &Rc<Promise>,
698 can_gc: CanGc,
699 ) {
700 match response {
701 Ok(pipeline) => promise.resolve_native(
702 &GPURenderPipeline::new(
703 &self.global(),
704 WebGPURenderPipeline(pipeline.id),
705 pipeline.label.into(),
706 self,
707 can_gc,
708 ),
709 can_gc,
710 ),
711 Err(webgpu_traits::Error::Validation(msg)) => promise.reject_native(
712 &GPUPipelineError::new(
713 &self.global(),
714 msg.into(),
715 GPUPipelineErrorReason::Validation,
716 can_gc,
717 ),
718 can_gc,
719 ),
720 Err(webgpu_traits::Error::OutOfMemory(msg) | webgpu_traits::Error::Internal(msg)) => {
721 promise.reject_native(
722 &GPUPipelineError::new(
723 &self.global(),
724 msg.into(),
725 GPUPipelineErrorReason::Internal,
726 can_gc,
727 ),
728 can_gc,
729 )
730 },
731 }
732 }
733}
734
735impl Drop for GPUDevice {
736 fn drop(&mut self) {
737 if let Err(e) = self
738 .channel
739 .0
740 .send(WebGPURequest::DropDevice(self.device.0))
741 {
742 warn!("Failed to send DropDevice ({:?}) ({})", self.device.0, e);
743 }
744 }
745}