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