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