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