wgpu_core/device/
global.rs

1use alloc::{borrow::Cow, boxed::Box, string::String, sync::Arc, vec::Vec};
2use core::{ptr::NonNull, sync::atomic::Ordering};
3
4#[cfg(feature = "trace")]
5use crate::device::trace::{self, IntoTrace};
6use crate::{
7    api_log,
8    binding_model::{
9        self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor,
10        ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding,
11    },
12    command::{self, CommandEncoder},
13    conv,
14    device::{life::WaitIdleError, DeviceError, DeviceLostClosure},
15    global::Global,
16    id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
17    instance::{self, Adapter, Surface},
18    pipeline::{
19        self, RenderPipelineVertexProcessor, ResolvedComputePipelineDescriptor,
20        ResolvedFragmentState, ResolvedGeneralRenderPipelineDescriptor, ResolvedMeshState,
21        ResolvedProgrammableStageDescriptor, ResolvedTaskState, ResolvedVertexState,
22    },
23    present,
24    resource::{
25        self, BufferAccessError, BufferAccessResult, BufferMapOperation, CreateBufferError,
26        Fallible,
27    },
28    storage::Storage,
29    Label, LabelHelpers,
30};
31
32use wgt::{BufferAddress, TextureFormat};
33
34use super::UserClosures;
35
36impl Global {
37    pub fn adapter_is_surface_supported(
38        &self,
39        adapter_id: AdapterId,
40        surface_id: SurfaceId,
41    ) -> bool {
42        let surface = self.surfaces.get(surface_id);
43        let adapter = self.hub.adapters.get(adapter_id);
44        adapter.is_surface_supported(&surface)
45    }
46
47    pub fn surface_get_capabilities(
48        &self,
49        surface_id: SurfaceId,
50        adapter_id: AdapterId,
51    ) -> Result<wgt::SurfaceCapabilities, instance::GetSurfaceSupportError> {
52        profiling::scope!("Surface::get_capabilities");
53        self.fetch_adapter_and_surface::<_, _>(surface_id, adapter_id, |adapter, surface| {
54            let mut hal_caps = surface.get_capabilities(adapter)?;
55
56            hal_caps.formats.sort_by_key(|f| !f.is_srgb());
57
58            let usages = conv::map_texture_usage_from_hal(hal_caps.usage);
59
60            Ok(wgt::SurfaceCapabilities {
61                formats: hal_caps.formats,
62                present_modes: hal_caps.present_modes,
63                alpha_modes: hal_caps.composite_alpha_modes,
64                usages,
65            })
66        })
67    }
68
69    fn fetch_adapter_and_surface<F: FnOnce(&Adapter, &Surface) -> B, B>(
70        &self,
71        surface_id: SurfaceId,
72        adapter_id: AdapterId,
73        get_supported_callback: F,
74    ) -> B {
75        let surface = self.surfaces.get(surface_id);
76        let adapter = self.hub.adapters.get(adapter_id);
77        get_supported_callback(&adapter, &surface)
78    }
79
80    pub fn device_features(&self, device_id: DeviceId) -> wgt::Features {
81        let device = self.hub.devices.get(device_id);
82        device.features
83    }
84
85    pub fn device_limits(&self, device_id: DeviceId) -> wgt::Limits {
86        let device = self.hub.devices.get(device_id);
87        device.limits.clone()
88    }
89
90    pub fn device_downlevel_properties(&self, device_id: DeviceId) -> wgt::DownlevelCapabilities {
91        let device = self.hub.devices.get(device_id);
92        device.downlevel.clone()
93    }
94
95    pub fn device_create_buffer(
96        &self,
97        device_id: DeviceId,
98        desc: &resource::BufferDescriptor,
99        id_in: Option<id::BufferId>,
100    ) -> (id::BufferId, Option<CreateBufferError>) {
101        profiling::scope!("Device::create_buffer");
102
103        let hub = &self.hub;
104        let fid = hub.buffers.prepare(id_in);
105
106        let error = 'error: {
107            let device = self.hub.devices.get(device_id);
108
109            let buffer = match device.create_buffer(desc) {
110                Ok(buffer) => buffer,
111                Err(e) => {
112                    break 'error e;
113                }
114            };
115
116            #[cfg(feature = "trace")]
117            if let Some(ref mut trace) = *device.trace.lock() {
118                let mut desc = desc.clone();
119                let mapped_at_creation = core::mem::replace(&mut desc.mapped_at_creation, false);
120                if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
121                    desc.usage |= wgt::BufferUsages::COPY_DST;
122                }
123                trace.add(trace::Action::CreateBuffer(buffer.to_trace(), desc));
124            }
125
126            let id = fid.assign(Fallible::Valid(buffer));
127
128            api_log!(
129                "Device::create_buffer({:?}{}) -> {id:?}",
130                desc.label.as_deref().unwrap_or(""),
131                if desc.mapped_at_creation {
132                    ", mapped_at_creation"
133                } else {
134                    ""
135                }
136            );
137
138            return (id, None);
139        };
140
141        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
142        (id, Some(error))
143    }
144
145    /// Assign `id_in` an error with the given `label`.
146    ///
147    /// Ensure that future attempts to use `id_in` as a buffer ID will propagate
148    /// the error, following the WebGPU ["contagious invalidity"] style.
149    ///
150    /// Firefox uses this function to comply strictly with the WebGPU spec,
151    /// which requires [`GPUBufferDescriptor`] validation to be generated on the
152    /// Device timeline and leave the newly created [`GPUBuffer`] invalid.
153    ///
154    /// Ideally, we would simply let [`device_create_buffer`] take care of all
155    /// of this, but some errors must be detected before we can even construct a
156    /// [`wgpu_types::BufferDescriptor`] to give it. For example, the WebGPU API
157    /// allows a `GPUBufferDescriptor`'s [`usage`] property to be any WebIDL
158    /// `unsigned long` value, but we can't construct a
159    /// [`wgpu_types::BufferUsages`] value from values with unassigned bits
160    /// set. This means we must validate `usage` before we can call
161    /// `device_create_buffer`.
162    ///
163    /// When that validation fails, we must arrange for the buffer id to be
164    /// considered invalid. This method provides the means to do so.
165    ///
166    /// ["contagious invalidity"]: https://www.w3.org/TR/webgpu/#invalidity
167    /// [`GPUBufferDescriptor`]: https://www.w3.org/TR/webgpu/#dictdef-gpubufferdescriptor
168    /// [`GPUBuffer`]: https://www.w3.org/TR/webgpu/#gpubuffer
169    /// [`wgpu_types::BufferDescriptor`]: wgt::BufferDescriptor
170    /// [`device_create_buffer`]: Global::device_create_buffer
171    /// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage
172    /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages
173    pub fn create_buffer_error(
174        &self,
175        id_in: Option<id::BufferId>,
176        desc: &resource::BufferDescriptor,
177    ) {
178        let fid = self.hub.buffers.prepare(id_in);
179        fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
180    }
181
182    /// Assign `id_in` an error with the given `label`.
183    ///
184    /// See [`Self::create_buffer_error`] for more context and explanation.
185    pub fn create_render_bundle_error(
186        &self,
187        id_in: Option<id::RenderBundleId>,
188        desc: &command::RenderBundleDescriptor,
189    ) {
190        let fid = self.hub.render_bundles.prepare(id_in);
191        fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
192    }
193
194    /// Assign `id_in` an error with the given `label`.
195    ///
196    /// See [`Self::create_buffer_error`] for more context and explanation.
197    pub fn create_texture_error(
198        &self,
199        id_in: Option<id::TextureId>,
200        desc: &resource::TextureDescriptor,
201    ) {
202        let fid = self.hub.textures.prepare(id_in);
203        fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
204    }
205
206    /// Assign `id_in` an error with the given `label`.
207    ///
208    /// See [`Self::create_buffer_error`] for more context and explanation.
209    pub fn create_external_texture_error(
210        &self,
211        id_in: Option<id::ExternalTextureId>,
212        desc: &resource::ExternalTextureDescriptor,
213    ) {
214        let fid = self.hub.external_textures.prepare(id_in);
215        fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
216    }
217
218    pub fn buffer_destroy(&self, buffer_id: id::BufferId) {
219        profiling::scope!("Buffer::destroy");
220        api_log!("Buffer::destroy {buffer_id:?}");
221
222        let hub = &self.hub;
223
224        let Ok(buffer) = hub.buffers.get(buffer_id).get() else {
225            // If the buffer is already invalid, there's nothing to do.
226            return;
227        };
228
229        #[cfg(feature = "trace")]
230        if let Some(trace) = buffer.device.trace.lock().as_mut() {
231            trace.add(trace::Action::FreeBuffer(buffer.to_trace()));
232        }
233
234        let _ = buffer.unmap();
235
236        buffer.destroy();
237    }
238
239    pub fn buffer_drop(&self, buffer_id: id::BufferId) {
240        profiling::scope!("Buffer::drop");
241        api_log!("Buffer::drop {buffer_id:?}");
242
243        let hub = &self.hub;
244
245        let buffer = match hub.buffers.remove(buffer_id).get() {
246            Ok(buffer) => buffer,
247            Err(_) => {
248                return;
249            }
250        };
251
252        #[cfg(feature = "trace")]
253        if let Some(t) = buffer.device.trace.lock().as_mut() {
254            t.add(trace::Action::DestroyBuffer(buffer.to_trace()));
255        }
256
257        let _ = buffer.unmap();
258    }
259
260    pub fn device_create_texture(
261        &self,
262        device_id: DeviceId,
263        desc: &resource::TextureDescriptor,
264        id_in: Option<id::TextureId>,
265    ) -> (id::TextureId, Option<resource::CreateTextureError>) {
266        profiling::scope!("Device::create_texture");
267
268        let hub = &self.hub;
269
270        let fid = hub.textures.prepare(id_in);
271
272        let error = 'error: {
273            let device = self.hub.devices.get(device_id);
274
275            let texture = match device.create_texture(desc) {
276                Ok(texture) => texture,
277                Err(error) => break 'error error,
278            };
279
280            #[cfg(feature = "trace")]
281            if let Some(ref mut trace) = *device.trace.lock() {
282                trace.add(trace::Action::CreateTexture(
283                    texture.to_trace(),
284                    desc.clone(),
285                ));
286            }
287
288            let id = fid.assign(Fallible::Valid(texture));
289            api_log!("Device::create_texture({desc:?}) -> {id:?}");
290
291            return (id, None);
292        };
293
294        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
295        (id, Some(error))
296    }
297
298    /// # Safety
299    ///
300    /// - `hal_texture` must be created from `device_id` corresponding raw handle.
301    /// - `hal_texture` must be created respecting `desc`
302    /// - `hal_texture` must be initialized
303    pub unsafe fn create_texture_from_hal(
304        &self,
305        hal_texture: Box<dyn hal::DynTexture>,
306        device_id: DeviceId,
307        desc: &resource::TextureDescriptor,
308        id_in: Option<id::TextureId>,
309    ) -> (id::TextureId, Option<resource::CreateTextureError>) {
310        profiling::scope!("Device::create_texture_from_hal");
311
312        let hub = &self.hub;
313
314        let fid = hub.textures.prepare(id_in);
315
316        let error = 'error: {
317            let device = self.hub.devices.get(device_id);
318
319            let texture = match device.create_texture_from_hal(hal_texture, desc) {
320                Ok(texture) => texture,
321                Err(error) => break 'error error,
322            };
323
324            // NB: Any change done through the raw texture handle will not be
325            // recorded in the replay
326            #[cfg(feature = "trace")]
327            if let Some(ref mut trace) = *device.trace.lock() {
328                trace.add(trace::Action::CreateTexture(
329                    texture.to_trace(),
330                    desc.clone(),
331                ));
332            }
333
334            let id = fid.assign(Fallible::Valid(texture));
335            api_log!("Device::create_texture({desc:?}) -> {id:?}");
336
337            return (id, None);
338        };
339
340        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
341        (id, Some(error))
342    }
343
344    /// # Safety
345    ///
346    /// - `hal_buffer` must be created from `device_id` corresponding raw handle.
347    /// - `hal_buffer` must be created respecting `desc`
348    /// - `hal_buffer` must be initialized
349    /// - `hal_buffer` must not have zero size.
350    pub unsafe fn create_buffer_from_hal<A: hal::Api>(
351        &self,
352        hal_buffer: A::Buffer,
353        device_id: DeviceId,
354        desc: &resource::BufferDescriptor,
355        id_in: Option<id::BufferId>,
356    ) -> (id::BufferId, Option<CreateBufferError>) {
357        profiling::scope!("Device::create_buffer");
358
359        let hub = &self.hub;
360        let fid = hub.buffers.prepare(id_in);
361
362        let device = self.hub.devices.get(device_id);
363
364        let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) };
365
366        // NB: Any change done through the raw buffer handle will not be
367        // recorded in the replay
368        #[cfg(feature = "trace")]
369        if let Some(trace) = device.trace.lock().as_mut() {
370            match &buffer {
371                Fallible::Valid(arc) => {
372                    trace.add(trace::Action::CreateBuffer(arc.to_trace(), desc.clone()))
373                }
374                Fallible::Invalid(_) => {}
375            }
376        }
377
378        let id = fid.assign(buffer);
379        api_log!("Device::create_buffer -> {id:?}");
380
381        (id, err)
382    }
383
384    pub fn texture_destroy(&self, texture_id: id::TextureId) {
385        profiling::scope!("Texture::destroy");
386        api_log!("Texture::destroy {texture_id:?}");
387
388        let hub = &self.hub;
389
390        let Ok(texture) = hub.textures.get(texture_id).get() else {
391            // If the texture is already invalid, there's nothing to do.
392            return;
393        };
394
395        #[cfg(feature = "trace")]
396        if let Some(trace) = texture.device.trace.lock().as_mut() {
397            trace.add(trace::Action::FreeTexture(texture.to_trace()));
398        }
399
400        texture.destroy();
401    }
402
403    pub fn texture_drop(&self, texture_id: id::TextureId) {
404        profiling::scope!("Texture::drop");
405        api_log!("Texture::drop {texture_id:?}");
406
407        let hub = &self.hub;
408
409        let _texture = hub.textures.remove(texture_id);
410        #[cfg(feature = "trace")]
411        if let Ok(texture) = _texture.get() {
412            if let Some(t) = texture.device.trace.lock().as_mut() {
413                t.add(trace::Action::DestroyTexture(texture.to_trace()));
414            }
415        }
416    }
417
418    pub fn texture_create_view(
419        &self,
420        texture_id: id::TextureId,
421        desc: &resource::TextureViewDescriptor,
422        id_in: Option<id::TextureViewId>,
423    ) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
424        profiling::scope!("Texture::create_view");
425
426        let hub = &self.hub;
427
428        let fid = hub.texture_views.prepare(id_in);
429
430        let error = 'error: {
431            let texture = match hub.textures.get(texture_id).get() {
432                Ok(texture) => texture,
433                Err(e) => break 'error e.into(),
434            };
435            let device = &texture.device;
436
437            let view = match device.create_texture_view(&texture, desc) {
438                Ok(view) => view,
439                Err(e) => break 'error e,
440            };
441
442            #[cfg(feature = "trace")]
443            if let Some(ref mut trace) = *device.trace.lock() {
444                trace.add(trace::Action::CreateTextureView {
445                    id: view.to_trace(),
446                    parent: texture.to_trace(),
447                    desc: desc.clone(),
448                });
449            }
450
451            let id = fid.assign(Fallible::Valid(view));
452
453            api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
454
455            return (id, None);
456        };
457
458        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
459        (id, Some(error))
460    }
461
462    pub fn texture_view_drop(
463        &self,
464        texture_view_id: id::TextureViewId,
465    ) -> Result<(), resource::TextureViewDestroyError> {
466        profiling::scope!("TextureView::drop");
467        api_log!("TextureView::drop {texture_view_id:?}");
468
469        let hub = &self.hub;
470
471        let _view = hub.texture_views.remove(texture_view_id);
472
473        #[cfg(feature = "trace")]
474        if let Ok(view) = _view.get() {
475            if let Some(t) = view.device.trace.lock().as_mut() {
476                t.add(trace::Action::DestroyTextureView(view.to_trace()));
477            }
478        }
479        Ok(())
480    }
481
482    pub fn device_create_external_texture(
483        &self,
484        device_id: DeviceId,
485        desc: &resource::ExternalTextureDescriptor,
486        planes: &[id::TextureViewId],
487        id_in: Option<id::ExternalTextureId>,
488    ) -> (
489        id::ExternalTextureId,
490        Option<resource::CreateExternalTextureError>,
491    ) {
492        profiling::scope!("Device::create_external_texture");
493
494        let hub = &self.hub;
495
496        let fid = hub.external_textures.prepare(id_in);
497
498        let error = 'error: {
499            let device = self.hub.devices.get(device_id);
500
501            let planes = planes
502                .iter()
503                .map(|plane_id| self.hub.texture_views.get(*plane_id).get())
504                .collect::<Result<Vec<_>, _>>();
505            let planes = match planes {
506                Ok(planes) => planes,
507                Err(error) => break 'error error.into(),
508            };
509
510            let external_texture = match device.create_external_texture(desc, &planes) {
511                Ok(external_texture) => external_texture,
512                Err(error) => break 'error error,
513            };
514
515            #[cfg(feature = "trace")]
516            if let Some(ref mut trace) = *device.trace.lock() {
517                let planes = Box::from(
518                    planes
519                        .into_iter()
520                        .map(|plane| plane.to_trace())
521                        .collect::<Vec<_>>(),
522                );
523                trace.add(trace::Action::CreateExternalTexture {
524                    id: external_texture.to_trace(),
525                    desc: desc.clone(),
526                    planes,
527                });
528            }
529
530            let id = fid.assign(Fallible::Valid(external_texture));
531            api_log!("Device::create_external_texture({desc:?}) -> {id:?}");
532
533            return (id, None);
534        };
535
536        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
537        (id, Some(error))
538    }
539
540    pub fn external_texture_destroy(&self, external_texture_id: id::ExternalTextureId) {
541        profiling::scope!("ExternalTexture::destroy");
542        api_log!("ExternalTexture::destroy {external_texture_id:?}");
543
544        let hub = &self.hub;
545
546        let Ok(external_texture) = hub.external_textures.get(external_texture_id).get() else {
547            // If the external texture is already invalid, there's nothing to do.
548            return;
549        };
550
551        #[cfg(feature = "trace")]
552        if let Some(trace) = external_texture.device.trace.lock().as_mut() {
553            trace.add(trace::Action::FreeExternalTexture(
554                external_texture.to_trace(),
555            ));
556        }
557
558        external_texture.destroy();
559    }
560
561    pub fn external_texture_drop(&self, external_texture_id: id::ExternalTextureId) {
562        profiling::scope!("ExternalTexture::drop");
563        api_log!("ExternalTexture::drop {external_texture_id:?}");
564
565        let hub = &self.hub;
566
567        let _external_texture = hub.external_textures.remove(external_texture_id);
568
569        #[cfg(feature = "trace")]
570        if let Ok(external_texture) = _external_texture.get() {
571            if let Some(t) = external_texture.device.trace.lock().as_mut() {
572                t.add(trace::Action::DestroyExternalTexture(
573                    external_texture.to_trace(),
574                ));
575            }
576        }
577    }
578
579    pub fn device_create_sampler(
580        &self,
581        device_id: DeviceId,
582        desc: &resource::SamplerDescriptor,
583        id_in: Option<id::SamplerId>,
584    ) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
585        profiling::scope!("Device::create_sampler");
586
587        let hub = &self.hub;
588        let fid = hub.samplers.prepare(id_in);
589
590        let error = 'error: {
591            let device = self.hub.devices.get(device_id);
592
593            let sampler = match device.create_sampler(desc) {
594                Ok(sampler) => sampler,
595                Err(e) => break 'error e,
596            };
597
598            #[cfg(feature = "trace")]
599            if let Some(ref mut trace) = *device.trace.lock() {
600                trace.add(trace::Action::CreateSampler(
601                    sampler.to_trace(),
602                    desc.clone(),
603                ));
604            }
605
606            let id = fid.assign(Fallible::Valid(sampler));
607            api_log!("Device::create_sampler -> {id:?}");
608
609            return (id, None);
610        };
611
612        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
613        (id, Some(error))
614    }
615
616    pub fn sampler_drop(&self, sampler_id: id::SamplerId) {
617        profiling::scope!("Sampler::drop");
618        api_log!("Sampler::drop {sampler_id:?}");
619
620        let hub = &self.hub;
621
622        let _sampler = hub.samplers.remove(sampler_id);
623
624        #[cfg(feature = "trace")]
625        if let Ok(sampler) = _sampler.get() {
626            if let Some(t) = sampler.device.trace.lock().as_mut() {
627                t.add(trace::Action::DestroySampler(sampler.to_trace()));
628            }
629        }
630    }
631
632    pub fn device_create_bind_group_layout(
633        &self,
634        device_id: DeviceId,
635        desc: &binding_model::BindGroupLayoutDescriptor,
636        id_in: Option<id::BindGroupLayoutId>,
637    ) -> (
638        id::BindGroupLayoutId,
639        Option<binding_model::CreateBindGroupLayoutError>,
640    ) {
641        profiling::scope!("Device::create_bind_group_layout");
642
643        let hub = &self.hub;
644        let fid = hub.bind_group_layouts.prepare(id_in);
645
646        let error = 'error: {
647            let device = self.hub.devices.get(device_id);
648
649            let layout = match device.create_bind_group_layout(desc) {
650                Ok(layout) => layout,
651                Err(e) => break 'error e,
652            };
653
654            #[cfg(feature = "trace")]
655            if let Some(ref mut trace) = *device.trace.lock() {
656                trace.add(trace::Action::CreateBindGroupLayout(
657                    layout.to_trace(),
658                    desc.clone(),
659                ));
660            }
661
662            let id = fid.assign(Fallible::Valid(layout.clone()));
663
664            api_log!("Device::create_bind_group_layout -> {id:?}");
665            return (id, None);
666        };
667
668        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
669        (id, Some(error))
670    }
671
672    pub fn bind_group_layout_drop(&self, bind_group_layout_id: id::BindGroupLayoutId) {
673        profiling::scope!("BindGroupLayout::drop");
674        api_log!("BindGroupLayout::drop {bind_group_layout_id:?}");
675
676        let hub = &self.hub;
677
678        let _layout = hub.bind_group_layouts.remove(bind_group_layout_id);
679
680        #[cfg(feature = "trace")]
681        if let Ok(layout) = _layout.get() {
682            if let Some(t) = layout.device.trace.lock().as_mut() {
683                t.add(trace::Action::DestroyBindGroupLayout(layout.to_trace()));
684            }
685        }
686    }
687
688    pub fn device_create_pipeline_layout(
689        &self,
690        device_id: DeviceId,
691        desc: &binding_model::PipelineLayoutDescriptor,
692        id_in: Option<id::PipelineLayoutId>,
693    ) -> (
694        id::PipelineLayoutId,
695        Option<binding_model::CreatePipelineLayoutError>,
696    ) {
697        profiling::scope!("Device::create_pipeline_layout");
698
699        let hub = &self.hub;
700        let fid = hub.pipeline_layouts.prepare(id_in);
701
702        let error = 'error: {
703            let device = self.hub.devices.get(device_id);
704
705            if let Err(e) = device.check_is_valid() {
706                break 'error e.into();
707            }
708
709            let bind_group_layouts = {
710                let bind_group_layouts_guard = hub.bind_group_layouts.read();
711                desc.bind_group_layouts
712                    .iter()
713                    .map(|bgl_id| bind_group_layouts_guard.get(*bgl_id).get())
714                    .collect::<Result<Vec<_>, _>>()
715            };
716
717            let bind_group_layouts = match bind_group_layouts {
718                Ok(bind_group_layouts) => bind_group_layouts,
719                Err(e) => break 'error e.into(),
720            };
721
722            let desc = binding_model::ResolvedPipelineLayoutDescriptor {
723                label: desc.label.clone(),
724                bind_group_layouts: Cow::Owned(bind_group_layouts),
725                push_constant_ranges: desc.push_constant_ranges.clone(),
726            };
727
728            let layout = match device.create_pipeline_layout(&desc) {
729                Ok(layout) => layout,
730                Err(e) => break 'error e,
731            };
732
733            #[cfg(feature = "trace")]
734            if let Some(ref mut trace) = *device.trace.lock() {
735                trace.add(trace::Action::CreatePipelineLayout(
736                    layout.to_trace(),
737                    desc.to_trace(),
738                ));
739            }
740
741            let id = fid.assign(Fallible::Valid(layout));
742            api_log!("Device::create_pipeline_layout -> {id:?}");
743            return (id, None);
744        };
745
746        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
747        (id, Some(error))
748    }
749
750    pub fn pipeline_layout_drop(&self, pipeline_layout_id: id::PipelineLayoutId) {
751        profiling::scope!("PipelineLayout::drop");
752        api_log!("PipelineLayout::drop {pipeline_layout_id:?}");
753
754        let hub = &self.hub;
755
756        let _layout = hub.pipeline_layouts.remove(pipeline_layout_id);
757
758        #[cfg(feature = "trace")]
759        if let Ok(layout) = _layout.get() {
760            if let Some(t) = layout.device.trace.lock().as_mut() {
761                t.add(trace::Action::DestroyPipelineLayout(layout.to_trace()));
762            }
763        }
764    }
765
766    pub fn device_create_bind_group(
767        &self,
768        device_id: DeviceId,
769        desc: &binding_model::BindGroupDescriptor,
770        id_in: Option<id::BindGroupId>,
771    ) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
772        profiling::scope!("Device::create_bind_group");
773
774        let hub = &self.hub;
775        let fid = hub.bind_groups.prepare(id_in);
776
777        let error = 'error: {
778            let device = self.hub.devices.get(device_id);
779
780            if let Err(e) = device.check_is_valid() {
781                break 'error e.into();
782            }
783
784            let layout = match hub.bind_group_layouts.get(desc.layout).get() {
785                Ok(layout) => layout,
786                Err(e) => break 'error e.into(),
787            };
788
789            fn resolve_entry<'a>(
790                e: &BindGroupEntry<'a>,
791                buffer_storage: &Storage<Fallible<resource::Buffer>>,
792                sampler_storage: &Storage<Fallible<resource::Sampler>>,
793                texture_view_storage: &Storage<Fallible<resource::TextureView>>,
794                tlas_storage: &Storage<Fallible<resource::Tlas>>,
795                external_texture_storage: &Storage<Fallible<resource::ExternalTexture>>,
796            ) -> Result<ResolvedBindGroupEntry<'a>, binding_model::CreateBindGroupError>
797            {
798                let resolve_buffer = |bb: &BufferBinding| {
799                    buffer_storage
800                        .get(bb.buffer)
801                        .get()
802                        .map(|buffer| ResolvedBufferBinding {
803                            buffer,
804                            offset: bb.offset,
805                            size: bb.size,
806                        })
807                        .map_err(binding_model::CreateBindGroupError::from)
808                };
809                let resolve_sampler = |id: &id::SamplerId| {
810                    sampler_storage
811                        .get(*id)
812                        .get()
813                        .map_err(binding_model::CreateBindGroupError::from)
814                };
815                let resolve_view = |id: &id::TextureViewId| {
816                    texture_view_storage
817                        .get(*id)
818                        .get()
819                        .map_err(binding_model::CreateBindGroupError::from)
820                };
821                let resolve_tlas = |id: &id::TlasId| {
822                    tlas_storage
823                        .get(*id)
824                        .get()
825                        .map_err(binding_model::CreateBindGroupError::from)
826                };
827                let resolve_external_texture = |id: &id::ExternalTextureId| {
828                    external_texture_storage
829                        .get(*id)
830                        .get()
831                        .map_err(binding_model::CreateBindGroupError::from)
832                };
833                let resource = match e.resource {
834                    BindingResource::Buffer(ref buffer) => {
835                        ResolvedBindingResource::Buffer(resolve_buffer(buffer)?)
836                    }
837                    BindingResource::BufferArray(ref buffers) => {
838                        let buffers = buffers
839                            .iter()
840                            .map(resolve_buffer)
841                            .collect::<Result<Vec<_>, _>>()?;
842                        ResolvedBindingResource::BufferArray(Cow::Owned(buffers))
843                    }
844                    BindingResource::Sampler(ref sampler) => {
845                        ResolvedBindingResource::Sampler(resolve_sampler(sampler)?)
846                    }
847                    BindingResource::SamplerArray(ref samplers) => {
848                        let samplers = samplers
849                            .iter()
850                            .map(resolve_sampler)
851                            .collect::<Result<Vec<_>, _>>()?;
852                        ResolvedBindingResource::SamplerArray(Cow::Owned(samplers))
853                    }
854                    BindingResource::TextureView(ref view) => {
855                        ResolvedBindingResource::TextureView(resolve_view(view)?)
856                    }
857                    BindingResource::TextureViewArray(ref views) => {
858                        let views = views
859                            .iter()
860                            .map(resolve_view)
861                            .collect::<Result<Vec<_>, _>>()?;
862                        ResolvedBindingResource::TextureViewArray(Cow::Owned(views))
863                    }
864                    BindingResource::AccelerationStructure(ref tlas) => {
865                        ResolvedBindingResource::AccelerationStructure(resolve_tlas(tlas)?)
866                    }
867                    BindingResource::ExternalTexture(ref et) => {
868                        ResolvedBindingResource::ExternalTexture(resolve_external_texture(et)?)
869                    }
870                };
871                Ok(ResolvedBindGroupEntry {
872                    binding: e.binding,
873                    resource,
874                })
875            }
876
877            let entries = {
878                let buffer_guard = hub.buffers.read();
879                let texture_view_guard = hub.texture_views.read();
880                let sampler_guard = hub.samplers.read();
881                let tlas_guard = hub.tlas_s.read();
882                let external_texture_guard = hub.external_textures.read();
883                desc.entries
884                    .iter()
885                    .map(|e| {
886                        resolve_entry(
887                            e,
888                            &buffer_guard,
889                            &sampler_guard,
890                            &texture_view_guard,
891                            &tlas_guard,
892                            &external_texture_guard,
893                        )
894                    })
895                    .collect::<Result<Vec<_>, _>>()
896            };
897            let entries = match entries {
898                Ok(entries) => Cow::Owned(entries),
899                Err(e) => break 'error e,
900            };
901
902            let desc = ResolvedBindGroupDescriptor {
903                label: desc.label.clone(),
904                layout,
905                entries,
906            };
907            #[cfg(feature = "trace")]
908            let trace_desc = (&desc).to_trace();
909
910            let bind_group = match device.create_bind_group(desc) {
911                Ok(bind_group) => bind_group,
912                Err(e) => break 'error e,
913            };
914
915            #[cfg(feature = "trace")]
916            if let Some(ref mut trace) = *device.trace.lock() {
917                trace.add(trace::Action::CreateBindGroup(
918                    bind_group.to_trace(),
919                    trace_desc,
920                ));
921            }
922
923            let id = fid.assign(Fallible::Valid(bind_group));
924
925            api_log!("Device::create_bind_group -> {id:?}");
926
927            return (id, None);
928        };
929
930        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
931        (id, Some(error))
932    }
933
934    pub fn bind_group_drop(&self, bind_group_id: id::BindGroupId) {
935        profiling::scope!("BindGroup::drop");
936        api_log!("BindGroup::drop {bind_group_id:?}");
937
938        let hub = &self.hub;
939
940        let _bind_group = hub.bind_groups.remove(bind_group_id);
941
942        #[cfg(feature = "trace")]
943        if let Ok(bind_group) = _bind_group.get() {
944            if let Some(t) = bind_group.device.trace.lock().as_mut() {
945                t.add(trace::Action::DestroyBindGroup(bind_group.to_trace()));
946            }
947        }
948    }
949
950    /// Create a shader module with the given `source`.
951    ///
952    /// <div class="warning">
953    // NOTE: Keep this in sync with `naga::front::wgsl::parse_str`!
954    // NOTE: Keep this in sync with `wgpu::Device::create_shader_module`!
955    ///
956    /// This function may consume a lot of stack space. Compiler-enforced limits for parsing
957    /// recursion exist; if shader compilation runs into them, it will return an error gracefully.
958    /// However, on some build profiles and platforms, the default stack size for a thread may be
959    /// exceeded before this limit is reached during parsing. Callers should ensure that there is
960    /// enough stack space for this, particularly if calls to this method are exposed to user
961    /// input.
962    ///
963    /// </div>
964    pub fn device_create_shader_module(
965        &self,
966        device_id: DeviceId,
967        desc: &pipeline::ShaderModuleDescriptor,
968        source: pipeline::ShaderModuleSource,
969        id_in: Option<id::ShaderModuleId>,
970    ) -> (
971        id::ShaderModuleId,
972        Option<pipeline::CreateShaderModuleError>,
973    ) {
974        profiling::scope!("Device::create_shader_module");
975
976        let hub = &self.hub;
977        let fid = hub.shader_modules.prepare(id_in);
978
979        let error = 'error: {
980            let device = self.hub.devices.get(device_id);
981
982            #[cfg(feature = "trace")]
983            let data = device.trace.lock().as_mut().map(|trace| match source {
984                #[cfg(feature = "wgsl")]
985                pipeline::ShaderModuleSource::Wgsl(ref code) => {
986                    trace.make_binary("wgsl", code.as_bytes())
987                }
988                #[cfg(feature = "glsl")]
989                pipeline::ShaderModuleSource::Glsl(ref code, _) => {
990                    trace.make_binary("glsl", code.as_bytes())
991                }
992                #[cfg(feature = "spirv")]
993                pipeline::ShaderModuleSource::SpirV(ref code, _) => {
994                    trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code))
995                }
996                pipeline::ShaderModuleSource::Naga(ref module) => {
997                    let string =
998                        ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default())
999                            .unwrap();
1000                    trace.make_binary("ron", string.as_bytes())
1001                }
1002                pipeline::ShaderModuleSource::Dummy(_) => {
1003                    panic!("found `ShaderModuleSource::Dummy`")
1004                }
1005            });
1006
1007            let shader = match device.create_shader_module(desc, source) {
1008                Ok(shader) => shader,
1009                Err(e) => break 'error e,
1010            };
1011
1012            #[cfg(feature = "trace")]
1013            if let Some(data) = data {
1014                // We don't need these two operations with the trace to be atomic.
1015                device
1016                    .trace
1017                    .lock()
1018                    .as_mut()
1019                    .expect("trace went away during create_shader_module?")
1020                    .add(trace::Action::CreateShaderModule {
1021                        id: shader.to_trace(),
1022                        desc: desc.clone(),
1023                        data,
1024                    });
1025            };
1026
1027            let id = fid.assign(Fallible::Valid(shader));
1028            api_log!("Device::create_shader_module -> {id:?}");
1029            return (id, None);
1030        };
1031
1032        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1033        (id, Some(error))
1034    }
1035
1036    #[allow(unused_unsafe)]
1037    /// # Safety
1038    ///
1039    /// This function passes source code or binary to the backend as-is and can potentially result in a
1040    /// driver crash.
1041    pub unsafe fn device_create_shader_module_passthrough(
1042        &self,
1043        device_id: DeviceId,
1044        desc: &pipeline::ShaderModuleDescriptorPassthrough<'_>,
1045        id_in: Option<id::ShaderModuleId>,
1046    ) -> (
1047        id::ShaderModuleId,
1048        Option<pipeline::CreateShaderModuleError>,
1049    ) {
1050        profiling::scope!("Device::create_shader_module_passthrough");
1051
1052        let hub = &self.hub;
1053        let fid = hub.shader_modules.prepare(id_in);
1054
1055        let error = 'error: {
1056            let device = self.hub.devices.get(device_id);
1057
1058            let result = unsafe { device.create_shader_module_passthrough(desc) };
1059
1060            let shader = match result {
1061                Ok(shader) => shader,
1062                Err(e) => break 'error e,
1063            };
1064
1065            #[cfg(feature = "trace")]
1066            if let Some(ref mut trace) = *device.trace.lock() {
1067                let mut file_names = Vec::new();
1068                for (data, ext) in [
1069                    (desc.spirv.as_ref().map(|a| bytemuck::cast_slice(a)), "spv"),
1070                    (desc.dxil.as_deref(), "dxil"),
1071                    (desc.hlsl.as_ref().map(|a| a.as_bytes()), "hlsl"),
1072                    (desc.msl.as_ref().map(|a| a.as_bytes()), "msl"),
1073                    (desc.glsl.as_ref().map(|a| a.as_bytes()), "glsl"),
1074                    (desc.wgsl.as_ref().map(|a| a.as_bytes()), "wgsl"),
1075                ] {
1076                    if let Some(data) = data {
1077                        file_names.push(trace.make_binary(ext, data));
1078                    }
1079                }
1080                trace.add(trace::Action::CreateShaderModulePassthrough {
1081                    id: shader.to_trace(),
1082                    data: file_names,
1083
1084                    entry_point: desc.entry_point.clone(),
1085                    label: desc.label.clone(),
1086                    num_workgroups: desc.num_workgroups,
1087                    runtime_checks: desc.runtime_checks,
1088                });
1089            };
1090
1091            let id = fid.assign(Fallible::Valid(shader));
1092            api_log!("Device::create_shader_module_spirv -> {id:?}");
1093            return (id, None);
1094        };
1095
1096        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1097        (id, Some(error))
1098    }
1099
1100    pub fn shader_module_drop(&self, shader_module_id: id::ShaderModuleId) {
1101        profiling::scope!("ShaderModule::drop");
1102        api_log!("ShaderModule::drop {shader_module_id:?}");
1103
1104        let hub = &self.hub;
1105
1106        let _shader_module = hub.shader_modules.remove(shader_module_id);
1107
1108        #[cfg(feature = "trace")]
1109        if let Ok(shader_module) = _shader_module.get() {
1110            if let Some(t) = shader_module.device.trace.lock().as_mut() {
1111                t.add(trace::Action::DestroyShaderModule(shader_module.to_trace()));
1112            }
1113        }
1114    }
1115
1116    pub fn device_create_command_encoder(
1117        &self,
1118        device_id: DeviceId,
1119        desc: &wgt::CommandEncoderDescriptor<Label>,
1120        id_in: Option<id::CommandEncoderId>,
1121    ) -> (id::CommandEncoderId, Option<DeviceError>) {
1122        profiling::scope!("Device::create_command_encoder");
1123
1124        let hub = &self.hub;
1125        let fid = hub.command_encoders.prepare(id_in);
1126
1127        let device = self.hub.devices.get(device_id);
1128
1129        let error = 'error: {
1130            let cmd_enc = match device.create_command_encoder(&desc.label) {
1131                Ok(cmd_enc) => cmd_enc,
1132                Err(e) => break 'error e,
1133            };
1134
1135            let id = fid.assign(cmd_enc);
1136            api_log!("Device::create_command_encoder -> {id:?}");
1137            return (id, None);
1138        };
1139
1140        let id = fid.assign(Arc::new(CommandEncoder::new_invalid(
1141            &device,
1142            &desc.label,
1143            error.clone().into(),
1144        )));
1145        (id, Some(error))
1146    }
1147
1148    pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
1149        profiling::scope!("CommandEncoder::drop");
1150        api_log!("CommandEncoder::drop {command_encoder_id:?}");
1151        let _cmd_enc = self.hub.command_encoders.remove(command_encoder_id);
1152    }
1153
1154    pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
1155        profiling::scope!("CommandBuffer::drop");
1156        api_log!("CommandBuffer::drop {command_buffer_id:?}");
1157        let _cmd_buf = self.hub.command_buffers.remove(command_buffer_id);
1158    }
1159
1160    pub fn device_create_render_bundle_encoder(
1161        &self,
1162        device_id: DeviceId,
1163        desc: &command::RenderBundleEncoderDescriptor,
1164    ) -> (
1165        *mut command::RenderBundleEncoder,
1166        Option<command::CreateRenderBundleError>,
1167    ) {
1168        profiling::scope!("Device::create_render_bundle_encoder");
1169        api_log!("Device::device_create_render_bundle_encoder");
1170        let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id) {
1171            Ok(encoder) => (encoder, None),
1172            Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)),
1173        };
1174        (Box::into_raw(Box::new(encoder)), error)
1175    }
1176
1177    pub fn render_bundle_encoder_finish(
1178        &self,
1179        bundle_encoder: command::RenderBundleEncoder,
1180        desc: &command::RenderBundleDescriptor,
1181        id_in: Option<id::RenderBundleId>,
1182    ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
1183        profiling::scope!("RenderBundleEncoder::finish");
1184
1185        let hub = &self.hub;
1186
1187        let fid = hub.render_bundles.prepare(id_in);
1188
1189        let error = 'error: {
1190            let device = self.hub.devices.get(bundle_encoder.parent());
1191
1192            #[cfg(feature = "trace")]
1193            let trace_desc = trace::new_render_bundle_encoder_descriptor(
1194                desc.label.clone(),
1195                &bundle_encoder.context,
1196                bundle_encoder.is_depth_read_only,
1197                bundle_encoder.is_stencil_read_only,
1198            );
1199
1200            let render_bundle = match bundle_encoder.finish(desc, &device, hub) {
1201                Ok(bundle) => bundle,
1202                Err(e) => break 'error e,
1203            };
1204
1205            #[cfg(feature = "trace")]
1206            if let Some(ref mut trace) = *device.trace.lock() {
1207                trace.add(trace::Action::CreateRenderBundle {
1208                    id: render_bundle.to_trace(),
1209                    desc: trace_desc,
1210                    base: render_bundle.to_base_pass().to_trace(),
1211                });
1212            }
1213
1214            let id = fid.assign(Fallible::Valid(render_bundle));
1215            api_log!("RenderBundleEncoder::finish -> {id:?}");
1216
1217            return (id, None);
1218        };
1219
1220        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1221        (id, Some(error))
1222    }
1223
1224    pub fn render_bundle_drop(&self, render_bundle_id: id::RenderBundleId) {
1225        profiling::scope!("RenderBundle::drop");
1226        api_log!("RenderBundle::drop {render_bundle_id:?}");
1227
1228        let hub = &self.hub;
1229
1230        let _bundle = hub.render_bundles.remove(render_bundle_id);
1231
1232        #[cfg(feature = "trace")]
1233        if let Ok(bundle) = _bundle.get() {
1234            if let Some(t) = bundle.device.trace.lock().as_mut() {
1235                t.add(trace::Action::DestroyRenderBundle(bundle.to_trace()));
1236            }
1237        }
1238    }
1239
1240    pub fn device_create_query_set(
1241        &self,
1242        device_id: DeviceId,
1243        desc: &resource::QuerySetDescriptor,
1244        id_in: Option<id::QuerySetId>,
1245    ) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
1246        profiling::scope!("Device::create_query_set");
1247
1248        let hub = &self.hub;
1249        let fid = hub.query_sets.prepare(id_in);
1250
1251        let error = 'error: {
1252            let device = self.hub.devices.get(device_id);
1253
1254            let query_set = match device.create_query_set(desc) {
1255                Ok(query_set) => query_set,
1256                Err(err) => break 'error err,
1257            };
1258
1259            #[cfg(feature = "trace")]
1260            if let Some(ref mut trace) = *device.trace.lock() {
1261                trace.add(trace::Action::CreateQuerySet {
1262                    id: query_set.to_trace(),
1263                    desc: desc.clone(),
1264                });
1265            }
1266
1267            let id = fid.assign(Fallible::Valid(query_set));
1268            api_log!("Device::create_query_set -> {id:?}");
1269
1270            return (id, None);
1271        };
1272
1273        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1274        (id, Some(error))
1275    }
1276
1277    pub fn query_set_drop(&self, query_set_id: id::QuerySetId) {
1278        profiling::scope!("QuerySet::drop");
1279        api_log!("QuerySet::drop {query_set_id:?}");
1280
1281        let hub = &self.hub;
1282
1283        let _query_set = hub.query_sets.remove(query_set_id);
1284
1285        #[cfg(feature = "trace")]
1286        if let Ok(query_set) = _query_set.get() {
1287            if let Some(trace) = query_set.device.trace.lock().as_mut() {
1288                trace.add(trace::Action::DestroyQuerySet(query_set.to_trace()));
1289            }
1290        }
1291    }
1292
1293    pub fn device_create_render_pipeline(
1294        &self,
1295        device_id: DeviceId,
1296        desc: &pipeline::RenderPipelineDescriptor,
1297        id_in: Option<id::RenderPipelineId>,
1298    ) -> (
1299        id::RenderPipelineId,
1300        Option<pipeline::CreateRenderPipelineError>,
1301    ) {
1302        profiling::scope!("Device::create_render_pipeline");
1303
1304        let hub = &self.hub;
1305
1306        let fid = hub.render_pipelines.prepare(id_in);
1307
1308        let device = self.hub.devices.get(device_id);
1309
1310        self.device_create_general_render_pipeline(desc.clone().into(), device, fid)
1311    }
1312
1313    pub fn device_create_mesh_pipeline(
1314        &self,
1315        device_id: DeviceId,
1316        desc: &pipeline::MeshPipelineDescriptor,
1317        id_in: Option<id::RenderPipelineId>,
1318    ) -> (
1319        id::RenderPipelineId,
1320        Option<pipeline::CreateRenderPipelineError>,
1321    ) {
1322        let hub = &self.hub;
1323
1324        let fid = hub.render_pipelines.prepare(id_in);
1325
1326        let device = self.hub.devices.get(device_id);
1327        self.device_create_general_render_pipeline(desc.clone().into(), device, fid)
1328    }
1329
1330    fn device_create_general_render_pipeline(
1331        &self,
1332        desc: pipeline::GeneralRenderPipelineDescriptor,
1333        device: Arc<crate::device::resource::Device>,
1334        fid: crate::registry::FutureId<Fallible<pipeline::RenderPipeline>>,
1335    ) -> (
1336        id::RenderPipelineId,
1337        Option<pipeline::CreateRenderPipelineError>,
1338    ) {
1339        profiling::scope!("Device::create_general_render_pipeline");
1340
1341        let hub = &self.hub;
1342
1343        let error = 'error: {
1344            if let Err(e) = device.check_is_valid() {
1345                break 'error e.into();
1346            }
1347
1348            let layout = desc
1349                .layout
1350                .map(|layout| hub.pipeline_layouts.get(layout).get())
1351                .transpose();
1352            let layout = match layout {
1353                Ok(layout) => layout,
1354                Err(e) => break 'error e.into(),
1355            };
1356
1357            let cache = desc
1358                .cache
1359                .map(|cache| hub.pipeline_caches.get(cache).get())
1360                .transpose();
1361            let cache = match cache {
1362                Ok(cache) => cache,
1363                Err(e) => break 'error e.into(),
1364            };
1365
1366            let vertex = match desc.vertex {
1367                RenderPipelineVertexProcessor::Vertex(ref vertex) => {
1368                    let module = hub
1369                        .shader_modules
1370                        .get(vertex.stage.module)
1371                        .get()
1372                        .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1373                            stage: wgt::ShaderStages::VERTEX,
1374                            error: e.into(),
1375                        });
1376                    let module = match module {
1377                        Ok(module) => module,
1378                        Err(e) => break 'error e,
1379                    };
1380                    let stage = ResolvedProgrammableStageDescriptor {
1381                        module,
1382                        entry_point: vertex.stage.entry_point.clone(),
1383                        constants: vertex.stage.constants.clone(),
1384                        zero_initialize_workgroup_memory: vertex
1385                            .stage
1386                            .zero_initialize_workgroup_memory,
1387                    };
1388                    RenderPipelineVertexProcessor::Vertex(ResolvedVertexState {
1389                        stage,
1390                        buffers: vertex.buffers.clone(),
1391                    })
1392                }
1393                RenderPipelineVertexProcessor::Mesh(ref task, ref mesh) => {
1394                    let task_module = if let Some(task) = task {
1395                        let module = hub
1396                            .shader_modules
1397                            .get(task.stage.module)
1398                            .get()
1399                            .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1400                                stage: wgt::ShaderStages::VERTEX,
1401                                error: e.into(),
1402                            });
1403                        let module = match module {
1404                            Ok(module) => module,
1405                            Err(e) => break 'error e,
1406                        };
1407                        let state = ResolvedProgrammableStageDescriptor {
1408                            module,
1409                            entry_point: task.stage.entry_point.clone(),
1410                            constants: task.stage.constants.clone(),
1411                            zero_initialize_workgroup_memory: task
1412                                .stage
1413                                .zero_initialize_workgroup_memory,
1414                        };
1415                        Some(ResolvedTaskState { stage: state })
1416                    } else {
1417                        None
1418                    };
1419                    let mesh_module =
1420                        hub.shader_modules
1421                            .get(mesh.stage.module)
1422                            .get()
1423                            .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1424                                stage: wgt::ShaderStages::MESH,
1425                                error: e.into(),
1426                            });
1427                    let mesh_module = match mesh_module {
1428                        Ok(module) => module,
1429                        Err(e) => break 'error e,
1430                    };
1431                    let mesh_stage = ResolvedProgrammableStageDescriptor {
1432                        module: mesh_module,
1433                        entry_point: mesh.stage.entry_point.clone(),
1434                        constants: mesh.stage.constants.clone(),
1435                        zero_initialize_workgroup_memory: mesh
1436                            .stage
1437                            .zero_initialize_workgroup_memory,
1438                    };
1439                    RenderPipelineVertexProcessor::Mesh(
1440                        task_module,
1441                        ResolvedMeshState { stage: mesh_stage },
1442                    )
1443                }
1444            };
1445
1446            let fragment = if let Some(ref state) = desc.fragment {
1447                let module = hub
1448                    .shader_modules
1449                    .get(state.stage.module)
1450                    .get()
1451                    .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1452                        stage: wgt::ShaderStages::FRAGMENT,
1453                        error: e.into(),
1454                    });
1455                let module = match module {
1456                    Ok(module) => module,
1457                    Err(e) => break 'error e,
1458                };
1459                let stage = ResolvedProgrammableStageDescriptor {
1460                    module,
1461                    entry_point: state.stage.entry_point.clone(),
1462                    constants: state.stage.constants.clone(),
1463                    zero_initialize_workgroup_memory: state.stage.zero_initialize_workgroup_memory,
1464                };
1465                Some(ResolvedFragmentState {
1466                    stage,
1467                    targets: state.targets.clone(),
1468                })
1469            } else {
1470                None
1471            };
1472
1473            let desc = ResolvedGeneralRenderPipelineDescriptor {
1474                label: desc.label.clone(),
1475                layout,
1476                vertex,
1477                primitive: desc.primitive,
1478                depth_stencil: desc.depth_stencil.clone(),
1479                multisample: desc.multisample,
1480                fragment,
1481                multiview_mask: desc.multiview_mask,
1482                cache,
1483            };
1484
1485            #[cfg(feature = "trace")]
1486            let trace_desc = desc.clone().into_trace();
1487
1488            let pipeline = match device.create_render_pipeline(desc) {
1489                Ok(pair) => pair,
1490                Err(e) => break 'error e,
1491            };
1492
1493            #[cfg(feature = "trace")]
1494            if let Some(ref mut trace) = *device.trace.lock() {
1495                trace.add(trace::Action::CreateGeneralRenderPipeline {
1496                    id: pipeline.to_trace(),
1497                    desc: trace_desc,
1498                });
1499            }
1500
1501            let id = fid.assign(Fallible::Valid(pipeline));
1502            api_log!("Device::create_render_pipeline -> {id:?}");
1503
1504            return (id, None);
1505        };
1506
1507        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1508
1509        (id, Some(error))
1510    }
1511
1512    /// Get an ID of one of the bind group layouts. The ID adds a refcount,
1513    /// which needs to be released by calling `bind_group_layout_drop`.
1514    pub fn render_pipeline_get_bind_group_layout(
1515        &self,
1516        pipeline_id: id::RenderPipelineId,
1517        index: u32,
1518        id_in: Option<id::BindGroupLayoutId>,
1519    ) -> (
1520        id::BindGroupLayoutId,
1521        Option<binding_model::GetBindGroupLayoutError>,
1522    ) {
1523        let hub = &self.hub;
1524
1525        let fid = hub.bind_group_layouts.prepare(id_in);
1526
1527        let error = 'error: {
1528            let pipeline = match hub.render_pipelines.get(pipeline_id).get() {
1529                Ok(pipeline) => pipeline,
1530                Err(e) => break 'error e.into(),
1531            };
1532            let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1533                Some(bg) => fid.assign(Fallible::Valid(bg.clone())),
1534                None => {
1535                    break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index)
1536                }
1537            };
1538            return (id, None);
1539        };
1540
1541        let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1542        (id, Some(error))
1543    }
1544
1545    pub fn render_pipeline_drop(&self, render_pipeline_id: id::RenderPipelineId) {
1546        profiling::scope!("RenderPipeline::drop");
1547        api_log!("RenderPipeline::drop {render_pipeline_id:?}");
1548
1549        let hub = &self.hub;
1550
1551        let _pipeline = hub.render_pipelines.remove(render_pipeline_id);
1552
1553        #[cfg(feature = "trace")]
1554        if let Ok(pipeline) = _pipeline.get() {
1555            if let Some(t) = pipeline.device.trace.lock().as_mut() {
1556                t.add(trace::Action::DestroyRenderPipeline(pipeline.to_trace()));
1557            }
1558        }
1559    }
1560
1561    pub fn device_create_compute_pipeline(
1562        &self,
1563        device_id: DeviceId,
1564        desc: &pipeline::ComputePipelineDescriptor,
1565        id_in: Option<id::ComputePipelineId>,
1566    ) -> (
1567        id::ComputePipelineId,
1568        Option<pipeline::CreateComputePipelineError>,
1569    ) {
1570        profiling::scope!("Device::create_compute_pipeline");
1571
1572        let hub = &self.hub;
1573
1574        let fid = hub.compute_pipelines.prepare(id_in);
1575
1576        let error = 'error: {
1577            let device = self.hub.devices.get(device_id);
1578
1579            if let Err(e) = device.check_is_valid() {
1580                break 'error e.into();
1581            }
1582
1583            let layout = desc
1584                .layout
1585                .map(|layout| hub.pipeline_layouts.get(layout).get())
1586                .transpose();
1587            let layout = match layout {
1588                Ok(layout) => layout,
1589                Err(e) => break 'error e.into(),
1590            };
1591
1592            let cache = desc
1593                .cache
1594                .map(|cache| hub.pipeline_caches.get(cache).get())
1595                .transpose();
1596            let cache = match cache {
1597                Ok(cache) => cache,
1598                Err(e) => break 'error e.into(),
1599            };
1600
1601            let module = hub.shader_modules.get(desc.stage.module).get();
1602            let module = match module {
1603                Ok(module) => module,
1604                Err(e) => break 'error e.into(),
1605            };
1606            let stage = ResolvedProgrammableStageDescriptor {
1607                module,
1608                entry_point: desc.stage.entry_point.clone(),
1609                constants: desc.stage.constants.clone(),
1610                zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
1611            };
1612
1613            let desc = ResolvedComputePipelineDescriptor {
1614                label: desc.label.clone(),
1615                layout,
1616                stage,
1617                cache,
1618            };
1619
1620            #[cfg(feature = "trace")]
1621            let trace_desc = desc.clone().into_trace();
1622
1623            let pipeline = match device.create_compute_pipeline(desc) {
1624                Ok(pair) => pair,
1625                Err(e) => break 'error e,
1626            };
1627
1628            #[cfg(feature = "trace")]
1629            if let Some(ref mut trace) = *device.trace.lock() {
1630                trace.add(trace::Action::CreateComputePipeline {
1631                    id: pipeline.to_trace(),
1632                    desc: trace_desc,
1633                });
1634            }
1635
1636            let id = fid.assign(Fallible::Valid(pipeline));
1637            api_log!("Device::create_compute_pipeline -> {id:?}");
1638
1639            return (id, None);
1640        };
1641
1642        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1643
1644        (id, Some(error))
1645    }
1646
1647    /// Get an ID of one of the bind group layouts. The ID adds a refcount,
1648    /// which needs to be released by calling `bind_group_layout_drop`.
1649    pub fn compute_pipeline_get_bind_group_layout(
1650        &self,
1651        pipeline_id: id::ComputePipelineId,
1652        index: u32,
1653        id_in: Option<id::BindGroupLayoutId>,
1654    ) -> (
1655        id::BindGroupLayoutId,
1656        Option<binding_model::GetBindGroupLayoutError>,
1657    ) {
1658        let hub = &self.hub;
1659
1660        let fid = hub.bind_group_layouts.prepare(id_in);
1661
1662        let error = 'error: {
1663            let pipeline = match hub.compute_pipelines.get(pipeline_id).get() {
1664                Ok(pipeline) => pipeline,
1665                Err(e) => break 'error e.into(),
1666            };
1667
1668            let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1669                Some(bg) => fid.assign(Fallible::Valid(bg.clone())),
1670                None => {
1671                    break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index)
1672                }
1673            };
1674
1675            return (id, None);
1676        };
1677
1678        let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1679        (id, Some(error))
1680    }
1681
1682    pub fn compute_pipeline_drop(&self, compute_pipeline_id: id::ComputePipelineId) {
1683        profiling::scope!("ComputePipeline::drop");
1684        api_log!("ComputePipeline::drop {compute_pipeline_id:?}");
1685
1686        let hub = &self.hub;
1687
1688        let _pipeline = hub.compute_pipelines.remove(compute_pipeline_id);
1689
1690        #[cfg(feature = "trace")]
1691        if let Ok(pipeline) = _pipeline.get() {
1692            if let Some(t) = pipeline.device.trace.lock().as_mut() {
1693                t.add(trace::Action::DestroyComputePipeline(pipeline.to_trace()));
1694            }
1695        }
1696    }
1697
1698    /// # Safety
1699    /// The `data` argument of `desc` must have been returned by
1700    /// [Self::pipeline_cache_get_data] for the same adapter
1701    pub unsafe fn device_create_pipeline_cache(
1702        &self,
1703        device_id: DeviceId,
1704        desc: &pipeline::PipelineCacheDescriptor<'_>,
1705        id_in: Option<id::PipelineCacheId>,
1706    ) -> (
1707        id::PipelineCacheId,
1708        Option<pipeline::CreatePipelineCacheError>,
1709    ) {
1710        profiling::scope!("Device::create_pipeline_cache");
1711
1712        let hub = &self.hub;
1713
1714        let fid = hub.pipeline_caches.prepare(id_in);
1715        let error: pipeline::CreatePipelineCacheError = 'error: {
1716            let device = self.hub.devices.get(device_id);
1717
1718            let cache = unsafe { device.create_pipeline_cache(desc) };
1719            match cache {
1720                Ok(cache) => {
1721                    #[cfg(feature = "trace")]
1722                    if let Some(ref mut trace) = *device.trace.lock() {
1723                        trace.add(trace::Action::CreatePipelineCache {
1724                            id: cache.to_trace(),
1725                            desc: desc.clone(),
1726                        });
1727                    }
1728
1729                    let id = fid.assign(Fallible::Valid(cache));
1730                    api_log!("Device::create_pipeline_cache -> {id:?}");
1731                    return (id, None);
1732                }
1733                Err(e) => break 'error e,
1734            }
1735        };
1736
1737        let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1738
1739        (id, Some(error))
1740    }
1741
1742    pub fn pipeline_cache_drop(&self, pipeline_cache_id: id::PipelineCacheId) {
1743        profiling::scope!("PipelineCache::drop");
1744        api_log!("PipelineCache::drop {pipeline_cache_id:?}");
1745
1746        let hub = &self.hub;
1747
1748        let _cache = hub.pipeline_caches.remove(pipeline_cache_id);
1749
1750        #[cfg(feature = "trace")]
1751        if let Ok(cache) = _cache.get() {
1752            if let Some(t) = cache.device.trace.lock().as_mut() {
1753                t.add(trace::Action::DestroyPipelineCache(cache.to_trace()));
1754            }
1755        }
1756    }
1757
1758    pub fn surface_configure(
1759        &self,
1760        surface_id: SurfaceId,
1761        device_id: DeviceId,
1762        config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
1763    ) -> Option<present::ConfigureSurfaceError> {
1764        let device = self.hub.devices.get(device_id);
1765        let surface = self.surfaces.get(surface_id);
1766
1767        #[cfg(feature = "trace")]
1768        if let Some(ref mut trace) = *device.trace.lock() {
1769            trace.add(trace::Action::ConfigureSurface(
1770                surface.to_trace(),
1771                config.clone(),
1772            ));
1773        }
1774
1775        device.configure_surface(&surface, config)
1776    }
1777
1778    /// Check `device_id` for freeable resources and completed buffer mappings.
1779    ///
1780    /// Return `queue_empty` indicating whether there are more queue submissions still in flight.
1781    pub fn device_poll(
1782        &self,
1783        device_id: DeviceId,
1784        poll_type: wgt::PollType<crate::SubmissionIndex>,
1785    ) -> Result<wgt::PollStatus, WaitIdleError> {
1786        api_log!("Device::poll {poll_type:?}");
1787
1788        let device = self.hub.devices.get(device_id);
1789
1790        let (closures, result) = device.poll_and_return_closures(poll_type);
1791
1792        closures.fire();
1793
1794        result
1795    }
1796
1797    /// Poll all devices belonging to the specified backend.
1798    ///
1799    /// If `force_wait` is true, block until all buffer mappings are done.
1800    ///
1801    /// Return `all_queue_empty` indicating whether there are more queue
1802    /// submissions still in flight.
1803    fn poll_all_devices_of_api(
1804        &self,
1805        force_wait: bool,
1806        closure_list: &mut UserClosures,
1807    ) -> Result<bool, WaitIdleError> {
1808        profiling::scope!("poll_device");
1809
1810        let hub = &self.hub;
1811        let mut all_queue_empty = true;
1812        {
1813            let device_guard = hub.devices.read();
1814
1815            for (_id, device) in device_guard.iter() {
1816                let poll_type = if force_wait {
1817                    // TODO(#8286): Should expose timeout to poll_all.
1818                    wgt::PollType::wait_indefinitely()
1819                } else {
1820                    wgt::PollType::Poll
1821                };
1822
1823                let (closures, result) = device.poll_and_return_closures(poll_type);
1824
1825                let is_queue_empty = matches!(result, Ok(wgt::PollStatus::QueueEmpty));
1826
1827                all_queue_empty &= is_queue_empty;
1828
1829                closure_list.extend(closures);
1830            }
1831        }
1832
1833        Ok(all_queue_empty)
1834    }
1835
1836    /// Poll all devices on all backends.
1837    ///
1838    /// This is the implementation of `wgpu::Instance::poll_all`.
1839    ///
1840    /// Return `all_queue_empty` indicating whether there are more queue
1841    /// submissions still in flight.
1842    pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
1843        api_log!("poll_all_devices");
1844        let mut closures = UserClosures::default();
1845        let all_queue_empty = self.poll_all_devices_of_api(force_wait, &mut closures)?;
1846
1847        closures.fire();
1848
1849        Ok(all_queue_empty)
1850    }
1851
1852    /// # Safety
1853    ///
1854    /// - See [wgpu::Device::start_graphics_debugger_capture][api] for details the safety.
1855    ///
1856    /// [api]: ../../wgpu/struct.Device.html#method.start_graphics_debugger_capture
1857    pub unsafe fn device_start_graphics_debugger_capture(&self, device_id: DeviceId) {
1858        unsafe {
1859            self.hub
1860                .devices
1861                .get(device_id)
1862                .start_graphics_debugger_capture();
1863        }
1864    }
1865
1866    /// # Safety
1867    ///
1868    /// - See [wgpu::Device::stop_graphics_debugger_capture][api] for details the safety.
1869    ///
1870    /// [api]: ../../wgpu/struct.Device.html#method.stop_graphics_debugger_capture
1871    pub unsafe fn device_stop_graphics_debugger_capture(&self, device_id: DeviceId) {
1872        unsafe {
1873            self.hub
1874                .devices
1875                .get(device_id)
1876                .stop_graphics_debugger_capture();
1877        }
1878    }
1879
1880    pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option<Vec<u8>> {
1881        use crate::pipeline_cache;
1882        api_log!("PipelineCache::get_data");
1883        let hub = &self.hub;
1884
1885        if let Ok(cache) = hub.pipeline_caches.get(id).get() {
1886            // TODO: Is this check needed?
1887            if !cache.device.is_valid() {
1888                return None;
1889            }
1890            let mut vec = unsafe { cache.device.raw().pipeline_cache_get_data(cache.raw()) }?;
1891            let validation_key = cache.device.raw().pipeline_cache_validation_key()?;
1892
1893            let mut header_contents = [0; pipeline_cache::HEADER_LENGTH];
1894            pipeline_cache::add_cache_header(
1895                &mut header_contents,
1896                &vec,
1897                &cache.device.adapter.raw.info,
1898                validation_key,
1899            );
1900
1901            let deleted = vec.splice(..0, header_contents).collect::<Vec<_>>();
1902            debug_assert!(deleted.is_empty());
1903
1904            return Some(vec);
1905        }
1906        None
1907    }
1908
1909    pub fn device_drop(&self, device_id: DeviceId) {
1910        profiling::scope!("Device::drop");
1911        api_log!("Device::drop {device_id:?}");
1912
1913        self.hub.devices.remove(device_id);
1914    }
1915
1916    /// `device_lost_closure` might never be called.
1917    pub fn device_set_device_lost_closure(
1918        &self,
1919        device_id: DeviceId,
1920        device_lost_closure: DeviceLostClosure,
1921    ) {
1922        let device = self.hub.devices.get(device_id);
1923
1924        device
1925            .device_lost_closure
1926            .lock()
1927            .replace(device_lost_closure);
1928    }
1929
1930    pub fn device_destroy(&self, device_id: DeviceId) {
1931        api_log!("Device::destroy {device_id:?}");
1932
1933        let device = self.hub.devices.get(device_id);
1934
1935        // Follow the steps at
1936        // https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy.
1937        // It's legal to call destroy multiple times, but if the device
1938        // is already invalid, there's nothing more to do. There's also
1939        // no need to return an error.
1940        if !device.is_valid() {
1941            return;
1942        }
1943
1944        // The last part of destroy is to lose the device. The spec says
1945        // delay that until all "currently-enqueued operations on any
1946        // queue on this device are completed." This is accomplished by
1947        // setting valid to false, and then relying upon maintain to
1948        // check for empty queues and a DeviceLostClosure. At that time,
1949        // the DeviceLostClosure will be called with "destroyed" as the
1950        // reason.
1951        device.valid.store(false, Ordering::Release);
1952    }
1953
1954    pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters {
1955        let device = self.hub.devices.get(device_id);
1956        wgt::InternalCounters {
1957            hal: device.get_hal_counters(),
1958            core: wgt::CoreCounters {},
1959        }
1960    }
1961
1962    pub fn device_generate_allocator_report(
1963        &self,
1964        device_id: DeviceId,
1965    ) -> Option<wgt::AllocatorReport> {
1966        let device = self.hub.devices.get(device_id);
1967        device.generate_allocator_report()
1968    }
1969
1970    pub fn queue_drop(&self, queue_id: QueueId) {
1971        profiling::scope!("Queue::drop");
1972        api_log!("Queue::drop {queue_id:?}");
1973
1974        self.hub.queues.remove(queue_id);
1975    }
1976
1977    /// `op.callback` is guaranteed to be called.
1978    pub fn buffer_map_async(
1979        &self,
1980        buffer_id: id::BufferId,
1981        offset: BufferAddress,
1982        size: Option<BufferAddress>,
1983        op: BufferMapOperation,
1984    ) -> Result<crate::SubmissionIndex, BufferAccessError> {
1985        profiling::scope!("Buffer::map_async");
1986        api_log!("Buffer::map_async {buffer_id:?} offset {offset:?} size {size:?} op: {op:?}");
1987
1988        let hub = &self.hub;
1989
1990        let map_result = match hub.buffers.get(buffer_id).get() {
1991            Ok(buffer) => buffer.map_async(offset, size, op),
1992            Err(e) => Err((op, e.into())),
1993        };
1994
1995        match map_result {
1996            Ok(submission_index) => Ok(submission_index),
1997            Err((mut operation, err)) => {
1998                if let Some(callback) = operation.callback.take() {
1999                    callback(Err(err.clone()));
2000                }
2001                Err(err)
2002            }
2003        }
2004    }
2005
2006    pub fn buffer_get_mapped_range(
2007        &self,
2008        buffer_id: id::BufferId,
2009        offset: BufferAddress,
2010        size: Option<BufferAddress>,
2011    ) -> Result<(NonNull<u8>, u64), BufferAccessError> {
2012        profiling::scope!("Buffer::get_mapped_range");
2013        api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
2014
2015        let hub = &self.hub;
2016
2017        let buffer = hub.buffers.get(buffer_id).get()?;
2018
2019        buffer.get_mapped_range(offset, size)
2020    }
2021
2022    pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult {
2023        profiling::scope!("unmap", "Buffer");
2024        api_log!("Buffer::unmap {buffer_id:?}");
2025
2026        let hub = &self.hub;
2027
2028        let buffer = hub.buffers.get(buffer_id).get()?;
2029
2030        let snatch_guard = buffer.device.snatchable_lock.read();
2031        buffer.check_destroyed(&snatch_guard)?;
2032        drop(snatch_guard);
2033
2034        buffer.device.check_is_valid()?;
2035        buffer.unmap()
2036    }
2037}