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