wgpu_hal/vulkan/
device.rs

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