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