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