Skip to main content

wgpu_core/device/
global.rs

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