wgpu_hal/vulkan/
device.rs

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