wgpu_hal/vulkan/
device.rs

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