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