wgpu_hal/vulkan/
mod.rs

1/*!
2# Vulkan API internals.
3
4## Stack memory
5
6Ash expects slices, which we don't generally have available.
7We cope with this requirement by the combination of the following ways:
8  - temporarily allocating `Vec` on heap, where overhead is permitted
9  - growing temporary local storage
10
11## Framebuffers and Render passes
12
13Render passes are cached on the device and kept forever.
14
15Framebuffers are also cached on the device, but they are removed when
16any of the image views (they have) gets removed.
17If Vulkan supports image-less framebuffers,
18then the actual views are excluded from the framebuffer key.
19
20## Fences
21
22If timeline semaphores are available, they are used 1:1 with wgpu-hal fences.
23Otherwise, we manage a pool of `VkFence` objects behind each `hal::Fence`.
24
25!*/
26
27mod adapter;
28mod command;
29pub mod conv;
30mod device;
31mod drm;
32mod instance;
33mod sampler;
34mod semaphore_list;
35mod swapchain;
36
37pub use adapter::PhysicalDeviceFeatures;
38
39use alloc::{boxed::Box, ffi::CString, sync::Arc, vec::Vec};
40use core::{
41    borrow::Borrow,
42    ffi::CStr,
43    fmt,
44    marker::PhantomData,
45    mem::{self, ManuallyDrop},
46    num::NonZeroU32,
47};
48
49use arrayvec::ArrayVec;
50use ash::{ext, khr, vk};
51use bytemuck::{Pod, Zeroable};
52use hashbrown::HashSet;
53use parking_lot::{Mutex, RwLock};
54
55use naga::FastHashMap;
56use wgt::InternalCounter;
57
58use semaphore_list::SemaphoreList;
59
60use crate::vulkan::semaphore_list::{SemaphoreListMode, SemaphoreType};
61
62const MAX_TOTAL_ATTACHMENTS: usize = crate::MAX_COLOR_ATTACHMENTS * 2 + 1;
63
64#[derive(Clone, Debug)]
65pub struct Api;
66
67impl crate::Api for Api {
68    const VARIANT: wgt::Backend = wgt::Backend::Vulkan;
69
70    type Instance = Instance;
71    type Surface = Surface;
72    type Adapter = Adapter;
73    type Device = Device;
74
75    type Queue = Queue;
76    type CommandEncoder = CommandEncoder;
77    type CommandBuffer = CommandBuffer;
78
79    type Buffer = Buffer;
80    type Texture = Texture;
81    type SurfaceTexture = SurfaceTexture;
82    type TextureView = TextureView;
83    type Sampler = Sampler;
84    type QuerySet = QuerySet;
85    type Fence = Fence;
86    type AccelerationStructure = AccelerationStructure;
87    type PipelineCache = PipelineCache;
88
89    type BindGroupLayout = BindGroupLayout;
90    type BindGroup = BindGroup;
91    type PipelineLayout = PipelineLayout;
92    type ShaderModule = ShaderModule;
93    type RenderPipeline = RenderPipeline;
94    type ComputePipeline = ComputePipeline;
95}
96
97crate::impl_dyn_resource!(
98    Adapter,
99    AccelerationStructure,
100    BindGroup,
101    BindGroupLayout,
102    Buffer,
103    CommandBuffer,
104    CommandEncoder,
105    ComputePipeline,
106    Device,
107    Fence,
108    Instance,
109    PipelineCache,
110    PipelineLayout,
111    QuerySet,
112    Queue,
113    RenderPipeline,
114    Sampler,
115    ShaderModule,
116    Surface,
117    SurfaceTexture,
118    Texture,
119    TextureView
120);
121
122struct DebugUtils {
123    extension: ext::debug_utils::Instance,
124    messenger: vk::DebugUtilsMessengerEXT,
125
126    /// Owning pointer to the debug messenger callback user data.
127    ///
128    /// `InstanceShared::drop` destroys the debug messenger before
129    /// dropping this, so the callback should never receive a dangling
130    /// user data pointer.
131    #[allow(dead_code)]
132    callback_data: Box<DebugUtilsMessengerUserData>,
133}
134
135pub struct DebugUtilsCreateInfo {
136    severity: vk::DebugUtilsMessageSeverityFlagsEXT,
137    message_type: vk::DebugUtilsMessageTypeFlagsEXT,
138    callback_data: Box<DebugUtilsMessengerUserData>,
139}
140
141#[derive(Debug)]
142/// The properties related to the validation layer needed for the
143/// DebugUtilsMessenger for their workarounds
144struct ValidationLayerProperties {
145    /// Validation layer description, from `vk::LayerProperties`.
146    layer_description: CString,
147
148    /// Validation layer specification version, from `vk::LayerProperties`.
149    layer_spec_version: u32,
150}
151
152/// User data needed by `instance::debug_utils_messenger_callback`.
153///
154/// When we create the [`vk::DebugUtilsMessengerEXT`], the `pUserData`
155/// pointer refers to one of these values.
156#[derive(Debug)]
157pub struct DebugUtilsMessengerUserData {
158    /// The properties related to the validation layer, if present
159    validation_layer_properties: Option<ValidationLayerProperties>,
160
161    /// If the OBS layer is present. OBS never increments the version of their layer,
162    /// so there's no reason to have the version.
163    has_obs_layer: bool,
164}
165
166pub struct InstanceShared {
167    raw: ash::Instance,
168    extensions: Vec<&'static CStr>,
169    flags: wgt::InstanceFlags,
170    memory_budget_thresholds: wgt::MemoryBudgetThresholds,
171    debug_utils: Option<DebugUtils>,
172    get_physical_device_properties: Option<khr::get_physical_device_properties2::Instance>,
173    entry: ash::Entry,
174    has_nv_optimus: bool,
175    android_sdk_version: u32,
176    /// The instance API version.
177    ///
178    /// Which is the version of Vulkan supported for instance-level functionality.
179    ///
180    /// It is associated with a `VkInstance` and its children,
181    /// except for a `VkPhysicalDevice` and its children.
182    instance_api_version: u32,
183
184    // The `drop_guard` field must be the last field of this struct so it is dropped last.
185    // Do not add new fields after it.
186    drop_guard: Option<crate::DropGuard>,
187}
188
189pub struct Instance {
190    shared: Arc<InstanceShared>,
191}
192
193pub struct Surface {
194    inner: ManuallyDrop<Box<dyn swapchain::Surface>>,
195    swapchain: RwLock<Option<Box<dyn swapchain::Swapchain>>>,
196}
197
198impl Surface {
199    /// Returns the raw Vulkan surface handle.
200    ///
201    /// Returns `None` if the surface is a DXGI surface.
202    pub unsafe fn raw_native_handle(&self) -> Option<vk::SurfaceKHR> {
203        Some(
204            self.inner
205                .as_any()
206                .downcast_ref::<swapchain::NativeSurface>()?
207                .as_raw(),
208        )
209    }
210
211    /// Get the raw Vulkan swapchain associated with this surface.
212    ///
213    /// Returns [`None`] if the surface is not configured or if the swapchain
214    /// is a DXGI swapchain.
215    pub fn raw_native_swapchain(&self) -> Option<vk::SwapchainKHR> {
216        let read = self.swapchain.read();
217        Some(
218            read.as_ref()?
219                .as_any()
220                .downcast_ref::<swapchain::NativeSwapchain>()?
221                .as_raw(),
222        )
223    }
224
225    /// Set the present timing information which will be used for the next [presentation](crate::Queue::present()) of this surface,
226    /// using [VK_GOOGLE_display_timing].
227    ///
228    /// This can be used to give an id to presentations, for future use of [`vk::PastPresentationTimingGOOGLE`].
229    /// Note that `wgpu-hal` does *not* provide a way to use that API - you should manually access this through [`ash`].
230    ///
231    /// This can also be used to add a "not before" timestamp to the presentation.
232    ///
233    /// The exact semantics of the fields are also documented in the [specification](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentTimeGOOGLE.html) for the extension.
234    ///
235    /// # Panics
236    ///
237    /// - If the surface hasn't been configured.
238    /// - If the surface has been configured for a DXGI swapchain.
239    /// - If the device doesn't [support present timing](wgt::Features::VULKAN_GOOGLE_DISPLAY_TIMING).
240    ///
241    /// [VK_GOOGLE_display_timing]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html
242    #[track_caller]
243    pub fn set_next_present_time(&self, present_timing: vk::PresentTimeGOOGLE) {
244        let mut swapchain = self.swapchain.write();
245        swapchain
246            .as_mut()
247            .expect("Surface should have been configured")
248            .as_any_mut()
249            .downcast_mut::<swapchain::NativeSwapchain>()
250            .expect("Surface should have a native Vulkan swapchain")
251            .set_next_present_time(present_timing);
252    }
253}
254
255#[derive(Debug)]
256pub struct SurfaceTexture {
257    index: u32,
258    texture: Texture,
259    metadata: Box<dyn swapchain::SurfaceTextureMetadata>,
260}
261
262impl crate::DynSurfaceTexture for SurfaceTexture {}
263
264impl Borrow<Texture> for SurfaceTexture {
265    fn borrow(&self) -> &Texture {
266        &self.texture
267    }
268}
269
270impl Borrow<dyn crate::DynTexture> for SurfaceTexture {
271    fn borrow(&self) -> &dyn crate::DynTexture {
272        &self.texture
273    }
274}
275
276pub struct Adapter {
277    raw: vk::PhysicalDevice,
278    instance: Arc<InstanceShared>,
279    //queue_families: Vec<vk::QueueFamilyProperties>,
280    known_memory_flags: vk::MemoryPropertyFlags,
281    phd_capabilities: adapter::PhysicalDeviceProperties,
282    phd_features: PhysicalDeviceFeatures,
283    downlevel_flags: wgt::DownlevelFlags,
284    private_caps: PrivateCapabilities,
285    workarounds: Workarounds,
286}
287
288// TODO there's no reason why this can't be unified--the function pointers should all be the same--it's not clear how to do this with `ash`.
289enum ExtensionFn<T> {
290    /// The loaded function pointer struct for an extension.
291    Extension(T),
292    /// The extension was promoted to a core version of Vulkan and the functions on `ash`'s `DeviceV1_x` traits should be used.
293    Promoted,
294}
295
296struct DeviceExtensionFunctions {
297    debug_utils: Option<ext::debug_utils::Device>,
298    draw_indirect_count: Option<khr::draw_indirect_count::Device>,
299    timeline_semaphore: Option<ExtensionFn<khr::timeline_semaphore::Device>>,
300    ray_tracing: Option<RayTracingDeviceExtensionFunctions>,
301    mesh_shading: Option<ext::mesh_shader::Device>,
302}
303
304struct RayTracingDeviceExtensionFunctions {
305    acceleration_structure: khr::acceleration_structure::Device,
306    buffer_device_address: khr::buffer_device_address::Device,
307}
308
309/// Set of internal capabilities, which don't show up in the exposed
310/// device geometry, but affect the code paths taken internally.
311#[derive(Clone, Debug)]
312struct PrivateCapabilities {
313    image_view_usage: bool,
314    timeline_semaphores: bool,
315    texture_d24: bool,
316    texture_d24_s8: bool,
317    texture_s8: bool,
318    /// Ability to present contents to any screen. Only needed to work around broken platform configurations.
319    can_present: bool,
320    non_coherent_map_mask: wgt::BufferAddress,
321    multi_draw_indirect: bool,
322
323    /// True if this adapter advertises the [`robustBufferAccess`][vrba] feature.
324    ///
325    /// Note that Vulkan's `robustBufferAccess` is not sufficient to implement
326    /// `wgpu_hal`'s guarantee that shaders will not access buffer contents via
327    /// a given bindgroup binding outside that binding's [accessible
328    /// region][ar]. Enabling `robustBufferAccess` does ensure that
329    /// out-of-bounds reads and writes are not undefined behavior (that's good),
330    /// but still permits out-of-bounds reads to return data from anywhere
331    /// within the buffer, not just the accessible region.
332    ///
333    /// [ar]: ../struct.BufferBinding.html#accessible-region
334    /// [vrba]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#features-robustBufferAccess
335    robust_buffer_access: bool,
336
337    robust_image_access: bool,
338
339    /// True if this adapter supports the [`VK_EXT_robustness2`] extension's
340    /// [`robustBufferAccess2`] feature.
341    ///
342    /// This is sufficient to implement `wgpu_hal`'s [required bounds-checking][ar] of
343    /// shader accesses to buffer contents. If this feature is not available,
344    /// this backend must have Naga inject bounds checks in the generated
345    /// SPIR-V.
346    ///
347    /// [`VK_EXT_robustness2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_robustness2.html
348    /// [`robustBufferAccess2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustBufferAccess2
349    /// [ar]: ../struct.BufferBinding.html#accessible-region
350    robust_buffer_access2: bool,
351
352    robust_image_access2: bool,
353    zero_initialize_workgroup_memory: bool,
354    image_format_list: bool,
355    maximum_samplers: u32,
356
357    /// True if this adapter supports the [`VK_KHR_shader_integer_dot_product`] extension
358    /// (promoted to Vulkan 1.3).
359    ///
360    /// This is used to generate optimized code for WGSL's `dot4{I, U}8Packed`.
361    ///
362    /// [`VK_KHR_shader_integer_dot_product`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_integer_dot_product.html
363    shader_integer_dot_product: bool,
364
365    /// True if this adapter supports 8-bit integers provided by the
366    /// [`VK_KHR_shader_float16_int8`] extension (promoted to Vulkan 1.2).
367    ///
368    /// Allows shaders to declare the "Int8" capability. Note, however, that this
369    /// feature alone allows the use of 8-bit integers "only in the `Private`,
370    /// `Workgroup` (for non-Block variables), and `Function` storage classes"
371    /// ([see spec]). To use 8-bit integers in the interface storage classes (e.g.,
372    /// `StorageBuffer`), you also need to enable the corresponding feature in
373    /// `VkPhysicalDevice8BitStorageFeatures` and declare the corresponding SPIR-V
374    /// capability (e.g., `StorageBuffer8BitAccess`).
375    ///
376    /// [`VK_KHR_shader_float16_int8`]: https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_shader_float16_int8.html
377    /// [see spec]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDeviceShaderFloat16Int8Features.html#extension-features-shaderInt8
378    shader_int8: bool,
379
380    /// This is done to panic before undefined behavior, and is imperfect.
381    /// Basically, to allow implementations to emulate mv using instancing, if you
382    /// want to draw `n` instances to VR, you must draw `2n` instances, but you
383    /// can never draw more than `u32::MAX` instances. Therefore, when drawing
384    /// multiview on some vulkan implementations, it might restrict the instance
385    /// count, which isn't usually a thing in webgpu. We don't expose this limit
386    /// because its strange, i.e. only occurs on certain vulkan implementations
387    /// if you are drawing more than 128 million instances. We still want to avoid
388    /// undefined behavior in this situation, so we panic if the limit is violated.
389    multiview_instance_index_limit: u32,
390}
391
392bitflags::bitflags!(
393    /// Workaround flags.
394    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
395    pub struct Workarounds: u32 {
396        /// Only generate SPIR-V for one entry point at a time.
397        const SEPARATE_ENTRY_POINTS = 0x1;
398        /// Qualcomm OOMs when there are zero color attachments but a non-null pointer
399        /// to a subpass resolve attachment array. This nulls out that pointer in that case.
400        const EMPTY_RESOLVE_ATTACHMENT_LISTS = 0x2;
401        /// If the following code returns false, then nvidia will end up filling the wrong range.
402        ///
403        /// ```skip
404        /// fn nvidia_succeeds() -> bool {
405        ///   # let (copy_length, start_offset) = (0, 0);
406        ///     if copy_length >= 4096 {
407        ///         if start_offset % 16 != 0 {
408        ///             if copy_length == 4096 {
409        ///                 return true;
410        ///             }
411        ///             if copy_length % 16 == 0 {
412        ///                 return false;
413        ///             }
414        ///         }
415        ///     }
416        ///     true
417        /// }
418        /// ```
419        ///
420        /// As such, we need to make sure all calls to vkCmdFillBuffer are aligned to 16 bytes
421        /// if they cover a range of 4096 bytes or more.
422        const FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16 = 0x4;
423    }
424);
425
426#[derive(Clone, Debug, Eq, Hash, PartialEq)]
427struct AttachmentKey {
428    format: vk::Format,
429    layout: vk::ImageLayout,
430    ops: crate::AttachmentOps,
431}
432
433impl AttachmentKey {
434    /// Returns an attachment key for a compatible attachment.
435    fn compatible(format: vk::Format, layout: vk::ImageLayout) -> Self {
436        Self {
437            format,
438            layout,
439            ops: crate::AttachmentOps::all(),
440        }
441    }
442}
443
444#[derive(Clone, Eq, Hash, PartialEq)]
445struct ColorAttachmentKey {
446    base: AttachmentKey,
447    resolve: Option<AttachmentKey>,
448}
449
450#[derive(Clone, Eq, Hash, PartialEq)]
451struct DepthStencilAttachmentKey {
452    base: AttachmentKey,
453    stencil_ops: crate::AttachmentOps,
454}
455
456#[derive(Clone, Eq, Default, Hash, PartialEq)]
457struct RenderPassKey {
458    colors: ArrayVec<Option<ColorAttachmentKey>, { crate::MAX_COLOR_ATTACHMENTS }>,
459    depth_stencil: Option<DepthStencilAttachmentKey>,
460    sample_count: u32,
461    multiview_mask: Option<NonZeroU32>,
462}
463
464struct DeviceShared {
465    raw: ash::Device,
466    family_index: u32,
467    queue_index: u32,
468    raw_queue: vk::Queue,
469    instance: Arc<InstanceShared>,
470    physical_device: vk::PhysicalDevice,
471    enabled_extensions: Vec<&'static CStr>,
472    extension_fns: DeviceExtensionFunctions,
473    vendor_id: u32,
474    pipeline_cache_validation_key: [u8; 16],
475    timestamp_period: f32,
476    private_caps: PrivateCapabilities,
477    workarounds: Workarounds,
478    features: wgt::Features,
479    render_passes: Mutex<FastHashMap<RenderPassKey, vk::RenderPass>>,
480    sampler_cache: Mutex<sampler::SamplerCache>,
481    memory_allocations_counter: InternalCounter,
482
483    /// Because we have cached framebuffers which are not deleted from until
484    /// the device is destroyed, if the implementation of vulkan re-uses handles
485    /// we need some way to differentiate between the old handle and the new handle.
486    /// This factory allows us to have a dedicated identity value for each texture.
487    texture_identity_factory: ResourceIdentityFactory<vk::Image>,
488    /// As above, for texture views.
489    texture_view_identity_factory: ResourceIdentityFactory<vk::ImageView>,
490
491    // The `drop_guard` field must be the last field of this struct so it is dropped last.
492    // Do not add new fields after it.
493    drop_guard: Option<crate::DropGuard>,
494}
495
496impl Drop for DeviceShared {
497    fn drop(&mut self) {
498        for &raw in self.render_passes.lock().values() {
499            unsafe { self.raw.destroy_render_pass(raw, None) };
500        }
501        if self.drop_guard.is_none() {
502            unsafe { self.raw.destroy_device(None) };
503        }
504    }
505}
506
507pub struct Device {
508    shared: Arc<DeviceShared>,
509    mem_allocator: Mutex<gpu_alloc::GpuAllocator<vk::DeviceMemory>>,
510    desc_allocator:
511        Mutex<gpu_descriptor::DescriptorAllocator<vk::DescriptorPool, vk::DescriptorSet>>,
512    valid_ash_memory_types: u32,
513    naga_options: naga::back::spv::Options<'static>,
514    #[cfg(feature = "renderdoc")]
515    render_doc: crate::auxil::renderdoc::RenderDoc,
516    counters: Arc<wgt::HalCounters>,
517}
518
519impl Drop for Device {
520    fn drop(&mut self) {
521        unsafe { self.mem_allocator.lock().cleanup(&*self.shared) };
522        unsafe { self.desc_allocator.lock().cleanup(&*self.shared) };
523    }
524}
525
526/// Semaphores for forcing queue submissions to run in order.
527///
528/// The [`wgpu_hal::Queue`] trait promises that if two calls to [`submit`] are
529/// ordered, then the first submission will finish on the GPU before the second
530/// submission begins. To get this behavior on Vulkan we need to pass semaphores
531/// to [`vkQueueSubmit`] for the commands to wait on before beginning execution,
532/// and to signal when their execution is done.
533///
534/// Normally this can be done with a single semaphore, waited on and then
535/// signalled for each submission. At any given time there's exactly one
536/// submission that would signal the semaphore, and exactly one waiting on it,
537/// as Vulkan requires.
538///
539/// However, as of Oct 2021, bug [#5508] in the Mesa ANV drivers caused them to
540/// hang if we use a single semaphore. The workaround is to alternate between
541/// two semaphores. The bug has been fixed in Mesa, but we should probably keep
542/// the workaround until, say, Oct 2026.
543///
544/// [`wgpu_hal::Queue`]: crate::Queue
545/// [`submit`]: crate::Queue::submit
546/// [`vkQueueSubmit`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#vkQueueSubmit
547/// [#5508]: https://gitlab.freedesktop.org/mesa/mesa/-/issues/5508
548#[derive(Clone)]
549struct RelaySemaphores {
550    /// The semaphore the next submission should wait on before beginning
551    /// execution on the GPU. This is `None` for the first submission, which
552    /// should not wait on anything at all.
553    wait: Option<vk::Semaphore>,
554
555    /// The semaphore the next submission should signal when it has finished
556    /// execution on the GPU.
557    signal: vk::Semaphore,
558}
559
560impl RelaySemaphores {
561    fn new(device: &DeviceShared) -> Result<Self, crate::DeviceError> {
562        Ok(Self {
563            wait: None,
564            signal: device.new_binary_semaphore("RelaySemaphores: 1")?,
565        })
566    }
567
568    /// Advances the semaphores, returning the semaphores that should be used for a submission.
569    fn advance(&mut self, device: &DeviceShared) -> Result<Self, crate::DeviceError> {
570        let old = self.clone();
571
572        // Build the state for the next submission.
573        match self.wait {
574            None => {
575                // The `old` values describe the first submission to this queue.
576                // The second submission should wait on `old.signal`, and then
577                // signal a new semaphore which we'll create now.
578                self.wait = Some(old.signal);
579                self.signal = device.new_binary_semaphore("RelaySemaphores: 2")?;
580            }
581            Some(ref mut wait) => {
582                // What this submission signals, the next should wait.
583                mem::swap(wait, &mut self.signal);
584            }
585        };
586
587        Ok(old)
588    }
589
590    /// Destroys the semaphores.
591    unsafe fn destroy(&self, device: &ash::Device) {
592        unsafe {
593            if let Some(wait) = self.wait {
594                device.destroy_semaphore(wait, None);
595            }
596            device.destroy_semaphore(self.signal, None);
597        }
598    }
599}
600
601pub struct Queue {
602    raw: vk::Queue,
603    device: Arc<DeviceShared>,
604    family_index: u32,
605    relay_semaphores: Mutex<RelaySemaphores>,
606    signal_semaphores: Mutex<SemaphoreList>,
607}
608
609impl Queue {
610    pub fn as_raw(&self) -> vk::Queue {
611        self.raw
612    }
613}
614
615impl Drop for Queue {
616    fn drop(&mut self) {
617        unsafe { self.relay_semaphores.lock().destroy(&self.device.raw) };
618    }
619}
620#[derive(Debug)]
621enum BufferMemoryBacking {
622    Managed(gpu_alloc::MemoryBlock<vk::DeviceMemory>),
623    VulkanMemory {
624        memory: vk::DeviceMemory,
625        offset: u64,
626        size: u64,
627    },
628}
629impl BufferMemoryBacking {
630    fn memory(&self) -> &vk::DeviceMemory {
631        match self {
632            Self::Managed(m) => m.memory(),
633            Self::VulkanMemory { memory, .. } => memory,
634        }
635    }
636    fn offset(&self) -> u64 {
637        match self {
638            Self::Managed(m) => m.offset(),
639            Self::VulkanMemory { offset, .. } => *offset,
640        }
641    }
642    fn size(&self) -> u64 {
643        match self {
644            Self::Managed(m) => m.size(),
645            Self::VulkanMemory { size, .. } => *size,
646        }
647    }
648}
649#[derive(Debug)]
650pub struct Buffer {
651    raw: vk::Buffer,
652    block: Option<Mutex<BufferMemoryBacking>>,
653}
654impl Buffer {
655    /// # Safety
656    ///
657    /// - `vk_buffer`'s memory must be managed by the caller
658    /// - Externally imported buffers can't be mapped by `wgpu`
659    pub unsafe fn from_raw(vk_buffer: vk::Buffer) -> Self {
660        Self {
661            raw: vk_buffer,
662            block: None,
663        }
664    }
665    /// # Safety
666    /// - We will use this buffer and the buffer's backing memory range as if we have exclusive ownership over it, until the wgpu resource is dropped and the wgpu-hal object is cleaned up
667    /// - Externally imported buffers can't be mapped by `wgpu`
668    /// - `offset` and `size` must be valid with the allocation of `memory`
669    pub unsafe fn from_raw_managed(
670        vk_buffer: vk::Buffer,
671        memory: vk::DeviceMemory,
672        offset: u64,
673        size: u64,
674    ) -> Self {
675        Self {
676            raw: vk_buffer,
677            block: Some(Mutex::new(BufferMemoryBacking::VulkanMemory {
678                memory,
679                offset,
680                size,
681            })),
682        }
683    }
684}
685
686impl crate::DynBuffer for Buffer {}
687
688#[derive(Debug)]
689pub struct AccelerationStructure {
690    raw: vk::AccelerationStructureKHR,
691    buffer: vk::Buffer,
692    block: Mutex<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
693    compacted_size_query: Option<vk::QueryPool>,
694}
695
696impl crate::DynAccelerationStructure for AccelerationStructure {}
697
698#[derive(Debug)]
699pub struct Texture {
700    raw: vk::Image,
701    external_memory: Option<vk::DeviceMemory>,
702    block: Option<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
703    format: wgt::TextureFormat,
704    copy_size: crate::CopyExtent,
705    identity: ResourceIdentity<vk::Image>,
706
707    // The `drop_guard` field must be the last field of this struct so it is dropped last.
708    // Do not add new fields after it.
709    drop_guard: Option<crate::DropGuard>,
710}
711
712impl crate::DynTexture for Texture {}
713
714impl Texture {
715    /// # Safety
716    ///
717    /// - The image handle must not be manually destroyed
718    pub unsafe fn raw_handle(&self) -> vk::Image {
719        self.raw
720    }
721
722    /// # Safety
723    ///
724    /// - The external memory must not be manually freed
725    pub unsafe fn external_memory(&self) -> Option<vk::DeviceMemory> {
726        self.external_memory
727    }
728}
729
730#[derive(Debug)]
731pub struct TextureView {
732    raw_texture: vk::Image,
733    raw: vk::ImageView,
734    _layers: NonZeroU32,
735    format: wgt::TextureFormat,
736    raw_format: vk::Format,
737    base_mip_level: u32,
738    dimension: wgt::TextureViewDimension,
739    texture_identity: ResourceIdentity<vk::Image>,
740    view_identity: ResourceIdentity<vk::ImageView>,
741}
742
743impl crate::DynTextureView for TextureView {}
744
745impl TextureView {
746    /// # Safety
747    ///
748    /// - The image view handle must not be manually destroyed
749    pub unsafe fn raw_handle(&self) -> vk::ImageView {
750        self.raw
751    }
752
753    /// Returns the raw texture view, along with its identity.
754    fn identified_raw_view(&self) -> IdentifiedTextureView {
755        IdentifiedTextureView {
756            raw: self.raw,
757            identity: self.view_identity,
758        }
759    }
760}
761
762#[derive(Debug)]
763pub struct Sampler {
764    raw: vk::Sampler,
765    create_info: vk::SamplerCreateInfo<'static>,
766}
767
768impl crate::DynSampler for Sampler {}
769
770/// Information about a binding within a specific BindGroupLayout / BindGroup.
771/// This will be used to construct a [`naga::back::spv::BindingInfo`], where
772/// the descriptor set value will be taken from the index of the group.
773#[derive(Copy, Clone, Debug)]
774struct BindingInfo {
775    binding: u32,
776    binding_array_size: Option<NonZeroU32>,
777}
778
779#[derive(Debug)]
780pub struct BindGroupLayout {
781    raw: vk::DescriptorSetLayout,
782    desc_count: gpu_descriptor::DescriptorTotalCount,
783    /// Sorted list of entries.
784    entries: Box<[wgt::BindGroupLayoutEntry]>,
785    /// Map of original binding index to remapped binding index and optional
786    /// array size.
787    binding_map: Vec<(u32, BindingInfo)>,
788    contains_binding_arrays: bool,
789}
790
791impl crate::DynBindGroupLayout for BindGroupLayout {}
792
793#[derive(Debug)]
794pub struct PipelineLayout {
795    raw: vk::PipelineLayout,
796    binding_map: naga::back::spv::BindingMap,
797}
798
799impl crate::DynPipelineLayout for PipelineLayout {}
800
801#[derive(Debug)]
802pub struct BindGroup {
803    set: gpu_descriptor::DescriptorSet<vk::DescriptorSet>,
804}
805
806impl crate::DynBindGroup for BindGroup {}
807
808/// Miscellaneous allocation recycling pool for `CommandAllocator`.
809#[derive(Default)]
810struct Temp {
811    marker: Vec<u8>,
812    buffer_barriers: Vec<vk::BufferMemoryBarrier<'static>>,
813    image_barriers: Vec<vk::ImageMemoryBarrier<'static>>,
814}
815
816impl Temp {
817    fn clear(&mut self) {
818        self.marker.clear();
819        self.buffer_barriers.clear();
820        self.image_barriers.clear();
821    }
822
823    fn make_c_str(&mut self, name: &str) -> &CStr {
824        self.marker.clear();
825        self.marker.extend_from_slice(name.as_bytes());
826        self.marker.push(0);
827        unsafe { CStr::from_bytes_with_nul_unchecked(&self.marker) }
828    }
829}
830
831/// Generates unique IDs for each resource of type `T`.
832///
833/// Because vk handles are not permanently unique, this
834/// provides a way to generate unique IDs for each resource.
835struct ResourceIdentityFactory<T> {
836    #[cfg(not(target_has_atomic = "64"))]
837    next_id: Mutex<u64>,
838    #[cfg(target_has_atomic = "64")]
839    next_id: core::sync::atomic::AtomicU64,
840    _phantom: PhantomData<T>,
841}
842
843impl<T> ResourceIdentityFactory<T> {
844    fn new() -> Self {
845        Self {
846            #[cfg(not(target_has_atomic = "64"))]
847            next_id: Mutex::new(0),
848            #[cfg(target_has_atomic = "64")]
849            next_id: core::sync::atomic::AtomicU64::new(0),
850            _phantom: PhantomData,
851        }
852    }
853
854    /// Returns a new unique ID for a resource of type `T`.
855    fn next(&self) -> ResourceIdentity<T> {
856        #[cfg(not(target_has_atomic = "64"))]
857        {
858            let mut next_id = self.next_id.lock();
859            let id = *next_id;
860            *next_id += 1;
861            ResourceIdentity {
862                id,
863                _phantom: PhantomData,
864            }
865        }
866
867        #[cfg(target_has_atomic = "64")]
868        ResourceIdentity {
869            id: self
870                .next_id
871                .fetch_add(1, core::sync::atomic::Ordering::Relaxed),
872            _phantom: PhantomData,
873        }
874    }
875}
876
877/// A unique identifier for a resource of type `T`.
878///
879/// This is used as a hashable key for resources, which
880/// is permanently unique through the lifetime of the program.
881#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
882struct ResourceIdentity<T> {
883    id: u64,
884    _phantom: PhantomData<T>,
885}
886
887#[derive(Clone, Eq, Hash, PartialEq)]
888struct FramebufferKey {
889    raw_pass: vk::RenderPass,
890    /// Because this is used as a key in a hash map, we need to include the identity
891    /// so that this hashes differently, even if the ImageView handles are the same
892    /// between different views.
893    attachment_identities: ArrayVec<ResourceIdentity<vk::ImageView>, { MAX_TOTAL_ATTACHMENTS }>,
894    /// While this is redundant for calculating the hash, we need access to an array
895    /// of all the raw ImageViews when we are creating the actual framebuffer,
896    /// so we store this here.
897    attachment_views: ArrayVec<vk::ImageView, { MAX_TOTAL_ATTACHMENTS }>,
898    extent: wgt::Extent3d,
899}
900
901impl FramebufferKey {
902    fn push_view(&mut self, view: IdentifiedTextureView) {
903        self.attachment_identities.push(view.identity);
904        self.attachment_views.push(view.raw);
905    }
906}
907
908/// A texture view paired with its identity.
909#[derive(Copy, Clone)]
910struct IdentifiedTextureView {
911    raw: vk::ImageView,
912    identity: ResourceIdentity<vk::ImageView>,
913}
914
915#[derive(Clone, Eq, Hash, PartialEq)]
916struct TempTextureViewKey {
917    texture: vk::Image,
918    /// As this is used in a hashmap, we need to
919    /// include the identity so that this hashes differently,
920    /// even if the Image handles are the same between different images.
921    texture_identity: ResourceIdentity<vk::Image>,
922    format: vk::Format,
923    mip_level: u32,
924    depth_slice: u32,
925}
926
927pub struct CommandEncoder {
928    raw: vk::CommandPool,
929    device: Arc<DeviceShared>,
930
931    /// The current command buffer, if `self` is in the ["recording"]
932    /// state.
933    ///
934    /// ["recording"]: crate::CommandEncoder
935    ///
936    /// If non-`null`, the buffer is in the Vulkan "recording" state.
937    active: vk::CommandBuffer,
938
939    /// What kind of pass we are currently within: compute or render.
940    bind_point: vk::PipelineBindPoint,
941
942    /// Allocation recycling pool for this encoder.
943    temp: Temp,
944
945    /// A pool of available command buffers.
946    ///
947    /// These are all in the Vulkan "initial" state.
948    free: Vec<vk::CommandBuffer>,
949
950    /// A pool of discarded command buffers.
951    ///
952    /// These could be in any Vulkan state except "pending".
953    discarded: Vec<vk::CommandBuffer>,
954
955    /// If this is true, the active renderpass enabled a debug span,
956    /// and needs to be disabled on renderpass close.
957    rpass_debug_marker_active: bool,
958
959    /// If set, the end of the next render/compute pass will write a timestamp at
960    /// the given pool & location.
961    end_of_pass_timer_query: Option<(vk::QueryPool, u32)>,
962
963    framebuffers: FastHashMap<FramebufferKey, vk::Framebuffer>,
964    temp_texture_views: FastHashMap<TempTextureViewKey, IdentifiedTextureView>,
965
966    counters: Arc<wgt::HalCounters>,
967
968    current_pipeline_is_multiview: bool,
969}
970
971impl Drop for CommandEncoder {
972    fn drop(&mut self) {
973        // SAFETY:
974        //
975        // VUID-vkDestroyCommandPool-commandPool-00041: wgpu_hal requires that a
976        // `CommandBuffer` must live until its execution is complete, and that a
977        // `CommandBuffer` must not outlive the `CommandEncoder` that built it.
978        // Thus, we know that none of our `CommandBuffers` are in the "pending"
979        // state.
980        //
981        // The other VUIDs are pretty obvious.
982        unsafe {
983            // `vkDestroyCommandPool` also frees any command buffers allocated
984            // from that pool, so there's no need to explicitly call
985            // `vkFreeCommandBuffers` on `cmd_encoder`'s `free` and `discarded`
986            // fields.
987            self.device.raw.destroy_command_pool(self.raw, None);
988        }
989
990        for (_, fb) in self.framebuffers.drain() {
991            unsafe { self.device.raw.destroy_framebuffer(fb, None) };
992        }
993
994        for (_, view) in self.temp_texture_views.drain() {
995            unsafe { self.device.raw.destroy_image_view(view.raw, None) };
996        }
997
998        self.counters.command_encoders.sub(1);
999    }
1000}
1001
1002impl CommandEncoder {
1003    /// # Safety
1004    ///
1005    /// - The command buffer handle must not be manually destroyed
1006    pub unsafe fn raw_handle(&self) -> vk::CommandBuffer {
1007        self.active
1008    }
1009}
1010
1011impl fmt::Debug for CommandEncoder {
1012    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1013        f.debug_struct("CommandEncoder")
1014            .field("raw", &self.raw)
1015            .finish()
1016    }
1017}
1018
1019#[derive(Debug)]
1020pub struct CommandBuffer {
1021    raw: vk::CommandBuffer,
1022}
1023
1024impl crate::DynCommandBuffer for CommandBuffer {}
1025
1026#[derive(Debug)]
1027#[allow(clippy::large_enum_variant)]
1028pub enum ShaderModule {
1029    Raw(vk::ShaderModule),
1030    Intermediate {
1031        naga_shader: crate::NagaShader,
1032        runtime_checks: wgt::ShaderRuntimeChecks,
1033    },
1034}
1035
1036impl crate::DynShaderModule for ShaderModule {}
1037
1038#[derive(Debug)]
1039pub struct RenderPipeline {
1040    raw: vk::Pipeline,
1041    is_multiview: bool,
1042}
1043
1044impl crate::DynRenderPipeline for RenderPipeline {}
1045
1046#[derive(Debug)]
1047pub struct ComputePipeline {
1048    raw: vk::Pipeline,
1049}
1050
1051impl crate::DynComputePipeline for ComputePipeline {}
1052
1053#[derive(Debug)]
1054pub struct PipelineCache {
1055    raw: vk::PipelineCache,
1056}
1057
1058impl crate::DynPipelineCache for PipelineCache {}
1059
1060#[derive(Debug)]
1061pub struct QuerySet {
1062    raw: vk::QueryPool,
1063}
1064
1065impl crate::DynQuerySet for QuerySet {}
1066
1067/// The [`Api::Fence`] type for [`vulkan::Api`].
1068///
1069/// This is an `enum` because there are two possible implementations of
1070/// `wgpu-hal` fences on Vulkan: Vulkan fences, which work on any version of
1071/// Vulkan, and Vulkan timeline semaphores, which are easier and cheaper but
1072/// require non-1.0 features.
1073///
1074/// [`Device::create_fence`] returns a [`TimelineSemaphore`] if
1075/// [`VK_KHR_timeline_semaphore`] is available and enabled, and a [`FencePool`]
1076/// otherwise.
1077///
1078/// [`Api::Fence`]: crate::Api::Fence
1079/// [`vulkan::Api`]: Api
1080/// [`Device::create_fence`]: crate::Device::create_fence
1081/// [`TimelineSemaphore`]: Fence::TimelineSemaphore
1082/// [`VK_KHR_timeline_semaphore`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_KHR_timeline_semaphore
1083/// [`FencePool`]: Fence::FencePool
1084#[derive(Debug)]
1085pub enum Fence {
1086    /// A Vulkan [timeline semaphore].
1087    ///
1088    /// These are simpler to use than Vulkan fences, since timeline semaphores
1089    /// work exactly the way [`wpgu_hal::Api::Fence`] is specified to work.
1090    ///
1091    /// [timeline semaphore]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-semaphores
1092    /// [`wpgu_hal::Api::Fence`]: crate::Api::Fence
1093    TimelineSemaphore(vk::Semaphore),
1094
1095    /// A collection of Vulkan [fence]s, each associated with a [`FenceValue`].
1096    ///
1097    /// The effective [`FenceValue`] of this variant is the greater of
1098    /// `last_completed` and the maximum value associated with a signalled fence
1099    /// in `active`.
1100    ///
1101    /// Fences are available in all versions of Vulkan, but since they only have
1102    /// two states, "signaled" and "unsignaled", we need to use a separate fence
1103    /// for each queue submission we might want to wait for, and remember which
1104    /// [`FenceValue`] each one represents.
1105    ///
1106    /// [fence]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-fences
1107    /// [`FenceValue`]: crate::FenceValue
1108    FencePool {
1109        last_completed: crate::FenceValue,
1110        /// The pending fence values have to be ascending.
1111        active: Vec<(crate::FenceValue, vk::Fence)>,
1112        free: Vec<vk::Fence>,
1113    },
1114}
1115
1116impl crate::DynFence for Fence {}
1117
1118impl Fence {
1119    /// Return the highest [`FenceValue`] among the signalled fences in `active`.
1120    ///
1121    /// As an optimization, assume that we already know that the fence has
1122    /// reached `last_completed`, and don't bother checking fences whose values
1123    /// are less than that: those fences remain in the `active` array only
1124    /// because we haven't called `maintain` yet to clean them up.
1125    ///
1126    /// [`FenceValue`]: crate::FenceValue
1127    fn check_active(
1128        device: &ash::Device,
1129        mut last_completed: crate::FenceValue,
1130        active: &[(crate::FenceValue, vk::Fence)],
1131    ) -> Result<crate::FenceValue, crate::DeviceError> {
1132        for &(value, raw) in active.iter() {
1133            unsafe {
1134                if value > last_completed
1135                    && device
1136                        .get_fence_status(raw)
1137                        .map_err(map_host_device_oom_and_lost_err)?
1138                {
1139                    last_completed = value;
1140                }
1141            }
1142        }
1143        Ok(last_completed)
1144    }
1145
1146    /// Return the highest signalled [`FenceValue`] for `self`.
1147    ///
1148    /// [`FenceValue`]: crate::FenceValue
1149    fn get_latest(
1150        &self,
1151        device: &ash::Device,
1152        extension: Option<&ExtensionFn<khr::timeline_semaphore::Device>>,
1153    ) -> Result<crate::FenceValue, crate::DeviceError> {
1154        match *self {
1155            Self::TimelineSemaphore(raw) => unsafe {
1156                Ok(match *extension.unwrap() {
1157                    ExtensionFn::Extension(ref ext) => ext
1158                        .get_semaphore_counter_value(raw)
1159                        .map_err(map_host_device_oom_and_lost_err)?,
1160                    ExtensionFn::Promoted => device
1161                        .get_semaphore_counter_value(raw)
1162                        .map_err(map_host_device_oom_and_lost_err)?,
1163                })
1164            },
1165            Self::FencePool {
1166                last_completed,
1167                ref active,
1168                free: _,
1169            } => Self::check_active(device, last_completed, active),
1170        }
1171    }
1172
1173    /// Trim the internal state of this [`Fence`].
1174    ///
1175    /// This function has no externally visible effect, but you should call it
1176    /// periodically to keep this fence's resource consumption under control.
1177    ///
1178    /// For fences using the [`FencePool`] implementation, this function
1179    /// recycles fences that have been signaled. If you don't call this,
1180    /// [`Queue::submit`] will just keep allocating a new Vulkan fence every
1181    /// time it's called.
1182    ///
1183    /// [`FencePool`]: Fence::FencePool
1184    /// [`Queue::submit`]: crate::Queue::submit
1185    fn maintain(&mut self, device: &ash::Device) -> Result<(), crate::DeviceError> {
1186        match *self {
1187            Self::TimelineSemaphore(_) => {}
1188            Self::FencePool {
1189                ref mut last_completed,
1190                ref mut active,
1191                ref mut free,
1192            } => {
1193                let latest = Self::check_active(device, *last_completed, active)?;
1194                let base_free = free.len();
1195                for &(value, raw) in active.iter() {
1196                    if value <= latest {
1197                        free.push(raw);
1198                    }
1199                }
1200                if free.len() != base_free {
1201                    active.retain(|&(value, _)| value > latest);
1202                    unsafe { device.reset_fences(&free[base_free..]) }
1203                        .map_err(map_device_oom_err)?
1204                }
1205                *last_completed = latest;
1206            }
1207        }
1208        Ok(())
1209    }
1210}
1211
1212impl crate::Queue for Queue {
1213    type A = Api;
1214
1215    unsafe fn submit(
1216        &self,
1217        command_buffers: &[&CommandBuffer],
1218        surface_textures: &[&SurfaceTexture],
1219        (signal_fence, signal_value): (&mut Fence, crate::FenceValue),
1220    ) -> Result<(), crate::DeviceError> {
1221        let mut fence_raw = vk::Fence::null();
1222
1223        let mut wait_semaphores = SemaphoreList::new(SemaphoreListMode::Wait);
1224        let mut signal_semaphores = SemaphoreList::new(SemaphoreListMode::Signal);
1225
1226        // Double check that the same swapchain image isn't being given to us multiple times,
1227        // as that will deadlock when we try to lock them all.
1228        debug_assert!(
1229            {
1230                let mut check = HashSet::with_capacity(surface_textures.len());
1231                // We compare the Box by pointer, as Eq isn't well defined for SurfaceSemaphores.
1232                for st in surface_textures {
1233                    let ptr: *const () = <*const _>::cast(&*st.metadata);
1234                    check.insert(ptr as usize);
1235                }
1236                check.len() == surface_textures.len()
1237            },
1238            "More than one surface texture is being used from the same swapchain. This will cause a deadlock in release."
1239        );
1240
1241        let locked_swapchain_semaphores = surface_textures
1242            .iter()
1243            .map(|st| st.metadata.get_semaphore_guard())
1244            .collect::<Vec<_>>();
1245
1246        for mut semaphores in locked_swapchain_semaphores {
1247            semaphores.set_used_fence_value(signal_value);
1248
1249            // If we're the first submission to operate on this image, wait on
1250            // its acquire semaphore, to make sure the presentation engine is
1251            // done with it.
1252            if let Some(sem) = semaphores.get_acquire_wait_semaphore() {
1253                wait_semaphores.push_wait(sem, vk::PipelineStageFlags::TOP_OF_PIPE);
1254            }
1255
1256            // Get a semaphore to signal when we're done writing to this surface
1257            // image. Presentation of this image will wait for this.
1258            let signal_semaphore = semaphores.get_submit_signal_semaphore(&self.device)?;
1259            signal_semaphores.push_signal(signal_semaphore);
1260        }
1261
1262        let mut guard = self.signal_semaphores.lock();
1263        if !guard.is_empty() {
1264            signal_semaphores.append(&mut guard);
1265        }
1266
1267        // In order for submissions to be strictly ordered, we encode a dependency between each submission
1268        // using a pair of semaphores. This adds a wait if it is needed, and signals the next semaphore.
1269        let semaphore_state = self.relay_semaphores.lock().advance(&self.device)?;
1270
1271        if let Some(sem) = semaphore_state.wait {
1272            wait_semaphores.push_wait(
1273                SemaphoreType::Binary(sem),
1274                vk::PipelineStageFlags::TOP_OF_PIPE,
1275            );
1276        }
1277
1278        signal_semaphores.push_signal(SemaphoreType::Binary(semaphore_state.signal));
1279
1280        // We need to signal our wgpu::Fence if we have one, this adds it to the signal list.
1281        signal_fence.maintain(&self.device.raw)?;
1282        match *signal_fence {
1283            Fence::TimelineSemaphore(raw) => {
1284                signal_semaphores.push_signal(SemaphoreType::Timeline(raw, signal_value));
1285            }
1286            Fence::FencePool {
1287                ref mut active,
1288                ref mut free,
1289                ..
1290            } => {
1291                fence_raw = match free.pop() {
1292                    Some(raw) => raw,
1293                    None => unsafe {
1294                        self.device
1295                            .raw
1296                            .create_fence(&vk::FenceCreateInfo::default(), None)
1297                            .map_err(map_host_device_oom_err)?
1298                    },
1299                };
1300                active.push((signal_value, fence_raw));
1301            }
1302        }
1303
1304        let vk_cmd_buffers = command_buffers
1305            .iter()
1306            .map(|cmd| cmd.raw)
1307            .collect::<Vec<_>>();
1308
1309        let mut vk_info = vk::SubmitInfo::default().command_buffers(&vk_cmd_buffers);
1310        let mut vk_timeline_info = mem::MaybeUninit::uninit();
1311        vk_info = SemaphoreList::add_to_submit(
1312            &mut wait_semaphores,
1313            &mut signal_semaphores,
1314            vk_info,
1315            &mut vk_timeline_info,
1316        );
1317
1318        profiling::scope!("vkQueueSubmit");
1319        unsafe {
1320            self.device
1321                .raw
1322                .queue_submit(self.raw, &[vk_info], fence_raw)
1323                .map_err(map_host_device_oom_and_lost_err)?
1324        };
1325        Ok(())
1326    }
1327
1328    unsafe fn present(
1329        &self,
1330        surface: &Surface,
1331        texture: SurfaceTexture,
1332    ) -> Result<(), crate::SurfaceError> {
1333        let mut swapchain = surface.swapchain.write();
1334
1335        unsafe { swapchain.as_mut().unwrap().present(self, texture) }
1336    }
1337
1338    unsafe fn get_timestamp_period(&self) -> f32 {
1339        self.device.timestamp_period
1340    }
1341}
1342
1343impl Queue {
1344    pub fn raw_device(&self) -> &ash::Device {
1345        &self.device.raw
1346    }
1347
1348    pub fn add_signal_semaphore(&self, semaphore: vk::Semaphore, semaphore_value: Option<u64>) {
1349        let mut guard = self.signal_semaphores.lock();
1350        if let Some(value) = semaphore_value {
1351            guard.push_signal(SemaphoreType::Timeline(semaphore, value));
1352        } else {
1353            guard.push_signal(SemaphoreType::Binary(semaphore));
1354        }
1355    }
1356}
1357
1358/// Maps
1359///
1360/// - VK_ERROR_OUT_OF_HOST_MEMORY
1361/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1362fn map_host_device_oom_err(err: vk::Result) -> crate::DeviceError {
1363    match err {
1364        vk::Result::ERROR_OUT_OF_HOST_MEMORY | vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
1365            get_oom_err(err)
1366        }
1367        e => get_unexpected_err(e),
1368    }
1369}
1370
1371/// Maps
1372///
1373/// - VK_ERROR_OUT_OF_HOST_MEMORY
1374/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1375/// - VK_ERROR_DEVICE_LOST
1376fn map_host_device_oom_and_lost_err(err: vk::Result) -> crate::DeviceError {
1377    match err {
1378        vk::Result::ERROR_DEVICE_LOST => get_lost_err(),
1379        other => map_host_device_oom_err(other),
1380    }
1381}
1382
1383/// Maps
1384///
1385/// - VK_ERROR_OUT_OF_HOST_MEMORY
1386/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1387/// - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1388fn map_host_device_oom_and_ioca_err(err: vk::Result) -> crate::DeviceError {
1389    // We don't use VK_KHR_buffer_device_address
1390    // VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1391    map_host_device_oom_err(err)
1392}
1393
1394/// Maps
1395///
1396/// - VK_ERROR_OUT_OF_HOST_MEMORY
1397fn map_host_oom_err(err: vk::Result) -> crate::DeviceError {
1398    match err {
1399        vk::Result::ERROR_OUT_OF_HOST_MEMORY => get_oom_err(err),
1400        e => get_unexpected_err(e),
1401    }
1402}
1403
1404/// Maps
1405///
1406/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1407fn map_device_oom_err(err: vk::Result) -> crate::DeviceError {
1408    match err {
1409        vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => get_oom_err(err),
1410        e => get_unexpected_err(e),
1411    }
1412}
1413
1414/// Maps
1415///
1416/// - VK_ERROR_OUT_OF_HOST_MEMORY
1417/// - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1418fn map_host_oom_and_ioca_err(err: vk::Result) -> crate::DeviceError {
1419    // We don't use VK_KHR_buffer_device_address
1420    // VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1421    map_host_oom_err(err)
1422}
1423
1424/// Maps
1425///
1426/// - VK_ERROR_OUT_OF_HOST_MEMORY
1427/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1428/// - VK_PIPELINE_COMPILE_REQUIRED_EXT
1429/// - VK_ERROR_INVALID_SHADER_NV
1430fn map_pipeline_err(err: vk::Result) -> crate::DeviceError {
1431    // We don't use VK_EXT_pipeline_creation_cache_control
1432    // VK_PIPELINE_COMPILE_REQUIRED_EXT
1433    // We don't use VK_NV_glsl_shader
1434    // VK_ERROR_INVALID_SHADER_NV
1435    map_host_device_oom_err(err)
1436}
1437
1438/// Returns [`crate::DeviceError::Unexpected`] or panics if the `internal_error_panic`
1439/// feature flag is enabled.
1440fn get_unexpected_err(_err: vk::Result) -> crate::DeviceError {
1441    #[cfg(feature = "internal_error_panic")]
1442    panic!("Unexpected Vulkan error: {_err:?}");
1443
1444    #[allow(unreachable_code)]
1445    crate::DeviceError::Unexpected
1446}
1447
1448/// Returns [`crate::DeviceError::OutOfMemory`].
1449fn get_oom_err(_err: vk::Result) -> crate::DeviceError {
1450    crate::DeviceError::OutOfMemory
1451}
1452
1453/// Returns [`crate::DeviceError::Lost`] or panics if the `device_lost_panic`
1454/// feature flag is enabled.
1455fn get_lost_err() -> crate::DeviceError {
1456    #[cfg(feature = "device_lost_panic")]
1457    panic!("Device lost");
1458
1459    #[allow(unreachable_code)]
1460    crate::DeviceError::Lost
1461}
1462
1463#[derive(Clone, Copy, Pod, Zeroable)]
1464#[repr(C)]
1465struct RawTlasInstance {
1466    transform: [f32; 12],
1467    custom_data_and_mask: u32,
1468    shader_binding_table_record_offset_and_flags: u32,
1469    acceleration_structure_reference: u64,
1470}
1471
1472/// Arguments to the [`CreateDeviceCallback`].
1473pub struct CreateDeviceCallbackArgs<'arg, 'pnext, 'this>
1474where
1475    'this: 'pnext,
1476{
1477    /// The extensions to enable for the device. You must not remove anything from this list,
1478    /// but you may add to it.
1479    pub extensions: &'arg mut Vec<&'static CStr>,
1480    /// The physical device features to enable. You may enable features, but must not disable any.
1481    pub device_features: &'arg mut PhysicalDeviceFeatures,
1482    /// The queue create infos for the device. You may add or modify queue create infos as needed.
1483    pub queue_create_infos: &'arg mut Vec<vk::DeviceQueueCreateInfo<'pnext>>,
1484    /// The create info for the device. You may add or modify things in the pnext chain, but
1485    /// do not turn features off. Additionally, do not add things to the list of extensions,
1486    /// or to the feature set, as all changes to that member will be overwritten.
1487    pub create_info: &'arg mut vk::DeviceCreateInfo<'pnext>,
1488    /// We need to have `'this` in the struct, so we can declare that all lifetimes coming from
1489    /// captures in the closure will live longer (and hence satisfy) `'pnext`. However, we
1490    /// don't actually directly use `'this`
1491    _phantom: PhantomData<&'this ()>,
1492}
1493
1494/// Callback to allow changing the vulkan device creation parameters.
1495///
1496/// # Safety:
1497/// - If you want to add extensions, add the to the `Vec<'static CStr>` not the create info,
1498///   as the create info value will be overwritten.
1499/// - Callback must not remove features.
1500/// - Callback must not change anything to what the instance does not support.
1501pub type CreateDeviceCallback<'this> =
1502    dyn for<'arg, 'pnext> FnOnce(CreateDeviceCallbackArgs<'arg, 'pnext, 'this>) + 'this;
1503
1504/// Arguments to the [`CreateInstanceCallback`].
1505pub struct CreateInstanceCallbackArgs<'arg, 'pnext, 'this>
1506where
1507    'this: 'pnext,
1508{
1509    /// The extensions to enable for the instance. You must not remove anything from this list,
1510    /// but you may add to it.
1511    pub extensions: &'arg mut Vec<&'static CStr>,
1512    /// The create info for the instance. You may add or modify things in the pnext chain, but
1513    /// do not turn features off. Additionally, do not add things to the list of extensions,
1514    /// all changes to that member will be overwritten.
1515    pub create_info: &'arg mut vk::InstanceCreateInfo<'pnext>,
1516    /// Vulkan entry point.
1517    pub entry: &'arg ash::Entry,
1518    /// We need to have `'this` in the struct, so we can declare that all lifetimes coming from
1519    /// captures in the closure will live longer (and hence satisfy) `'pnext`. However, we
1520    /// don't actually directly use `'this`
1521    _phantom: PhantomData<&'this ()>,
1522}
1523
1524/// Callback to allow changing the vulkan instance creation parameters.
1525///
1526/// # Safety:
1527/// - If you want to add extensions, add the to the `Vec<'static CStr>` not the create info,
1528///   as the create info value will be overwritten.
1529/// - Callback must not remove features.
1530/// - Callback must not change anything to what the instance does not support.
1531pub type CreateInstanceCallback<'this> =
1532    dyn for<'arg, 'pnext> FnOnce(CreateInstanceCallbackArgs<'arg, 'pnext, 'this>) + 'this;