Skip to main content

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