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