wgpu_hal/vulkan/
device.rs

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