wgpu_core/device/
global.rs

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