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    mem_allocator: Mutex<gpu_allocator::vulkan::Allocator>,
509    desc_allocator:
510        Mutex<gpu_descriptor::DescriptorAllocator<vk::DescriptorPool, vk::DescriptorSet>>,
511    valid_ash_memory_types: u32,
512    naga_options: naga::back::spv::Options<'static>,
513    #[cfg(feature = "renderdoc")]
514    render_doc: crate::auxil::renderdoc::RenderDoc,
515    counters: Arc<wgt::HalCounters>,
516    // Struct members are dropped from first to last, put the Device last to ensure that
517    // all resources that depends on it are destroyed before it like the mem_allocator
518    shared: Arc<DeviceShared>,
519}
520
521impl Drop for Device {
522    fn drop(&mut self) {
523        unsafe { self.desc_allocator.lock().cleanup(&*self.shared) };
524    }
525}
526
527/// Semaphores for forcing queue submissions to run in order.
528///
529/// The [`wgpu_hal::Queue`] trait promises that if two calls to [`submit`] are
530/// ordered, then the first submission will finish on the GPU before the second
531/// submission begins. To get this behavior on Vulkan we need to pass semaphores
532/// to [`vkQueueSubmit`] for the commands to wait on before beginning execution,
533/// and to signal when their execution is done.
534///
535/// Normally this can be done with a single semaphore, waited on and then
536/// signalled for each submission. At any given time there's exactly one
537/// submission that would signal the semaphore, and exactly one waiting on it,
538/// as Vulkan requires.
539///
540/// However, as of Oct 2021, bug [#5508] in the Mesa ANV drivers caused them to
541/// hang if we use a single semaphore. The workaround is to alternate between
542/// two semaphores. The bug has been fixed in Mesa, but we should probably keep
543/// the workaround until, say, Oct 2026.
544///
545/// [`wgpu_hal::Queue`]: crate::Queue
546/// [`submit`]: crate::Queue::submit
547/// [`vkQueueSubmit`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#vkQueueSubmit
548/// [#5508]: https://gitlab.freedesktop.org/mesa/mesa/-/issues/5508
549#[derive(Clone)]
550struct RelaySemaphores {
551    /// The semaphore the next submission should wait on before beginning
552    /// execution on the GPU. This is `None` for the first submission, which
553    /// should not wait on anything at all.
554    wait: Option<vk::Semaphore>,
555
556    /// The semaphore the next submission should signal when it has finished
557    /// execution on the GPU.
558    signal: vk::Semaphore,
559}
560
561impl RelaySemaphores {
562    fn new(device: &DeviceShared) -> Result<Self, crate::DeviceError> {
563        Ok(Self {
564            wait: None,
565            signal: device.new_binary_semaphore("RelaySemaphores: 1")?,
566        })
567    }
568
569    /// Advances the semaphores, returning the semaphores that should be used for a submission.
570    fn advance(&mut self, device: &DeviceShared) -> Result<Self, crate::DeviceError> {
571        let old = self.clone();
572
573        // Build the state for the next submission.
574        match self.wait {
575            None => {
576                // The `old` values describe the first submission to this queue.
577                // The second submission should wait on `old.signal`, and then
578                // signal a new semaphore which we'll create now.
579                self.wait = Some(old.signal);
580                self.signal = device.new_binary_semaphore("RelaySemaphores: 2")?;
581            }
582            Some(ref mut wait) => {
583                // What this submission signals, the next should wait.
584                mem::swap(wait, &mut self.signal);
585            }
586        };
587
588        Ok(old)
589    }
590
591    /// Destroys the semaphores.
592    unsafe fn destroy(&self, device: &ash::Device) {
593        unsafe {
594            if let Some(wait) = self.wait {
595                device.destroy_semaphore(wait, None);
596            }
597            device.destroy_semaphore(self.signal, None);
598        }
599    }
600}
601
602pub struct Queue {
603    raw: vk::Queue,
604    device: Arc<DeviceShared>,
605    family_index: u32,
606    relay_semaphores: Mutex<RelaySemaphores>,
607    signal_semaphores: Mutex<SemaphoreList>,
608}
609
610impl Queue {
611    pub fn as_raw(&self) -> vk::Queue {
612        self.raw
613    }
614}
615
616impl Drop for Queue {
617    fn drop(&mut self) {
618        unsafe { self.relay_semaphores.lock().destroy(&self.device.raw) };
619    }
620}
621#[derive(Debug)]
622enum BufferMemoryBacking {
623    Managed(gpu_allocator::vulkan::Allocation),
624    VulkanMemory {
625        memory: vk::DeviceMemory,
626        offset: u64,
627        size: u64,
628    },
629}
630impl BufferMemoryBacking {
631    fn memory(&self) -> vk::DeviceMemory {
632        match self {
633            Self::Managed(m) => unsafe { m.memory() },
634            Self::VulkanMemory { memory, .. } => *memory,
635        }
636    }
637    fn offset(&self) -> u64 {
638        match self {
639            Self::Managed(m) => m.offset(),
640            Self::VulkanMemory { offset, .. } => *offset,
641        }
642    }
643    fn size(&self) -> u64 {
644        match self {
645            Self::Managed(m) => m.size(),
646            Self::VulkanMemory { size, .. } => *size,
647        }
648    }
649}
650#[derive(Debug)]
651pub struct Buffer {
652    raw: vk::Buffer,
653    allocation: Option<Mutex<BufferMemoryBacking>>,
654}
655impl Buffer {
656    /// # Safety
657    ///
658    /// - `vk_buffer`'s memory must be managed by the caller
659    /// - Externally imported buffers can't be mapped by `wgpu`
660    pub unsafe fn from_raw(vk_buffer: vk::Buffer) -> Self {
661        Self {
662            raw: vk_buffer,
663            allocation: None,
664        }
665    }
666    /// # Safety
667    /// - 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
668    /// - Externally imported buffers can't be mapped by `wgpu`
669    /// - `offset` and `size` must be valid with the allocation of `memory`
670    pub unsafe fn from_raw_managed(
671        vk_buffer: vk::Buffer,
672        memory: vk::DeviceMemory,
673        offset: u64,
674        size: u64,
675    ) -> Self {
676        Self {
677            raw: vk_buffer,
678            allocation: Some(Mutex::new(BufferMemoryBacking::VulkanMemory {
679                memory,
680                offset,
681                size,
682            })),
683        }
684    }
685}
686
687impl crate::DynBuffer for Buffer {}
688
689#[derive(Debug)]
690pub struct AccelerationStructure {
691    raw: vk::AccelerationStructureKHR,
692    buffer: vk::Buffer,
693    allocation: gpu_allocator::vulkan::Allocation,
694    compacted_size_query: Option<vk::QueryPool>,
695}
696
697impl crate::DynAccelerationStructure for AccelerationStructure {}
698
699#[derive(Debug)]
700pub enum TextureMemory {
701    // shared memory in GPU allocator (owned by wgpu-hal)
702    Allocation(gpu_allocator::vulkan::Allocation),
703
704    // dedicated memory (owned by wgpu-hal)
705    Dedicated(vk::DeviceMemory),
706
707    // memory not owned by wgpu
708    External,
709}
710
711#[derive(Debug)]
712pub struct Texture {
713    raw: vk::Image,
714    memory: TextureMemory,
715    format: wgt::TextureFormat,
716    copy_size: crate::CopyExtent,
717    identity: ResourceIdentity<vk::Image>,
718
719    // The `drop_guard` field must be the last field of this struct so it is dropped last.
720    // Do not add new fields after it.
721    drop_guard: Option<crate::DropGuard>,
722}
723
724impl crate::DynTexture for Texture {}
725
726impl Texture {
727    /// # Safety
728    ///
729    /// - The image handle must not be manually destroyed
730    pub unsafe fn raw_handle(&self) -> vk::Image {
731        self.raw
732    }
733
734    /// # Safety
735    ///
736    /// - The caller must not free the `vk::DeviceMemory` or
737    ///   `gpu_alloc::MemoryBlock` in the returned `TextureMemory`.
738    pub unsafe fn memory(&self) -> &TextureMemory {
739        &self.memory
740    }
741}
742
743#[derive(Debug)]
744pub struct TextureView {
745    raw_texture: vk::Image,
746    raw: vk::ImageView,
747    _layers: NonZeroU32,
748    format: wgt::TextureFormat,
749    raw_format: vk::Format,
750    base_mip_level: u32,
751    dimension: wgt::TextureViewDimension,
752    texture_identity: ResourceIdentity<vk::Image>,
753    view_identity: ResourceIdentity<vk::ImageView>,
754}
755
756impl crate::DynTextureView for TextureView {}
757
758impl TextureView {
759    /// # Safety
760    ///
761    /// - The image view handle must not be manually destroyed
762    pub unsafe fn raw_handle(&self) -> vk::ImageView {
763        self.raw
764    }
765
766    /// Returns the raw texture view, along with its identity.
767    fn identified_raw_view(&self) -> IdentifiedTextureView {
768        IdentifiedTextureView {
769            raw: self.raw,
770            identity: self.view_identity,
771        }
772    }
773}
774
775#[derive(Debug)]
776pub struct Sampler {
777    raw: vk::Sampler,
778    create_info: vk::SamplerCreateInfo<'static>,
779}
780
781impl crate::DynSampler for Sampler {}
782
783/// Information about a binding within a specific BindGroupLayout / BindGroup.
784/// This will be used to construct a [`naga::back::spv::BindingInfo`], where
785/// the descriptor set value will be taken from the index of the group.
786#[derive(Copy, Clone, Debug)]
787struct BindingInfo {
788    binding: u32,
789    binding_array_size: Option<NonZeroU32>,
790}
791
792#[derive(Debug)]
793pub struct BindGroupLayout {
794    raw: vk::DescriptorSetLayout,
795    desc_count: gpu_descriptor::DescriptorTotalCount,
796    /// Sorted list of entries.
797    entries: Box<[wgt::BindGroupLayoutEntry]>,
798    /// Map of original binding index to remapped binding index and optional
799    /// array size.
800    binding_map: Vec<(u32, BindingInfo)>,
801    contains_binding_arrays: bool,
802}
803
804impl crate::DynBindGroupLayout for BindGroupLayout {}
805
806#[derive(Debug)]
807pub struct PipelineLayout {
808    raw: vk::PipelineLayout,
809    binding_map: naga::back::spv::BindingMap,
810}
811
812impl crate::DynPipelineLayout for PipelineLayout {}
813
814#[derive(Debug)]
815pub struct BindGroup {
816    set: gpu_descriptor::DescriptorSet<vk::DescriptorSet>,
817}
818
819impl crate::DynBindGroup for BindGroup {}
820
821/// Miscellaneous allocation recycling pool for `CommandAllocator`.
822#[derive(Default)]
823struct Temp {
824    marker: Vec<u8>,
825    buffer_barriers: Vec<vk::BufferMemoryBarrier<'static>>,
826    image_barriers: Vec<vk::ImageMemoryBarrier<'static>>,
827}
828
829impl Temp {
830    fn clear(&mut self) {
831        self.marker.clear();
832        self.buffer_barriers.clear();
833        self.image_barriers.clear();
834    }
835
836    fn make_c_str(&mut self, name: &str) -> &CStr {
837        self.marker.clear();
838        self.marker.extend_from_slice(name.as_bytes());
839        self.marker.push(0);
840        unsafe { CStr::from_bytes_with_nul_unchecked(&self.marker) }
841    }
842}
843
844/// Generates unique IDs for each resource of type `T`.
845///
846/// Because vk handles are not permanently unique, this
847/// provides a way to generate unique IDs for each resource.
848struct ResourceIdentityFactory<T> {
849    #[cfg(not(target_has_atomic = "64"))]
850    next_id: Mutex<u64>,
851    #[cfg(target_has_atomic = "64")]
852    next_id: core::sync::atomic::AtomicU64,
853    _phantom: PhantomData<T>,
854}
855
856impl<T> ResourceIdentityFactory<T> {
857    fn new() -> Self {
858        Self {
859            #[cfg(not(target_has_atomic = "64"))]
860            next_id: Mutex::new(0),
861            #[cfg(target_has_atomic = "64")]
862            next_id: core::sync::atomic::AtomicU64::new(0),
863            _phantom: PhantomData,
864        }
865    }
866
867    /// Returns a new unique ID for a resource of type `T`.
868    fn next(&self) -> ResourceIdentity<T> {
869        #[cfg(not(target_has_atomic = "64"))]
870        {
871            let mut next_id = self.next_id.lock();
872            let id = *next_id;
873            *next_id += 1;
874            ResourceIdentity {
875                id,
876                _phantom: PhantomData,
877            }
878        }
879
880        #[cfg(target_has_atomic = "64")]
881        ResourceIdentity {
882            id: self
883                .next_id
884                .fetch_add(1, core::sync::atomic::Ordering::Relaxed),
885            _phantom: PhantomData,
886        }
887    }
888}
889
890/// A unique identifier for a resource of type `T`.
891///
892/// This is used as a hashable key for resources, which
893/// is permanently unique through the lifetime of the program.
894#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
895struct ResourceIdentity<T> {
896    id: u64,
897    _phantom: PhantomData<T>,
898}
899
900#[derive(Clone, Eq, Hash, PartialEq)]
901struct FramebufferKey {
902    raw_pass: vk::RenderPass,
903    /// Because this is used as a key in a hash map, we need to include the identity
904    /// so that this hashes differently, even if the ImageView handles are the same
905    /// between different views.
906    attachment_identities: ArrayVec<ResourceIdentity<vk::ImageView>, { MAX_TOTAL_ATTACHMENTS }>,
907    /// While this is redundant for calculating the hash, we need access to an array
908    /// of all the raw ImageViews when we are creating the actual framebuffer,
909    /// so we store this here.
910    attachment_views: ArrayVec<vk::ImageView, { MAX_TOTAL_ATTACHMENTS }>,
911    extent: wgt::Extent3d,
912}
913
914impl FramebufferKey {
915    fn push_view(&mut self, view: IdentifiedTextureView) {
916        self.attachment_identities.push(view.identity);
917        self.attachment_views.push(view.raw);
918    }
919}
920
921/// A texture view paired with its identity.
922#[derive(Copy, Clone)]
923struct IdentifiedTextureView {
924    raw: vk::ImageView,
925    identity: ResourceIdentity<vk::ImageView>,
926}
927
928#[derive(Clone, Eq, Hash, PartialEq)]
929struct TempTextureViewKey {
930    texture: vk::Image,
931    /// As this is used in a hashmap, we need to
932    /// include the identity so that this hashes differently,
933    /// even if the Image handles are the same between different images.
934    texture_identity: ResourceIdentity<vk::Image>,
935    format: vk::Format,
936    mip_level: u32,
937    depth_slice: u32,
938}
939
940pub struct CommandEncoder {
941    raw: vk::CommandPool,
942    device: Arc<DeviceShared>,
943
944    /// The current command buffer, if `self` is in the ["recording"]
945    /// state.
946    ///
947    /// ["recording"]: crate::CommandEncoder
948    ///
949    /// If non-`null`, the buffer is in the Vulkan "recording" state.
950    active: vk::CommandBuffer,
951
952    /// What kind of pass we are currently within: compute or render.
953    bind_point: vk::PipelineBindPoint,
954
955    /// Allocation recycling pool for this encoder.
956    temp: Temp,
957
958    /// A pool of available command buffers.
959    ///
960    /// These are all in the Vulkan "initial" state.
961    free: Vec<vk::CommandBuffer>,
962
963    /// A pool of discarded command buffers.
964    ///
965    /// These could be in any Vulkan state except "pending".
966    discarded: Vec<vk::CommandBuffer>,
967
968    /// If this is true, the active renderpass enabled a debug span,
969    /// and needs to be disabled on renderpass close.
970    rpass_debug_marker_active: bool,
971
972    /// If set, the end of the next render/compute pass will write a timestamp at
973    /// the given pool & location.
974    end_of_pass_timer_query: Option<(vk::QueryPool, u32)>,
975
976    framebuffers: FastHashMap<FramebufferKey, vk::Framebuffer>,
977    temp_texture_views: FastHashMap<TempTextureViewKey, IdentifiedTextureView>,
978
979    counters: Arc<wgt::HalCounters>,
980
981    current_pipeline_is_multiview: bool,
982}
983
984impl Drop for CommandEncoder {
985    fn drop(&mut self) {
986        // SAFETY:
987        //
988        // VUID-vkDestroyCommandPool-commandPool-00041: wgpu_hal requires that a
989        // `CommandBuffer` must live until its execution is complete, and that a
990        // `CommandBuffer` must not outlive the `CommandEncoder` that built it.
991        // Thus, we know that none of our `CommandBuffers` are in the "pending"
992        // state.
993        //
994        // The other VUIDs are pretty obvious.
995        unsafe {
996            // `vkDestroyCommandPool` also frees any command buffers allocated
997            // from that pool, so there's no need to explicitly call
998            // `vkFreeCommandBuffers` on `cmd_encoder`'s `free` and `discarded`
999            // fields.
1000            self.device.raw.destroy_command_pool(self.raw, None);
1001        }
1002
1003        for (_, fb) in self.framebuffers.drain() {
1004            unsafe { self.device.raw.destroy_framebuffer(fb, None) };
1005        }
1006
1007        for (_, view) in self.temp_texture_views.drain() {
1008            unsafe { self.device.raw.destroy_image_view(view.raw, None) };
1009        }
1010
1011        self.counters.command_encoders.sub(1);
1012    }
1013}
1014
1015impl CommandEncoder {
1016    /// # Safety
1017    ///
1018    /// - The command buffer handle must not be manually destroyed
1019    pub unsafe fn raw_handle(&self) -> vk::CommandBuffer {
1020        self.active
1021    }
1022}
1023
1024impl fmt::Debug for CommandEncoder {
1025    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1026        f.debug_struct("CommandEncoder")
1027            .field("raw", &self.raw)
1028            .finish()
1029    }
1030}
1031
1032#[derive(Debug)]
1033pub struct CommandBuffer {
1034    raw: vk::CommandBuffer,
1035}
1036
1037impl crate::DynCommandBuffer for CommandBuffer {}
1038
1039#[derive(Debug)]
1040#[allow(clippy::large_enum_variant)]
1041pub enum ShaderModule {
1042    Raw(vk::ShaderModule),
1043    Intermediate {
1044        naga_shader: crate::NagaShader,
1045        runtime_checks: wgt::ShaderRuntimeChecks,
1046    },
1047}
1048
1049impl crate::DynShaderModule for ShaderModule {}
1050
1051#[derive(Debug)]
1052pub struct RenderPipeline {
1053    raw: vk::Pipeline,
1054    is_multiview: bool,
1055}
1056
1057impl crate::DynRenderPipeline for RenderPipeline {}
1058
1059#[derive(Debug)]
1060pub struct ComputePipeline {
1061    raw: vk::Pipeline,
1062}
1063
1064impl crate::DynComputePipeline for ComputePipeline {}
1065
1066#[derive(Debug)]
1067pub struct PipelineCache {
1068    raw: vk::PipelineCache,
1069}
1070
1071impl crate::DynPipelineCache for PipelineCache {}
1072
1073#[derive(Debug)]
1074pub struct QuerySet {
1075    raw: vk::QueryPool,
1076}
1077
1078impl crate::DynQuerySet for QuerySet {}
1079
1080/// The [`Api::Fence`] type for [`vulkan::Api`].
1081///
1082/// This is an `enum` because there are two possible implementations of
1083/// `wgpu-hal` fences on Vulkan: Vulkan fences, which work on any version of
1084/// Vulkan, and Vulkan timeline semaphores, which are easier and cheaper but
1085/// require non-1.0 features.
1086///
1087/// [`Device::create_fence`] returns a [`TimelineSemaphore`] if
1088/// [`VK_KHR_timeline_semaphore`] is available and enabled, and a [`FencePool`]
1089/// otherwise.
1090///
1091/// [`Api::Fence`]: crate::Api::Fence
1092/// [`vulkan::Api`]: Api
1093/// [`Device::create_fence`]: crate::Device::create_fence
1094/// [`TimelineSemaphore`]: Fence::TimelineSemaphore
1095/// [`VK_KHR_timeline_semaphore`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_KHR_timeline_semaphore
1096/// [`FencePool`]: Fence::FencePool
1097#[derive(Debug)]
1098pub enum Fence {
1099    /// A Vulkan [timeline semaphore].
1100    ///
1101    /// These are simpler to use than Vulkan fences, since timeline semaphores
1102    /// work exactly the way [`wpgu_hal::Api::Fence`] is specified to work.
1103    ///
1104    /// [timeline semaphore]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-semaphores
1105    /// [`wpgu_hal::Api::Fence`]: crate::Api::Fence
1106    TimelineSemaphore(vk::Semaphore),
1107
1108    /// A collection of Vulkan [fence]s, each associated with a [`FenceValue`].
1109    ///
1110    /// The effective [`FenceValue`] of this variant is the greater of
1111    /// `last_completed` and the maximum value associated with a signalled fence
1112    /// in `active`.
1113    ///
1114    /// Fences are available in all versions of Vulkan, but since they only have
1115    /// two states, "signaled" and "unsignaled", we need to use a separate fence
1116    /// for each queue submission we might want to wait for, and remember which
1117    /// [`FenceValue`] each one represents.
1118    ///
1119    /// [fence]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-fences
1120    /// [`FenceValue`]: crate::FenceValue
1121    FencePool {
1122        last_completed: crate::FenceValue,
1123        /// The pending fence values have to be ascending.
1124        active: Vec<(crate::FenceValue, vk::Fence)>,
1125        free: Vec<vk::Fence>,
1126    },
1127}
1128
1129impl crate::DynFence for Fence {}
1130
1131impl Fence {
1132    /// Return the highest [`FenceValue`] among the signalled fences in `active`.
1133    ///
1134    /// As an optimization, assume that we already know that the fence has
1135    /// reached `last_completed`, and don't bother checking fences whose values
1136    /// are less than that: those fences remain in the `active` array only
1137    /// because we haven't called `maintain` yet to clean them up.
1138    ///
1139    /// [`FenceValue`]: crate::FenceValue
1140    fn check_active(
1141        device: &ash::Device,
1142        mut last_completed: crate::FenceValue,
1143        active: &[(crate::FenceValue, vk::Fence)],
1144    ) -> Result<crate::FenceValue, crate::DeviceError> {
1145        for &(value, raw) in active.iter() {
1146            unsafe {
1147                if value > last_completed
1148                    && device
1149                        .get_fence_status(raw)
1150                        .map_err(map_host_device_oom_and_lost_err)?
1151                {
1152                    last_completed = value;
1153                }
1154            }
1155        }
1156        Ok(last_completed)
1157    }
1158
1159    /// Return the highest signalled [`FenceValue`] for `self`.
1160    ///
1161    /// [`FenceValue`]: crate::FenceValue
1162    fn get_latest(
1163        &self,
1164        device: &ash::Device,
1165        extension: Option<&ExtensionFn<khr::timeline_semaphore::Device>>,
1166    ) -> Result<crate::FenceValue, crate::DeviceError> {
1167        match *self {
1168            Self::TimelineSemaphore(raw) => unsafe {
1169                Ok(match *extension.unwrap() {
1170                    ExtensionFn::Extension(ref ext) => ext
1171                        .get_semaphore_counter_value(raw)
1172                        .map_err(map_host_device_oom_and_lost_err)?,
1173                    ExtensionFn::Promoted => device
1174                        .get_semaphore_counter_value(raw)
1175                        .map_err(map_host_device_oom_and_lost_err)?,
1176                })
1177            },
1178            Self::FencePool {
1179                last_completed,
1180                ref active,
1181                free: _,
1182            } => Self::check_active(device, last_completed, active),
1183        }
1184    }
1185
1186    /// Trim the internal state of this [`Fence`].
1187    ///
1188    /// This function has no externally visible effect, but you should call it
1189    /// periodically to keep this fence's resource consumption under control.
1190    ///
1191    /// For fences using the [`FencePool`] implementation, this function
1192    /// recycles fences that have been signaled. If you don't call this,
1193    /// [`Queue::submit`] will just keep allocating a new Vulkan fence every
1194    /// time it's called.
1195    ///
1196    /// [`FencePool`]: Fence::FencePool
1197    /// [`Queue::submit`]: crate::Queue::submit
1198    fn maintain(&mut self, device: &ash::Device) -> Result<(), crate::DeviceError> {
1199        match *self {
1200            Self::TimelineSemaphore(_) => {}
1201            Self::FencePool {
1202                ref mut last_completed,
1203                ref mut active,
1204                ref mut free,
1205            } => {
1206                let latest = Self::check_active(device, *last_completed, active)?;
1207                let base_free = free.len();
1208                for &(value, raw) in active.iter() {
1209                    if value <= latest {
1210                        free.push(raw);
1211                    }
1212                }
1213                if free.len() != base_free {
1214                    active.retain(|&(value, _)| value > latest);
1215                    unsafe { device.reset_fences(&free[base_free..]) }
1216                        .map_err(map_device_oom_err)?
1217                }
1218                *last_completed = latest;
1219            }
1220        }
1221        Ok(())
1222    }
1223}
1224
1225impl crate::Queue for Queue {
1226    type A = Api;
1227
1228    unsafe fn submit(
1229        &self,
1230        command_buffers: &[&CommandBuffer],
1231        surface_textures: &[&SurfaceTexture],
1232        (signal_fence, signal_value): (&mut Fence, crate::FenceValue),
1233    ) -> Result<(), crate::DeviceError> {
1234        let mut fence_raw = vk::Fence::null();
1235
1236        let mut wait_semaphores = SemaphoreList::new(SemaphoreListMode::Wait);
1237        let mut signal_semaphores = SemaphoreList::new(SemaphoreListMode::Signal);
1238
1239        // Double check that the same swapchain image isn't being given to us multiple times,
1240        // as that will deadlock when we try to lock them all.
1241        debug_assert!(
1242            {
1243                let mut check = HashSet::with_capacity(surface_textures.len());
1244                // We compare the Box by pointer, as Eq isn't well defined for SurfaceSemaphores.
1245                for st in surface_textures {
1246                    let ptr: *const () = <*const _>::cast(&*st.metadata);
1247                    check.insert(ptr as usize);
1248                }
1249                check.len() == surface_textures.len()
1250            },
1251            "More than one surface texture is being used from the same swapchain. This will cause a deadlock in release."
1252        );
1253
1254        let locked_swapchain_semaphores = surface_textures
1255            .iter()
1256            .map(|st| st.metadata.get_semaphore_guard())
1257            .collect::<Vec<_>>();
1258
1259        for mut semaphores in locked_swapchain_semaphores {
1260            semaphores.set_used_fence_value(signal_value);
1261
1262            // If we're the first submission to operate on this image, wait on
1263            // its acquire semaphore, to make sure the presentation engine is
1264            // done with it.
1265            if let Some(sem) = semaphores.get_acquire_wait_semaphore() {
1266                wait_semaphores.push_wait(sem, vk::PipelineStageFlags::TOP_OF_PIPE);
1267            }
1268
1269            // Get a semaphore to signal when we're done writing to this surface
1270            // image. Presentation of this image will wait for this.
1271            let signal_semaphore = semaphores.get_submit_signal_semaphore(&self.device)?;
1272            signal_semaphores.push_signal(signal_semaphore);
1273        }
1274
1275        let mut guard = self.signal_semaphores.lock();
1276        if !guard.is_empty() {
1277            signal_semaphores.append(&mut guard);
1278        }
1279
1280        // In order for submissions to be strictly ordered, we encode a dependency between each submission
1281        // using a pair of semaphores. This adds a wait if it is needed, and signals the next semaphore.
1282        let semaphore_state = self.relay_semaphores.lock().advance(&self.device)?;
1283
1284        if let Some(sem) = semaphore_state.wait {
1285            wait_semaphores.push_wait(
1286                SemaphoreType::Binary(sem),
1287                vk::PipelineStageFlags::TOP_OF_PIPE,
1288            );
1289        }
1290
1291        signal_semaphores.push_signal(SemaphoreType::Binary(semaphore_state.signal));
1292
1293        // We need to signal our wgpu::Fence if we have one, this adds it to the signal list.
1294        signal_fence.maintain(&self.device.raw)?;
1295        match *signal_fence {
1296            Fence::TimelineSemaphore(raw) => {
1297                signal_semaphores.push_signal(SemaphoreType::Timeline(raw, signal_value));
1298            }
1299            Fence::FencePool {
1300                ref mut active,
1301                ref mut free,
1302                ..
1303            } => {
1304                fence_raw = match free.pop() {
1305                    Some(raw) => raw,
1306                    None => unsafe {
1307                        self.device
1308                            .raw
1309                            .create_fence(&vk::FenceCreateInfo::default(), None)
1310                            .map_err(map_host_device_oom_err)?
1311                    },
1312                };
1313                active.push((signal_value, fence_raw));
1314            }
1315        }
1316
1317        let vk_cmd_buffers = command_buffers
1318            .iter()
1319            .map(|cmd| cmd.raw)
1320            .collect::<Vec<_>>();
1321
1322        let mut vk_info = vk::SubmitInfo::default().command_buffers(&vk_cmd_buffers);
1323        let mut vk_timeline_info = mem::MaybeUninit::uninit();
1324        vk_info = SemaphoreList::add_to_submit(
1325            &mut wait_semaphores,
1326            &mut signal_semaphores,
1327            vk_info,
1328            &mut vk_timeline_info,
1329        );
1330
1331        profiling::scope!("vkQueueSubmit");
1332        unsafe {
1333            self.device
1334                .raw
1335                .queue_submit(self.raw, &[vk_info], fence_raw)
1336                .map_err(map_host_device_oom_and_lost_err)?
1337        };
1338        Ok(())
1339    }
1340
1341    unsafe fn present(
1342        &self,
1343        surface: &Surface,
1344        texture: SurfaceTexture,
1345    ) -> Result<(), crate::SurfaceError> {
1346        let mut swapchain = surface.swapchain.write();
1347
1348        unsafe { swapchain.as_mut().unwrap().present(self, texture) }
1349    }
1350
1351    unsafe fn get_timestamp_period(&self) -> f32 {
1352        self.device.timestamp_period
1353    }
1354}
1355
1356impl Queue {
1357    pub fn raw_device(&self) -> &ash::Device {
1358        &self.device.raw
1359    }
1360
1361    pub fn add_signal_semaphore(&self, semaphore: vk::Semaphore, semaphore_value: Option<u64>) {
1362        let mut guard = self.signal_semaphores.lock();
1363        if let Some(value) = semaphore_value {
1364            guard.push_signal(SemaphoreType::Timeline(semaphore, value));
1365        } else {
1366            guard.push_signal(SemaphoreType::Binary(semaphore));
1367        }
1368    }
1369}
1370
1371/// Maps
1372///
1373/// - VK_ERROR_OUT_OF_HOST_MEMORY
1374/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1375fn map_host_device_oom_err(err: vk::Result) -> crate::DeviceError {
1376    match err {
1377        vk::Result::ERROR_OUT_OF_HOST_MEMORY | vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
1378            get_oom_err(err)
1379        }
1380        e => get_unexpected_err(e),
1381    }
1382}
1383
1384/// Maps
1385///
1386/// - VK_ERROR_OUT_OF_HOST_MEMORY
1387/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1388/// - VK_ERROR_DEVICE_LOST
1389fn map_host_device_oom_and_lost_err(err: vk::Result) -> crate::DeviceError {
1390    match err {
1391        vk::Result::ERROR_DEVICE_LOST => get_lost_err(),
1392        other => map_host_device_oom_err(other),
1393    }
1394}
1395
1396/// Maps
1397///
1398/// - VK_ERROR_OUT_OF_HOST_MEMORY
1399/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1400/// - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1401fn map_host_device_oom_and_ioca_err(err: vk::Result) -> crate::DeviceError {
1402    // We don't use VK_KHR_buffer_device_address
1403    // VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1404    map_host_device_oom_err(err)
1405}
1406
1407/// Maps
1408///
1409/// - VK_ERROR_OUT_OF_HOST_MEMORY
1410fn map_host_oom_err(err: vk::Result) -> crate::DeviceError {
1411    match err {
1412        vk::Result::ERROR_OUT_OF_HOST_MEMORY => get_oom_err(err),
1413        e => get_unexpected_err(e),
1414    }
1415}
1416
1417/// Maps
1418///
1419/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1420fn map_device_oom_err(err: vk::Result) -> crate::DeviceError {
1421    match err {
1422        vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => get_oom_err(err),
1423        e => get_unexpected_err(e),
1424    }
1425}
1426
1427/// Maps
1428///
1429/// - VK_ERROR_OUT_OF_HOST_MEMORY
1430/// - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1431fn map_host_oom_and_ioca_err(err: vk::Result) -> crate::DeviceError {
1432    // We don't use VK_KHR_buffer_device_address
1433    // VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR
1434    map_host_oom_err(err)
1435}
1436
1437/// Maps
1438///
1439/// - VK_ERROR_OUT_OF_HOST_MEMORY
1440/// - VK_ERROR_OUT_OF_DEVICE_MEMORY
1441/// - VK_PIPELINE_COMPILE_REQUIRED_EXT
1442/// - VK_ERROR_INVALID_SHADER_NV
1443fn map_pipeline_err(err: vk::Result) -> crate::DeviceError {
1444    // We don't use VK_EXT_pipeline_creation_cache_control
1445    // VK_PIPELINE_COMPILE_REQUIRED_EXT
1446    // We don't use VK_NV_glsl_shader
1447    // VK_ERROR_INVALID_SHADER_NV
1448    map_host_device_oom_err(err)
1449}
1450
1451/// Returns [`crate::DeviceError::Unexpected`] or panics if the `internal_error_panic`
1452/// feature flag is enabled.
1453fn get_unexpected_err(_err: vk::Result) -> crate::DeviceError {
1454    #[cfg(feature = "internal_error_panic")]
1455    panic!("Unexpected Vulkan error: {_err:?}");
1456
1457    #[allow(unreachable_code)]
1458    crate::DeviceError::Unexpected
1459}
1460
1461/// Returns [`crate::DeviceError::OutOfMemory`].
1462fn get_oom_err(_err: vk::Result) -> crate::DeviceError {
1463    crate::DeviceError::OutOfMemory
1464}
1465
1466/// Returns [`crate::DeviceError::Lost`] or panics if the `device_lost_panic`
1467/// feature flag is enabled.
1468fn get_lost_err() -> crate::DeviceError {
1469    #[cfg(feature = "device_lost_panic")]
1470    panic!("Device lost");
1471
1472    #[allow(unreachable_code)]
1473    crate::DeviceError::Lost
1474}
1475
1476#[derive(Clone, Copy, Pod, Zeroable)]
1477#[repr(C)]
1478struct RawTlasInstance {
1479    transform: [f32; 12],
1480    custom_data_and_mask: u32,
1481    shader_binding_table_record_offset_and_flags: u32,
1482    acceleration_structure_reference: u64,
1483}
1484
1485/// Arguments to the [`CreateDeviceCallback`].
1486pub struct CreateDeviceCallbackArgs<'arg, 'pnext, 'this>
1487where
1488    'this: 'pnext,
1489{
1490    /// The extensions to enable for the device. You must not remove anything from this list,
1491    /// but you may add to it.
1492    pub extensions: &'arg mut Vec<&'static CStr>,
1493    /// The physical device features to enable. You may enable features, but must not disable any.
1494    pub device_features: &'arg mut PhysicalDeviceFeatures,
1495    /// The queue create infos for the device. You may add or modify queue create infos as needed.
1496    pub queue_create_infos: &'arg mut Vec<vk::DeviceQueueCreateInfo<'pnext>>,
1497    /// The create info for the device. You may add or modify things in the pnext chain, but
1498    /// do not turn features off. Additionally, do not add things to the list of extensions,
1499    /// or to the feature set, as all changes to that member will be overwritten.
1500    pub create_info: &'arg mut vk::DeviceCreateInfo<'pnext>,
1501    /// We need to have `'this` in the struct, so we can declare that all lifetimes coming from
1502    /// captures in the closure will live longer (and hence satisfy) `'pnext`. However, we
1503    /// don't actually directly use `'this`
1504    _phantom: PhantomData<&'this ()>,
1505}
1506
1507/// Callback to allow changing the vulkan device creation parameters.
1508///
1509/// # Safety:
1510/// - If you want to add extensions, add the to the `Vec<'static CStr>` not the create info,
1511///   as the create info value will be overwritten.
1512/// - Callback must not remove features.
1513/// - Callback must not change anything to what the instance does not support.
1514pub type CreateDeviceCallback<'this> =
1515    dyn for<'arg, 'pnext> FnOnce(CreateDeviceCallbackArgs<'arg, 'pnext, 'this>) + 'this;
1516
1517/// Arguments to the [`CreateInstanceCallback`].
1518pub struct CreateInstanceCallbackArgs<'arg, 'pnext, 'this>
1519where
1520    'this: 'pnext,
1521{
1522    /// The extensions to enable for the instance. You must not remove anything from this list,
1523    /// but you may add to it.
1524    pub extensions: &'arg mut Vec<&'static CStr>,
1525    /// The create info for the instance. You may add or modify things in the pnext chain, but
1526    /// do not turn features off. Additionally, do not add things to the list of extensions,
1527    /// all changes to that member will be overwritten.
1528    pub create_info: &'arg mut vk::InstanceCreateInfo<'pnext>,
1529    /// Vulkan entry point.
1530    pub entry: &'arg ash::Entry,
1531    /// We need to have `'this` in the struct, so we can declare that all lifetimes coming from
1532    /// captures in the closure will live longer (and hence satisfy) `'pnext`. However, we
1533    /// don't actually directly use `'this`
1534    _phantom: PhantomData<&'this ()>,
1535}
1536
1537/// Callback to allow changing the vulkan instance creation parameters.
1538///
1539/// # Safety:
1540/// - If you want to add extensions, add the to the `Vec<'static CStr>` not the create info,
1541///   as the create info value will be overwritten.
1542/// - Callback must not remove features.
1543/// - Callback must not change anything to what the instance does not support.
1544pub type CreateInstanceCallback<'this> =
1545    dyn for<'arg, 'pnext> FnOnce(CreateInstanceCallbackArgs<'arg, 'pnext, 'this>) + 'this;