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