wgpu_hal/vulkan/
device.rs

1use alloc::{borrow::ToOwned as _, collections::BTreeMap, ffi::CString, sync::Arc, vec::Vec};
2use core::{
3    ffi::CStr,
4    mem::{self, MaybeUninit},
5    num::NonZeroU32,
6    ptr,
7    time::Duration,
8};
9
10use arrayvec::ArrayVec;
11use ash::{ext, vk};
12use hashbrown::hash_map::Entry;
13use wgpu_sync::{Mutex, RwLock};
14
15use super::{conv, descriptor::DescriptorCounts, RawTlasInstance};
16use crate::TlasInstance;
17
18impl super::DeviceShared {
19    /// Set the name of `object` to `name`.
20    ///
21    /// If `name` contains an interior null byte, then the name set will be truncated to that byte.
22    ///
23    /// # Safety
24    ///
25    /// This method inherits the safety contract from [`vkSetDebugUtilsObjectName`]. In particular:
26    ///
27    /// - `object` must be a valid handle for one of the following:
28    ///   - An instance-level object from the same instance as this device.
29    ///   - A physical-device-level object that descends from the same physical device as this
30    ///     device.
31    ///   - A device-level object that descends from this device.
32    /// - `object` must be externally synchronized—only the calling thread should access it during
33    ///   this call.
34    ///
35    /// [`vkSetDebugUtilsObjectName`]: https://registry.khronos.org/vulkan/specs/latest/man/html/vkSetDebugUtilsObjectNameEXT.html
36    pub(super) unsafe fn set_object_name(&self, object: impl vk::Handle, name: &str) {
37        let Some(extension) = self.extension_fns.debug_utils.as_ref() else {
38            return;
39        };
40
41        // Keep variables outside the if-else block to ensure they do not
42        // go out of scope while we hold a pointer to them
43        let mut buffer: [u8; 64] = [0u8; 64];
44        let buffer_vec: Vec<u8>;
45
46        // Append a null terminator to the string
47        let name_bytes = if name.len() < buffer.len() {
48            // Common case, string is very small. Allocate a copy on the stack.
49            buffer[..name.len()].copy_from_slice(name.as_bytes());
50            // Add null terminator
51            buffer[name.len()] = 0;
52            &buffer[..name.len() + 1]
53        } else {
54            // Less common case, the string is large.
55            // This requires a heap allocation.
56            buffer_vec = name
57                .as_bytes()
58                .iter()
59                .cloned()
60                .chain(core::iter::once(0))
61                .collect();
62            &buffer_vec
63        };
64
65        let name = CStr::from_bytes_until_nul(name_bytes).expect("We have added a null byte");
66
67        let _result = unsafe {
68            extension.set_debug_utils_object_name(
69                &vk::DebugUtilsObjectNameInfoEXT::default()
70                    .object_handle(object)
71                    .object_name(name),
72            )
73        };
74    }
75
76    pub fn make_render_pass(
77        &self,
78        key: super::RenderPassKey,
79    ) -> Result<vk::RenderPass, crate::DeviceError> {
80        Ok(match self.render_passes.lock().entry(key) {
81            Entry::Occupied(e) => *e.get(),
82            Entry::Vacant(e) => {
83                let super::RenderPassKey {
84                    ref colors,
85                    ref depth_stencil,
86                    sample_count,
87                    multiview_mask,
88                    depth_read_only,
89                    stencil_read_only,
90                } = *e.key();
91
92                let mut vk_attachments = Vec::new();
93                let mut color_refs = Vec::with_capacity(colors.len());
94                let mut resolve_refs = Vec::with_capacity(color_refs.capacity());
95                let mut ds_ref = None;
96                let samples = vk::SampleCountFlags::from_raw(sample_count);
97                let unused = vk::AttachmentReference {
98                    attachment: vk::ATTACHMENT_UNUSED,
99                    layout: vk::ImageLayout::UNDEFINED,
100                };
101                for cat in colors.iter() {
102                    let (color_ref, resolve_ref) =
103                        if let Some(super::ColorAttachmentKey { base, resolve }) = cat {
104                            let super::AttachmentKey {
105                                format,
106                                layout,
107                                ops,
108                            } = *base;
109
110                            let color_ref = vk::AttachmentReference {
111                                attachment: vk_attachments.len() as u32,
112                                layout,
113                            };
114                            vk_attachments.push({
115                                let (load_op, store_op) = conv::map_attachment_ops(ops);
116                                vk::AttachmentDescription::default()
117                                    .format(format)
118                                    .samples(samples)
119                                    .load_op(load_op)
120                                    .store_op(store_op)
121                                    .initial_layout(layout)
122                                    .final_layout(layout)
123                            });
124                            let resolve_ref = if let Some(rat) = resolve {
125                                let super::AttachmentKey {
126                                    format,
127                                    layout,
128                                    ops,
129                                } = *rat;
130
131                                let (load_op, store_op) = conv::map_attachment_ops(ops);
132                                let vk_attachment = vk::AttachmentDescription::default()
133                                    .format(format)
134                                    .samples(vk::SampleCountFlags::TYPE_1)
135                                    .load_op(load_op)
136                                    .store_op(store_op)
137                                    .initial_layout(layout)
138                                    .final_layout(layout);
139                                vk_attachments.push(vk_attachment);
140
141                                vk::AttachmentReference {
142                                    attachment: vk_attachments.len() as u32 - 1,
143                                    layout,
144                                }
145                            } else {
146                                unused
147                            };
148
149                            (color_ref, resolve_ref)
150                        } else {
151                            (unused, unused)
152                        };
153
154                    color_refs.push(color_ref);
155                    resolve_refs.push(resolve_ref);
156                }
157
158                if let Some(ds) = depth_stencil {
159                    let super::DepthStencilAttachmentKey {
160                        ref base,
161                        stencil_ops,
162                    } = *ds;
163
164                    let super::AttachmentKey {
165                        format,
166                        layout,
167                        ops,
168                    } = *base;
169
170                    ds_ref = Some(vk::AttachmentReference {
171                        attachment: vk_attachments.len() as u32,
172                        layout,
173                    });
174                    let (load_op, mut store_op) = conv::map_attachment_ops(ops);
175                    let (stencil_load_op, mut stencil_store_op) =
176                        conv::map_attachment_ops(stencil_ops);
177
178                    let store_op_for_read_only = if self.private_caps.store_op_none {
179                        vk::AttachmentStoreOp::NONE
180                    } else {
181                        vk::AttachmentStoreOp::STORE
182                    };
183                    if depth_read_only {
184                        store_op = store_op_for_read_only;
185                    }
186                    if stencil_read_only {
187                        stencil_store_op = store_op_for_read_only;
188                    }
189
190                    let vk_attachment = vk::AttachmentDescription::default()
191                        .format(format)
192                        .samples(samples)
193                        .load_op(load_op)
194                        .store_op(store_op)
195                        .stencil_load_op(stencil_load_op)
196                        .stencil_store_op(stencil_store_op)
197                        .initial_layout(layout)
198                        .final_layout(layout);
199                    vk_attachments.push(vk_attachment);
200                }
201
202                let vk_subpasses = [{
203                    let mut vk_subpass = vk::SubpassDescription::default()
204                        .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
205                        .color_attachments(&color_refs)
206                        .resolve_attachments(&resolve_refs);
207
208                    if self
209                        .workarounds
210                        .contains(super::Workarounds::EMPTY_RESOLVE_ATTACHMENT_LISTS)
211                        && resolve_refs.is_empty()
212                    {
213                        vk_subpass.p_resolve_attachments = ptr::null();
214                    }
215
216                    if let Some(ref reference) = ds_ref {
217                        vk_subpass = vk_subpass.depth_stencil_attachment(reference)
218                    }
219                    vk_subpass
220                }];
221
222                let mut vk_info = vk::RenderPassCreateInfo::default()
223                    .attachments(&vk_attachments)
224                    .subpasses(&vk_subpasses);
225
226                let mut multiview_info;
227                let mask;
228                if let Some(multiview_mask) = multiview_mask {
229                    mask = [multiview_mask.get()];
230
231                    // On Vulkan 1.1 or later, this is an alias for core functionality
232                    multiview_info = vk::RenderPassMultiviewCreateInfoKHR::default()
233                        .view_masks(&mask)
234                        .correlation_masks(&mask);
235                    vk_info = vk_info.push_next(&mut multiview_info);
236                }
237
238                let raw = unsafe {
239                    self.raw
240                        .create_render_pass(&vk_info, None)
241                        .map_err(super::map_host_device_oom_err)?
242                };
243
244                *e.insert(raw)
245            }
246        })
247    }
248
249    fn make_memory_ranges<'a, I: 'a + Iterator<Item = crate::MemoryRange>>(
250        &self,
251        buffer: &'a super::Buffer,
252        ranges: I,
253    ) -> Option<impl 'a + Iterator<Item = vk::MappedMemoryRange<'a>>> {
254        let super::BufferOwnership::Managed(ref allocation) = buffer.ownership else {
255            return None;
256        };
257        let allocation = allocation.lock();
258        let mask = self.private_caps.non_coherent_map_mask;
259        Some(ranges.map(move |range| {
260            vk::MappedMemoryRange::default()
261                .memory(allocation.memory())
262                .offset((allocation.offset() + range.start) & !mask)
263                .size((range.end - range.start + mask) & !mask)
264        }))
265    }
266}
267
268struct CompiledStage {
269    create_info: vk::PipelineShaderStageCreateInfo<'static>,
270    _entry_point: CString,
271    temp_raw_module: Option<vk::ShaderModule>,
272}
273
274struct MemoryProperties {
275    base: vk::PhysicalDeviceMemoryProperties,
276    heap_budget: ArrayVec<vk::DeviceSize, { vk::MAX_MEMORY_HEAPS }>,
277    heap_usage: ArrayVec<vk::DeviceSize, { vk::MAX_MEMORY_HEAPS }>,
278}
279
280impl MemoryProperties {
281    fn types(&self) -> &[vk::MemoryType] {
282        let count = self.base.memory_type_count as usize;
283        &self.base.memory_types[0..count]
284    }
285
286    fn heaps(&self) -> &[vk::MemoryHeap] {
287        let count = self.base.memory_heap_count as usize;
288        &self.base.memory_heaps[0..count]
289    }
290
291    fn heap_budget(&self) -> &[vk::DeviceSize] {
292        let count = self.base.memory_heap_count as usize;
293        &self.heap_budget[0..count]
294    }
295
296    fn heap_usage(&self) -> &[vk::DeviceSize] {
297        let count = self.base.memory_heap_count as usize;
298        &self.heap_usage[0..count]
299    }
300}
301
302impl super::Device {
303    /// # Safety
304    ///
305    /// - `vk_image` must be created respecting `desc`
306    /// - If `drop_callback` is [`None`], wgpu-hal will take ownership of `vk_image`. If
307    ///   `drop_callback` is [`Some`], `vk_image` must be valid until the callback is called.
308    /// - If the `ImageCreateFlags` does not contain `MUTABLE_FORMAT`, the `view_formats` of `desc` must be empty.
309    /// - If `memory` is not [`super::TextureMemory::External`], wgpu-hal will take ownership of the
310    ///   memory (which is presumed to back `vk_image`). Otherwise, the memory must remain valid until
311    ///   `drop_callback` is called.
312    pub unsafe fn texture_from_raw(
313        &self,
314        vk_image: vk::Image,
315        desc: &crate::TextureDescriptor,
316        drop_callback: Option<crate::DropCallback>,
317        memory: super::TextureMemory,
318    ) -> super::Texture {
319        let identity = self.shared.texture_identity_factory.next();
320        let drop_guard = crate::DropGuard::from_option(drop_callback);
321
322        if let Some(label) = desc.label {
323            unsafe { self.shared.set_object_name(vk_image, label) };
324        }
325
326        super::Texture {
327            raw: vk_image,
328            drop_guard,
329            memory,
330            format: desc.format,
331            copy_size: desc.copy_extent(),
332            identity,
333        }
334    }
335
336    fn find_memory_type_index(
337        &self,
338        type_bits_req: u32,
339        flags_req: vk::MemoryPropertyFlags,
340    ) -> Option<usize> {
341        let mem_properties = unsafe {
342            self.shared
343                .instance
344                .raw
345                .get_physical_device_memory_properties(self.shared.physical_device)
346        };
347
348        // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryProperties.html
349        for (i, mem_ty) in mem_properties.memory_types_as_slice().iter().enumerate() {
350            let types_bits = 1 << i;
351            let is_required_memory_type = type_bits_req & types_bits != 0;
352            let has_required_properties = mem_ty.property_flags & flags_req == flags_req;
353            if is_required_memory_type && has_required_properties {
354                return Some(i);
355            }
356        }
357
358        None
359    }
360
361    fn create_image_without_memory(
362        &self,
363        desc: &crate::TextureDescriptor,
364        external_memory_image_create_info: Option<&mut vk::ExternalMemoryImageCreateInfo>,
365    ) -> Result<ImageWithoutMemory, crate::DeviceError> {
366        self.create_image_without_memory_with_tiling(
367            desc,
368            vk::ImageTiling::OPTIMAL,
369            external_memory_image_create_info,
370            None,
371        )
372    }
373
374    fn create_image_without_memory_with_tiling(
375        &self,
376        desc: &crate::TextureDescriptor,
377        tiling: vk::ImageTiling,
378        external_memory_image_create_info: Option<&mut vk::ExternalMemoryImageCreateInfo>,
379        drm_modifier_info: Option<&mut vk::ImageDrmFormatModifierExplicitCreateInfoEXT>,
380    ) -> Result<ImageWithoutMemory, crate::DeviceError> {
381        let copy_size = desc.copy_extent();
382
383        let mut raw_flags = vk::ImageCreateFlags::empty();
384        if desc.dimension == wgt::TextureDimension::D3
385            && desc.usage.contains(wgt::TextureUses::COLOR_TARGET)
386        {
387            raw_flags |= vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE;
388        }
389        if desc.is_cube_compatible() {
390            raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE;
391        }
392
393        let original_format = self.shared.private_caps.map_texture_format(desc.format);
394        let mut vk_view_formats = vec![];
395        if !desc.view_formats.is_empty() {
396            raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
397
398            if self.shared.private_caps.image_format_list {
399                vk_view_formats = desc
400                    .view_formats
401                    .iter()
402                    .map(|f| self.shared.private_caps.map_texture_format(*f))
403                    .collect();
404                vk_view_formats.push(original_format)
405            }
406        }
407        if desc.format.is_multi_planar_format() {
408            raw_flags |=
409                vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE;
410        }
411
412        let mut vk_info = vk::ImageCreateInfo::default()
413            .flags(raw_flags)
414            .image_type(conv::map_texture_dimension(desc.dimension))
415            .format(original_format)
416            .extent(conv::map_copy_extent(&copy_size))
417            .mip_levels(desc.mip_level_count)
418            .array_layers(desc.array_layer_count())
419            .samples(vk::SampleCountFlags::from_raw(desc.sample_count))
420            .tiling(tiling)
421            .usage(conv::map_texture_usage(desc.usage))
422            .sharing_mode(vk::SharingMode::EXCLUSIVE)
423            .initial_layout(vk::ImageLayout::UNDEFINED);
424
425        let mut format_list_info = vk::ImageFormatListCreateInfo::default();
426        if !vk_view_formats.is_empty() {
427            format_list_info = format_list_info.view_formats(&vk_view_formats);
428            vk_info = vk_info.push_next(&mut format_list_info);
429        }
430
431        if let Some(ext_info) = external_memory_image_create_info {
432            vk_info = vk_info.push_next(ext_info);
433        }
434
435        if let Some(drm_info) = drm_modifier_info {
436            vk_info = vk_info.push_next(drm_info);
437        }
438
439        let raw = unsafe { self.shared.raw.create_image(&vk_info, None) }.map_err(map_err)?;
440        fn map_err(err: vk::Result) -> crate::DeviceError {
441            // We don't use VK_EXT_image_compression_control
442            // VK_ERROR_COMPRESSION_EXHAUSTED_EXT
443            super::map_host_device_oom_and_ioca_err(err)
444        }
445        let mut req = unsafe { self.shared.raw.get_image_memory_requirements(raw) };
446
447        if desc.usage.contains(wgt::TextureUses::TRANSIENT) {
448            let mem_type_index = self.find_memory_type_index(
449                req.memory_type_bits,
450                vk::MemoryPropertyFlags::LAZILY_ALLOCATED,
451            );
452            if let Some(mem_type_index) = mem_type_index {
453                req.memory_type_bits = 1 << mem_type_index;
454            }
455        }
456
457        Ok(ImageWithoutMemory {
458            raw,
459            requirements: req,
460        })
461    }
462
463    /// # Safety
464    ///
465    /// - Vulkan (with VK_KHR_external_memory_win32)
466    /// - The `d3d11_shared_handle` must be valid and respecting `desc`
467    /// - `VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT` flag is used because we need to hold a reference to the handle
468    #[cfg(windows)]
469    pub unsafe fn texture_from_d3d11_shared_handle(
470        &self,
471        d3d11_shared_handle: windows::Win32::Foundation::HANDLE,
472        desc: &crate::TextureDescriptor,
473    ) -> Result<super::Texture, crate::DeviceError> {
474        if !self
475            .shared
476            .features
477            .contains(wgt::Features::VULKAN_EXTERNAL_MEMORY_WIN32)
478        {
479            log::error!("Vulkan driver does not support VK_KHR_external_memory_win32");
480            return Err(crate::DeviceError::Unexpected);
481        }
482
483        let mut external_memory_image_info = vk::ExternalMemoryImageCreateInfo::default()
484            .handle_types(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE);
485
486        let image =
487            self.create_image_without_memory(desc, Some(&mut external_memory_image_info))?;
488
489        // Some external memory types require dedicated allocation
490        // https://docs.vulkan.org/guide/latest/extensions/external.html#_importing_memory
491        let mut dedicated_allocate_info =
492            vk::MemoryDedicatedAllocateInfo::default().image(image.raw);
493
494        let mut import_memory_info = vk::ImportMemoryWin32HandleInfoKHR::default()
495            .handle_type(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE)
496            .handle(d3d11_shared_handle.0 as _);
497        // TODO: We should use `push_next` instead, but currently ash does not provide this method for the `ImportMemoryWin32HandleInfoKHR` type.
498        #[allow(clippy::unnecessary_mut_passed)]
499        {
500            import_memory_info.p_next = <*const _>::cast(&mut dedicated_allocate_info);
501        }
502
503        let mem_type_index = self
504            .find_memory_type_index(
505                image.requirements.memory_type_bits,
506                vk::MemoryPropertyFlags::DEVICE_LOCAL,
507            )
508            .ok_or(crate::DeviceError::Unexpected)?;
509
510        let memory_allocate_info = vk::MemoryAllocateInfo::default()
511            .allocation_size(image.requirements.size)
512            .memory_type_index(mem_type_index as _)
513            .push_next(&mut import_memory_info);
514        let memory = unsafe { self.shared.raw.allocate_memory(&memory_allocate_info, None) }
515            .map_err(super::map_host_device_oom_err)?;
516
517        unsafe { self.shared.raw.bind_image_memory(image.raw, memory, 0) }
518            .map_err(super::map_host_device_oom_err)?;
519
520        Ok(unsafe {
521            self.texture_from_raw(
522                image.raw,
523                desc,
524                None,
525                super::TextureMemory::Dedicated(memory),
526            )
527        })
528    }
529
530    /// Import a DMA-buf as a texture. Currently only supports single-plane DMA-bufs.
531    ///
532    /// # Safety
533    ///
534    /// - Requires `VULKAN_EXTERNAL_MEMORY_DMA_BUF` feature (implies VK_EXT_external_memory_dma_buf
535    ///   and VK_EXT_image_drm_format_modifier)
536    /// - The `fd` must be a valid DMA-buf file descriptor matching `desc`
537    /// - On success, Vulkan takes ownership of the file descriptor. On failure,
538    ///   the file descriptor is closed.
539    /// - The `drm_modifier`, `stride`, and `offset` must match the DMA-buf layout
540    #[cfg(unix)]
541    pub unsafe fn texture_from_dmabuf_fd(
542        &self,
543        fd: std::os::unix::io::OwnedFd,
544        desc: &crate::TextureDescriptor,
545        drm_modifier: u64,
546        stride: u64,
547        offset: u64,
548    ) -> Result<super::Texture, crate::DeviceError> {
549        use std::os::unix::io::IntoRawFd;
550
551        if !self
552            .shared
553            .features
554            .contains(wgt::Features::VULKAN_EXTERNAL_MEMORY_DMA_BUF)
555        {
556            log::error!(
557                "Vulkan driver does not support VK_EXT_external_memory_dma_buf \
558                 or VK_EXT_image_drm_format_modifier"
559            );
560            return Err(crate::DeviceError::Unexpected);
561        }
562
563        let external_memory_fd_fn = self
564            .shared
565            .extension_fns
566            .external_memory_fd
567            .as_ref()
568            .ok_or_else(|| {
569                log::error!("VK_KHR_external_memory_fd extension not loaded");
570                crate::DeviceError::Unexpected
571            })?;
572
573        let mut external_memory_image_info = vk::ExternalMemoryImageCreateInfo::default()
574            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
575
576        let plane_layout = vk::SubresourceLayout {
577            offset,
578            row_pitch: stride,
579            size: 0,
580            array_pitch: 0,
581            depth_pitch: 0,
582        };
583        let mut drm_modifier_info = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default()
584            .drm_format_modifier(drm_modifier)
585            .plane_layouts(core::slice::from_ref(&plane_layout));
586
587        let image = self.create_image_without_memory_with_tiling(
588            desc,
589            vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT,
590            Some(&mut external_memory_image_info),
591            Some(&mut drm_modifier_info),
592        )?;
593
594        // Convert to raw fd. We must close it ourselves if any operation below
595        // fails, since Vulkan only takes ownership on successful vkAllocateMemory.
596        let fd_raw = fd.into_raw_fd();
597
598        let result = self.import_dmabuf_memory(
599            external_memory_fd_fn,
600            fd_raw,
601            image.raw,
602            &image.requirements,
603        );
604
605        match result {
606            Ok(memory) => Ok(unsafe {
607                self.texture_from_raw(
608                    image.raw,
609                    desc,
610                    None,
611                    super::TextureMemory::Dedicated(memory),
612                )
613            }),
614            Err(e) => {
615                // Clean up the VkImage on failure.
616                unsafe { self.shared.raw.destroy_image(image.raw, None) };
617                Err(e)
618            }
619        }
620    }
621
622    /// Import DMA-buf memory and bind it to the image.
623    ///
624    /// On failure, the raw fd is closed (if not yet consumed by Vulkan) and the
625    /// caller is responsible for destroying the VkImage.
626    #[cfg(unix)]
627    fn import_dmabuf_memory(
628        &self,
629        external_memory_fd_fn: &ash::khr::external_memory_fd::Device,
630        fd_raw: i32,
631        image: vk::Image,
632        requirements: &vk::MemoryRequirements,
633    ) -> Result<vk::DeviceMemory, crate::DeviceError> {
634        let mut fd_props = vk::MemoryFdPropertiesKHR::default();
635        unsafe {
636            external_memory_fd_fn.get_memory_fd_properties(
637                vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT,
638                fd_raw,
639                &mut fd_props,
640            )
641        }
642        .map_err(|e| {
643            unsafe { libc::close(fd_raw) };
644            super::map_host_device_oom_err(e)
645        })?;
646
647        let mem_type_index = self
648            .find_memory_type_index(
649                requirements.memory_type_bits & fd_props.memory_type_bits,
650                vk::MemoryPropertyFlags::empty(),
651            )
652            .ok_or_else(|| {
653                unsafe { libc::close(fd_raw) };
654                crate::DeviceError::Unexpected
655            })?;
656
657        let mut dedicated_allocate_info = vk::MemoryDedicatedAllocateInfo::default().image(image);
658
659        let mut import_memory_info = vk::ImportMemoryFdInfoKHR::default()
660            .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
661            .fd(fd_raw);
662
663        let memory_allocate_info = vk::MemoryAllocateInfo::default()
664            .allocation_size(requirements.size)
665            .memory_type_index(mem_type_index as _)
666            .push_next(&mut import_memory_info)
667            .push_next(&mut dedicated_allocate_info);
668
669        // vkAllocateMemory takes ownership of the fd on success.
670        // On failure, the fd is NOT consumed and we must close it.
671        let memory = unsafe { self.shared.raw.allocate_memory(&memory_allocate_info, None) }
672            .map_err(|e| {
673                unsafe { libc::close(fd_raw) };
674                super::map_host_device_oom_err(e)
675            })?;
676
677        // From this point, the fd is consumed. Only VkDeviceMemory needs cleanup on error.
678        unsafe { self.shared.raw.bind_image_memory(image, memory, 0) }.map_err(|e| {
679            unsafe { self.shared.raw.free_memory(memory, None) };
680            super::map_host_device_oom_err(e)
681        })?;
682
683        Ok(memory)
684    }
685
686    fn create_shader_module_impl(
687        &self,
688        spv: &[u32],
689        label: &crate::Label<'_>,
690    ) -> Result<vk::ShaderModule, crate::DeviceError> {
691        let vk_info = vk::ShaderModuleCreateInfo::default()
692            .flags(vk::ShaderModuleCreateFlags::empty())
693            .code(spv);
694
695        let raw = unsafe {
696            profiling::scope!("vkCreateShaderModule");
697            self.shared
698                .raw
699                .create_shader_module(&vk_info, None)
700                .map_err(map_err)?
701        };
702        fn map_err(err: vk::Result) -> crate::DeviceError {
703            // We don't use VK_NV_glsl_shader
704            // VK_ERROR_INVALID_SHADER_NV
705            super::map_host_device_oom_err(err)
706        }
707
708        if let Some(label) = label {
709            unsafe { self.shared.set_object_name(raw, label) };
710        }
711
712        Ok(raw)
713    }
714
715    fn compile_stage(
716        &self,
717        stage: &crate::ProgrammableStage<super::ShaderModule>,
718        naga_stage: naga::ShaderStage,
719        binding_map: &naga::back::spv::BindingMap,
720    ) -> Result<CompiledStage, crate::PipelineError> {
721        let stage_flags = crate::auxil::map_naga_stage(naga_stage);
722        let vk_module = match *stage.module {
723            super::ShaderModule::Raw(raw) => raw,
724            super::ShaderModule::Intermediate {
725                ref naga_shader,
726                runtime_checks,
727            } => {
728                let pipeline_options = naga::back::spv::PipelineOptions {
729                    entry_point: stage.entry_point.to_owned(),
730                    shader_stage: naga_stage,
731                };
732                let needs_temp_options = !runtime_checks.bounds_checks
733                    || !runtime_checks.force_loop_bounding
734                    || !runtime_checks.ray_query_initialization_tracking
735                    || !binding_map.is_empty()
736                    || naga_shader.debug_source.is_some()
737                    || !stage.zero_initialize_workgroup_memory
738                    || !runtime_checks.task_shader_dispatch_tracking
739                    || !runtime_checks.mesh_shader_primitive_indices_clamp
740                    || !runtime_checks.int_div_checks;
741
742                let mut temp_options;
743                let options = if needs_temp_options {
744                    temp_options = self.naga_options.clone();
745                    if !runtime_checks.bounds_checks {
746                        temp_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
747                            index: naga::proc::BoundsCheckPolicy::Unchecked,
748                            buffer: naga::proc::BoundsCheckPolicy::Unchecked,
749                            image_load: naga::proc::BoundsCheckPolicy::Unchecked,
750                            binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
751                        };
752                    }
753                    if !runtime_checks.force_loop_bounding {
754                        temp_options.force_loop_bounding = false;
755                    }
756                    if !runtime_checks.ray_query_initialization_tracking {
757                        temp_options.ray_query_initialization_tracking = false;
758                    }
759                    if !binding_map.is_empty() {
760                        temp_options.binding_map = binding_map.clone();
761                    }
762
763                    if let Some(ref debug) = naga_shader.debug_source {
764                        temp_options.debug_info = Some(naga::back::spv::DebugInfo {
765                            source_code: &debug.source_code,
766                            file_name: debug.file_name.as_ref(),
767                            language: naga::back::spv::SourceLanguage::WGSL,
768                        })
769                    }
770                    if !stage.zero_initialize_workgroup_memory {
771                        temp_options.zero_initialize_workgroup_memory =
772                            naga::back::spv::ZeroInitializeWorkgroupMemoryMode::None;
773                    }
774                    if !runtime_checks.task_shader_dispatch_tracking {
775                        temp_options.task_dispatch_limits = None;
776                    }
777                    temp_options.mesh_shader_primitive_indices_clamp =
778                        runtime_checks.mesh_shader_primitive_indices_clamp;
779                    temp_options.emit_int_div_checks = runtime_checks.int_div_checks;
780
781                    &temp_options
782                } else {
783                    &self.naga_options
784                };
785
786                let (module, info) = naga::back::pipeline_constants::process_overrides(
787                    &naga_shader.module,
788                    &naga_shader.info,
789                    Some((naga_stage, stage.entry_point)),
790                    stage.constants,
791                )
792                .map_err(|e| {
793                    crate::PipelineError::PipelineConstants(stage_flags, format!("{e}"))
794                })?;
795
796                let spv = {
797                    profiling::scope!("naga::spv::write_vec");
798                    naga::back::spv::write_vec(&module, &info, options, Some(&pipeline_options))
799                }
800                .map_err(|e| crate::PipelineError::Linkage(stage_flags, format!("{e}")))?;
801                self.create_shader_module_impl(&spv, &None)?
802            }
803        };
804
805        let mut flags = vk::PipelineShaderStageCreateFlags::empty();
806        if self.shared.features.contains(wgt::Features::SUBGROUP) {
807            flags |= vk::PipelineShaderStageCreateFlags::ALLOW_VARYING_SUBGROUP_SIZE
808        }
809
810        let entry_point = CString::new(stage.entry_point).unwrap();
811        let mut create_info = vk::PipelineShaderStageCreateInfo::default()
812            .flags(flags)
813            .stage(conv::map_shader_stage(stage_flags))
814            .module(vk_module);
815
816        // Circumvent struct lifetime check because of a self-reference inside CompiledStage
817        create_info.p_name = entry_point.as_ptr();
818
819        Ok(CompiledStage {
820            create_info,
821            _entry_point: entry_point,
822            temp_raw_module: match *stage.module {
823                super::ShaderModule::Raw(_) => None,
824                super::ShaderModule::Intermediate { .. } => Some(vk_module),
825            },
826        })
827    }
828
829    /// Returns the queue family index of the device's internal queue.
830    ///
831    /// This is useful for constructing memory barriers needed for queue family ownership transfer when
832    /// external memory is involved (from/to `VK_QUEUE_FAMILY_EXTERNAL_KHR` and `VK_QUEUE_FAMILY_FOREIGN_EXT`
833    /// for example).
834    pub fn queue_family_index(&self) -> u32 {
835        self.shared.family_index
836    }
837
838    pub fn queue_index(&self) -> u32 {
839        self.shared.queue_index
840    }
841
842    pub fn raw_device(&self) -> &ash::Device {
843        &self.shared.raw
844    }
845
846    pub fn raw_physical_device(&self) -> vk::PhysicalDevice {
847        self.shared.physical_device
848    }
849
850    pub fn raw_queue(&self) -> vk::Queue {
851        self.shared.raw_queue
852    }
853
854    pub fn enabled_device_extensions(&self) -> &[&'static CStr] {
855        &self.shared.enabled_extensions
856    }
857
858    pub fn shared_instance(&self) -> &super::InstanceShared {
859        &self.shared.instance
860    }
861
862    fn get_memory_properties(&self) -> Option<MemoryProperties> {
863        if !self
864            .shared
865            .enabled_extensions
866            .contains(&ext::memory_budget::NAME)
867        {
868            return None;
869        }
870
871        let get_physical_device_properties = self
872            .shared
873            .instance
874            .get_physical_device_properties
875            .as_ref()
876            .unwrap();
877
878        let mut budget = vk::PhysicalDeviceMemoryBudgetPropertiesEXT::default();
879        let mut props = vk::PhysicalDeviceMemoryProperties2::default().push_next(&mut budget);
880
881        unsafe {
882            get_physical_device_properties
883                .get_physical_device_memory_properties2(self.shared.physical_device, &mut props);
884        }
885
886        let vk::PhysicalDeviceMemoryProperties2 {
887            memory_properties, ..
888        } = props;
889
890        let mut heap_budget = ArrayVec::from(budget.heap_budget);
891        let mut heap_usage = ArrayVec::from(budget.heap_usage);
892        heap_budget.truncate(memory_properties.memory_heap_count as usize);
893        heap_usage.truncate(memory_properties.memory_heap_count as usize);
894
895        Some(MemoryProperties {
896            base: memory_properties,
897            heap_budget,
898            heap_usage,
899        })
900    }
901
902    /// Predict whether a proposed allocation will result in an OOM condition.
903    ///
904    /// If so, returns `Err(crate::DeviceError::OutOfMemory)`. If not, returns
905    /// `Ok(())`.
906    ///
907    /// The prediction quality depends on accurately selecting the heap that
908    /// [`gpu_allocator`] will use for the allocation, and is subject to
909    /// deteriorate if the logic in [`gpu_allocator`] changes.
910    fn error_if_would_oom_on_resource_allocation(
911        &self,
912        location: gpu_allocator::MemoryLocation,
913        requirements: &vk::MemoryRequirements,
914    ) -> Result<(), crate::DeviceError> {
915        use gpu_allocator::MemoryLocation;
916
917        let Some(threshold) = self
918            .shared
919            .instance
920            .memory_budget_thresholds
921            .for_resource_creation
922        else {
923            return Ok(());
924        };
925
926        let Some(memory_properties) = self.get_memory_properties() else {
927            return Ok(());
928        };
929
930        let preferred_flags = match location {
931            MemoryLocation::GpuOnly => vk::MemoryPropertyFlags::DEVICE_LOCAL,
932            MemoryLocation::CpuToGpu => {
933                vk::MemoryPropertyFlags::HOST_VISIBLE
934                    | vk::MemoryPropertyFlags::HOST_COHERENT
935                    | vk::MemoryPropertyFlags::DEVICE_LOCAL
936            }
937            MemoryLocation::GpuToCpu => {
938                vk::MemoryPropertyFlags::HOST_VISIBLE
939                    | vk::MemoryPropertyFlags::HOST_COHERENT
940                    | vk::MemoryPropertyFlags::HOST_CACHED
941            }
942            MemoryLocation::Unknown => vk::MemoryPropertyFlags::empty(),
943        };
944
945        let mut selected_heap = memory_properties
946            .types()
947            .iter()
948            .enumerate()
949            .find(|(i, ty)| {
950                (1 << i) & requirements.memory_type_bits != 0
951                    && ty.property_flags.contains(preferred_flags)
952            });
953
954        if selected_heap.is_none() {
955            let required_flags = match location {
956                MemoryLocation::GpuOnly => vk::MemoryPropertyFlags::DEVICE_LOCAL,
957                MemoryLocation::CpuToGpu | MemoryLocation::GpuToCpu => {
958                    vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT
959                }
960                MemoryLocation::Unknown => vk::MemoryPropertyFlags::empty(),
961            };
962            selected_heap = memory_properties
963                .types()
964                .iter()
965                .enumerate()
966                .find(|(i, ty)| {
967                    (1 << i) & requirements.memory_type_bits != 0
968                        && ty.property_flags.contains(required_flags)
969                });
970        }
971
972        if let Some((_, ty)) = selected_heap {
973            let i = ty.heap_index as usize;
974            let heap_usage = memory_properties.heap_usage()[i];
975            let heap_budget = memory_properties.heap_budget()[i];
976            if heap_usage + requirements.size < heap_budget / 100 * threshold as u64 {
977                Ok(())
978            } else {
979                log::warn!(
980                    "Allocation would result in an OOM condition\n\
981                    Request: {requirements:?}\n\
982                    Heap {index} had {heap_usage}B used of {heap_budget}B total before this request.",
983                    index = ty.heap_index,
984                );
985                Err(crate::DeviceError::OutOfMemory)
986            }
987        } else {
988            log::warn!("Failed to find a suitable heap for {requirements:?}");
989            Err(crate::DeviceError::OutOfMemory)
990        }
991    }
992}
993
994impl crate::Device for super::Device {
995    type A = super::Api;
996
997    unsafe fn create_buffer(
998        &self,
999        desc: &crate::BufferDescriptor,
1000    ) -> Result<super::Buffer, crate::DeviceError> {
1001        let vk_info = vk::BufferCreateInfo::default()
1002            .size(desc.size)
1003            .usage(conv::map_buffer_usage(desc.usage))
1004            .sharing_mode(vk::SharingMode::EXCLUSIVE);
1005
1006        let raw = unsafe {
1007            self.shared
1008                .raw
1009                .create_buffer(&vk_info, None)
1010                .map_err(super::map_host_device_oom_and_ioca_err)?
1011        };
1012
1013        let mut requirements = unsafe { self.shared.raw.get_buffer_memory_requirements(raw) };
1014
1015        let is_cpu_read = desc.usage.contains(wgt::BufferUses::MAP_READ);
1016        let is_cpu_write = desc.usage.contains(wgt::BufferUses::MAP_WRITE);
1017
1018        let location = match (is_cpu_read, is_cpu_write) {
1019            (true, true) => gpu_allocator::MemoryLocation::CpuToGpu,
1020            (true, false) => gpu_allocator::MemoryLocation::GpuToCpu,
1021            (false, true) => gpu_allocator::MemoryLocation::CpuToGpu,
1022            (false, false) => gpu_allocator::MemoryLocation::GpuOnly,
1023        };
1024
1025        self.error_if_would_oom_on_resource_allocation(location, &requirements)
1026            .inspect_err(|_| {
1027                unsafe { self.shared.raw.destroy_buffer(raw, None) };
1028            })?;
1029
1030        let name = desc.label.unwrap_or("Unlabeled buffer");
1031
1032        if desc
1033            .usage
1034            .contains(wgt::BufferUses::ACCELERATION_STRUCTURE_SCRATCH)
1035        {
1036            // There is no way to specify this usage to Vulkan so we must make sure the alignment requirement is large enough.
1037            requirements.alignment = requirements
1038                .alignment
1039                .max(self.shared.private_caps.scratch_buffer_alignment as u64);
1040        }
1041
1042        let allocation = self
1043            .mem_allocator
1044            .lock()
1045            .allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
1046                name,
1047                requirements: vk::MemoryRequirements {
1048                    memory_type_bits: requirements.memory_type_bits & self.valid_ash_memory_types,
1049                    ..requirements
1050                },
1051                location,
1052                linear: true, // Buffers are always linear
1053                allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
1054            })
1055            .inspect_err(|_| {
1056                unsafe { self.shared.raw.destroy_buffer(raw, None) };
1057            })?;
1058
1059        unsafe {
1060            self.shared
1061                .raw
1062                .bind_buffer_memory(raw, allocation.memory(), allocation.offset())
1063        }
1064        .map_err(super::map_host_device_oom_and_ioca_err)
1065        .inspect_err(|_| {
1066            unsafe { self.shared.raw.destroy_buffer(raw, None) };
1067        })?;
1068
1069        if let Some(label) = desc.label {
1070            unsafe { self.shared.set_object_name(raw, label) };
1071        }
1072
1073        self.counters.buffer_memory.add(allocation.size() as isize);
1074        self.counters.buffers.add(1);
1075
1076        Ok(super::Buffer {
1077            raw,
1078            ownership: super::BufferOwnership::Managed(Mutex::new(
1079                super::BufferMemoryBacking::Managed(allocation),
1080            )),
1081        })
1082    }
1083    unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
1084        match buffer.ownership {
1085            super::BufferOwnership::Managed(allocation) => {
1086                unsafe { self.shared.raw.destroy_buffer(buffer.raw, None) };
1087                let allocation = allocation.into_inner();
1088                self.counters.buffer_memory.sub(allocation.size() as isize);
1089                match allocation {
1090                    super::BufferMemoryBacking::Managed(allocation) => {
1091                        let result = self.mem_allocator.lock().free(allocation);
1092                        if let Err(err) = result {
1093                            log::warn!("Failed to free buffer allocation: {err}");
1094                        }
1095                    }
1096                    super::BufferMemoryBacking::VulkanMemory { memory, .. } => unsafe {
1097                        self.shared.raw.free_memory(memory, None);
1098                    },
1099                }
1100            }
1101            super::BufferOwnership::RawHandle => {
1102                unsafe { self.shared.raw.destroy_buffer(buffer.raw, None) };
1103            }
1104            super::BufferOwnership::External(_drop_guard) => {
1105                // The caller owns the `vk::Buffer` and its memory. Dropping
1106                // `_drop_guard` at the end of this arm runs the cleanup callback.
1107            }
1108        }
1109
1110        self.counters.buffers.sub(1);
1111    }
1112
1113    unsafe fn add_raw_buffer(&self, _buffer: &super::Buffer) {
1114        self.counters.buffers.add(1);
1115    }
1116
1117    unsafe fn map_buffer(
1118        &self,
1119        buffer: &super::Buffer,
1120        range: crate::MemoryRange,
1121    ) -> Result<crate::BufferMapping, crate::DeviceError> {
1122        let super::BufferOwnership::Managed(ref allocation) = buffer.ownership else {
1123            crate::hal_usage_error("tried to map external buffer")
1124        };
1125        let mut allocation = allocation.lock();
1126        let super::BufferMemoryBacking::Managed(ref mut allocation) = *allocation else {
1127            crate::hal_usage_error("tried to map externally created buffer")
1128        };
1129        let is_coherent = allocation
1130            .memory_properties()
1131            .contains(vk::MemoryPropertyFlags::HOST_COHERENT);
1132        Ok(crate::BufferMapping {
1133            ptr: unsafe {
1134                allocation
1135                    .mapped_ptr()
1136                    .unwrap()
1137                    .cast()
1138                    .offset(range.start as isize)
1139            },
1140            is_coherent,
1141        })
1142    }
1143
1144    unsafe fn unmap_buffer(&self, buffer: &super::Buffer) {
1145        match buffer.ownership {
1146            super::BufferOwnership::Managed(_) => {
1147                // gpu-allocator maps the buffer when allocated and unmaps it when free'd
1148            }
1149            super::BufferOwnership::RawHandle | super::BufferOwnership::External(_) => {
1150                crate::hal_usage_error("tried to unmap external buffer")
1151            }
1152        }
1153    }
1154
1155    unsafe fn flush_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
1156    where
1157        I: Iterator<Item = crate::MemoryRange>,
1158    {
1159        if let Some(vk_ranges) = self.shared.make_memory_ranges(buffer, ranges) {
1160            unsafe {
1161                self.shared
1162                    .raw
1163                    .flush_mapped_memory_ranges(
1164                        &smallvec::SmallVec::<[vk::MappedMemoryRange; 32]>::from_iter(vk_ranges),
1165                    )
1166            }
1167            .unwrap();
1168        }
1169    }
1170    unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
1171    where
1172        I: Iterator<Item = crate::MemoryRange>,
1173    {
1174        if let Some(vk_ranges) = self.shared.make_memory_ranges(buffer, ranges) {
1175            unsafe {
1176                self.shared
1177                    .raw
1178                    .invalidate_mapped_memory_ranges(&smallvec::SmallVec::<
1179                        [vk::MappedMemoryRange; 32],
1180                    >::from_iter(vk_ranges))
1181            }
1182            .unwrap();
1183        }
1184    }
1185
1186    unsafe fn create_texture(
1187        &self,
1188        desc: &crate::TextureDescriptor,
1189    ) -> Result<super::Texture, crate::DeviceError> {
1190        let image = self.create_image_without_memory(desc, None)?;
1191
1192        self.error_if_would_oom_on_resource_allocation(
1193            gpu_allocator::MemoryLocation::GpuOnly,
1194            &image.requirements,
1195        )
1196        .inspect_err(|_| {
1197            unsafe { self.shared.raw.destroy_image(image.raw, None) };
1198        })?;
1199
1200        let name = desc.label.unwrap_or("Unlabeled texture");
1201
1202        let allocation = self
1203            .mem_allocator
1204            .lock()
1205            .allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
1206                name,
1207                requirements: vk::MemoryRequirements {
1208                    memory_type_bits: image.requirements.memory_type_bits
1209                        & self.valid_ash_memory_types,
1210                    ..image.requirements
1211                },
1212                location: gpu_allocator::MemoryLocation::GpuOnly,
1213                linear: false,
1214                allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
1215            })
1216            .inspect_err(|_| {
1217                unsafe { self.shared.raw.destroy_image(image.raw, None) };
1218            })?;
1219
1220        unsafe {
1221            self.shared
1222                .raw
1223                .bind_image_memory(image.raw, allocation.memory(), allocation.offset())
1224        }
1225        .map_err(super::map_host_device_oom_err)
1226        .inspect_err(|_| {
1227            unsafe { self.shared.raw.destroy_image(image.raw, None) };
1228        })?;
1229
1230        self.counters.texture_memory.add(allocation.size() as isize);
1231        self.counters.textures.add(1);
1232
1233        Ok(unsafe {
1234            self.texture_from_raw(
1235                image.raw,
1236                desc,
1237                None,
1238                super::TextureMemory::Allocation(allocation),
1239            )
1240        })
1241    }
1242
1243    unsafe fn destroy_texture(&self, texture: super::Texture) {
1244        if texture.drop_guard.is_none() {
1245            unsafe { self.shared.raw.destroy_image(texture.raw, None) };
1246        }
1247
1248        match texture.memory {
1249            super::TextureMemory::Allocation(allocation) => {
1250                self.counters.texture_memory.sub(allocation.size() as isize);
1251                let result = self.mem_allocator.lock().free(allocation);
1252                if let Err(err) = result {
1253                    log::warn!("Failed to free texture allocation: {err}");
1254                }
1255            }
1256            super::TextureMemory::Dedicated(memory) => unsafe {
1257                self.shared.raw.free_memory(memory, None);
1258            },
1259            super::TextureMemory::External => {}
1260        }
1261
1262        self.counters.textures.sub(1);
1263    }
1264
1265    unsafe fn add_raw_texture(&self, _texture: &super::Texture) {
1266        self.counters.textures.add(1);
1267    }
1268
1269    unsafe fn create_texture_view(
1270        &self,
1271        texture: &super::Texture,
1272        desc: &crate::TextureViewDescriptor,
1273    ) -> Result<super::TextureView, crate::DeviceError> {
1274        let mut swizzle = desc.swizzle;
1275
1276        // https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#textures-component-swizzle
1277        // If the image view has a depth/stencil format and the VkComponentSwizzle is VK_COMPONENT_SWIZZLE_ONE,
1278        // and VkPhysicalDeviceMaintenance5Properties::depthStencilSwizzleOneSupport is not VK_TRUE,
1279        // the value of the texel after swizzle is undefined.
1280        //
1281        // We convert `One` to `A` which should sample as 1.0,
1282        // according to https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#images-component-substitution
1283        if texture.format.is_depth_stencil_format()
1284            && !self.shared.private_caps.depth_stencil_swizzle_one_support
1285        {
1286            for component in [
1287                &mut swizzle.r,
1288                &mut swizzle.g,
1289                &mut swizzle.b,
1290                &mut swizzle.a,
1291            ] {
1292                if *component == wgt::ComponentSwizzle::One {
1293                    *component = wgt::ComponentSwizzle::A;
1294                }
1295            }
1296        }
1297
1298        let subresource_range = conv::map_subresource_range(&desc.range, texture.format);
1299        let raw_format = self.shared.private_caps.map_texture_format(desc.format);
1300        let mut vk_info = vk::ImageViewCreateInfo::default()
1301            .flags(vk::ImageViewCreateFlags::empty())
1302            .image(texture.raw)
1303            .view_type(conv::map_view_dimension(desc.dimension))
1304            .format(raw_format)
1305            .subresource_range(subresource_range)
1306            .components(conv::map_texture_component_swizzle(swizzle));
1307        let layers =
1308            NonZeroU32::new(subresource_range.layer_count).expect("Unexpected zero layer count");
1309
1310        let mut image_view_info;
1311        if self.shared.private_caps.image_view_usage && !desc.usage.is_empty() {
1312            image_view_info =
1313                vk::ImageViewUsageCreateInfo::default().usage(conv::map_texture_usage(desc.usage));
1314            vk_info = vk_info.push_next(&mut image_view_info);
1315        }
1316
1317        let raw = unsafe { self.shared.raw.create_image_view(&vk_info, None) }
1318            .map_err(super::map_host_device_oom_and_ioca_err)?;
1319
1320        if let Some(label) = desc.label {
1321            unsafe { self.shared.set_object_name(raw, label) };
1322        }
1323
1324        let identity = self.shared.texture_view_identity_factory.next();
1325
1326        self.counters.texture_views.add(1);
1327
1328        Ok(super::TextureView {
1329            raw_texture: texture.raw,
1330            raw,
1331            _layers: layers,
1332            format: desc.format,
1333            raw_format,
1334            base_mip_level: desc.range.base_mip_level,
1335            dimension: desc.dimension,
1336            texture_identity: texture.identity,
1337            view_identity: identity,
1338        })
1339    }
1340    unsafe fn destroy_texture_view(&self, view: super::TextureView) {
1341        unsafe { self.shared.raw.destroy_image_view(view.raw, None) };
1342
1343        self.counters.texture_views.sub(1);
1344    }
1345
1346    unsafe fn create_sampler(
1347        &self,
1348        desc: &crate::SamplerDescriptor,
1349    ) -> Result<super::Sampler, crate::DeviceError> {
1350        let mut create_info = vk::SamplerCreateInfo::default()
1351            .flags(vk::SamplerCreateFlags::empty())
1352            .mag_filter(conv::map_filter_mode(desc.mag_filter))
1353            .min_filter(conv::map_filter_mode(desc.min_filter))
1354            .mipmap_mode(conv::map_mip_filter_mode(desc.mipmap_filter))
1355            .address_mode_u(conv::map_address_mode(desc.address_modes[0]))
1356            .address_mode_v(conv::map_address_mode(desc.address_modes[1]))
1357            .address_mode_w(conv::map_address_mode(desc.address_modes[2]))
1358            .min_lod(desc.lod_clamp.start)
1359            .max_lod(desc.lod_clamp.end);
1360
1361        if let Some(fun) = desc.compare {
1362            create_info = create_info
1363                .compare_enable(true)
1364                .compare_op(conv::map_comparison(fun));
1365        }
1366
1367        if desc.anisotropy_clamp != 1 {
1368            // We only enable anisotropy if it is supported, and wgpu-hal interface guarantees
1369            // the clamp is in the range [1, 16] which is always supported if anisotropy is.
1370            create_info = create_info
1371                .anisotropy_enable(true)
1372                .max_anisotropy(desc.anisotropy_clamp as f32);
1373        }
1374
1375        if let Some(color) = desc.border_color {
1376            create_info = create_info.border_color(conv::map_border_color(color));
1377        }
1378
1379        let mut sampler_cache_guard = self.shared.sampler_cache.lock();
1380
1381        let raw = sampler_cache_guard.create_sampler(&self.shared.raw, create_info)?;
1382
1383        // Note: Cached samplers will just continually overwrite the label
1384        //
1385        // https://github.com/gfx-rs/wgpu/issues/6867
1386        if let Some(label) = desc.label {
1387            // SAFETY: we are holding a lock on the sampler cache,
1388            // so we can only be setting the name from one thread.
1389            unsafe { self.shared.set_object_name(raw, label) };
1390        }
1391
1392        drop(sampler_cache_guard);
1393
1394        self.counters.samplers.add(1);
1395
1396        Ok(super::Sampler { raw, create_info })
1397    }
1398    unsafe fn destroy_sampler(&self, sampler: super::Sampler) {
1399        self.shared.sampler_cache.lock().destroy_sampler(
1400            &self.shared.raw,
1401            sampler.create_info,
1402            sampler.raw,
1403        );
1404
1405        self.counters.samplers.sub(1);
1406    }
1407
1408    unsafe fn create_command_encoder(
1409        &self,
1410        desc: &crate::CommandEncoderDescriptor<super::Queue>,
1411    ) -> Result<super::CommandEncoder, crate::DeviceError> {
1412        let vk_info = vk::CommandPoolCreateInfo::default()
1413            .queue_family_index(desc.queue.family_index)
1414            .flags(vk::CommandPoolCreateFlags::TRANSIENT);
1415
1416        let raw = unsafe {
1417            self.shared
1418                .raw
1419                .create_command_pool(&vk_info, None)
1420                .map_err(super::map_host_device_oom_err)?
1421        };
1422
1423        self.counters.command_encoders.add(1);
1424
1425        Ok(super::CommandEncoder {
1426            raw,
1427            device: Arc::clone(&self.shared),
1428            active: vk::CommandBuffer::null(),
1429            bind_point: vk::PipelineBindPoint::default(),
1430            temp: super::Temp::default(),
1431            free: Vec::new(),
1432            discarded: Vec::new(),
1433            rpass_debug_marker_active: false,
1434            end_of_pass_timer_query: None,
1435            framebuffers: Default::default(),
1436            temp_texture_views: Default::default(),
1437            counters: Arc::clone(&self.counters),
1438            current_pipeline_is_multiview: false,
1439        })
1440    }
1441
1442    unsafe fn create_bind_group_layout(
1443        &self,
1444        desc: &crate::BindGroupLayoutDescriptor,
1445    ) -> Result<super::BindGroupLayout, crate::DeviceError> {
1446        // Iterate through the entries and accumulate our Vulkan
1447        // DescriptorSetLayoutBindings and DescriptorBindingFlags, as well as
1448        // our binding map and our descriptor counts.
1449        // Note: not bothering with on stack arrays here as it's low frequency
1450        let mut vk_bindings = Vec::new();
1451        let mut binding_flags = Vec::new();
1452        let mut binding_map = Vec::new();
1453        let mut next_binding = 0;
1454        let mut contains_binding_arrays = false;
1455        let mut desc_count = DescriptorCounts::default();
1456        for entry in desc.entries {
1457            if entry.count.is_some() {
1458                contains_binding_arrays = true;
1459            }
1460
1461            let partially_bound = desc
1462                .flags
1463                .contains(crate::BindGroupLayoutFlags::PARTIALLY_BOUND);
1464            let mut flags = vk::DescriptorBindingFlags::empty();
1465            if partially_bound && entry.count.is_some() {
1466                flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
1467            }
1468            if entry.count.is_some() {
1469                flags |= vk::DescriptorBindingFlags::UPDATE_AFTER_BIND;
1470            }
1471
1472            let count = entry.count.map_or(1, |c| c.get());
1473            match entry.ty {
1474                wgt::BindingType::ExternalTexture => unimplemented!(),
1475                _ => {
1476                    vk_bindings.push(vk::DescriptorSetLayoutBinding {
1477                        binding: next_binding,
1478                        descriptor_type: conv::map_binding_type(entry.ty),
1479                        descriptor_count: count,
1480                        stage_flags: conv::map_shader_stage(entry.visibility),
1481                        p_immutable_samplers: ptr::null(),
1482                        _marker: Default::default(),
1483                    });
1484                    binding_flags.push(flags);
1485                    binding_map.push((
1486                        entry.binding,
1487                        super::BindingInfo {
1488                            binding: next_binding,
1489                            binding_array_size: entry.count,
1490                        },
1491                    ));
1492                    next_binding += 1;
1493                }
1494            }
1495
1496            match entry.ty {
1497                wgt::BindingType::Buffer {
1498                    ty,
1499                    has_dynamic_offset,
1500                    ..
1501                } => match ty {
1502                    wgt::BufferBindingType::Uniform => {
1503                        if has_dynamic_offset {
1504                            desc_count.uniform_buffer_dynamic += count;
1505                        } else {
1506                            desc_count.uniform_buffer += count;
1507                        }
1508                    }
1509                    wgt::BufferBindingType::Storage { .. } => {
1510                        if has_dynamic_offset {
1511                            desc_count.storage_buffer_dynamic += count;
1512                        } else {
1513                            desc_count.storage_buffer += count;
1514                        }
1515                    }
1516                },
1517                wgt::BindingType::Sampler { .. } => {
1518                    desc_count.sampler += count;
1519                }
1520                wgt::BindingType::Texture { .. } => {
1521                    desc_count.sampled_image += count;
1522                }
1523                wgt::BindingType::StorageTexture { .. } => {
1524                    desc_count.storage_image += count;
1525                }
1526                wgt::BindingType::AccelerationStructure { .. } => {
1527                    desc_count.acceleration_structure += count;
1528                }
1529                wgt::BindingType::ExternalTexture => unimplemented!(),
1530            }
1531        }
1532
1533        let vk_info = vk::DescriptorSetLayoutCreateInfo::default()
1534            .bindings(&vk_bindings)
1535            .flags(if contains_binding_arrays {
1536                vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL
1537            } else {
1538                vk::DescriptorSetLayoutCreateFlags::empty()
1539            });
1540
1541        let mut binding_flag_info =
1542            vk::DescriptorSetLayoutBindingFlagsCreateInfo::default().binding_flags(&binding_flags);
1543
1544        let vk_info = vk_info.push_next(&mut binding_flag_info);
1545
1546        let raw = unsafe {
1547            self.shared
1548                .raw
1549                .create_descriptor_set_layout(&vk_info, None)
1550                .map_err(super::map_host_device_oom_err)?
1551        };
1552
1553        if let Some(label) = desc.label {
1554            unsafe { self.shared.set_object_name(raw, label) };
1555        }
1556
1557        let layout = super::BindGroupLayout {
1558            raw,
1559            desc_count,
1560            entries: desc.entries.into(),
1561            binding_map,
1562            contains_binding_arrays,
1563        };
1564
1565        let result = self
1566            .desc_allocator
1567            .lock()
1568            .register_layout(&self.shared.raw, &layout);
1569        if let Err(err) = result {
1570            unsafe {
1571                self.shared
1572                    .raw
1573                    .destroy_descriptor_set_layout(layout.raw, None)
1574            };
1575            return Err(err);
1576        }
1577
1578        self.counters.bind_group_layouts.add(1);
1579
1580        Ok(layout)
1581    }
1582    unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) {
1583        self.desc_allocator
1584            .lock()
1585            .unregister_layout(&self.shared.raw, &bg_layout);
1586
1587        unsafe {
1588            self.shared
1589                .raw
1590                .destroy_descriptor_set_layout(bg_layout.raw, None)
1591        };
1592
1593        self.counters.bind_group_layouts.sub(1);
1594    }
1595
1596    unsafe fn create_pipeline_layout(
1597        &self,
1598        desc: &crate::PipelineLayoutDescriptor<super::BindGroupLayout>,
1599    ) -> Result<super::PipelineLayout, crate::DeviceError> {
1600        //Note: not bothering with on stack array here as it's low frequency
1601        let vk_set_layouts = desc
1602            .bind_group_layouts
1603            .iter()
1604            .map(|bgl| match bgl {
1605                Some(bgl) => bgl.raw,
1606                None => {
1607                    // `VUID-VkPipelineLayoutCreateInfo-pSetLayouts-parameter`
1608                    // says `VK_NULL_HANDLE` is allowed but
1609                    // `VUID-VkPipelineLayoutCreateInfo-graphicsPipelineLibrary-06753`
1610                    // says it's not, unless the `graphicsPipelineLibrary`
1611                    // feature is enabled.
1612                    //
1613                    // We use an empty descriptor set layout to work around this.
1614                    self.shared.empty_descriptor_set_layout
1615                }
1616            })
1617            .collect::<Vec<_>>();
1618        let vk_immediates_ranges: Option<vk::PushConstantRange> = if desc.immediate_size != 0 {
1619            Some(vk::PushConstantRange {
1620                stage_flags: vk::ShaderStageFlags::ALL,
1621                offset: 0,
1622                size: desc.immediate_size,
1623            })
1624        } else {
1625            None
1626        };
1627
1628        let vk_info = vk::PipelineLayoutCreateInfo::default()
1629            .flags(vk::PipelineLayoutCreateFlags::empty())
1630            .set_layouts(&vk_set_layouts)
1631            .push_constant_ranges(vk_immediates_ranges.as_slice());
1632
1633        let raw = {
1634            profiling::scope!("vkCreatePipelineLayout");
1635            unsafe {
1636                self.shared
1637                    .raw
1638                    .create_pipeline_layout(&vk_info, None)
1639                    .map_err(super::map_host_device_oom_err)?
1640            }
1641        };
1642
1643        if let Some(label) = desc.label {
1644            unsafe { self.shared.set_object_name(raw, label) };
1645        }
1646
1647        let mut binding_map = BTreeMap::new();
1648        for (group, layout) in desc.bind_group_layouts.iter().enumerate() {
1649            let Some(layout) = layout else {
1650                continue;
1651            };
1652
1653            for &(binding, binding_info) in &layout.binding_map {
1654                binding_map.insert(
1655                    naga::ResourceBinding {
1656                        group: group as u32,
1657                        binding,
1658                    },
1659                    naga::back::spv::BindingInfo {
1660                        descriptor_set: group as u32,
1661                        binding: binding_info.binding,
1662                        binding_array_size: binding_info.binding_array_size.map(NonZeroU32::get),
1663                    },
1664                );
1665            }
1666        }
1667
1668        self.counters.pipeline_layouts.add(1);
1669        Ok(super::PipelineLayout { raw, binding_map })
1670    }
1671    unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
1672        unsafe {
1673            self.shared
1674                .raw
1675                .destroy_pipeline_layout(pipeline_layout.raw, None)
1676        };
1677
1678        self.counters.pipeline_layouts.sub(1);
1679    }
1680
1681    unsafe fn create_bind_group(
1682        &self,
1683        desc: &crate::BindGroupDescriptor<
1684            super::BindGroupLayout,
1685            super::Buffer,
1686            super::Sampler,
1687            super::TextureView,
1688            super::AccelerationStructure,
1689        >,
1690    ) -> Result<super::BindGroup, crate::DeviceError> {
1691        let set = unsafe {
1692            self.desc_allocator
1693                .lock()
1694                .alloc(&self.shared.raw, desc.layout)?
1695        };
1696
1697        if let Some(label) = desc.label {
1698            unsafe { self.shared.set_object_name(set.raw(), label) };
1699        }
1700
1701        /// Helper for splitting off and initializing a given number of elements on a pre-allocated
1702        /// stack, based on items returned from an [`ExactSizeIterator`].  Typically created from a
1703        /// [`MaybeUninit`] slice (see [`Vec::spare_capacity_mut()`]).
1704        /// The updated [`ExtensionStack`] of remaining uninitialized elements is returned, safely
1705        /// representing that the initialized and remaining elements are two independent mutable
1706        /// borrows.
1707        struct ExtendStack<'a, T> {
1708            remainder: &'a mut [MaybeUninit<T>],
1709        }
1710
1711        impl<'a, T> ExtendStack<'a, T> {
1712            fn from_vec_capacity(vec: &'a mut Vec<T>) -> Self {
1713                Self {
1714                    remainder: vec.spare_capacity_mut(),
1715                }
1716            }
1717
1718            fn extend_one(self, value: T) -> (Self, &'a mut T) {
1719                let (to_init, remainder) = self.remainder.split_first_mut().unwrap();
1720                let init = to_init.write(value);
1721                (Self { remainder }, init)
1722            }
1723
1724            fn extend(
1725                self,
1726                iter: impl IntoIterator<Item = T> + ExactSizeIterator,
1727            ) -> (Self, &'a mut [T]) {
1728                let (to_init, remainder) = self.remainder.split_at_mut(iter.len());
1729
1730                for (value, to_init) in iter.into_iter().zip(to_init.iter_mut()) {
1731                    to_init.write(value);
1732                }
1733
1734                // we can't use the safe (yet unstable) MaybeUninit::write_slice() here because of having an iterator to write
1735
1736                let init = {
1737                    // SAFETY: The loop above has initialized exactly as many items as to_init is
1738                    // long, so it is safe to cast away the MaybeUninit<T> wrapper into T.
1739
1740                    // Additional safety docs from unstable slice_assume_init_mut
1741                    // SAFETY: similar to safety notes for `slice_get_ref`, but we have a
1742                    // mutable reference which is also guaranteed to be valid for writes.
1743                    unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(to_init) }
1744                };
1745                (Self { remainder }, init)
1746            }
1747        }
1748
1749        let mut writes = Vec::with_capacity(desc.entries.len());
1750        let mut buffer_infos = Vec::with_capacity(desc.buffers.len());
1751        let mut buffer_infos = ExtendStack::from_vec_capacity(&mut buffer_infos);
1752        let mut image_infos = Vec::with_capacity(desc.samplers.len() + desc.textures.len());
1753        let mut image_infos = ExtendStack::from_vec_capacity(&mut image_infos);
1754        // TODO: This length could be reduced to just the number of top-level acceleration
1755        // structure bindings, where multiple consecutive TLAS bindings that are set via
1756        // one `WriteDescriptorSet` count towards one "info" struct, not the total number of
1757        // acceleration structure bindings to write:
1758        let mut acceleration_structure_infos =
1759            Vec::with_capacity(desc.acceleration_structures.len());
1760        let mut acceleration_structure_infos =
1761            ExtendStack::from_vec_capacity(&mut acceleration_structure_infos);
1762        let mut raw_acceleration_structures =
1763            Vec::with_capacity(desc.acceleration_structures.len());
1764        let mut raw_acceleration_structures =
1765            ExtendStack::from_vec_capacity(&mut raw_acceleration_structures);
1766
1767        let layout_and_entry_iter = desc.entries.iter().map(|entry| {
1768            let layout = desc
1769                .layout
1770                .entries
1771                .iter()
1772                .find(|layout_entry| layout_entry.binding == entry.binding)
1773                .expect("internal error: no layout entry found with binding slot");
1774            (layout, entry)
1775        });
1776        let mut next_binding = 0;
1777        for (layout, entry) in layout_and_entry_iter {
1778            let write = vk::WriteDescriptorSet::default().dst_set(set.raw());
1779
1780            match layout.ty {
1781                wgt::BindingType::Sampler(_) => {
1782                    let start = entry.resource_index;
1783                    let end = start + entry.count;
1784                    let local_image_infos;
1785                    (image_infos, local_image_infos) =
1786                        image_infos.extend(desc.samplers[start as usize..end as usize].iter().map(
1787                            |sampler| vk::DescriptorImageInfo::default().sampler(sampler.raw),
1788                        ));
1789                    writes.push(
1790                        write
1791                            .dst_binding(next_binding)
1792                            .descriptor_type(conv::map_binding_type(layout.ty))
1793                            .image_info(local_image_infos),
1794                    );
1795                    next_binding += 1;
1796                }
1797                wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => {
1798                    let start = entry.resource_index;
1799                    let end = start + entry.count;
1800                    let local_image_infos;
1801                    (image_infos, local_image_infos) =
1802                        image_infos.extend(desc.textures[start as usize..end as usize].iter().map(
1803                            |binding| {
1804                                let layout =
1805                                    conv::derive_image_layout(binding.usage, binding.view.format);
1806                                vk::DescriptorImageInfo::default()
1807                                    .image_view(binding.view.raw)
1808                                    .image_layout(layout)
1809                            },
1810                        ));
1811                    writes.push(
1812                        write
1813                            .dst_binding(next_binding)
1814                            .descriptor_type(conv::map_binding_type(layout.ty))
1815                            .image_info(local_image_infos),
1816                    );
1817                    next_binding += 1;
1818                }
1819                wgt::BindingType::Buffer { .. } => {
1820                    let start = entry.resource_index;
1821                    let end = start + entry.count;
1822                    let local_buffer_infos;
1823                    (buffer_infos, local_buffer_infos) =
1824                        buffer_infos.extend(desc.buffers[start as usize..end as usize].iter().map(
1825                            |binding| {
1826                                vk::DescriptorBufferInfo::default()
1827                                    .buffer(binding.buffer.raw)
1828                                    .offset(binding.offset)
1829                                    .range(
1830                                        binding.size.map_or(vk::WHOLE_SIZE, wgt::BufferSize::get),
1831                                    )
1832                            },
1833                        ));
1834                    writes.push(
1835                        write
1836                            .dst_binding(next_binding)
1837                            .descriptor_type(conv::map_binding_type(layout.ty))
1838                            .buffer_info(local_buffer_infos),
1839                    );
1840                    next_binding += 1;
1841                }
1842                wgt::BindingType::AccelerationStructure { .. } => {
1843                    let start = entry.resource_index;
1844                    let end = start + entry.count;
1845
1846                    let local_raw_acceleration_structures;
1847                    (
1848                        raw_acceleration_structures,
1849                        local_raw_acceleration_structures,
1850                    ) = raw_acceleration_structures.extend(
1851                        desc.acceleration_structures[start as usize..end as usize]
1852                            .iter()
1853                            .map(|acceleration_structure| acceleration_structure.raw),
1854                    );
1855
1856                    let local_acceleration_structure_infos;
1857                    (
1858                        acceleration_structure_infos,
1859                        local_acceleration_structure_infos,
1860                    ) = acceleration_structure_infos.extend_one(
1861                        vk::WriteDescriptorSetAccelerationStructureKHR::default()
1862                            .acceleration_structures(local_raw_acceleration_structures),
1863                    );
1864
1865                    writes.push(
1866                        write
1867                            .dst_binding(next_binding)
1868                            .descriptor_type(conv::map_binding_type(layout.ty))
1869                            .descriptor_count(entry.count)
1870                            .push_next(local_acceleration_structure_infos),
1871                    );
1872                    next_binding += 1;
1873                }
1874                wgt::BindingType::ExternalTexture => unimplemented!(),
1875            }
1876        }
1877
1878        unsafe { self.shared.raw.update_descriptor_sets(&writes, &[]) };
1879
1880        self.counters.bind_groups.add(1);
1881
1882        Ok(super::BindGroup { set })
1883    }
1884
1885    unsafe fn destroy_bind_group(&self, group: super::BindGroup) {
1886        unsafe { self.desc_allocator.lock().free(&self.shared.raw, group.set) };
1887
1888        self.counters.bind_groups.sub(1);
1889    }
1890
1891    unsafe fn create_shader_module(
1892        &self,
1893        desc: &crate::ShaderModuleDescriptor,
1894        shader: crate::ShaderInput,
1895    ) -> Result<super::ShaderModule, crate::ShaderError> {
1896        let shader_module = match shader {
1897            crate::ShaderInput::Naga(naga_shader)
1898                if self
1899                    .shared
1900                    .workarounds
1901                    .contains(super::Workarounds::SEPARATE_ENTRY_POINTS)
1902                    || !naga_shader.module.overrides.is_empty() =>
1903            {
1904                super::ShaderModule::Intermediate {
1905                    naga_shader,
1906                    runtime_checks: desc.runtime_checks,
1907                }
1908            }
1909            crate::ShaderInput::Naga(naga_shader) => {
1910                let mut naga_options = self.naga_options.clone();
1911                naga_options.debug_info =
1912                    naga_shader
1913                        .debug_source
1914                        .as_ref()
1915                        .map(|d| naga::back::spv::DebugInfo {
1916                            source_code: d.source_code.as_ref(),
1917                            file_name: d.file_name.as_ref(),
1918                            language: naga::back::spv::SourceLanguage::WGSL,
1919                        });
1920                if !desc.runtime_checks.bounds_checks {
1921                    naga_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
1922                        index: naga::proc::BoundsCheckPolicy::Unchecked,
1923                        buffer: naga::proc::BoundsCheckPolicy::Unchecked,
1924                        image_load: naga::proc::BoundsCheckPolicy::Unchecked,
1925                        binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
1926                    };
1927                }
1928                let spv = naga::back::spv::write_vec(
1929                    &naga_shader.module,
1930                    &naga_shader.info,
1931                    &naga_options,
1932                    None,
1933                )
1934                .map_err(|e| crate::ShaderError::Compilation(format!("{e}")))?;
1935                super::ShaderModule::Raw(self.create_shader_module_impl(&spv, &desc.label)?)
1936            }
1937            crate::ShaderInput::SpirV(data) => {
1938                super::ShaderModule::Raw(self.create_shader_module_impl(data, &desc.label)?)
1939            }
1940            crate::ShaderInput::MetalLib { .. }
1941            | crate::ShaderInput::Msl { .. }
1942            | crate::ShaderInput::Dxil { .. }
1943            | crate::ShaderInput::Hlsl { .. }
1944            | crate::ShaderInput::Glsl { .. } => unreachable!(),
1945        };
1946
1947        self.counters.shader_modules.add(1);
1948
1949        Ok(shader_module)
1950    }
1951
1952    unsafe fn destroy_shader_module(&self, module: super::ShaderModule) {
1953        match module {
1954            super::ShaderModule::Raw(raw) => {
1955                unsafe { self.shared.raw.destroy_shader_module(raw, None) };
1956            }
1957            super::ShaderModule::Intermediate { .. } => {}
1958        }
1959
1960        self.counters.shader_modules.sub(1);
1961    }
1962
1963    unsafe fn create_render_pipeline(
1964        &self,
1965        desc: &crate::RenderPipelineDescriptor<
1966            super::PipelineLayout,
1967            super::ShaderModule,
1968            super::PipelineCache,
1969        >,
1970    ) -> Result<super::RenderPipeline, crate::PipelineError> {
1971        let dynamic_states = [
1972            vk::DynamicState::VIEWPORT,
1973            vk::DynamicState::SCISSOR,
1974            vk::DynamicState::BLEND_CONSTANTS,
1975            vk::DynamicState::STENCIL_REFERENCE,
1976        ];
1977        let mut compatible_rp_key = super::RenderPassKey {
1978            sample_count: desc.multisample.count,
1979            multiview_mask: desc.multiview_mask,
1980            ..Default::default()
1981        };
1982        let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
1983        let mut vertex_buffers = Vec::new();
1984        let mut vertex_attributes = Vec::new();
1985
1986        if let crate::VertexProcessor::Standard {
1987            vertex_buffers: desc_vertex_buffers,
1988            vertex_stage: _,
1989        } = &desc.vertex_processor
1990        {
1991            vertex_buffers = Vec::with_capacity(desc_vertex_buffers.len());
1992            for (i, vb) in desc_vertex_buffers.iter().enumerate() {
1993                let Some(vb) = vb else {
1994                    continue;
1995                };
1996                vertex_buffers.push(vk::VertexInputBindingDescription {
1997                    binding: i as u32,
1998                    stride: vb.array_stride as u32,
1999                    input_rate: match vb.step_mode {
2000                        wgt::VertexStepMode::Vertex => vk::VertexInputRate::VERTEX,
2001                        wgt::VertexStepMode::Instance => vk::VertexInputRate::INSTANCE,
2002                    },
2003                });
2004                for at in vb.attributes {
2005                    vertex_attributes.push(vk::VertexInputAttributeDescription {
2006                        location: at.shader_location,
2007                        binding: i as u32,
2008                        format: conv::map_vertex_format(at.format),
2009                        offset: at.offset as u32,
2010                    });
2011                }
2012            }
2013        }
2014
2015        let vk_vertex_input = vk::PipelineVertexInputStateCreateInfo::default()
2016            .vertex_binding_descriptions(&vertex_buffers)
2017            .vertex_attribute_descriptions(&vertex_attributes);
2018
2019        let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
2020            .topology(conv::map_topology(desc.primitive.topology))
2021            .primitive_restart_enable(desc.primitive.strip_index_format.is_some());
2022
2023        let mut compiled_vs = None;
2024        let mut compiled_ms = None;
2025        let mut compiled_ts = None;
2026        match &desc.vertex_processor {
2027            crate::VertexProcessor::Standard {
2028                vertex_buffers: _,
2029                vertex_stage,
2030            } => {
2031                compiled_vs = Some(self.compile_stage(
2032                    vertex_stage,
2033                    naga::ShaderStage::Vertex,
2034                    &desc.layout.binding_map,
2035                )?);
2036                stages.push(compiled_vs.as_ref().unwrap().create_info);
2037            }
2038            crate::VertexProcessor::Mesh {
2039                task_stage,
2040                mesh_stage,
2041            } => {
2042                if let Some(t) = task_stage.as_ref() {
2043                    compiled_ts = Some(self.compile_stage(
2044                        t,
2045                        naga::ShaderStage::Task,
2046                        &desc.layout.binding_map,
2047                    )?);
2048                    stages.push(compiled_ts.as_ref().unwrap().create_info);
2049                }
2050                compiled_ms = Some(self.compile_stage(
2051                    mesh_stage,
2052                    naga::ShaderStage::Mesh,
2053                    &desc.layout.binding_map,
2054                )?);
2055                stages.push(compiled_ms.as_ref().unwrap().create_info);
2056            }
2057        }
2058        let compiled_fs = match desc.fragment_stage {
2059            Some(ref stage) => {
2060                let compiled = self.compile_stage(
2061                    stage,
2062                    naga::ShaderStage::Fragment,
2063                    &desc.layout.binding_map,
2064                )?;
2065                stages.push(compiled.create_info);
2066                Some(compiled)
2067            }
2068            None => None,
2069        };
2070
2071        let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
2072            .polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
2073            .front_face(conv::map_front_face(desc.primitive.front_face))
2074            .line_width(1.0)
2075            .depth_clamp_enable(desc.primitive.unclipped_depth);
2076        if let Some(face) = desc.primitive.cull_mode {
2077            vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face))
2078        }
2079        let mut vk_rasterization_conservative_state =
2080            vk::PipelineRasterizationConservativeStateCreateInfoEXT::default()
2081                .conservative_rasterization_mode(
2082                    vk::ConservativeRasterizationModeEXT::OVERESTIMATE,
2083                );
2084        if desc.primitive.conservative {
2085            vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state);
2086        }
2087
2088        let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
2089        if let Some(ref ds) = desc.depth_stencil {
2090            (
2091                compatible_rp_key.depth_read_only,
2092                compatible_rp_key.stencil_read_only,
2093            ) = (
2094                ds.is_depth_read_only(),
2095                ds.is_stencil_read_only(desc.primitive.cull_mode),
2096            );
2097            let vk_format = self.shared.private_caps.map_texture_format(ds.format);
2098            let vk_layout = match (
2099                compatible_rp_key.depth_read_only,
2100                compatible_rp_key.stencil_read_only,
2101            ) {
2102                (true, true) => vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL,
2103                (true, false) => vk::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
2104                (false, true) => vk::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
2105                (false, false) => vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2106            };
2107            compatible_rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey {
2108                base: super::AttachmentKey::compatible(vk_format, vk_layout),
2109                stencil_ops: crate::AttachmentOps::all(),
2110            });
2111
2112            if ds.is_depth_enabled() {
2113                vk_depth_stencil = vk_depth_stencil
2114                    .depth_test_enable(true)
2115                    .depth_write_enable(ds.depth_write_enabled.unwrap_or_default())
2116                    .depth_compare_op(conv::map_comparison(ds.depth_compare.unwrap_or_default()));
2117            }
2118            if ds.stencil.is_enabled() {
2119                let s = &ds.stencil;
2120                let front = conv::map_stencil_face(&s.front, s.read_mask, s.write_mask);
2121                let back = conv::map_stencil_face(&s.back, s.read_mask, s.write_mask);
2122                vk_depth_stencil = vk_depth_stencil
2123                    .stencil_test_enable(true)
2124                    .front(front)
2125                    .back(back);
2126            }
2127
2128            if ds.bias.is_enabled() {
2129                vk_rasterization = vk_rasterization
2130                    .depth_bias_enable(true)
2131                    .depth_bias_constant_factor(ds.bias.constant as f32)
2132                    .depth_bias_clamp(ds.bias.clamp)
2133                    .depth_bias_slope_factor(ds.bias.slope_scale);
2134            }
2135        }
2136
2137        let vk_viewport = vk::PipelineViewportStateCreateInfo::default()
2138            .flags(vk::PipelineViewportStateCreateFlags::empty())
2139            .scissor_count(1)
2140            .viewport_count(1);
2141
2142        let vk_sample_mask = [
2143            desc.multisample.mask as u32,
2144            (desc.multisample.mask >> 32) as u32,
2145        ];
2146        let vk_multisample = vk::PipelineMultisampleStateCreateInfo::default()
2147            .rasterization_samples(vk::SampleCountFlags::from_raw(desc.multisample.count))
2148            .alpha_to_coverage_enable(desc.multisample.alpha_to_coverage_enabled)
2149            .sample_mask(&vk_sample_mask);
2150
2151        let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
2152        for cat in desc.color_targets {
2153            let (key, attarchment) = if let Some(cat) = cat.as_ref() {
2154                let mut vk_attachment = vk::PipelineColorBlendAttachmentState::default()
2155                    .color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
2156                if let Some(ref blend) = cat.blend {
2157                    let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
2158                    let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
2159                    vk_attachment = vk_attachment
2160                        .blend_enable(true)
2161                        .color_blend_op(color_op)
2162                        .src_color_blend_factor(color_src)
2163                        .dst_color_blend_factor(color_dst)
2164                        .alpha_blend_op(alpha_op)
2165                        .src_alpha_blend_factor(alpha_src)
2166                        .dst_alpha_blend_factor(alpha_dst);
2167                }
2168
2169                let vk_format = self.shared.private_caps.map_texture_format(cat.format);
2170                (
2171                    Some(super::ColorAttachmentKey {
2172                        base: super::AttachmentKey::compatible(
2173                            vk_format,
2174                            vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
2175                        ),
2176                        resolve: None,
2177                    }),
2178                    vk_attachment,
2179                )
2180            } else {
2181                (None, vk::PipelineColorBlendAttachmentState::default())
2182            };
2183
2184            compatible_rp_key.colors.push(key);
2185            vk_attachments.push(attarchment);
2186        }
2187
2188        let vk_color_blend =
2189            vk::PipelineColorBlendStateCreateInfo::default().attachments(&vk_attachments);
2190
2191        let vk_dynamic_state =
2192            vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
2193
2194        let raw_pass = self.shared.make_render_pass(compatible_rp_key)?;
2195
2196        let vk_infos = [{
2197            vk::GraphicsPipelineCreateInfo::default()
2198                .layout(desc.layout.raw)
2199                .stages(&stages)
2200                .vertex_input_state(&vk_vertex_input)
2201                .input_assembly_state(&vk_input_assembly)
2202                .rasterization_state(&vk_rasterization)
2203                .viewport_state(&vk_viewport)
2204                .multisample_state(&vk_multisample)
2205                .depth_stencil_state(&vk_depth_stencil)
2206                .color_blend_state(&vk_color_blend)
2207                .dynamic_state(&vk_dynamic_state)
2208                .render_pass(raw_pass)
2209        }];
2210
2211        let pipeline_cache = desc
2212            .cache
2213            .map(|it| it.raw)
2214            .unwrap_or(vk::PipelineCache::null());
2215
2216        let mut raw_vec = {
2217            profiling::scope!("vkCreateGraphicsPipelines");
2218            unsafe {
2219                self.shared
2220                    .raw
2221                    .create_graphics_pipelines(pipeline_cache, &vk_infos, None)
2222                    .map_err(|(_, e)| super::map_pipeline_err(e))
2223            }?
2224        };
2225
2226        let raw = raw_vec.pop().unwrap();
2227        if let Some(label) = desc.label {
2228            unsafe { self.shared.set_object_name(raw, label) };
2229        }
2230
2231        if let Some(CompiledStage {
2232            temp_raw_module: Some(raw_module),
2233            ..
2234        }) = compiled_vs
2235        {
2236            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2237        }
2238        if let Some(CompiledStage {
2239            temp_raw_module: Some(raw_module),
2240            ..
2241        }) = compiled_ts
2242        {
2243            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2244        }
2245        if let Some(CompiledStage {
2246            temp_raw_module: Some(raw_module),
2247            ..
2248        }) = compiled_ms
2249        {
2250            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2251        }
2252        if let Some(CompiledStage {
2253            temp_raw_module: Some(raw_module),
2254            ..
2255        }) = compiled_fs
2256        {
2257            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2258        }
2259
2260        self.counters.render_pipelines.add(1);
2261
2262        Ok(super::RenderPipeline {
2263            raw,
2264            is_multiview: desc.multiview_mask.is_some(),
2265        })
2266    }
2267
2268    unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
2269        unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2270
2271        self.counters.render_pipelines.sub(1);
2272    }
2273
2274    unsafe fn create_compute_pipeline(
2275        &self,
2276        desc: &crate::ComputePipelineDescriptor<
2277            super::PipelineLayout,
2278            super::ShaderModule,
2279            super::PipelineCache,
2280        >,
2281    ) -> Result<super::ComputePipeline, crate::PipelineError> {
2282        let compiled = self.compile_stage(
2283            &desc.stage,
2284            naga::ShaderStage::Compute,
2285            &desc.layout.binding_map,
2286        )?;
2287
2288        let vk_infos = [{
2289            vk::ComputePipelineCreateInfo::default()
2290                .layout(desc.layout.raw)
2291                .stage(compiled.create_info)
2292        }];
2293
2294        let pipeline_cache = desc
2295            .cache
2296            .map(|it| it.raw)
2297            .unwrap_or(vk::PipelineCache::null());
2298
2299        let mut raw_vec = {
2300            profiling::scope!("vkCreateComputePipelines");
2301            unsafe {
2302                self.shared
2303                    .raw
2304                    .create_compute_pipelines(pipeline_cache, &vk_infos, None)
2305                    .map_err(|(_, e)| super::map_pipeline_err(e))
2306            }?
2307        };
2308
2309        let raw = raw_vec.pop().unwrap();
2310        if let Some(label) = desc.label {
2311            unsafe { self.shared.set_object_name(raw, label) };
2312        }
2313
2314        if let Some(raw_module) = compiled.temp_raw_module {
2315            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2316        }
2317
2318        self.counters.compute_pipelines.add(1);
2319
2320        Ok(super::ComputePipeline { raw })
2321    }
2322
2323    unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
2324        unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2325
2326        self.counters.compute_pipelines.sub(1);
2327    }
2328
2329    unsafe fn create_ray_tracing_pipeline(
2330        &self,
2331        desc: &crate::RayTracingPipelineDescriptor<
2332            super::PipelineLayout,
2333            super::ShaderModule,
2334            super::PipelineCache,
2335        >,
2336    ) -> Result<super::RayTracingPipeline, crate::PipelineError> {
2337        let mut stages = Vec::new();
2338        let mut groups = Vec::new();
2339
2340        let compiled_ray_gen = self.compile_stage(
2341            &desc.ray_generation,
2342            naga::ShaderStage::RayGeneration,
2343            &desc.layout.binding_map,
2344        )?;
2345
2346        groups.push(
2347            vk::RayTracingShaderGroupCreateInfoKHR::default()
2348                .closest_hit_shader(vk::SHADER_UNUSED_KHR)
2349                .any_hit_shader(vk::SHADER_UNUSED_KHR)
2350                .intersection_shader(vk::SHADER_UNUSED_KHR)
2351                .general_shader(0) // stages is empty so next index is 0.
2352                .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL),
2353        );
2354
2355        stages.push(compiled_ray_gen.create_info);
2356
2357        let compiled_miss = self.compile_stage(
2358            &desc.miss,
2359            naga::ShaderStage::Miss,
2360            &desc.layout.binding_map,
2361        )?;
2362
2363        groups.push(
2364            vk::RayTracingShaderGroupCreateInfoKHR::default()
2365                .closest_hit_shader(vk::SHADER_UNUSED_KHR)
2366                .any_hit_shader(vk::SHADER_UNUSED_KHR)
2367                .intersection_shader(vk::SHADER_UNUSED_KHR)
2368                .general_shader(1) // stages always has one element so next index is 1.
2369                .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL),
2370        );
2371
2372        stages.push(compiled_miss.create_info);
2373
2374        // This is to keep alive the CStrings, as the ones in the loop would be deallocated
2375        // causing UB otherwise.
2376        let mut compiled_stages = Vec::new();
2377
2378        for group in desc.intersection {
2379            let compiled_closest_hits = self.compile_stage(
2380                &group.closest_hit,
2381                naga::ShaderStage::ClosestHit,
2382                &desc.layout.binding_map,
2383            )?;
2384
2385            let closest_idx = stages.len();
2386
2387            stages.push(compiled_closest_hits.create_info);
2388
2389            compiled_stages.push(compiled_closest_hits);
2390
2391            let mut raw_hit: vk::RayTracingShaderGroupCreateInfoKHR<'_> =
2392                vk::RayTracingShaderGroupCreateInfoKHR::default()
2393                    .closest_hit_shader(closest_idx as _)
2394                    .any_hit_shader(vk::SHADER_UNUSED_KHR)
2395                    .intersection_shader(vk::SHADER_UNUSED_KHR)
2396                    .general_shader(vk::SHADER_UNUSED_KHR)
2397                    .ty(vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP);
2398
2399            if let Some(any_hit) = &group.any_hit {
2400                let compiled_any_hit = self.compile_stage(
2401                    any_hit,
2402                    naga::ShaderStage::AnyHit,
2403                    &desc.layout.binding_map,
2404                )?;
2405
2406                let any_idx = stages.len();
2407
2408                stages.push(compiled_any_hit.create_info);
2409
2410                compiled_stages.push(compiled_any_hit);
2411
2412                raw_hit = raw_hit.any_hit_shader(any_idx as _);
2413            }
2414
2415            groups.push(raw_hit);
2416        }
2417
2418        let create_infos = [{
2419            vk::RayTracingPipelineCreateInfoKHR::default()
2420                .layout(desc.layout.raw)
2421                .max_pipeline_ray_recursion_depth(desc.max_recursion_depth)
2422                .stages(&stages)
2423                .groups(&groups)
2424        }];
2425
2426        let pipeline_cache = desc
2427            .cache
2428            .map(|it| it.raw)
2429            .unwrap_or(vk::PipelineCache::null());
2430
2431        let fns = self
2432            .shared
2433            .extension_fns
2434            .ray_tracing_pipelines
2435            .as_ref()
2436            .unwrap();
2437        let pipelines = unsafe {
2438            fns.create_ray_tracing_pipelines(
2439                vk::DeferredOperationKHR::null(),
2440                pipeline_cache,
2441                &create_infos,
2442                None,
2443            )
2444            .map_err(|(_, e)| super::map_pipeline_err(e))
2445        }?;
2446
2447        if let Some(raw_module) = compiled_ray_gen.temp_raw_module {
2448            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2449        }
2450
2451        if let Some(raw_module) = compiled_miss.temp_raw_module {
2452            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2453        }
2454
2455        for raw_module in compiled_stages
2456            .into_iter()
2457            .flat_map(|stage| stage.temp_raw_module)
2458        {
2459            unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2460        }
2461
2462        self.counters.ray_tracing_pipelines.add(1);
2463
2464        Ok(super::RayTracingPipeline { raw: pipelines[0] })
2465    }
2466
2467    unsafe fn destroy_ray_tracing_pipeline(&self, pipeline: super::RayTracingPipeline) {
2468        unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2469
2470        self.counters.ray_tracing_pipelines.sub(1);
2471    }
2472
2473    unsafe fn get_raytracing_pipeline_group_data(
2474        &self,
2475        pipeline: &super::RayTracingPipeline,
2476        groups: core::ops::Range<u32>,
2477    ) -> Result<Vec<u8>, crate::DeviceError> {
2478        let fns = self
2479            .shared
2480            .extension_fns
2481            .ray_tracing_pipelines
2482            .as_ref()
2483            .unwrap();
2484
2485        let num = groups.end - groups.start;
2486
2487        unsafe {
2488            fns.get_ray_tracing_shader_group_handles(
2489                pipeline.raw,
2490                groups.start,
2491                num,
2492                (num * self
2493                    .shared
2494                    .private_caps
2495                    .ray_tracing_pipeline_group_data_size) as usize,
2496            )
2497        }
2498        .map_err(super::map_host_device_oom_err)
2499    }
2500
2501    unsafe fn create_pipeline_cache(
2502        &self,
2503        desc: &crate::PipelineCacheDescriptor<'_>,
2504    ) -> Result<super::PipelineCache, crate::PipelineCacheError> {
2505        let mut info = vk::PipelineCacheCreateInfo::default();
2506        if let Some(data) = desc.data {
2507            info = info.initial_data(data)
2508        }
2509        profiling::scope!("vkCreatePipelineCache");
2510        let raw = unsafe { self.shared.raw.create_pipeline_cache(&info, None) }
2511            .map_err(super::map_host_device_oom_err)?;
2512
2513        Ok(super::PipelineCache { raw })
2514    }
2515    fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> {
2516        Some(self.shared.pipeline_cache_validation_key)
2517    }
2518    unsafe fn destroy_pipeline_cache(&self, cache: super::PipelineCache) {
2519        unsafe { self.shared.raw.destroy_pipeline_cache(cache.raw, None) }
2520    }
2521    unsafe fn create_query_set(
2522        &self,
2523        desc: &wgt::QuerySetDescriptor<crate::Label>,
2524    ) -> Result<super::QuerySet, crate::DeviceError> {
2525        // Assume each query is 256 bytes. This is the case for occlusion
2526        // queries on an AMD W6800 with driver version 32.0.12030.9. The
2527        // size and allocation policy may vary; this is an approximate
2528        // check only.
2529        self.error_if_would_oom_on_resource_allocation(
2530            gpu_allocator::MemoryLocation::GpuToCpu,
2531            &vk::MemoryRequirements {
2532                size: desc.count as u64 * 256,
2533                alignment: 256,
2534                memory_type_bits: self.valid_ash_memory_types,
2535            },
2536        )?;
2537
2538        let (vk_type, pipeline_statistics) = match desc.ty {
2539            wgt::QueryType::Occlusion => (
2540                vk::QueryType::OCCLUSION,
2541                vk::QueryPipelineStatisticFlags::empty(),
2542            ),
2543            wgt::QueryType::PipelineStatistics(statistics) => (
2544                vk::QueryType::PIPELINE_STATISTICS,
2545                conv::map_pipeline_statistics(statistics),
2546            ),
2547            wgt::QueryType::Timestamp => (
2548                vk::QueryType::TIMESTAMP,
2549                vk::QueryPipelineStatisticFlags::empty(),
2550            ),
2551        };
2552
2553        let vk_info = vk::QueryPoolCreateInfo::default()
2554            .query_type(vk_type)
2555            .query_count(desc.count)
2556            .pipeline_statistics(pipeline_statistics);
2557
2558        let raw = unsafe { self.shared.raw.create_query_pool(&vk_info, None) }
2559            .map_err(super::map_host_device_oom_err)?;
2560        if let Some(label) = desc.label {
2561            unsafe { self.shared.set_object_name(raw, label) };
2562        }
2563
2564        self.counters.query_sets.add(1);
2565
2566        Ok(super::QuerySet { raw })
2567    }
2568
2569    unsafe fn destroy_query_set(&self, set: super::QuerySet) {
2570        unsafe { self.shared.raw.destroy_query_pool(set.raw, None) };
2571
2572        self.counters.query_sets.sub(1);
2573    }
2574
2575    unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
2576        self.counters.fences.add(1);
2577
2578        Ok(if self.shared.private_caps.timeline_semaphores {
2579            let mut sem_type_info =
2580                vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::TIMELINE);
2581            let vk_info = vk::SemaphoreCreateInfo::default().push_next(&mut sem_type_info);
2582            let raw = unsafe { self.shared.raw.create_semaphore(&vk_info, None) }
2583                .map_err(super::map_host_device_oom_err)?;
2584
2585            super::Fence::TimelineSemaphore(raw)
2586        } else {
2587            super::Fence::FencePool(RwLock::new(super::FencePool {
2588                last_completed: 0,
2589                active: Vec::new(),
2590                free: Vec::new(),
2591            }))
2592        })
2593    }
2594    unsafe fn destroy_fence(&self, fence: super::Fence) {
2595        match fence {
2596            super::Fence::TimelineSemaphore(raw) => {
2597                unsafe { self.shared.raw.destroy_semaphore(raw, None) };
2598            }
2599            super::Fence::FencePool(pool) => {
2600                let super::FencePool {
2601                    active,
2602                    free,
2603                    last_completed: _,
2604                } = pool.into_inner();
2605
2606                for (_, raw) in active {
2607                    unsafe {
2608                        self.shared.raw.destroy_fence(Arc::into_inner(raw).expect("Fence should have its reference count be one by the end of each function"), None)
2609                    };
2610                }
2611                for raw in free {
2612                    unsafe { self.shared.raw.destroy_fence(raw, None) };
2613                }
2614            }
2615        }
2616
2617        self.counters.fences.sub(1);
2618    }
2619    unsafe fn get_fence_value(
2620        &self,
2621        fence: &super::Fence,
2622    ) -> Result<crate::FenceValue, crate::DeviceError> {
2623        fence.get_latest(
2624            &self.shared.raw,
2625            self.shared.extension_fns.timeline_semaphore.as_ref(),
2626        )
2627    }
2628    unsafe fn wait(
2629        &self,
2630        fence: &super::Fence,
2631        wait_value: crate::FenceValue,
2632        timeout: Option<Duration>,
2633    ) -> Result<bool, crate::DeviceError> {
2634        let timeout_ns = timeout
2635            .unwrap_or(Duration::MAX)
2636            .as_nanos()
2637            .min(u64::MAX as _) as u64;
2638        self.shared.wait_for_fence(fence, wait_value, timeout_ns)
2639    }
2640
2641    unsafe fn start_graphics_debugger_capture(&self) -> bool {
2642        #[cfg(feature = "renderdoc")]
2643        {
2644            // Renderdoc requires us to give us the pointer that vkInstance _points to_.
2645            let raw_vk_instance =
2646                vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2647            let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2648            unsafe {
2649                self.render_doc
2650                    .start_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2651            }
2652        }
2653        #[cfg(not(feature = "renderdoc"))]
2654        false
2655    }
2656    unsafe fn stop_graphics_debugger_capture(&self) {
2657        #[cfg(feature = "renderdoc")]
2658        {
2659            // Renderdoc requires us to give us the pointer that vkInstance _points to_.
2660            let raw_vk_instance =
2661                vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2662            let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2663
2664            unsafe {
2665                self.render_doc
2666                    .end_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2667            }
2668        }
2669    }
2670
2671    unsafe fn pipeline_cache_get_data(&self, cache: &super::PipelineCache) -> Option<Vec<u8>> {
2672        let data = unsafe { self.raw_device().get_pipeline_cache_data(cache.raw) };
2673        data.ok()
2674    }
2675
2676    unsafe fn get_acceleration_structure_build_sizes<'a>(
2677        &self,
2678        desc: &crate::GetAccelerationStructureBuildSizesDescriptor<'a, super::Buffer>,
2679    ) -> crate::AccelerationStructureBuildSizes {
2680        const CAPACITY: usize = 8;
2681
2682        let ray_tracing_functions = self
2683            .shared
2684            .extension_fns
2685            .ray_tracing
2686            .as_ref()
2687            .expect("Feature `RAY_TRACING` not enabled");
2688
2689        let (geometries, primitive_counts) = match *desc.entries {
2690            crate::AccelerationStructureEntries::Instances(ref instances) => {
2691                let instance_data = vk::AccelerationStructureGeometryInstancesDataKHR::default();
2692
2693                let geometry = vk::AccelerationStructureGeometryKHR::default()
2694                    .geometry_type(vk::GeometryTypeKHR::INSTANCES)
2695                    .geometry(vk::AccelerationStructureGeometryDataKHR {
2696                        instances: instance_data,
2697                    });
2698
2699                (
2700                    smallvec::smallvec![geometry],
2701                    smallvec::smallvec![instances.count],
2702                )
2703            }
2704            crate::AccelerationStructureEntries::Triangles(ref in_geometries) => {
2705                let mut primitive_counts =
2706                    smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2707                let mut geometries = smallvec::SmallVec::<
2708                    [vk::AccelerationStructureGeometryKHR; CAPACITY],
2709                >::with_capacity(in_geometries.len());
2710
2711                for triangles in in_geometries {
2712                    let mut triangle_data =
2713                        vk::AccelerationStructureGeometryTrianglesDataKHR::default()
2714                            .index_type(vk::IndexType::NONE_KHR)
2715                            .vertex_format(conv::map_vertex_format(triangles.vertex_format))
2716                            .max_vertex(triangles.vertex_count)
2717                            .vertex_stride(triangles.vertex_stride)
2718                            // The vulkan spec suggests we could pass a non-zero invalid address here if fetching
2719                            // the real address has significant overhead, but we pass the real one to be on the
2720                            // safe side for now.
2721                            // from https://registry.khronos.org/vulkan/specs/latest/man/html/vkGetAccelerationStructureBuildSizesKHR.html
2722                            // > The srcAccelerationStructure, dstAccelerationStructure, and mode members
2723                            // > of pBuildInfo are ignored. Any VkDeviceOrHostAddressKHR or VkDeviceOrHostAddressConstKHR
2724                            // > members of pBuildInfo are ignored by this command, except that the hostAddress
2725                            // > member of VkAccelerationStructureGeometryTrianglesDataKHR::transformData will
2726                            // > be examined to check if it is NULL.
2727                            .transform_data(vk::DeviceOrHostAddressConstKHR {
2728                                device_address: if desc
2729                                    .flags
2730                                    .contains(wgt::AccelerationStructureFlags::USE_TRANSFORM)
2731                                {
2732                                    unsafe {
2733                                        ray_tracing_functions
2734                                            .buffer_device_address
2735                                            .get_buffer_device_address(
2736                                                &vk::BufferDeviceAddressInfo::default().buffer(
2737                                                    triangles
2738                                                        .transform
2739                                                        .as_ref()
2740                                                        .unwrap()
2741                                                        .buffer
2742                                                        .raw,
2743                                                ),
2744                                            )
2745                                    }
2746                                } else {
2747                                    0
2748                                },
2749                            });
2750
2751                    let pritive_count = if let Some(ref indices) = triangles.indices {
2752                        triangle_data =
2753                            triangle_data.index_type(conv::map_index_format(indices.format));
2754                        indices.count / 3
2755                    } else {
2756                        triangles.vertex_count / 3
2757                    };
2758
2759                    let geometry = vk::AccelerationStructureGeometryKHR::default()
2760                        .geometry_type(vk::GeometryTypeKHR::TRIANGLES)
2761                        .geometry(vk::AccelerationStructureGeometryDataKHR {
2762                            triangles: triangle_data,
2763                        })
2764                        .flags(conv::map_acceleration_structure_geometry_flags(
2765                            triangles.flags,
2766                        ));
2767
2768                    geometries.push(geometry);
2769                    primitive_counts.push(pritive_count);
2770                }
2771                (geometries, primitive_counts)
2772            }
2773            crate::AccelerationStructureEntries::AABBs(ref in_geometries) => {
2774                let mut primitive_counts =
2775                    smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2776                let mut geometries = smallvec::SmallVec::<
2777                    [vk::AccelerationStructureGeometryKHR; CAPACITY],
2778                >::with_capacity(in_geometries.len());
2779                for aabb in in_geometries {
2780                    let aabbs_data = vk::AccelerationStructureGeometryAabbsDataKHR::default()
2781                        .stride(aabb.stride);
2782
2783                    let geometry = vk::AccelerationStructureGeometryKHR::default()
2784                        .geometry_type(vk::GeometryTypeKHR::AABBS)
2785                        .geometry(vk::AccelerationStructureGeometryDataKHR { aabbs: aabbs_data })
2786                        .flags(conv::map_acceleration_structure_geometry_flags(aabb.flags));
2787
2788                    geometries.push(geometry);
2789                    primitive_counts.push(aabb.count);
2790                }
2791                (geometries, primitive_counts)
2792            }
2793        };
2794
2795        let ty = match *desc.entries {
2796            crate::AccelerationStructureEntries::Instances(_) => {
2797                vk::AccelerationStructureTypeKHR::TOP_LEVEL
2798            }
2799            _ => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
2800        };
2801
2802        let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
2803            .ty(ty)
2804            .flags(conv::map_acceleration_structure_flags(desc.flags))
2805            .geometries(&geometries);
2806
2807        let mut raw = Default::default();
2808        unsafe {
2809            ray_tracing_functions
2810                .acceleration_structure
2811                .get_acceleration_structure_build_sizes(
2812                    vk::AccelerationStructureBuildTypeKHR::DEVICE,
2813                    &geometry_info,
2814                    &primitive_counts,
2815                    &mut raw,
2816                )
2817        }
2818
2819        crate::AccelerationStructureBuildSizes {
2820            acceleration_structure_size: raw.acceleration_structure_size,
2821            update_scratch_size: raw.update_scratch_size,
2822            build_scratch_size: raw.build_scratch_size,
2823        }
2824    }
2825
2826    unsafe fn get_acceleration_structure_device_address(
2827        &self,
2828        acceleration_structure: &super::AccelerationStructure,
2829    ) -> wgt::BufferAddress {
2830        let ray_tracing_functions = self
2831            .shared
2832            .extension_fns
2833            .ray_tracing
2834            .as_ref()
2835            .expect("Feature `RAY_TRACING` not enabled");
2836
2837        unsafe {
2838            ray_tracing_functions
2839                .acceleration_structure
2840                .get_acceleration_structure_device_address(
2841                    &vk::AccelerationStructureDeviceAddressInfoKHR::default()
2842                        .acceleration_structure(acceleration_structure.raw),
2843                )
2844        }
2845    }
2846
2847    unsafe fn create_acceleration_structure(
2848        &self,
2849        desc: &crate::AccelerationStructureDescriptor,
2850    ) -> Result<super::AccelerationStructure, crate::DeviceError> {
2851        let ray_tracing_functions = self
2852            .shared
2853            .extension_fns
2854            .ray_tracing
2855            .as_ref()
2856            .expect("Feature `RAY_TRACING` not enabled");
2857
2858        let vk_buffer_info = vk::BufferCreateInfo::default()
2859            .size(desc.size)
2860            .usage(
2861                vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR
2862                    | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
2863            )
2864            .sharing_mode(vk::SharingMode::EXCLUSIVE);
2865
2866        unsafe {
2867            let raw_buffer = self
2868                .shared
2869                .raw
2870                .create_buffer(&vk_buffer_info, None)
2871                .map_err(super::map_host_device_oom_and_ioca_err)?;
2872
2873            let requirements = self.shared.raw.get_buffer_memory_requirements(raw_buffer);
2874
2875            self.error_if_would_oom_on_resource_allocation(
2876                gpu_allocator::MemoryLocation::GpuOnly,
2877                &requirements,
2878            )
2879            .inspect_err(|_| {
2880                self.shared.raw.destroy_buffer(raw_buffer, None);
2881            })?;
2882
2883            let name = desc
2884                .label
2885                .unwrap_or("Unlabeled acceleration structure buffer");
2886
2887            let allocation = self
2888                .mem_allocator
2889                .lock()
2890                .allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
2891                    name,
2892                    requirements,
2893                    location: gpu_allocator::MemoryLocation::GpuOnly,
2894                    linear: true, // Buffers are always linear
2895                    allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
2896                })
2897                .inspect_err(|_| {
2898                    self.shared.raw.destroy_buffer(raw_buffer, None);
2899                })?;
2900
2901            self.shared
2902                .raw
2903                .bind_buffer_memory(raw_buffer, allocation.memory(), allocation.offset())
2904                .map_err(super::map_host_device_oom_and_ioca_err)
2905                .inspect_err(|_| {
2906                    self.shared.raw.destroy_buffer(raw_buffer, None);
2907                })?;
2908
2909            if let Some(label) = desc.label {
2910                self.shared.set_object_name(raw_buffer, label);
2911            }
2912
2913            let vk_info = vk::AccelerationStructureCreateInfoKHR::default()
2914                .buffer(raw_buffer)
2915                .offset(0)
2916                .size(desc.size)
2917                .ty(conv::map_acceleration_structure_format(desc.format));
2918
2919            let raw_acceleration_structure = ray_tracing_functions
2920                .acceleration_structure
2921                .create_acceleration_structure(&vk_info, None)
2922                .map_err(super::map_host_oom_and_ioca_err)
2923                .inspect_err(|_| {
2924                    self.shared.raw.destroy_buffer(raw_buffer, None);
2925                })?;
2926
2927            if let Some(label) = desc.label {
2928                self.shared
2929                    .set_object_name(raw_acceleration_structure, label);
2930            }
2931
2932            let pool = if desc.allow_compaction {
2933                let vk_info = vk::QueryPoolCreateInfo::default()
2934                    .query_type(vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR)
2935                    .query_count(1);
2936
2937                let raw = self
2938                    .shared
2939                    .raw
2940                    .create_query_pool(&vk_info, None)
2941                    .map_err(super::map_host_device_oom_err)
2942                    .inspect_err(|_| {
2943                        ray_tracing_functions
2944                            .acceleration_structure
2945                            .destroy_acceleration_structure(raw_acceleration_structure, None);
2946                        self.shared.raw.destroy_buffer(raw_buffer, None);
2947                    })?;
2948                Some(raw)
2949            } else {
2950                None
2951            };
2952
2953            Ok(super::AccelerationStructure {
2954                raw: raw_acceleration_structure,
2955                buffer: raw_buffer,
2956                allocation,
2957                compacted_size_query: pool,
2958            })
2959        }
2960    }
2961
2962    unsafe fn destroy_acceleration_structure(
2963        &self,
2964        acceleration_structure: super::AccelerationStructure,
2965    ) {
2966        let ray_tracing_functions = self
2967            .shared
2968            .extension_fns
2969            .ray_tracing
2970            .as_ref()
2971            .expect("Feature `RAY_TRACING` not enabled");
2972
2973        unsafe {
2974            ray_tracing_functions
2975                .acceleration_structure
2976                .destroy_acceleration_structure(acceleration_structure.raw, None);
2977            self.shared
2978                .raw
2979                .destroy_buffer(acceleration_structure.buffer, None);
2980            let result = self
2981                .mem_allocator
2982                .lock()
2983                .free(acceleration_structure.allocation);
2984            if let Err(err) = result {
2985                log::warn!("Failed to free buffer acceleration structure: {err}");
2986            }
2987            if let Some(query) = acceleration_structure.compacted_size_query {
2988                self.shared.raw.destroy_query_pool(query, None)
2989            }
2990        }
2991    }
2992
2993    fn get_internal_counters(&self) -> wgt::HalCounters {
2994        self.counters
2995            .memory_allocations
2996            .set(self.shared.memory_allocations_counter.read());
2997
2998        self.counters.as_ref().clone()
2999    }
3000
3001    fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
3002        let gpu_allocator::AllocatorReport {
3003            allocations,
3004            blocks,
3005            total_allocated_bytes,
3006            total_capacity_bytes,
3007        } = self.mem_allocator.lock().generate_report();
3008
3009        let allocations = allocations
3010            .into_iter()
3011            .map(|alloc| wgt::AllocationReport {
3012                name: alloc.name,
3013                offset: alloc.offset,
3014                size: alloc.size,
3015            })
3016            .collect();
3017
3018        let blocks = blocks
3019            .into_iter()
3020            .map(|block| wgt::MemoryBlockReport {
3021                size: block.size,
3022                allocations: block.allocations.clone(),
3023            })
3024            .collect();
3025
3026        Some(wgt::AllocatorReport {
3027            allocations,
3028            blocks,
3029            total_allocated_bytes,
3030            total_reserved_bytes: total_capacity_bytes,
3031        })
3032    }
3033
3034    fn tlas_instance_to_bytes(&self, instance: TlasInstance, to_extend: &mut Vec<u8>) {
3035        const MAX_U24: u32 = (1u32 << 24u32) - 1u32;
3036        let temp = RawTlasInstance {
3037            transform: instance.transform,
3038            custom_data_and_mask: (instance.custom_data & MAX_U24)
3039                | (u32::from(instance.mask) << 24),
3040            shader_binding_table_record_offset_and_flags: (instance
3041                .pipeline_intersection_data_offset
3042                & MAX_U24),
3043            acceleration_structure_reference: instance.blas_address,
3044        };
3045        to_extend.extend_from_slice(bytemuck::bytes_of(&temp))
3046    }
3047
3048    fn check_if_oom(&self) -> Result<(), crate::DeviceError> {
3049        let Some(threshold) = self
3050            .shared
3051            .instance
3052            .memory_budget_thresholds
3053            .for_device_loss
3054        else {
3055            return Ok(());
3056        };
3057
3058        let Some(memory_properties) = self.get_memory_properties() else {
3059            return Ok(());
3060        };
3061
3062        for i in 0..memory_properties.heaps().len() {
3063            let heap_usage = memory_properties.heap_usage()[i];
3064            let heap_budget = memory_properties.heap_budget()[i];
3065
3066            if heap_usage >= heap_budget / 100 * threshold as u64 {
3067                return Err(crate::DeviceError::OutOfMemory);
3068            }
3069        }
3070
3071        Ok(())
3072    }
3073}
3074
3075impl super::DeviceShared {
3076    pub(super) fn new_binary_semaphore(
3077        &self,
3078        name: &str,
3079    ) -> Result<vk::Semaphore, crate::DeviceError> {
3080        unsafe {
3081            let semaphore = self
3082                .raw
3083                .create_semaphore(&vk::SemaphoreCreateInfo::default(), None)
3084                .map_err(super::map_host_device_oom_err)?;
3085
3086            if !self
3087                .instance
3088                .flags
3089                .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
3090            {
3091                self.set_object_name(semaphore, name);
3092            }
3093
3094            Ok(semaphore)
3095        }
3096    }
3097
3098    pub(super) fn wait_for_fence(
3099        &self,
3100        fence: &super::Fence,
3101        wait_value: crate::FenceValue,
3102        timeout_ns: u64,
3103    ) -> Result<bool, crate::DeviceError> {
3104        profiling::scope!("Device::wait");
3105        match *fence {
3106            super::Fence::TimelineSemaphore(raw) => {
3107                let semaphores = [raw];
3108                let values = [wait_value];
3109                let vk_info = vk::SemaphoreWaitInfo::default()
3110                    .semaphores(&semaphores)
3111                    .values(&values);
3112                let result = match self.extension_fns.timeline_semaphore {
3113                    Some(super::ExtensionFn::Extension(ref ext)) => unsafe {
3114                        ext.wait_semaphores(&vk_info, timeout_ns)
3115                    },
3116                    Some(super::ExtensionFn::Promoted) => unsafe {
3117                        self.raw.wait_semaphores(&vk_info, timeout_ns)
3118                    },
3119                    None => unreachable!(),
3120                };
3121                match result {
3122                    Ok(()) => Ok(true),
3123                    Err(vk::Result::TIMEOUT) => Ok(false),
3124                    Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3125                }
3126            }
3127            super::Fence::FencePool(ref pool) => {
3128                let pool = pool.read();
3129                let super::FencePool {
3130                    last_completed,
3131                    ref active,
3132                    free: _,
3133                } = *pool;
3134                if wait_value <= last_completed {
3135                    Ok(true)
3136                } else {
3137                    match active.iter().find(|&&(value, _)| value >= wait_value) {
3138                        Some((_, fence)) => {
3139                            // clone to show we are using this fence while the pool is unlocked.
3140                            let fence = fence.clone();
3141                            drop(pool);
3142                            match unsafe {
3143                                self.raw.wait_for_fences(
3144                                    core::slice::from_ref(&fence),
3145                                    true,
3146                                    timeout_ns,
3147                                )
3148                            } {
3149                                Ok(()) => Ok(true),
3150                                Err(vk::Result::TIMEOUT) => Ok(false),
3151                                Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3152                            }
3153                        }
3154                        None => {
3155                            crate::hal_usage_error(format!(
3156                                "no signals reached value {wait_value}"
3157                            ));
3158                        }
3159                    }
3160                }
3161            }
3162        }
3163    }
3164}
3165
3166struct ImageWithoutMemory {
3167    raw: vk::Image,
3168    requirements: vk::MemoryRequirements,
3169}