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