wgpu_core/device/
global.rs

1use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
2use core::ptr::NonNull;
3
4#[cfg(feature = "trace")]
5use crate::device::trace;
6use crate::{
7    binding_model::{self},
8    command,
9    device::{life::WaitIdleError, DeviceError, DeviceLostClosure},
10    global::Global,
11    id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
12    instance::{self, Adapter, Surface},
13    pipeline::{
14        self, MeshState, ProgrammableStageDescriptor, RenderPipelineVertexProcessor,
15        ResolvedGeneralRenderPipelineDescriptor, TaskState,
16    },
17    present,
18    resource::{
19        self, BufferAccessError, BufferAccessResult, BufferMapOperation, CreateBufferError,
20    },
21    storage::Storage,
22    Label, LabelHelpers,
23};
24
25use wgt::{BufferAddress, TextureFormat};
26
27pub type BindGroupDescriptor<'a> = binding_model::BindGroupDescriptor<
28    'a,
29    id::BindGroupLayoutId,
30    id::BufferId,
31    id::SamplerId,
32    id::TextureViewId,
33    id::TlasId,
34    id::ExternalTextureId,
35>;
36
37pub type BindGroupEntry<'a> = binding_model::BindGroupEntry<
38    'a,
39    id::BufferId,
40    id::SamplerId,
41    id::TextureViewId,
42    id::TlasId,
43    id::ExternalTextureId,
44>;
45
46pub type BufferBinding = binding_model::BufferBinding<id::BufferId>;
47
48pub type BindingResource<'a> = binding_model::BindingResource<
49    'a,
50    id::BufferId,
51    id::SamplerId,
52    id::TextureViewId,
53    id::TlasId,
54    id::ExternalTextureId,
55>;
56
57pub type ComputePipelineDescriptor<'a> = pipeline::ComputePipelineDescriptor<
58    'a,
59    id::PipelineLayoutId,
60    id::ShaderModuleId,
61    id::PipelineCacheId,
62>;
63
64pub type VertexState<'a> = pipeline::VertexState<'a, id::ShaderModuleId>;
65
66pub type MeshPipelineDescriptor<'a> = pipeline::MeshPipelineDescriptor<
67    'a,
68    id::PipelineLayoutId,
69    id::ShaderModuleId,
70    id::PipelineCacheId,
71>;
72
73pub type RenderPipelineDescriptor<'a> = pipeline::RenderPipelineDescriptor<
74    'a,
75    id::PipelineLayoutId,
76    id::ShaderModuleId,
77    id::PipelineCacheId,
78>;
79
80pub type GeneralRenderPipelineDescriptor<'a> = pipeline::GeneralRenderPipelineDescriptor<
81    'a,
82    id::PipelineLayoutId,
83    id::ShaderModuleId,
84    id::PipelineCacheId,
85>;
86
87impl Global {
88    pub fn adapter_is_surface_supported(
89        &self,
90        adapter_id: AdapterId,
91        surface_id: SurfaceId,
92    ) -> bool {
93        let surface = self.surfaces.get(surface_id);
94        let adapter = self.hub.adapters.get(adapter_id);
95        adapter.is_surface_supported(&surface)
96    }
97
98    pub fn surface_get_capabilities(
99        &self,
100        surface_id: SurfaceId,
101        adapter_id: AdapterId,
102    ) -> Result<wgt::SurfaceCapabilities, instance::GetSurfaceSupportError> {
103        self.fetch_adapter_and_surface::<_, _>(surface_id, adapter_id, |adapter, surface| {
104            surface.get_capabilities(adapter)
105        })
106    }
107
108    /// Returns the HDR and luminance characteristics of the display backing
109    /// `surface_id` on `adapter_id`.
110    ///
111    /// Reports the raw display state, independent of the surface's configured
112    /// color space; see [`wgt::DisplayHdrInfo`] for per-field platform coverage.
113    /// Returns [`wgt::DisplayHdrInfo::default`] (all fields `None`) when nothing
114    /// is known: the surface is not on `adapter_id`'s backend, the backend has
115    /// no display-query path, or the Metal backend is queried off the main
116    /// thread.
117    pub fn surface_display_hdr_info(
118        &self,
119        surface_id: SurfaceId,
120        adapter_id: AdapterId,
121    ) -> wgt::DisplayHdrInfo {
122        self.fetch_adapter_and_surface(surface_id, adapter_id, |adapter, surface| {
123            surface.display_hdr_info(adapter)
124        })
125    }
126
127    fn fetch_adapter_and_surface<F: FnOnce(&Adapter, &Surface) -> B, B>(
128        &self,
129        surface_id: SurfaceId,
130        adapter_id: AdapterId,
131        get_supported_callback: F,
132    ) -> B {
133        let surface = self.surfaces.get(surface_id);
134        let adapter = self.hub.adapters.get(adapter_id);
135        get_supported_callback(&adapter, &surface)
136    }
137
138    pub fn device_features(&self, device_id: DeviceId) -> wgt::Features {
139        let device = self.hub.devices.get(device_id);
140        *device.features()
141    }
142
143    pub fn device_limits(&self, device_id: DeviceId) -> wgt::Limits {
144        let device = self.hub.devices.get(device_id);
145        device.limits().clone()
146    }
147
148    pub fn device_adapter_info(&self, device_id: DeviceId) -> wgt::AdapterInfo {
149        let device = self.hub.devices.get(device_id);
150        device.adapter.get_info()
151    }
152
153    pub fn device_downlevel_properties(&self, device_id: DeviceId) -> wgt::DownlevelCapabilities {
154        let device = self.hub.devices.get(device_id);
155        device.downlevel().clone()
156    }
157
158    pub fn device_create_buffer(
159        &self,
160        device_id: DeviceId,
161        desc: &resource::BufferDescriptor,
162        id_in: Option<id::BufferId>,
163    ) -> (id::BufferId, Option<CreateBufferError>) {
164        let hub = &self.hub;
165        let fid = hub.buffers.prepare(id_in);
166
167        let device = self.hub.devices.get(device_id);
168
169        let (buffer, error) = device.create_buffer(desc);
170
171        let id = fid.assign(buffer);
172
173        (id, error)
174    }
175
176    /// Assign `id_in` an error with the given `label`.
177    ///
178    /// Ensure that future attempts to use `id_in` as a buffer ID will propagate
179    /// the error, following the WebGPU ["contagious invalidity"] style.
180    ///
181    /// Firefox uses this function to comply strictly with the WebGPU spec,
182    /// which requires [`GPUBufferDescriptor`] validation to be generated on the
183    /// Device timeline and leave the newly created [`GPUBuffer`] invalid.
184    ///
185    /// Ideally, we would simply let [`Device::create_buffer`] take care of all
186    /// of this, but some errors must be detected before we can even construct a
187    /// [`wgpu_types::BufferDescriptor`] to give it. For example, the WebGPU API
188    /// allows a `GPUBufferDescriptor`'s [`usage`] property to be any WebIDL
189    /// `unsigned long` value, but we can't construct a
190    /// [`wgpu_types::BufferUsages`] value from values with unassigned bits
191    /// set. This means we must validate `usage` before we can call
192    /// `Device::create_buffer`.
193    ///
194    /// When that validation fails, we must arrange for the buffer id to be
195    /// considered invalid. This method provides the means to do so.
196    ///
197    /// ["contagious invalidity"]: https://www.w3.org/TR/webgpu/#invalidity
198    /// [`GPUBufferDescriptor`]: https://www.w3.org/TR/webgpu/#dictdef-gpubufferdescriptor
199    /// [`GPUBuffer`]: https://www.w3.org/TR/webgpu/#gpubuffer
200    /// [`wgpu_types::BufferDescriptor`]: wgt::BufferDescriptor
201    /// [`Device::create_buffer`]: crate::device::Device::create_buffer
202    /// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage
203    /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages
204    pub fn create_buffer_error(
205        &self,
206        device_id: DeviceId,
207        id_in: Option<id::BufferId>,
208        desc: &resource::BufferDescriptor,
209    ) {
210        let fid = self.hub.buffers.prepare(id_in);
211        let device = self.hub.devices.get(device_id);
212        fid.assign(resource::Buffer::invalid(device, desc));
213    }
214
215    /// Assign `id_in` an error with the given `label`.
216    ///
217    /// See [`Self::create_buffer_error`] for more context and explanation.
218    pub fn create_render_bundle_error(
219        &self,
220        device_id: DeviceId,
221        id_in: Option<id::RenderBundleId>,
222        desc: &command::RenderBundleDescriptor,
223    ) {
224        let device = self.hub.devices.get(device_id);
225        let fid = self.hub.render_bundles.prepare(id_in);
226        fid.assign(command::RenderBundle::invalid(device, desc));
227    }
228
229    /// Assign `id_in` an error with the given `label`.
230    ///
231    /// See [`Self::create_buffer_error`] for more context and explanation.
232    pub fn create_texture_error(
233        &self,
234        device_id: DeviceId,
235        id_in: Option<id::TextureId>,
236        desc: &resource::TextureDescriptor,
237    ) -> id::TextureId {
238        let fid = self.hub.textures.prepare(id_in);
239        let device = self.hub.devices.get(device_id);
240        let texture = device.create_texture_error(desc);
241        fid.assign(texture)
242    }
243
244    /// Assign `id_in` an error with the given `label`.
245    ///
246    /// See [`Self::create_buffer_error`] for more context and explanation.
247    pub fn create_external_texture_error(
248        &self,
249        device_id: DeviceId,
250        id_in: Option<id::ExternalTextureId>,
251        desc: &resource::ExternalTextureDescriptor,
252    ) {
253        let fid = self.hub.external_textures.prepare(id_in);
254        let device = self.hub.devices.get(device_id);
255        fid.assign(resource::ExternalTexture::invalid(device, desc));
256    }
257
258    /// Assign `id_in` an error with the given `label`.
259    ///
260    /// In JavaScript environments, it is possible to call `GPUDevice.createBindGroupLayout` with
261    /// entries that are invalid. Because our Rust's types for bind group layouts prevent even
262    /// calling [`Self::device_create_bind_group`], we let standards-compliant environments
263    /// register an invalid bind group layout so this crate's API can still be consistently used.
264    ///
265    /// See [`Self::create_buffer_error`] for additional context and explanation.
266    pub fn create_bind_group_layout_error(
267        &self,
268        device_id: DeviceId,
269        id_in: Option<id::BindGroupLayoutId>,
270        label: Option<Cow<'_, str>>,
271    ) {
272        let fid = self.hub.bind_group_layouts.prepare(id_in);
273        let device = self.hub.devices.get(device_id);
274        fid.assign(binding_model::BindGroupLayout::invalid(
275            &device,
276            label.to_string(),
277        ));
278    }
279
280    pub fn buffer_destroy(&self, buffer_id: id::BufferId) {
281        let hub = &self.hub;
282
283        let buffer = hub.buffers.get(buffer_id);
284
285        buffer.destroy();
286    }
287
288    pub fn buffer_drop(&self, buffer_id: id::BufferId) {
289        let hub = &self.hub;
290
291        let _buffer = hub.buffers.remove(buffer_id);
292    }
293
294    pub fn device_create_texture(
295        &self,
296        device_id: DeviceId,
297        desc: &resource::TextureDescriptor,
298        id_in: Option<id::TextureId>,
299    ) -> (id::TextureId, Option<resource::CreateTextureError>) {
300        let hub = &self.hub;
301
302        let fid = hub.textures.prepare(id_in);
303
304        let device = self.hub.devices.get(device_id);
305
306        let (texture, error) = device.create_texture(desc);
307
308        let id = fid.assign(texture);
309
310        (id, error)
311    }
312
313    pub fn device_validate_texture_descriptor(
314        &self,
315        device_id: DeviceId,
316        desc: &resource::TextureDescriptor,
317    ) -> Option<resource::CreateTextureError> {
318        self.hub
319            .devices
320            .get(device_id)
321            .validate_texture_descriptor(desc)
322            .err()
323    }
324
325    /// # Safety
326    ///
327    /// - `hal_texture` must be created from `device_id` corresponding raw handle.
328    /// - `hal_texture` must be created respecting `desc`
329    /// - `hal_texture` must be initialized
330    /// - The `initial_state` must match the actual driver-side state of
331    ///   the wrapped resource at the moment of wrap.
332    pub unsafe fn create_texture_from_hal(
333        &self,
334        hal_texture: Box<dyn hal::DynTexture>,
335        device_id: DeviceId,
336        desc: &resource::TextureDescriptor,
337        initial_state: wgt::TextureUses,
338        id_in: Option<id::TextureId>,
339    ) -> (id::TextureId, Option<resource::CreateTextureError>) {
340        let hub = &self.hub;
341
342        let fid = hub.textures.prepare(id_in);
343
344        let device = self.hub.devices.get(device_id);
345
346        let (texture, error) =
347            unsafe { device.create_texture_from_hal(hal_texture, desc, initial_state) };
348
349        let id = fid.assign(texture);
350        (id, error)
351    }
352
353    /// # Safety
354    ///
355    /// - `hal_buffer` must be created from `device_id` corresponding raw handle.
356    /// - `hal_buffer` must be created respecting `desc`
357    /// - `hal_buffer` must be initialized
358    /// - `hal_buffer` must not have zero size.
359    pub unsafe fn create_buffer_from_hal<A: hal::Api>(
360        &self,
361        hal_buffer: A::Buffer,
362        device_id: DeviceId,
363        desc: &resource::BufferDescriptor,
364        id_in: Option<id::BufferId>,
365    ) -> (id::BufferId, Option<CreateBufferError>) {
366        let hub = &self.hub;
367        let fid = hub.buffers.prepare(id_in);
368
369        let device = self.hub.devices.get(device_id);
370
371        let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) };
372
373        let id = fid.assign(buffer);
374
375        (id, err)
376    }
377
378    pub fn texture_destroy(&self, texture_id: id::TextureId) {
379        let hub = &self.hub;
380
381        let texture = hub.textures.get(texture_id);
382
383        texture.destroy();
384    }
385
386    pub fn texture_drop(&self, texture_id: id::TextureId) {
387        let hub = &self.hub;
388
389        hub.textures.remove(texture_id);
390    }
391
392    pub fn texture_create_view(
393        &self,
394        texture_id: id::TextureId,
395        desc: &resource::TextureViewDescriptor,
396        id_in: Option<id::TextureViewId>,
397    ) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
398        let hub = &self.hub;
399
400        let fid = hub.texture_views.prepare(id_in);
401
402        let texture = hub.textures.get(texture_id);
403
404        let (view, error) = texture.create_view(desc);
405
406        let id = fid.assign(view);
407
408        (id, error)
409    }
410
411    pub fn texture_view_drop(&self, texture_view_id: id::TextureViewId) {
412        let hub = &self.hub;
413
414        let _view = hub.texture_views.remove(texture_view_id);
415    }
416
417    pub fn device_create_external_texture(
418        &self,
419        device_id: DeviceId,
420        desc: &resource::ExternalTextureDescriptor,
421        planes: &[id::TextureViewId],
422        id_in: Option<id::ExternalTextureId>,
423    ) -> (
424        id::ExternalTextureId,
425        Option<resource::CreateExternalTextureError>,
426    ) {
427        let hub = &self.hub;
428
429        let fid = hub.external_textures.prepare(id_in);
430
431        let device = self.hub.devices.get(device_id);
432
433        let planes = planes
434            .iter()
435            .map(|plane_id| self.hub.texture_views.get(*plane_id))
436            .collect::<Vec<_>>();
437
438        let (external_texture, error) = device.create_external_texture(desc, &planes);
439
440        let id = fid.assign(external_texture);
441
442        (id, error)
443    }
444
445    pub fn external_texture_destroy(&self, external_texture_id: id::ExternalTextureId) {
446        let hub = &self.hub;
447
448        let external_texture = hub.external_textures.get(external_texture_id);
449
450        external_texture.destroy();
451    }
452
453    pub fn external_texture_drop(&self, external_texture_id: id::ExternalTextureId) {
454        let hub = &self.hub;
455
456        let _external_texture = hub.external_textures.remove(external_texture_id);
457    }
458
459    pub fn device_create_sampler(
460        &self,
461        device_id: DeviceId,
462        desc: &resource::SamplerDescriptor,
463        id_in: Option<id::SamplerId>,
464    ) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
465        let hub = &self.hub;
466        let fid = hub.samplers.prepare(id_in);
467
468        let device = self.hub.devices.get(device_id);
469
470        let (sampler, error) = device.create_sampler(desc);
471
472        let id = fid.assign(sampler);
473
474        (id, error)
475    }
476
477    pub fn sampler_drop(&self, sampler_id: id::SamplerId) {
478        let hub = &self.hub;
479
480        let _sampler = hub.samplers.remove(sampler_id);
481    }
482
483    pub fn device_create_bind_group_layout(
484        &self,
485        device_id: DeviceId,
486        desc: &binding_model::BindGroupLayoutDescriptor,
487        id_in: Option<id::BindGroupLayoutId>,
488    ) -> (
489        id::BindGroupLayoutId,
490        Option<binding_model::CreateBindGroupLayoutError>,
491    ) {
492        let hub = &self.hub;
493        let fid = hub.bind_group_layouts.prepare(id_in);
494
495        let device = self.hub.devices.get(device_id);
496
497        let (bgl, error) = device.create_bind_group_layout(desc);
498
499        let id = fid.assign(bgl);
500
501        (id, error)
502    }
503
504    pub fn bind_group_layout_drop(&self, bind_group_layout_id: id::BindGroupLayoutId) {
505        let hub = &self.hub;
506
507        let _layout = hub.bind_group_layouts.remove(bind_group_layout_id);
508    }
509
510    pub fn device_create_pipeline_layout(
511        &self,
512        device_id: DeviceId,
513        desc: &binding_model::PipelineLayoutDescriptor<id::BindGroupLayoutId>,
514        id_in: Option<id::PipelineLayoutId>,
515    ) -> (
516        id::PipelineLayoutId,
517        Option<binding_model::CreatePipelineLayoutError>,
518    ) {
519        let hub = &self.hub;
520        let fid = hub.pipeline_layouts.prepare(id_in);
521
522        let device = self.hub.devices.get(device_id);
523
524        let bind_group_layouts = {
525            let bind_group_layouts_guard = hub.bind_group_layouts.read();
526            desc.bind_group_layouts
527                .iter()
528                .map(|bgl_id| bgl_id.map(|bgl_id| bind_group_layouts_guard.get(bgl_id)))
529                .collect::<Vec<_>>()
530        };
531
532        let desc = binding_model::PipelineLayoutDescriptor {
533            label: desc.label.clone(),
534            bind_group_layouts: Cow::Owned(bind_group_layouts),
535            immediate_size: desc.immediate_size,
536        };
537
538        let (layout, error) = device.create_pipeline_layout(&desc);
539        let id = fid.assign(layout);
540        (id, error)
541    }
542
543    pub fn pipeline_layout_drop(&self, pipeline_layout_id: id::PipelineLayoutId) {
544        let hub = &self.hub;
545
546        let _layout = hub.pipeline_layouts.remove(pipeline_layout_id);
547    }
548
549    pub fn device_create_bind_group(
550        &self,
551        device_id: DeviceId,
552        desc: &BindGroupDescriptor,
553        id_in: Option<id::BindGroupId>,
554    ) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
555        let hub = &self.hub;
556        let fid = hub.bind_groups.prepare(id_in);
557
558        let device = hub.devices.get(device_id);
559
560        let layout = hub.bind_group_layouts.get(desc.layout);
561
562        fn resolve_entry<'a>(
563            e: &BindGroupEntry<'a>,
564            buffer_storage: &Storage<Arc<resource::Buffer>>,
565            sampler_storage: &Storage<Arc<resource::Sampler>>,
566            texture_view_storage: &Storage<Arc<resource::TextureView>>,
567            tlas_storage: &Storage<Arc<resource::Tlas>>,
568            external_texture_storage: &Storage<Arc<resource::ExternalTexture>>,
569        ) -> binding_model::BindGroupEntry<'a> {
570            let resolve_buffer = |bb: &BufferBinding| {
571                let buffer = buffer_storage.get(bb.buffer);
572                binding_model::BufferBinding {
573                    buffer,
574                    offset: bb.offset,
575                    size: bb.size,
576                }
577            };
578            let resolve_sampler = |id: &id::SamplerId| sampler_storage.get(*id);
579            let resolve_view = |id: &id::TextureViewId| texture_view_storage.get(*id);
580            let resolve_tlas = |id: &id::TlasId| tlas_storage.get(*id);
581            let resolve_external_texture =
582                |id: &id::ExternalTextureId| external_texture_storage.get(*id);
583            let resource = match e.resource {
584                BindingResource::Buffer(ref buffer) => {
585                    binding_model::BindingResource::Buffer(resolve_buffer(buffer))
586                }
587                BindingResource::BufferArray(ref buffers) => {
588                    let buffers = buffers.iter().map(resolve_buffer).collect::<Vec<_>>();
589                    binding_model::BindingResource::BufferArray(Cow::Owned(buffers))
590                }
591                BindingResource::Sampler(ref sampler) => {
592                    binding_model::BindingResource::Sampler(resolve_sampler(sampler))
593                }
594                BindingResource::SamplerArray(ref samplers) => {
595                    let samplers = samplers.iter().map(resolve_sampler).collect::<Vec<_>>();
596                    binding_model::BindingResource::SamplerArray(Cow::Owned(samplers))
597                }
598                BindingResource::TextureView(ref view) => {
599                    binding_model::BindingResource::TextureView(resolve_view(view))
600                }
601                BindingResource::TextureViewArray(ref views) => {
602                    let views = views.iter().map(resolve_view).collect::<Vec<_>>();
603                    binding_model::BindingResource::TextureViewArray(Cow::Owned(views))
604                }
605                BindingResource::AccelerationStructure(ref tlas) => {
606                    binding_model::BindingResource::AccelerationStructure(resolve_tlas(tlas))
607                }
608                BindingResource::AccelerationStructureArray(ref tlas_array) => {
609                    let tlas_array = tlas_array.iter().map(resolve_tlas).collect::<Vec<_>>();
610                    binding_model::BindingResource::AccelerationStructureArray(Cow::Owned(
611                        tlas_array,
612                    ))
613                }
614                BindingResource::ExternalTexture(ref et) => {
615                    binding_model::BindingResource::ExternalTexture(resolve_external_texture(et))
616                }
617            };
618            binding_model::BindGroupEntry {
619                binding: e.binding,
620                resource,
621            }
622        }
623
624        let entries = {
625            let buffer_guard = hub.buffers.read();
626            let texture_view_guard = hub.texture_views.read();
627            let sampler_guard = hub.samplers.read();
628            let tlas_guard = hub.tlas_s.read();
629            let external_texture_guard = hub.external_textures.read();
630            desc.entries
631                .iter()
632                .map(|e| {
633                    resolve_entry(
634                        e,
635                        &buffer_guard,
636                        &sampler_guard,
637                        &texture_view_guard,
638                        &tlas_guard,
639                        &external_texture_guard,
640                    )
641                })
642                .collect::<Vec<_>>()
643        };
644        let entries = Cow::Owned(entries);
645
646        let desc = binding_model::BindGroupDescriptor {
647            label: desc.label.clone(),
648            layout,
649            entries,
650        };
651
652        let (bind_group, error) = device.create_bind_group(&desc);
653
654        let id = fid.assign(bind_group);
655        (id, error)
656    }
657
658    pub fn bind_group_drop(&self, bind_group_id: id::BindGroupId) {
659        let hub = &self.hub;
660
661        let _bind_group = hub.bind_groups.remove(bind_group_id);
662    }
663
664    /// Create a shader module with the given `source`.
665    ///
666    /// <div class="warning">
667    // NOTE: Keep this in sync with `naga::front::wgsl::parse_str`!
668    // NOTE: Keep this in sync with `wgpu::Device::create_shader_module`!
669    ///
670    /// This function may consume a lot of stack space. Compiler-enforced limits for parsing
671    /// recursion exist; if shader compilation runs into them, it will return an error gracefully.
672    /// However, on some build profiles and platforms, the default stack size for a thread may be
673    /// exceeded before this limit is reached during parsing. Callers should ensure that there is
674    /// enough stack space for this, particularly if calls to this method are exposed to user
675    /// input.
676    ///
677    /// </div>
678    pub fn device_create_shader_module(
679        &self,
680        device_id: DeviceId,
681        desc: &pipeline::ShaderModuleDescriptor,
682        source: pipeline::ShaderModuleSource,
683        id_in: Option<id::ShaderModuleId>,
684    ) -> (
685        id::ShaderModuleId,
686        Option<pipeline::CreateShaderModuleError>,
687    ) {
688        let hub = &self.hub;
689        let fid = hub.shader_modules.prepare(id_in);
690
691        let device = self.hub.devices.get(device_id);
692
693        let (shader, error) = device.create_shader_module(desc, source);
694
695        let id = fid.assign(shader);
696
697        (id, error)
698    }
699
700    /// # Safety
701    ///
702    /// This function passes source code or binary to the backend as-is and can potentially result in a
703    /// driver crash.
704    pub unsafe fn device_create_shader_module_passthrough(
705        &self,
706        device_id: DeviceId,
707        desc: &pipeline::ShaderModuleDescriptorPassthrough<'_>,
708        id_in: Option<id::ShaderModuleId>,
709    ) -> (
710        id::ShaderModuleId,
711        Option<pipeline::CreateShaderModuleError>,
712    ) {
713        let hub = &self.hub;
714        let fid = hub.shader_modules.prepare(id_in);
715
716        let device = self.hub.devices.get(device_id);
717
718        let (shader, error) = unsafe { device.create_shader_module_passthrough(desc) };
719
720        let id = fid.assign(shader);
721
722        (id, error)
723    }
724
725    pub fn shader_module_drop(&self, shader_module_id: id::ShaderModuleId) {
726        let hub = &self.hub;
727
728        let _shader_module = hub.shader_modules.remove(shader_module_id);
729    }
730
731    pub fn device_create_command_encoder(
732        &self,
733        device_id: DeviceId,
734        desc: &wgt::CommandEncoderDescriptor<Label>,
735        id_in: Option<id::CommandEncoderId>,
736    ) -> (id::CommandEncoderId, Option<DeviceError>) {
737        let hub = &self.hub;
738        let fid = hub.command_encoders.prepare(id_in);
739
740        let device = self.hub.devices.get(device_id);
741
742        let (cmd_enc, error) = device.create_command_encoder(desc);
743
744        let id = fid.assign(cmd_enc);
745        (id, error)
746    }
747
748    pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
749        let _cmd_enc = self.hub.command_encoders.remove(command_encoder_id);
750    }
751
752    pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
753        let _cmd_buf = self.hub.command_buffers.remove(command_buffer_id);
754    }
755
756    pub fn device_create_render_bundle_encoder(
757        &self,
758        device_id: DeviceId,
759        desc: &command::RenderBundleEncoderDescriptor,
760    ) -> (
761        Box<command::RenderBundleEncoder>,
762        Option<command::CreateRenderBundleError>,
763    ) {
764        let device = self.hub.devices.get(device_id);
765        device.create_render_bundle_encoder(desc)
766    }
767
768    pub fn device_create_render_bundle_encoder_with_id(
769        &self,
770        device_id: DeviceId,
771        desc: &command::RenderBundleEncoderDescriptor,
772        id_in: Option<id::RenderBundleEncoderId>,
773    ) -> (
774        id::RenderBundleEncoderId,
775        Option<command::CreateRenderBundleError>,
776    ) {
777        let fid = self.hub.render_bundle_encoders.prepare(id_in);
778
779        let (render_bundle_encoder, error) =
780            self.device_create_render_bundle_encoder(device_id, desc);
781
782        // no lock rank here because only one thread should be using compute pass
783        // and it's only used by id variants of compute pass methods on global
784        // so no deadlock (or concurrent lock) should happen in practise
785        let id = fid.assign(Arc::new(parking_lot::Mutex::new(*render_bundle_encoder)));
786
787        (id, error)
788    }
789
790    pub fn render_bundle_encoder_finish(
791        &self,
792        bundle_encoder: &mut command::RenderBundleEncoder,
793        desc: &command::RenderBundleDescriptor,
794        id_in: Option<id::RenderBundleId>,
795    ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
796        let hub = &self.hub;
797
798        let fid = hub.render_bundles.prepare(id_in);
799
800        let (render_bundle, error) = bundle_encoder.finish(desc);
801
802        let id = fid.assign(render_bundle);
803
804        (id, error)
805    }
806
807    pub fn render_bundle_encoder_finish_with_id(
808        &self,
809        render_bundle_encoder_id: id::RenderBundleEncoderId,
810        desc: &command::RenderBundleDescriptor,
811        id_in: Option<id::RenderBundleId>,
812    ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
813        let bundle_encoder = self
814            .hub
815            .render_bundle_encoders
816            .get(render_bundle_encoder_id);
817
818        let mut bundle_encoder = bundle_encoder
819            .try_lock()
820            .expect("RenderBundleEncoders should not be accessed concurrently");
821
822        let (id, error) = self.render_bundle_encoder_finish(&mut bundle_encoder, desc, id_in);
823
824        (id, error)
825    }
826
827    pub fn render_bundle_encoder_drop(&self, render_bundle_encoder_id: id::RenderBundleEncoderId) {
828        let hub = &self.hub;
829
830        let _bundle_encoder = hub.render_bundle_encoders.remove(render_bundle_encoder_id);
831    }
832
833    pub fn render_bundle_drop(&self, render_bundle_id: id::RenderBundleId) {
834        let hub = &self.hub;
835
836        let _bundle = hub.render_bundles.remove(render_bundle_id);
837    }
838
839    pub fn device_create_query_set(
840        &self,
841        device_id: DeviceId,
842        desc: &resource::QuerySetDescriptor,
843        id_in: Option<id::QuerySetId>,
844    ) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
845        let hub = &self.hub;
846        let fid = hub.query_sets.prepare(id_in);
847
848        let device = self.hub.devices.get(device_id);
849
850        let (query_set, error) = device.create_query_set(desc);
851
852        let id = fid.assign(query_set);
853
854        (id, error)
855    }
856
857    pub fn query_set_destroy(&self, query_set_id: id::QuerySetId) {
858        let hub = &self.hub;
859
860        let query_set = hub.query_sets.get(query_set_id);
861
862        query_set.destroy();
863    }
864
865    pub fn query_set_drop(&self, query_set_id: id::QuerySetId) {
866        let hub = &self.hub;
867
868        let _query_set = hub.query_sets.remove(query_set_id);
869    }
870
871    pub fn device_create_render_pipeline(
872        &self,
873        device_id: DeviceId,
874        desc: &RenderPipelineDescriptor,
875        id_in: Option<id::RenderPipelineId>,
876    ) -> (
877        id::RenderPipelineId,
878        Option<pipeline::CreateRenderPipelineError>,
879    ) {
880        let hub = &self.hub;
881
882        let fid = hub.render_pipelines.prepare(id_in);
883
884        let device = self.hub.devices.get(device_id);
885
886        self.device_create_general_render_pipeline(desc.clone().into(), device, fid)
887    }
888
889    pub fn device_create_mesh_pipeline(
890        &self,
891        device_id: DeviceId,
892        desc: &MeshPipelineDescriptor,
893        id_in: Option<id::RenderPipelineId>,
894    ) -> (
895        id::RenderPipelineId,
896        Option<pipeline::CreateRenderPipelineError>,
897    ) {
898        let hub = &self.hub;
899
900        let fid = hub.render_pipelines.prepare(id_in);
901
902        let device = self.hub.devices.get(device_id);
903        self.device_create_general_render_pipeline(desc.clone().into(), device, fid)
904    }
905
906    fn device_create_general_render_pipeline(
907        &self,
908        desc: GeneralRenderPipelineDescriptor,
909        device: Arc<crate::device::resource::Device>,
910        fid: crate::registry::FutureId<Arc<pipeline::RenderPipeline>>,
911    ) -> (
912        id::RenderPipelineId,
913        Option<pipeline::CreateRenderPipelineError>,
914    ) {
915        let hub = &self.hub;
916
917        let layout = desc.layout.map(|layout| hub.pipeline_layouts.get(layout));
918
919        let cache = desc.cache.map(|cache| hub.pipeline_caches.get(cache));
920
921        let vertex = match desc.vertex {
922            RenderPipelineVertexProcessor::Vertex(ref vertex) => {
923                let module = hub.shader_modules.get(vertex.stage.module);
924                let stage = ProgrammableStageDescriptor {
925                    module,
926                    entry_point: vertex.stage.entry_point.clone(),
927                    constants: vertex.stage.constants.clone(),
928                    zero_initialize_workgroup_memory: vertex.stage.zero_initialize_workgroup_memory,
929                };
930                RenderPipelineVertexProcessor::Vertex(pipeline::VertexState {
931                    stage,
932                    buffers: vertex.buffers.clone(),
933                })
934            }
935            RenderPipelineVertexProcessor::Mesh(ref task, ref mesh) => {
936                let task_module = if let Some(task) = task {
937                    let module = hub.shader_modules.get(task.stage.module);
938
939                    let state = ProgrammableStageDescriptor {
940                        module,
941                        entry_point: task.stage.entry_point.clone(),
942                        constants: task.stage.constants.clone(),
943                        zero_initialize_workgroup_memory: task
944                            .stage
945                            .zero_initialize_workgroup_memory,
946                    };
947                    Some(TaskState { stage: state })
948                } else {
949                    None
950                };
951                let mesh_module = hub.shader_modules.get(mesh.stage.module);
952                let mesh_stage = ProgrammableStageDescriptor {
953                    module: mesh_module,
954                    entry_point: mesh.stage.entry_point.clone(),
955                    constants: mesh.stage.constants.clone(),
956                    zero_initialize_workgroup_memory: mesh.stage.zero_initialize_workgroup_memory,
957                };
958                RenderPipelineVertexProcessor::Mesh(task_module, MeshState { stage: mesh_stage })
959            }
960        };
961
962        let fragment = if let Some(ref state) = desc.fragment {
963            let module = hub.shader_modules.get(state.stage.module);
964
965            let stage = ProgrammableStageDescriptor {
966                module,
967                entry_point: state.stage.entry_point.clone(),
968                constants: state.stage.constants.clone(),
969                zero_initialize_workgroup_memory: state.stage.zero_initialize_workgroup_memory,
970            };
971            Some(pipeline::FragmentState {
972                stage,
973                targets: state.targets.clone(),
974            })
975        } else {
976            None
977        };
978
979        let desc = ResolvedGeneralRenderPipelineDescriptor {
980            label: desc.label.clone(),
981            layout,
982            vertex,
983            primitive: desc.primitive,
984            depth_stencil: desc.depth_stencil.clone(),
985            multisample: desc.multisample,
986            fragment,
987            multiview_mask: desc.multiview_mask,
988            cache,
989        };
990
991        let (pipeline, error) = device.create_render_pipeline(desc);
992
993        let id = fid.assign(pipeline);
994
995        (id, error)
996    }
997
998    /// Get an ID of one of the bind group layouts. The ID adds a refcount,
999    /// which needs to be released by calling `bind_group_layout_drop`.
1000    pub fn render_pipeline_get_bind_group_layout(
1001        &self,
1002        pipeline_id: id::RenderPipelineId,
1003        index: u32,
1004        id_in: Option<id::BindGroupLayoutId>,
1005    ) -> (
1006        id::BindGroupLayoutId,
1007        Option<binding_model::GetBindGroupLayoutError>,
1008    ) {
1009        let hub = &self.hub;
1010
1011        let fid = hub.bind_group_layouts.prepare(id_in);
1012
1013        let pipeline = hub.render_pipelines.get(pipeline_id);
1014
1015        let (bgl, error) = pipeline.get_bind_group_layout(index);
1016
1017        let id = fid.assign(bgl);
1018
1019        (id, error)
1020    }
1021
1022    pub fn render_pipeline_drop(&self, render_pipeline_id: id::RenderPipelineId) {
1023        let hub = &self.hub;
1024
1025        let _pipeline = hub.render_pipelines.remove(render_pipeline_id);
1026    }
1027
1028    pub fn device_create_compute_pipeline(
1029        &self,
1030        device_id: DeviceId,
1031        desc: &ComputePipelineDescriptor,
1032        id_in: Option<id::ComputePipelineId>,
1033    ) -> (
1034        id::ComputePipelineId,
1035        Option<pipeline::CreateComputePipelineError>,
1036    ) {
1037        let hub = &self.hub;
1038
1039        let fid = hub.compute_pipelines.prepare(id_in);
1040
1041        let device = self.hub.devices.get(device_id);
1042
1043        let layout = desc.layout.map(|layout| hub.pipeline_layouts.get(layout));
1044
1045        let cache = desc.cache.map(|cache| hub.pipeline_caches.get(cache));
1046
1047        let module = hub.shader_modules.get(desc.stage.module);
1048
1049        let stage = ProgrammableStageDescriptor {
1050            module,
1051            entry_point: desc.stage.entry_point.clone(),
1052            constants: desc.stage.constants.clone(),
1053            zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
1054        };
1055
1056        let desc = pipeline::ComputePipelineDescriptor {
1057            label: desc.label.clone(),
1058            layout,
1059            stage,
1060            cache,
1061        };
1062
1063        let (pipeline, error) = device.create_compute_pipeline(desc);
1064
1065        let id = fid.assign(pipeline);
1066
1067        (id, error)
1068    }
1069
1070    /// Get an ID of one of the bind group layouts. The ID adds a refcount,
1071    /// which needs to be released by calling `bind_group_layout_drop`.
1072    pub fn compute_pipeline_get_bind_group_layout(
1073        &self,
1074        pipeline_id: id::ComputePipelineId,
1075        index: u32,
1076        id_in: Option<id::BindGroupLayoutId>,
1077    ) -> (
1078        id::BindGroupLayoutId,
1079        Option<binding_model::GetBindGroupLayoutError>,
1080    ) {
1081        let hub = &self.hub;
1082
1083        let fid = hub.bind_group_layouts.prepare(id_in);
1084
1085        let pipeline = hub.compute_pipelines.get(pipeline_id);
1086
1087        let (bgl, error) = pipeline.get_bind_group_layout(index);
1088
1089        let id = fid.assign(bgl);
1090
1091        (id, error)
1092    }
1093
1094    pub fn compute_pipeline_drop(&self, compute_pipeline_id: id::ComputePipelineId) {
1095        let hub = &self.hub;
1096
1097        let _pipeline = hub.compute_pipelines.remove(compute_pipeline_id);
1098    }
1099
1100    /// # Safety
1101    /// The `data` argument of `desc` must have been returned by
1102    /// [Self::pipeline_cache_get_data] for the same adapter
1103    pub unsafe fn device_create_pipeline_cache(
1104        &self,
1105        device_id: DeviceId,
1106        desc: &pipeline::PipelineCacheDescriptor<'_>,
1107        id_in: Option<id::PipelineCacheId>,
1108    ) -> (
1109        id::PipelineCacheId,
1110        Option<pipeline::CreatePipelineCacheError>,
1111    ) {
1112        let hub = &self.hub;
1113
1114        let fid = hub.pipeline_caches.prepare(id_in);
1115        let device = self.hub.devices.get(device_id);
1116
1117        let (cache, error) = unsafe { device.create_pipeline_cache(desc) };
1118
1119        let id = fid.assign(cache);
1120
1121        (id, error)
1122    }
1123
1124    pub fn pipeline_cache_drop(&self, pipeline_cache_id: id::PipelineCacheId) {
1125        let hub = &self.hub;
1126
1127        let _cache = hub.pipeline_caches.remove(pipeline_cache_id);
1128    }
1129
1130    pub fn surface_configure(
1131        &self,
1132        surface_id: SurfaceId,
1133        device_id: DeviceId,
1134        config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
1135    ) -> Option<present::ConfigureSurfaceError> {
1136        let device = self.hub.devices.get(device_id);
1137        let surface = self.surfaces.get(surface_id);
1138
1139        surface.configure(&device, config)
1140    }
1141
1142    /// Check `device_id` for freeable resources and completed buffer mappings.
1143    ///
1144    /// Return `queue_empty` indicating whether there are more queue submissions still in flight.
1145    pub fn device_poll(
1146        &self,
1147        device_id: DeviceId,
1148        poll_type: wgt::PollType<crate::SubmissionIndex>,
1149    ) -> Result<wgt::PollStatus, WaitIdleError> {
1150        let device = self.hub.devices.get(device_id);
1151
1152        device.poll(poll_type)
1153    }
1154
1155    /// Poll all devices on all backends.
1156    ///
1157    /// This is the implementation of `wgpu::Instance::poll_all`.
1158    ///
1159    /// Return `all_queue_empty` indicating whether there are more queue
1160    /// submissions still in flight.
1161    pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
1162        self.instance.poll_all_devices(force_wait)
1163    }
1164
1165    /// # Safety
1166    ///
1167    /// - See [wgpu::Device::start_graphics_debugger_capture][api] for details the safety.
1168    ///
1169    /// [api]: ../../wgpu/struct.Device.html#method.start_graphics_debugger_capture
1170    pub unsafe fn device_start_graphics_debugger_capture(&self, device_id: DeviceId) {
1171        unsafe {
1172            self.hub
1173                .devices
1174                .get(device_id)
1175                .start_graphics_debugger_capture();
1176        }
1177    }
1178
1179    /// # Safety
1180    ///
1181    /// - See [wgpu::Device::stop_graphics_debugger_capture][api] for details the safety.
1182    ///
1183    /// [api]: ../../wgpu/struct.Device.html#method.stop_graphics_debugger_capture
1184    pub unsafe fn device_stop_graphics_debugger_capture(&self, device_id: DeviceId) {
1185        unsafe {
1186            self.hub
1187                .devices
1188                .get(device_id)
1189                .stop_graphics_debugger_capture();
1190        }
1191    }
1192
1193    pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option<Vec<u8>> {
1194        let hub = &self.hub;
1195
1196        hub.pipeline_caches.get(id).get_data()
1197    }
1198
1199    pub fn device_drop(&self, device_id: DeviceId) {
1200        self.hub.devices.remove(device_id);
1201    }
1202
1203    /// `device_lost_closure` might never be called.
1204    pub fn device_set_device_lost_closure(
1205        &self,
1206        device_id: DeviceId,
1207        device_lost_closure: DeviceLostClosure,
1208    ) {
1209        let device = self.hub.devices.get(device_id);
1210
1211        device.set_device_lost_closure(device_lost_closure);
1212    }
1213
1214    pub fn device_destroy(&self, device_id: DeviceId) {
1215        let device = self.hub.devices.get(device_id);
1216        device.destroy();
1217    }
1218
1219    pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters {
1220        let device = self.hub.devices.get(device_id);
1221        device.get_internal_counters()
1222    }
1223
1224    pub fn device_generate_allocator_report(
1225        &self,
1226        device_id: DeviceId,
1227    ) -> Option<wgt::AllocatorReport> {
1228        let device = self.hub.devices.get(device_id);
1229        device.generate_allocator_report()
1230    }
1231
1232    #[cfg(feature = "trace")]
1233    pub fn device_take_trace(
1234        &self,
1235        device_id: DeviceId,
1236    ) -> Option<Box<dyn trace::Trace + Send + Sync + 'static>> {
1237        let device = self.hub.devices.get(device_id);
1238        device.take_trace()
1239    }
1240
1241    pub fn queue_drop(&self, queue_id: QueueId) {
1242        self.hub.queues.remove(queue_id);
1243    }
1244
1245    /// `op.callback` is always called, even in case of errors.
1246    pub fn buffer_map_async(
1247        &self,
1248        buffer_id: id::BufferId,
1249        offset: BufferAddress,
1250        size: Option<BufferAddress>,
1251        op: BufferMapOperation,
1252    ) -> Result<crate::SubmissionIndex, BufferAccessError> {
1253        let hub = &self.hub;
1254
1255        let buffer = hub.buffers.get(buffer_id);
1256
1257        buffer.map_async(offset, size, op)
1258    }
1259
1260    pub fn buffer_get_mapped_range(
1261        &self,
1262        buffer_id: id::BufferId,
1263        offset: BufferAddress,
1264        size: Option<BufferAddress>,
1265    ) -> Result<(NonNull<u8>, u64), BufferAccessError> {
1266        let hub = &self.hub;
1267
1268        let buffer = hub.buffers.get(buffer_id);
1269
1270        buffer.get_mapped_range(offset, size)
1271    }
1272
1273    pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult {
1274        let hub = &self.hub;
1275
1276        let buffer = hub.buffers.get(buffer_id);
1277
1278        buffer.unmap()
1279    }
1280}