Skip to main content

vk_graph/driver/
mod.rs

1//! **ADVANCED**: Raw Vulkan wrappers. Most users should use [`Graph`](crate::Graph),
2//! [`cmd`](crate::cmd), and [`node`](crate::node) instead.
3//!
4//! # Resources
5//!
6//! Resources are created and destroyed using RAII-style wrapper structures.
7//!
8//! The following resources are available:
9//!
10//! - [`AccelerationStructure`](accel_struct::AccelerationStructure)
11//! - [`Buffer`]
12//! - [`Image`](image::Image)
13//!
14//! Resources are logically mutable. All resource types contain useful read-only public fields, for
15//! example:
16//!
17//! | [`Buffer`] field | Type |
18//! | --- | --- |
19//! | [`device`](Buffer::device) | [`Device`](device::Device) |
20//! | [`handle`](Buffer::handle) | [`vk::Buffer`] |
21//! | [`info`](Buffer::info) | [`BufferInfo`] |
22//!
23//! Resources use atomic [`AccessType`](sync::AccessType) values to maintain consistency and track
24//! changes.
25//!
26//! # Pipelines
27//!
28//! Pipelines enable reading and writing resources using shader code running on physical graphics
29//! hardware.
30//!
31//! The following pipelines are available:
32//!
33//! - [`ComputePipeline`](compute::ComputePipeline)
34//! - [`GraphicsPipeline`](graphics::GraphicsPipeline)
35//! - [`RayTracingPipeline`](ray_tracing::RayTracingPipeline)
36//!
37//! Pipelines are immutable. All pipeline types contain useful public methods, for
38//! example:
39//!
40//! | [`ComputePipeline`](compute::ComputePipeline) method | Type |
41//! | --- | --- |
42//! | [`device(&self)`](compute::ComputePipeline::device) | [`Device`](device::Device) |
43//! | [`handle(&self)`](compute::ComputePipeline::handle) | [`vk::Pipeline`] |
44//! | [`info(&self)`](compute::ComputePipeline::info) | [`ComputePipelineInfo`](compute::ComputePipelineInfo) |
45
46pub mod accel_struct;
47pub mod buffer;
48pub mod cmd_buf;
49pub mod compute;
50pub mod device;
51pub mod fence;
52pub mod graphics;
53pub mod image;
54pub mod instance;
55pub mod physical_device;
56pub mod ray_tracing;
57pub mod render_pass;
58pub mod shader;
59pub mod surface;
60pub mod swapchain;
61
62pub(crate) mod descriptor_set;
63pub(crate) mod query_pool;
64
65mod descriptor_set_layout;
66
67/// Re-export of the [`ash`] crate — the foundational Vulkan bindings that every wrapper in this
68/// crate is built on.
69///
70/// `vk-graph` is **ash+graph**: it wraps `ash` to make Vulkan easier to use, but does not replace
71/// it. Expert users can always reach through to the raw bindings via `vk_graph::driver::ash`.
72///
73/// # Hidden from docs
74///
75/// This re-export is `#[doc(hidden)]` to avoid duplicating the entire `ash` API surface in
76/// `vk-graph`'s documentation. It is intentionally public and stable — not deprecated.
77#[doc(hidden)]
78pub use ash::{self};
79
80/// Re-export of [`vk_sync`] under the `sync` alias — Vulkan synchronization primitives.
81///
82/// Provides [`AccessType`](sync::AccessType) and related types that are the foundation of
83/// `vk-graph`'s automatic resource tracking.
84///
85/// # Hidden from docs
86///
87/// This re-export is `#[doc(hidden)]` to avoid duplicating the entire `vk_sync` API surface in
88/// `vk-graph`'s documentation. It is intentionally public and stable — not deprecated.
89#[doc(hidden)]
90pub use vk_sync::{self as sync};
91
92pub(crate) use self::{
93    descriptor_set::DescriptorSet,
94    descriptor_set_layout::DescriptorSetLayout,
95    render_pass::{
96        AttachmentInfo, AttachmentRef, FramebufferAttachmentImageInfo, FramebufferInfo,
97        SubpassDependency, SubpassInfo,
98    },
99    shader::{Descriptor, DescriptorBindingMap, DescriptorInfo},
100    surface::Surface,
101};
102
103use {
104    self::{
105        buffer::{Buffer, BufferInfo},
106        graphics::VertexInputState,
107    },
108    ash::vk,
109    gpu_allocator::AllocationError,
110    std::{
111        cmp::Ordering,
112        convert::Infallible,
113        error::Error,
114        fmt::{Display, Formatter},
115    },
116};
117
118macro_rules! access_type_u8_map {
119    ($($idx:literal => $name:ident),* $(,)?) => {
120        pub(super) const fn access_type_into_u8(ty: self::sync::AccessType) -> u8 {
121            use self::sync::AccessType::*;
122
123            match ty {
124                $($name => $idx,)*
125            }
126        }
127
128        pub(super) const fn access_type_from_u8(value: u8) -> self::sync::AccessType {
129            use self::sync::AccessType::*;
130
131            match value {
132                $($idx => $name,)*
133                _ => panic!("invalid packed access type"),
134            }
135        }
136    };
137}
138
139access_type_u8_map! {
140    0 => Nothing,
141    1 => CommandBufferReadNVX,
142    2 => IndirectBuffer,
143    3 => IndexBuffer,
144    4 => VertexBuffer,
145    5 => VertexShaderReadUniformBuffer,
146    6 => VertexShaderReadSampledImageOrUniformTexelBuffer,
147    7 => VertexShaderReadOther,
148    8 => TessellationControlShaderReadUniformBuffer,
149    9 => TessellationControlShaderReadSampledImageOrUniformTexelBuffer,
150    10 => TessellationControlShaderReadOther,
151    11 => TessellationEvaluationShaderReadUniformBuffer,
152    12 => TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer,
153    13 => TessellationEvaluationShaderReadOther,
154    14 => GeometryShaderReadUniformBuffer,
155    15 => GeometryShaderReadSampledImageOrUniformTexelBuffer,
156    16 => GeometryShaderReadOther,
157    17 => FragmentShaderReadUniformBuffer,
158    18 => FragmentShaderReadSampledImageOrUniformTexelBuffer,
159    19 => FragmentShaderReadColorInputAttachment,
160    20 => FragmentShaderReadDepthStencilInputAttachment,
161    21 => FragmentShaderReadOther,
162    22 => ColorAttachmentRead,
163    23 => DepthStencilAttachmentRead,
164    24 => ComputeShaderReadUniformBuffer,
165    25 => ComputeShaderReadSampledImageOrUniformTexelBuffer,
166    26 => ComputeShaderReadOther,
167    27 => AnyShaderReadUniformBuffer,
168    28 => AnyShaderReadUniformBufferOrVertexBuffer,
169    29 => AnyShaderReadSampledImageOrUniformTexelBuffer,
170    30 => AnyShaderReadOther,
171    31 => TransferRead,
172    32 => HostRead,
173    33 => Present,
174    34 => CommandBufferWriteNVX,
175    35 => VertexShaderWrite,
176    36 => TessellationControlShaderWrite,
177    37 => TessellationEvaluationShaderWrite,
178    38 => GeometryShaderWrite,
179    39 => FragmentShaderWrite,
180    40 => ColorAttachmentWrite,
181    41 => DepthStencilAttachmentWrite,
182    42 => DepthStencilAttachmentReadWrite,
183    43 => DepthAttachmentWriteStencilReadOnly,
184    44 => StencilAttachmentWriteDepthReadOnly,
185    45 => ComputeShaderWrite,
186    46 => ComputeShaderReadWrite,
187    47 => AnyShaderWrite,
188    48 => TransferWrite,
189    49 => HostWrite,
190    50 => ColorAttachmentReadWrite,
191    51 => General,
192    52 => RayTracingShaderReadSampledImageOrUniformTexelBuffer,
193    53 => RayTracingShaderReadColorInputAttachment,
194    54 => RayTracingShaderReadDepthStencilInputAttachment,
195    55 => RayTracingShaderReadAccelerationStructure,
196    56 => RayTracingShaderReadOther,
197    57 => AccelerationStructureBuildWrite,
198    58 => AccelerationStructureBuildRead,
199    59 => AccelerationStructureBufferWrite,
200    60 => MeshShaderReadUniformBuffer,
201    61 => MeshShaderReadSampledImageOrUniformTexelBuffer,
202    62 => MeshShaderReadOther,
203    63 => TaskShaderReadUniformBuffer,
204    64 => TaskShaderReadSampledImageOrUniformTexelBuffer,
205    65 => TaskShaderReadOther,
206    66 => MeshShaderWrite,
207    67 => TaskShaderWrite,
208}
209
210pub(super) const fn format_aspect_mask(fmt: vk::Format) -> vk::ImageAspectFlags {
211    match fmt {
212        vk::Format::D16_UNORM | vk::Format::D32_SFLOAT | vk::Format::X8_D24_UNORM_PACK32 => {
213            vk::ImageAspectFlags::DEPTH
214        }
215        vk::Format::S8_UINT => vk::ImageAspectFlags::STENCIL,
216        vk::Format::D16_UNORM_S8_UINT
217        | vk::Format::D24_UNORM_S8_UINT
218        | vk::Format::D32_SFLOAT_S8_UINT => vk::ImageAspectFlags::from_raw(
219            vk::ImageAspectFlags::DEPTH.as_raw() | vk::ImageAspectFlags::STENCIL.as_raw(),
220        ),
221        _ => vk::ImageAspectFlags::COLOR,
222    }
223}
224
225/// Returns number of bytes used to store one texel block (a single addressable element of an
226/// uncompressed image, or a single compressed block of a compressed image).
227///
228/// See the [Texel Block Size](https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#texel-block-size)
229/// section of the Vulkan specification.
230pub const fn format_texel_block_size(fmt: vk::Format) -> u32 {
231    match fmt {
232        vk::Format::UNDEFINED => 0,
233        vk::Format::R4G4_UNORM_PACK8
234        | vk::Format::R8_UNORM
235        | vk::Format::R8_SNORM
236        | vk::Format::R8_USCALED
237        | vk::Format::R8_SSCALED
238        | vk::Format::R8_UINT
239        | vk::Format::R8_SINT
240        | vk::Format::R8_SRGB => 1,
241        vk::Format::A1B5G5R5_UNORM_PACK16_KHR
242        | vk::Format::R10X6_UNORM_PACK16
243        | vk::Format::R12X4_UNORM_PACK16
244        | vk::Format::A4R4G4B4_UNORM_PACK16
245        | vk::Format::A4B4G4R4_UNORM_PACK16
246        | vk::Format::R4G4B4A4_UNORM_PACK16
247        | vk::Format::B4G4R4A4_UNORM_PACK16
248        | vk::Format::R5G6B5_UNORM_PACK16
249        | vk::Format::B5G6R5_UNORM_PACK16
250        | vk::Format::R5G5B5A1_UNORM_PACK16
251        | vk::Format::B5G5R5A1_UNORM_PACK16
252        | vk::Format::A1R5G5B5_UNORM_PACK16
253        | vk::Format::R8G8_UNORM
254        | vk::Format::R8G8_SNORM
255        | vk::Format::R8G8_USCALED
256        | vk::Format::R8G8_SSCALED
257        | vk::Format::R8G8_UINT
258        | vk::Format::R8G8_SINT
259        | vk::Format::R8G8_SRGB
260        | vk::Format::R16_UNORM
261        | vk::Format::R16_SNORM
262        | vk::Format::R16_USCALED
263        | vk::Format::R16_SSCALED
264        | vk::Format::R16_UINT
265        | vk::Format::R16_SINT
266        | vk::Format::R16_SFLOAT => 2,
267        vk::Format::A8_UNORM_KHR => 1,
268        vk::Format::R8G8B8_UNORM
269        | vk::Format::R8G8B8_SNORM
270        | vk::Format::R8G8B8_USCALED
271        | vk::Format::R8G8B8_SSCALED
272        | vk::Format::R8G8B8_UINT
273        | vk::Format::R8G8B8_SINT
274        | vk::Format::R8G8B8_SRGB
275        | vk::Format::B8G8R8_UNORM
276        | vk::Format::B8G8R8_SNORM
277        | vk::Format::B8G8R8_USCALED
278        | vk::Format::B8G8R8_SSCALED
279        | vk::Format::B8G8R8_UINT
280        | vk::Format::B8G8R8_SINT
281        | vk::Format::B8G8R8_SRGB => 3,
282        vk::Format::R10X6G10X6_UNORM_2PACK16
283        | vk::Format::R12X4G12X4_UNORM_2PACK16
284        | vk::Format::R16G16_S10_5_NV
285        | vk::Format::R8G8B8A8_UNORM
286        | vk::Format::R8G8B8A8_SNORM
287        | vk::Format::R8G8B8A8_USCALED
288        | vk::Format::R8G8B8A8_SSCALED
289        | vk::Format::R8G8B8A8_UINT
290        | vk::Format::R8G8B8A8_SINT
291        | vk::Format::R8G8B8A8_SRGB
292        | vk::Format::B8G8R8A8_UNORM
293        | vk::Format::B8G8R8A8_SNORM
294        | vk::Format::B8G8R8A8_USCALED
295        | vk::Format::B8G8R8A8_SSCALED
296        | vk::Format::B8G8R8A8_UINT
297        | vk::Format::B8G8R8A8_SINT
298        | vk::Format::B8G8R8A8_SRGB
299        | vk::Format::A8B8G8R8_UNORM_PACK32
300        | vk::Format::A8B8G8R8_SNORM_PACK32
301        | vk::Format::A8B8G8R8_USCALED_PACK32
302        | vk::Format::A8B8G8R8_SSCALED_PACK32
303        | vk::Format::A8B8G8R8_UINT_PACK32
304        | vk::Format::A8B8G8R8_SINT_PACK32
305        | vk::Format::A8B8G8R8_SRGB_PACK32
306        | vk::Format::A2R10G10B10_UNORM_PACK32
307        | vk::Format::A2R10G10B10_SNORM_PACK32
308        | vk::Format::A2R10G10B10_USCALED_PACK32
309        | vk::Format::A2R10G10B10_SSCALED_PACK32
310        | vk::Format::A2R10G10B10_UINT_PACK32
311        | vk::Format::A2R10G10B10_SINT_PACK32
312        | vk::Format::A2B10G10R10_UNORM_PACK32
313        | vk::Format::A2B10G10R10_SNORM_PACK32
314        | vk::Format::A2B10G10R10_USCALED_PACK32
315        | vk::Format::A2B10G10R10_SSCALED_PACK32
316        | vk::Format::A2B10G10R10_UINT_PACK32
317        | vk::Format::A2B10G10R10_SINT_PACK32
318        | vk::Format::R16G16_UNORM
319        | vk::Format::R16G16_SNORM
320        | vk::Format::R16G16_USCALED
321        | vk::Format::R16G16_SSCALED
322        | vk::Format::R16G16_UINT
323        | vk::Format::R16G16_SINT
324        | vk::Format::R16G16_SFLOAT
325        | vk::Format::R32_UINT
326        | vk::Format::R32_SINT
327        | vk::Format::R32_SFLOAT
328        | vk::Format::B10G11R11_UFLOAT_PACK32
329        | vk::Format::E5B9G9R9_UFLOAT_PACK32 => 4,
330        vk::Format::R16G16B16_UNORM
331        | vk::Format::R16G16B16_SNORM
332        | vk::Format::R16G16B16_USCALED
333        | vk::Format::R16G16B16_SSCALED
334        | vk::Format::R16G16B16_UINT
335        | vk::Format::R16G16B16_SINT
336        | vk::Format::R16G16B16_SFLOAT => 6,
337        vk::Format::R16G16B16A16_UNORM
338        | vk::Format::R16G16B16A16_SNORM
339        | vk::Format::R16G16B16A16_USCALED
340        | vk::Format::R16G16B16A16_SSCALED
341        | vk::Format::R16G16B16A16_UINT
342        | vk::Format::R16G16B16A16_SINT
343        | vk::Format::R16G16B16A16_SFLOAT
344        | vk::Format::R32G32_UINT
345        | vk::Format::R32G32_SINT
346        | vk::Format::R32G32_SFLOAT
347        | vk::Format::R64_UINT
348        | vk::Format::R64_SINT
349        | vk::Format::R64_SFLOAT => 8,
350        vk::Format::R32G32B32_UINT | vk::Format::R32G32B32_SINT | vk::Format::R32G32B32_SFLOAT => {
351            12
352        }
353        vk::Format::R32G32B32A32_UINT
354        | vk::Format::R32G32B32A32_SINT
355        | vk::Format::R32G32B32A32_SFLOAT
356        | vk::Format::R64G64_UINT
357        | vk::Format::R64G64_SINT
358        | vk::Format::R64G64_SFLOAT => 16,
359        vk::Format::R64G64B64_UINT | vk::Format::R64G64B64_SINT | vk::Format::R64G64B64_SFLOAT => {
360            24
361        }
362        vk::Format::R64G64B64A64_UINT
363        | vk::Format::R64G64B64A64_SINT
364        | vk::Format::R64G64B64A64_SFLOAT => 32,
365        vk::Format::D16_UNORM => 2,
366        vk::Format::X8_D24_UNORM_PACK32 => 4,
367        vk::Format::D32_SFLOAT => 4,
368        vk::Format::S8_UINT => 1,
369        vk::Format::D16_UNORM_S8_UINT => 3,
370        vk::Format::D24_UNORM_S8_UINT => 4,
371        vk::Format::D32_SFLOAT_S8_UINT => 5,
372        vk::Format::BC1_RGB_UNORM_BLOCK
373        | vk::Format::BC1_RGB_SRGB_BLOCK
374        | vk::Format::BC1_RGBA_UNORM_BLOCK
375        | vk::Format::BC1_RGBA_SRGB_BLOCK
376        | vk::Format::BC4_UNORM_BLOCK
377        | vk::Format::BC4_SNORM_BLOCK
378        | vk::Format::ETC2_R8G8B8_UNORM_BLOCK
379        | vk::Format::ETC2_R8G8B8_SRGB_BLOCK
380        | vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK
381        | vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK
382        | vk::Format::EAC_R11_UNORM_BLOCK
383        | vk::Format::EAC_R11_SNORM_BLOCK => 8,
384        vk::Format::BC2_UNORM_BLOCK
385        | vk::Format::BC2_SRGB_BLOCK
386        | vk::Format::BC3_UNORM_BLOCK
387        | vk::Format::BC3_SRGB_BLOCK
388        | vk::Format::BC5_UNORM_BLOCK
389        | vk::Format::BC5_SNORM_BLOCK
390        | vk::Format::BC6H_UFLOAT_BLOCK
391        | vk::Format::BC6H_SFLOAT_BLOCK
392        | vk::Format::BC7_UNORM_BLOCK
393        | vk::Format::BC7_SRGB_BLOCK
394        | vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK
395        | vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK
396        | vk::Format::EAC_R11G11_UNORM_BLOCK
397        | vk::Format::EAC_R11G11_SNORM_BLOCK => 16,
398        vk::Format::ASTC_4X4_SFLOAT_BLOCK
399        | vk::Format::ASTC_4X4_UNORM_BLOCK
400        | vk::Format::ASTC_4X4_SRGB_BLOCK
401        | vk::Format::ASTC_5X4_SFLOAT_BLOCK
402        | vk::Format::ASTC_5X4_UNORM_BLOCK
403        | vk::Format::ASTC_5X4_SRGB_BLOCK
404        | vk::Format::ASTC_5X5_SFLOAT_BLOCK
405        | vk::Format::ASTC_5X5_UNORM_BLOCK
406        | vk::Format::ASTC_5X5_SRGB_BLOCK
407        | vk::Format::ASTC_6X5_SFLOAT_BLOCK
408        | vk::Format::ASTC_6X5_UNORM_BLOCK
409        | vk::Format::ASTC_6X5_SRGB_BLOCK
410        | vk::Format::ASTC_6X6_SFLOAT_BLOCK
411        | vk::Format::ASTC_6X6_UNORM_BLOCK
412        | vk::Format::ASTC_6X6_SRGB_BLOCK
413        | vk::Format::ASTC_8X5_SFLOAT_BLOCK
414        | vk::Format::ASTC_8X5_UNORM_BLOCK
415        | vk::Format::ASTC_8X5_SRGB_BLOCK
416        | vk::Format::ASTC_8X6_SFLOAT_BLOCK
417        | vk::Format::ASTC_8X6_UNORM_BLOCK
418        | vk::Format::ASTC_8X6_SRGB_BLOCK
419        | vk::Format::ASTC_8X8_SFLOAT_BLOCK
420        | vk::Format::ASTC_8X8_UNORM_BLOCK
421        | vk::Format::ASTC_8X8_SRGB_BLOCK
422        | vk::Format::ASTC_10X5_SFLOAT_BLOCK
423        | vk::Format::ASTC_10X5_UNORM_BLOCK
424        | vk::Format::ASTC_10X5_SRGB_BLOCK
425        | vk::Format::ASTC_10X6_SFLOAT_BLOCK
426        | vk::Format::ASTC_10X6_UNORM_BLOCK
427        | vk::Format::ASTC_10X6_SRGB_BLOCK
428        | vk::Format::ASTC_10X8_SFLOAT_BLOCK
429        | vk::Format::ASTC_10X8_UNORM_BLOCK
430        | vk::Format::ASTC_10X8_SRGB_BLOCK
431        | vk::Format::ASTC_10X10_SFLOAT_BLOCK
432        | vk::Format::ASTC_10X10_UNORM_BLOCK
433        | vk::Format::ASTC_10X10_SRGB_BLOCK
434        | vk::Format::ASTC_12X10_SFLOAT_BLOCK
435        | vk::Format::ASTC_12X10_UNORM_BLOCK
436        | vk::Format::ASTC_12X10_SRGB_BLOCK
437        | vk::Format::ASTC_12X12_SFLOAT_BLOCK
438        | vk::Format::ASTC_12X12_UNORM_BLOCK
439        | vk::Format::ASTC_12X12_SRGB_BLOCK => 16,
440        vk::Format::G8B8G8R8_422_UNORM | vk::Format::B8G8R8G8_422_UNORM => 4,
441        vk::Format::G8_B8_R8_3PLANE_420_UNORM
442        | vk::Format::G8_B8R8_2PLANE_420_UNORM
443        | vk::Format::G8_B8_R8_3PLANE_422_UNORM
444        | vk::Format::G8_B8R8_2PLANE_422_UNORM
445        | vk::Format::G8_B8_R8_3PLANE_444_UNORM => 3,
446        vk::Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16
447        | vk::Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16
448        | vk::Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16
449        | vk::Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16
450        | vk::Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16
451        | vk::Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16
452        | vk::Format::G16B16G16R16_422_UNORM
453        | vk::Format::B16G16R16G16_422_UNORM => 8,
454        vk::Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16
455        | vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16
456        | vk::Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16
457        | vk::Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16
458        | vk::Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16
459        | vk::Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16
460        | vk::Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16
461        | vk::Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16
462        | vk::Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16
463        | vk::Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16
464        | vk::Format::G16_B16_R16_3PLANE_420_UNORM
465        | vk::Format::G16_B16R16_2PLANE_420_UNORM
466        | vk::Format::G16_B16_R16_3PLANE_422_UNORM
467        | vk::Format::G16_B16R16_2PLANE_422_UNORM
468        | vk::Format::G16_B16_R16_3PLANE_444_UNORM => 6,
469        vk::Format::PVRTC1_2BPP_UNORM_BLOCK_IMG
470        | vk::Format::PVRTC1_2BPP_SRGB_BLOCK_IMG
471        | vk::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG
472        | vk::Format::PVRTC1_4BPP_SRGB_BLOCK_IMG
473        | vk::Format::PVRTC2_2BPP_UNORM_BLOCK_IMG
474        | vk::Format::PVRTC2_2BPP_SRGB_BLOCK_IMG
475        | vk::Format::PVRTC2_4BPP_UNORM_BLOCK_IMG
476        | vk::Format::PVRTC2_4BPP_SRGB_BLOCK_IMG => 8,
477        vk::Format::G8_B8R8_2PLANE_444_UNORM => 3,
478        vk::Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16
479        | vk::Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16
480        | vk::Format::G16_B16R16_2PLANE_444_UNORM => 6,
481        /*
482        Vulkan is extensible; new formats can appear at any time. The caller is expected to know the
483        format is valid; no runtime assertion needed per the project's philosophy.
484        */
485        _ => 0,
486    }
487}
488
489/// Returns the extent of a block of texels for the given Vulkan format.
490/// Uncompressed formats typically have a block extent of `(1, 1)`.
491///
492/// See the [Texel Block Size](https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#texel-block-size)
493/// section of the Vulkan specification.
494pub const fn format_texel_block_extent(vk_format: vk::Format) -> (u32, u32) {
495    match vk_format {
496        vk::Format::UNDEFINED => (1, 1),
497        vk::Format::R4G4_UNORM_PACK8
498        | vk::Format::R8_UNORM
499        | vk::Format::R8_SNORM
500        | vk::Format::R8_USCALED
501        | vk::Format::R8_SSCALED
502        | vk::Format::R8_UINT
503        | vk::Format::R8_SINT
504        | vk::Format::R8_SRGB
505        | vk::Format::A1B5G5R5_UNORM_PACK16_KHR
506        | vk::Format::R10X6_UNORM_PACK16
507        | vk::Format::R12X4_UNORM_PACK16
508        | vk::Format::A4R4G4B4_UNORM_PACK16
509        | vk::Format::A4B4G4R4_UNORM_PACK16
510        | vk::Format::R4G4B4A4_UNORM_PACK16
511        | vk::Format::B4G4R4A4_UNORM_PACK16
512        | vk::Format::R5G6B5_UNORM_PACK16
513        | vk::Format::B5G6R5_UNORM_PACK16
514        | vk::Format::R5G5B5A1_UNORM_PACK16
515        | vk::Format::B5G5R5A1_UNORM_PACK16
516        | vk::Format::A1R5G5B5_UNORM_PACK16
517        | vk::Format::R8G8_UNORM
518        | vk::Format::R8G8_SNORM
519        | vk::Format::R8G8_USCALED
520        | vk::Format::R8G8_SSCALED
521        | vk::Format::R8G8_UINT
522        | vk::Format::R8G8_SINT
523        | vk::Format::R8G8_SRGB
524        | vk::Format::R16_UNORM
525        | vk::Format::R16_SNORM
526        | vk::Format::R16_USCALED
527        | vk::Format::R16_SSCALED
528        | vk::Format::R16_UINT
529        | vk::Format::R16_SINT
530        | vk::Format::R16_SFLOAT
531        | vk::Format::A8_UNORM_KHR
532        | vk::Format::R8G8B8_UNORM
533        | vk::Format::R8G8B8_SNORM
534        | vk::Format::R8G8B8_USCALED
535        | vk::Format::R8G8B8_SSCALED
536        | vk::Format::R8G8B8_UINT
537        | vk::Format::R8G8B8_SINT
538        | vk::Format::R8G8B8_SRGB
539        | vk::Format::B8G8R8_UNORM
540        | vk::Format::B8G8R8_SNORM
541        | vk::Format::B8G8R8_USCALED
542        | vk::Format::B8G8R8_SSCALED
543        | vk::Format::B8G8R8_UINT
544        | vk::Format::B8G8R8_SINT
545        | vk::Format::B8G8R8_SRGB
546        | vk::Format::R10X6G10X6_UNORM_2PACK16
547        | vk::Format::R12X4G12X4_UNORM_2PACK16
548        | vk::Format::R16G16_S10_5_NV
549        | vk::Format::R8G8B8A8_UNORM
550        | vk::Format::R8G8B8A8_SNORM
551        | vk::Format::R8G8B8A8_USCALED
552        | vk::Format::R8G8B8A8_SSCALED
553        | vk::Format::R8G8B8A8_UINT
554        | vk::Format::R8G8B8A8_SINT
555        | vk::Format::R8G8B8A8_SRGB
556        | vk::Format::B8G8R8A8_UNORM
557        | vk::Format::B8G8R8A8_SNORM
558        | vk::Format::B8G8R8A8_USCALED
559        | vk::Format::B8G8R8A8_SSCALED
560        | vk::Format::B8G8R8A8_UINT
561        | vk::Format::B8G8R8A8_SINT
562        | vk::Format::B8G8R8A8_SRGB
563        | vk::Format::A8B8G8R8_UNORM_PACK32
564        | vk::Format::A8B8G8R8_SNORM_PACK32
565        | vk::Format::A8B8G8R8_USCALED_PACK32
566        | vk::Format::A8B8G8R8_SSCALED_PACK32
567        | vk::Format::A8B8G8R8_UINT_PACK32
568        | vk::Format::A8B8G8R8_SINT_PACK32
569        | vk::Format::A8B8G8R8_SRGB_PACK32
570        | vk::Format::A2R10G10B10_UNORM_PACK32
571        | vk::Format::A2R10G10B10_SNORM_PACK32
572        | vk::Format::A2R10G10B10_USCALED_PACK32
573        | vk::Format::A2R10G10B10_SSCALED_PACK32
574        | vk::Format::A2R10G10B10_UINT_PACK32
575        | vk::Format::A2R10G10B10_SINT_PACK32
576        | vk::Format::A2B10G10R10_UNORM_PACK32
577        | vk::Format::A2B10G10R10_SNORM_PACK32
578        | vk::Format::A2B10G10R10_USCALED_PACK32
579        | vk::Format::A2B10G10R10_SSCALED_PACK32
580        | vk::Format::A2B10G10R10_UINT_PACK32
581        | vk::Format::A2B10G10R10_SINT_PACK32
582        | vk::Format::R16G16_UNORM
583        | vk::Format::R16G16_SNORM
584        | vk::Format::R16G16_USCALED
585        | vk::Format::R16G16_SSCALED
586        | vk::Format::R16G16_UINT
587        | vk::Format::R16G16_SINT
588        | vk::Format::R16G16_SFLOAT
589        | vk::Format::R32_UINT
590        | vk::Format::R32_SINT
591        | vk::Format::R32_SFLOAT
592        | vk::Format::B10G11R11_UFLOAT_PACK32
593        | vk::Format::E5B9G9R9_UFLOAT_PACK32
594        | vk::Format::R16G16B16_UNORM
595        | vk::Format::R16G16B16_SNORM
596        | vk::Format::R16G16B16_USCALED
597        | vk::Format::R16G16B16_SSCALED
598        | vk::Format::R16G16B16_UINT
599        | vk::Format::R16G16B16_SINT
600        | vk::Format::R16G16B16_SFLOAT
601        | vk::Format::R16G16B16A16_UNORM
602        | vk::Format::R16G16B16A16_SNORM
603        | vk::Format::R16G16B16A16_USCALED
604        | vk::Format::R16G16B16A16_SSCALED
605        | vk::Format::R16G16B16A16_UINT
606        | vk::Format::R16G16B16A16_SINT
607        | vk::Format::R16G16B16A16_SFLOAT
608        | vk::Format::R32G32_UINT
609        | vk::Format::R32G32_SINT
610        | vk::Format::R32G32_SFLOAT
611        | vk::Format::R64_UINT
612        | vk::Format::R64_SINT
613        | vk::Format::R64_SFLOAT
614        | vk::Format::R32G32B32_UINT
615        | vk::Format::R32G32B32_SINT
616        | vk::Format::R32G32B32_SFLOAT
617        | vk::Format::R32G32B32A32_UINT
618        | vk::Format::R32G32B32A32_SINT
619        | vk::Format::R32G32B32A32_SFLOAT
620        | vk::Format::R64G64_UINT
621        | vk::Format::R64G64_SINT
622        | vk::Format::R64G64_SFLOAT
623        | vk::Format::R64G64B64_UINT
624        | vk::Format::R64G64B64_SINT
625        | vk::Format::R64G64B64_SFLOAT
626        | vk::Format::R64G64B64A64_UINT
627        | vk::Format::R64G64B64A64_SINT
628        | vk::Format::R64G64B64A64_SFLOAT
629        | vk::Format::D16_UNORM
630        | vk::Format::X8_D24_UNORM_PACK32
631        | vk::Format::D32_SFLOAT
632        | vk::Format::S8_UINT
633        | vk::Format::D16_UNORM_S8_UINT
634        | vk::Format::D24_UNORM_S8_UINT
635        | vk::Format::D32_SFLOAT_S8_UINT => (1, 1),
636        vk::Format::BC1_RGB_UNORM_BLOCK
637        | vk::Format::BC1_RGB_SRGB_BLOCK
638        | vk::Format::BC1_RGBA_UNORM_BLOCK
639        | vk::Format::BC1_RGBA_SRGB_BLOCK
640        | vk::Format::BC2_UNORM_BLOCK
641        | vk::Format::BC2_SRGB_BLOCK
642        | vk::Format::BC3_UNORM_BLOCK
643        | vk::Format::BC3_SRGB_BLOCK
644        | vk::Format::BC4_UNORM_BLOCK
645        | vk::Format::BC4_SNORM_BLOCK
646        | vk::Format::BC5_UNORM_BLOCK
647        | vk::Format::BC5_SNORM_BLOCK
648        | vk::Format::BC6H_UFLOAT_BLOCK
649        | vk::Format::BC6H_SFLOAT_BLOCK
650        | vk::Format::BC7_UNORM_BLOCK
651        | vk::Format::BC7_SRGB_BLOCK
652        | vk::Format::ETC2_R8G8B8_UNORM_BLOCK
653        | vk::Format::ETC2_R8G8B8_SRGB_BLOCK
654        | vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK
655        | vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK
656        | vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK
657        | vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK
658        | vk::Format::EAC_R11_UNORM_BLOCK
659        | vk::Format::EAC_R11_SNORM_BLOCK
660        | vk::Format::EAC_R11G11_UNORM_BLOCK
661        | vk::Format::EAC_R11G11_SNORM_BLOCK => (4, 4),
662        vk::Format::ASTC_4X4_SFLOAT_BLOCK
663        | vk::Format::ASTC_4X4_UNORM_BLOCK
664        | vk::Format::ASTC_4X4_SRGB_BLOCK => (4, 4),
665        vk::Format::ASTC_5X4_SFLOAT_BLOCK
666        | vk::Format::ASTC_5X4_UNORM_BLOCK
667        | vk::Format::ASTC_5X4_SRGB_BLOCK => (5, 4),
668        vk::Format::ASTC_5X5_SFLOAT_BLOCK
669        | vk::Format::ASTC_5X5_UNORM_BLOCK
670        | vk::Format::ASTC_5X5_SRGB_BLOCK => (5, 5),
671        vk::Format::ASTC_6X5_SFLOAT_BLOCK
672        | vk::Format::ASTC_6X5_UNORM_BLOCK
673        | vk::Format::ASTC_6X5_SRGB_BLOCK => (6, 5),
674        vk::Format::ASTC_6X6_SFLOAT_BLOCK
675        | vk::Format::ASTC_6X6_UNORM_BLOCK
676        | vk::Format::ASTC_6X6_SRGB_BLOCK => (6, 6),
677        vk::Format::ASTC_8X5_SFLOAT_BLOCK
678        | vk::Format::ASTC_8X5_UNORM_BLOCK
679        | vk::Format::ASTC_8X5_SRGB_BLOCK => (8, 5),
680        vk::Format::ASTC_8X6_SFLOAT_BLOCK
681        | vk::Format::ASTC_8X6_UNORM_BLOCK
682        | vk::Format::ASTC_8X6_SRGB_BLOCK => (8, 6),
683        vk::Format::ASTC_8X8_SFLOAT_BLOCK
684        | vk::Format::ASTC_8X8_UNORM_BLOCK
685        | vk::Format::ASTC_8X8_SRGB_BLOCK => (8, 8),
686        vk::Format::ASTC_10X5_SFLOAT_BLOCK
687        | vk::Format::ASTC_10X5_UNORM_BLOCK
688        | vk::Format::ASTC_10X5_SRGB_BLOCK => (10, 5),
689        vk::Format::ASTC_10X6_SFLOAT_BLOCK
690        | vk::Format::ASTC_10X6_UNORM_BLOCK
691        | vk::Format::ASTC_10X6_SRGB_BLOCK => (10, 6),
692        vk::Format::ASTC_10X8_SFLOAT_BLOCK
693        | vk::Format::ASTC_10X8_UNORM_BLOCK
694        | vk::Format::ASTC_10X8_SRGB_BLOCK => (10, 8),
695        vk::Format::ASTC_10X10_SFLOAT_BLOCK
696        | vk::Format::ASTC_10X10_UNORM_BLOCK
697        | vk::Format::ASTC_10X10_SRGB_BLOCK => (10, 10),
698        vk::Format::ASTC_12X10_SFLOAT_BLOCK
699        | vk::Format::ASTC_12X10_UNORM_BLOCK
700        | vk::Format::ASTC_12X10_SRGB_BLOCK => (12, 10),
701        vk::Format::ASTC_12X12_SFLOAT_BLOCK
702        | vk::Format::ASTC_12X12_UNORM_BLOCK
703        | vk::Format::ASTC_12X12_SRGB_BLOCK => (12, 12),
704        vk::Format::G8B8G8R8_422_UNORM | vk::Format::B8G8R8G8_422_UNORM => (2, 1),
705        vk::Format::G8_B8_R8_3PLANE_420_UNORM
706        | vk::Format::G8_B8R8_2PLANE_420_UNORM
707        | vk::Format::G8_B8_R8_3PLANE_422_UNORM
708        | vk::Format::G8_B8R8_2PLANE_422_UNORM
709        | vk::Format::G8_B8_R8_3PLANE_444_UNORM
710        | vk::Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16
711        | vk::Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16
712        | vk::Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16
713        | vk::Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16
714        | vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16
715        | vk::Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16
716        | vk::Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16
717        | vk::Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16
718        | vk::Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16
719        | vk::Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16
720        | vk::Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16
721        | vk::Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16
722        | vk::Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16
723        | vk::Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16
724        | vk::Format::G16_B16_R16_3PLANE_420_UNORM
725        | vk::Format::G16_B16R16_2PLANE_420_UNORM
726        | vk::Format::G16_B16_R16_3PLANE_422_UNORM
727        | vk::Format::G16_B16R16_2PLANE_422_UNORM
728        | vk::Format::G16_B16_R16_3PLANE_444_UNORM
729        | vk::Format::G8_B8R8_2PLANE_444_UNORM
730        | vk::Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16
731        | vk::Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16
732        | vk::Format::G16_B16R16_2PLANE_444_UNORM => (1, 1),
733        vk::Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16
734        | vk::Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16
735        | vk::Format::G16B16G16R16_422_UNORM
736        | vk::Format::B16G16R16G16_422_UNORM => (2, 1),
737        vk::Format::PVRTC1_2BPP_UNORM_BLOCK_IMG
738        | vk::Format::PVRTC1_2BPP_SRGB_BLOCK_IMG
739        | vk::Format::PVRTC2_2BPP_UNORM_BLOCK_IMG
740        | vk::Format::PVRTC2_2BPP_SRGB_BLOCK_IMG => (8, 4),
741        vk::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG
742        | vk::Format::PVRTC1_4BPP_SRGB_BLOCK_IMG
743        | vk::Format::PVRTC2_4BPP_UNORM_BLOCK_IMG
744        | vk::Format::PVRTC2_4BPP_SRGB_BLOCK_IMG => (4, 4),
745        /*
746        Vulkan is extensible; new formats can appear at any time. The caller is expected to know the
747        format is valid; no runtime assertion needed per the project's philosophy.
748        */
749        _ => (1, 1),
750    }
751}
752
753pub(super) const fn image_subresource_range_from_layers(
754    vk::ImageSubresourceLayers {
755        aspect_mask,
756        mip_level,
757        base_array_layer,
758        layer_count,
759    }: vk::ImageSubresourceLayers,
760) -> vk::ImageSubresourceRange {
761    vk::ImageSubresourceRange {
762        aspect_mask,
763        base_mip_level: mip_level,
764        level_count: 1,
765        base_array_layer,
766        layer_count,
767    }
768}
769
770pub(super) const fn initial_image_layout_access(
771    ty: self::sync::AccessType,
772) -> self::sync::AccessType {
773    use self::sync::AccessType::*;
774    match ty {
775        DepthStencilAttachmentReadWrite => DepthStencilAttachmentRead,
776        _ => ty,
777    }
778}
779
780pub(super) const fn is_read_access(ty: self::sync::AccessType) -> bool {
781    use self::sync::AccessType::*;
782    match ty {
783        Nothing
784        | CommandBufferWriteNVX
785        | VertexShaderWrite
786        | TessellationControlShaderWrite
787        | TessellationEvaluationShaderWrite
788        | GeometryShaderWrite
789        | FragmentShaderWrite
790        | ColorAttachmentWrite
791        | DepthStencilAttachmentWrite
792        | ComputeShaderWrite
793        | AnyShaderWrite
794        | TransferWrite
795        | HostWrite
796        | AccelerationStructureBuildWrite
797        | AccelerationStructureBufferWrite
798        | MeshShaderWrite
799        | TaskShaderWrite => false,
800        CommandBufferReadNVX
801        | IndirectBuffer
802        | IndexBuffer
803        | VertexBuffer
804        | VertexShaderReadUniformBuffer
805        | VertexShaderReadSampledImageOrUniformTexelBuffer
806        | VertexShaderReadOther
807        | TessellationControlShaderReadUniformBuffer
808        | TessellationControlShaderReadSampledImageOrUniformTexelBuffer
809        | TessellationControlShaderReadOther
810        | TessellationEvaluationShaderReadUniformBuffer
811        | TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer
812        | TessellationEvaluationShaderReadOther
813        | GeometryShaderReadUniformBuffer
814        | GeometryShaderReadSampledImageOrUniformTexelBuffer
815        | GeometryShaderReadOther
816        | FragmentShaderReadUniformBuffer
817        | FragmentShaderReadSampledImageOrUniformTexelBuffer
818        | FragmentShaderReadColorInputAttachment
819        | FragmentShaderReadDepthStencilInputAttachment
820        | FragmentShaderReadOther
821        | ColorAttachmentRead
822        | DepthStencilAttachmentRead
823        | ComputeShaderReadUniformBuffer
824        | ComputeShaderReadSampledImageOrUniformTexelBuffer
825        | ComputeShaderReadOther
826        | AnyShaderReadUniformBuffer
827        | AnyShaderReadUniformBufferOrVertexBuffer
828        | AnyShaderReadSampledImageOrUniformTexelBuffer
829        | AnyShaderReadOther
830        | TransferRead
831        | HostRead
832        | Present
833        | RayTracingShaderReadSampledImageOrUniformTexelBuffer
834        | RayTracingShaderReadColorInputAttachment
835        | RayTracingShaderReadDepthStencilInputAttachment
836        | RayTracingShaderReadAccelerationStructure
837        | RayTracingShaderReadOther
838        | AccelerationStructureBuildRead
839        | MeshShaderReadUniformBuffer
840        | MeshShaderReadSampledImageOrUniformTexelBuffer
841        | MeshShaderReadOther
842        | TaskShaderReadUniformBuffer
843        | TaskShaderReadSampledImageOrUniformTexelBuffer
844        | TaskShaderReadOther
845        | DepthStencilAttachmentReadWrite
846        | DepthAttachmentWriteStencilReadOnly
847        | StencilAttachmentWriteDepthReadOnly
848        | ColorAttachmentReadWrite
849        | General
850        | ComputeShaderReadWrite => true,
851    }
852}
853
854// Convert overlapping push constant regions such as this:
855// VERTEX 0..64
856// FRAGMENT 0..80
857//
858// To this:
859// VERTEX | FRAGMENT 0..64
860// FRAGMENT 64..80
861//
862// We do this so that submission doesn't need to check for overlaps
863// See https://github.com/KhronosGroup/Vulkan-Docs/issues/609
864#[profiling::function]
865fn merge_push_constant_ranges(pcr: &[vk::PushConstantRange]) -> Vec<vk::PushConstantRange> {
866    // Each specified range must be for a single stage and each stage must be specified once
867    #[cfg(feature = "checked")]
868    {
869        let mut stage_flags = vk::ShaderStageFlags::empty();
870        for item in pcr.iter() {
871            assert_eq!(item.stage_flags.as_raw().count_ones(), 1);
872            assert!(!stage_flags.contains(item.stage_flags));
873            assert!(item.size > 0);
874
875            stage_flags |= item.stage_flags;
876        }
877    }
878
879    match pcr.len() {
880        0 => vec![],
881        1 => vec![pcr[0]],
882        _ => {
883            let mut res = pcr.to_vec();
884            let sort_fn = |lhs: &vk::PushConstantRange, rhs: &vk::PushConstantRange| match lhs
885                .offset
886                .cmp(&rhs.offset)
887            {
888                Ordering::Equal => lhs.size.cmp(&rhs.size),
889                res => res,
890            };
891
892            res.sort_unstable_by(sort_fn);
893
894            let mut i = 0;
895            let mut j = 1;
896
897            while j < res.len() {
898                let lhs = res[i];
899                let rhs = res[j];
900
901                if lhs.offset == rhs.offset && lhs.size == rhs.size {
902                    res[i].stage_flags |= rhs.stage_flags;
903                    let _ = res.remove(j);
904                } else if lhs.offset == rhs.offset {
905                    res[i].stage_flags |= rhs.stage_flags;
906                    res[j].offset += lhs.size;
907                    res[j].size -= lhs.size;
908                    res[j..].sort_unstable_by(sort_fn);
909                } else if lhs.offset + lhs.size > rhs.offset + rhs.size {
910                    res[i].size = rhs.offset - lhs.offset;
911                    res[j].stage_flags = lhs.stage_flags;
912                    res[j].offset += rhs.size;
913                    res[j].size = (lhs.offset + lhs.size) - (rhs.offset + rhs.size);
914                    res.insert(
915                        j,
916                        vk::PushConstantRange {
917                            stage_flags: lhs.stage_flags | rhs.stage_flags,
918                            offset: rhs.offset,
919                            size: rhs.size,
920                        },
921                    );
922                    res[j..].sort_unstable_by(sort_fn);
923                    i += 1;
924                    j += 1;
925                } else if lhs.offset + lhs.size == rhs.offset + rhs.size {
926                    res[i].size -= rhs.size;
927                    res[j].stage_flags |= lhs.stage_flags;
928                    i += 1;
929                    j += 1;
930                } else if lhs.offset + lhs.size > rhs.offset
931                    && lhs.offset + lhs.size < rhs.offset + rhs.size
932                {
933                    res[i].size = rhs.offset - lhs.offset;
934                    res[j].offset = lhs.offset + lhs.size;
935                    res[j].size = (rhs.offset + rhs.size) - (lhs.offset + lhs.size);
936                    res.insert(
937                        j,
938                        vk::PushConstantRange {
939                            stage_flags: lhs.stage_flags | rhs.stage_flags,
940                            offset: rhs.offset,
941                            size: (lhs.offset + lhs.size) - rhs.offset,
942                        },
943                    );
944                    res[j..].sort_unstable_by(sort_fn);
945                } else {
946                    i += 1;
947                    j += 1;
948                }
949            }
950
951            res
952        }
953    }
954}
955
956pub(super) const fn pipeline_stage_access_flags(
957    access_type: vk_sync::AccessType,
958) -> (vk::PipelineStageFlags, vk::AccessFlags) {
959    use {
960        vk::{AccessFlags as access, PipelineStageFlags as stage},
961        vk_sync::AccessType as ty,
962    };
963
964    match access_type {
965        ty::Nothing => (stage::empty(), access::empty()),
966        ty::CommandBufferReadNVX => (
967            stage::COMMAND_PREPROCESS_NV,
968            access::COMMAND_PREPROCESS_READ_NV,
969        ),
970        ty::IndirectBuffer => (stage::DRAW_INDIRECT, access::INDIRECT_COMMAND_READ),
971        ty::IndexBuffer => (stage::VERTEX_INPUT, access::INDEX_READ),
972        ty::VertexBuffer => (stage::VERTEX_INPUT, access::VERTEX_ATTRIBUTE_READ),
973        ty::VertexShaderReadUniformBuffer => (stage::VERTEX_SHADER, access::SHADER_READ),
974        ty::VertexShaderReadSampledImageOrUniformTexelBuffer => {
975            (stage::VERTEX_SHADER, access::SHADER_READ)
976        }
977        ty::VertexShaderReadOther => (stage::VERTEX_SHADER, access::SHADER_READ),
978        ty::TessellationControlShaderReadUniformBuffer => {
979            (stage::TESSELLATION_CONTROL_SHADER, access::UNIFORM_READ)
980        }
981        ty::TessellationControlShaderReadSampledImageOrUniformTexelBuffer => {
982            (stage::TESSELLATION_CONTROL_SHADER, access::SHADER_READ)
983        }
984        ty::TessellationControlShaderReadOther => {
985            (stage::TESSELLATION_CONTROL_SHADER, access::SHADER_READ)
986        }
987        ty::TessellationEvaluationShaderReadUniformBuffer => {
988            (stage::TESSELLATION_EVALUATION_SHADER, access::UNIFORM_READ)
989        }
990        ty::TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer => {
991            (stage::TESSELLATION_EVALUATION_SHADER, access::SHADER_READ)
992        }
993        ty::TessellationEvaluationShaderReadOther => {
994            (stage::TESSELLATION_EVALUATION_SHADER, access::SHADER_READ)
995        }
996        ty::GeometryShaderReadUniformBuffer => (stage::GEOMETRY_SHADER, access::UNIFORM_READ),
997        ty::GeometryShaderReadSampledImageOrUniformTexelBuffer => {
998            (stage::GEOMETRY_SHADER, access::SHADER_READ)
999        }
1000        ty::GeometryShaderReadOther => (stage::GEOMETRY_SHADER, access::SHADER_READ),
1001        ty::FragmentShaderReadUniformBuffer => (stage::FRAGMENT_SHADER, access::UNIFORM_READ),
1002        ty::FragmentShaderReadSampledImageOrUniformTexelBuffer => {
1003            (stage::FRAGMENT_SHADER, access::SHADER_READ)
1004        }
1005        ty::FragmentShaderReadColorInputAttachment => {
1006            (stage::FRAGMENT_SHADER, access::INPUT_ATTACHMENT_READ)
1007        }
1008        ty::FragmentShaderReadDepthStencilInputAttachment => {
1009            (stage::FRAGMENT_SHADER, access::INPUT_ATTACHMENT_READ)
1010        }
1011        ty::FragmentShaderReadOther => (stage::FRAGMENT_SHADER, access::SHADER_READ),
1012        ty::ColorAttachmentRead => (
1013            stage::COLOR_ATTACHMENT_OUTPUT,
1014            access::COLOR_ATTACHMENT_READ,
1015        ),
1016        ty::DepthStencilAttachmentRead => (
1017            stage::from_raw(
1018                stage::EARLY_FRAGMENT_TESTS.as_raw()
1019                    | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS.as_raw(),
1020            ),
1021            access::DEPTH_STENCIL_ATTACHMENT_READ,
1022        ),
1023        ty::ComputeShaderReadUniformBuffer => (stage::COMPUTE_SHADER, access::UNIFORM_READ),
1024        ty::ComputeShaderReadSampledImageOrUniformTexelBuffer => {
1025            (stage::COMPUTE_SHADER, access::SHADER_READ)
1026        }
1027        ty::ComputeShaderReadOther => (stage::COMPUTE_SHADER, access::SHADER_READ),
1028        ty::AnyShaderReadUniformBuffer => (stage::ALL_COMMANDS, access::UNIFORM_READ),
1029        ty::AnyShaderReadUniformBufferOrVertexBuffer => (
1030            stage::ALL_COMMANDS,
1031            access::from_raw(
1032                access::UNIFORM_READ.as_raw() | vk::AccessFlags::VERTEX_ATTRIBUTE_READ.as_raw(),
1033            ),
1034        ),
1035        ty::AnyShaderReadSampledImageOrUniformTexelBuffer => {
1036            (stage::ALL_COMMANDS, access::SHADER_READ)
1037        }
1038        ty::AnyShaderReadOther => (stage::ALL_COMMANDS, access::SHADER_READ),
1039        ty::TransferRead => (stage::TRANSFER, access::TRANSFER_READ),
1040        ty::HostRead => (stage::HOST, access::HOST_READ),
1041        ty::Present => (stage::empty(), access::empty()),
1042        ty::CommandBufferWriteNVX => (
1043            stage::COMMAND_PREPROCESS_NV,
1044            access::COMMAND_PREPROCESS_WRITE_NV,
1045        ),
1046        ty::VertexShaderWrite => (stage::VERTEX_SHADER, access::SHADER_WRITE),
1047        ty::TessellationControlShaderWrite => {
1048            (stage::TESSELLATION_CONTROL_SHADER, access::SHADER_WRITE)
1049        }
1050        ty::TessellationEvaluationShaderWrite => {
1051            (stage::TESSELLATION_EVALUATION_SHADER, access::SHADER_WRITE)
1052        }
1053        ty::GeometryShaderWrite => (stage::GEOMETRY_SHADER, access::SHADER_WRITE),
1054        ty::FragmentShaderWrite => (stage::FRAGMENT_SHADER, access::SHADER_WRITE),
1055        ty::ColorAttachmentWrite => (
1056            stage::COLOR_ATTACHMENT_OUTPUT,
1057            access::COLOR_ATTACHMENT_WRITE,
1058        ),
1059        ty::DepthStencilAttachmentWrite => (
1060            stage::from_raw(
1061                stage::EARLY_FRAGMENT_TESTS.as_raw()
1062                    | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS.as_raw(),
1063            ),
1064            access::DEPTH_STENCIL_ATTACHMENT_WRITE,
1065        ),
1066        ty::DepthStencilAttachmentReadWrite => (
1067            stage::from_raw(
1068                stage::EARLY_FRAGMENT_TESTS.as_raw()
1069                    | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS.as_raw(),
1070            ),
1071            access::from_raw(
1072                access::DEPTH_STENCIL_ATTACHMENT_WRITE.as_raw()
1073                    | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ.as_raw(),
1074            ),
1075        ),
1076        ty::DepthAttachmentWriteStencilReadOnly => (
1077            stage::from_raw(
1078                stage::EARLY_FRAGMENT_TESTS.as_raw()
1079                    | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS.as_raw(),
1080            ),
1081            access::from_raw(
1082                access::DEPTH_STENCIL_ATTACHMENT_WRITE.as_raw()
1083                    | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ.as_raw(),
1084            ),
1085        ),
1086        ty::StencilAttachmentWriteDepthReadOnly => (
1087            stage::from_raw(
1088                stage::EARLY_FRAGMENT_TESTS.as_raw()
1089                    | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS.as_raw(),
1090            ),
1091            access::from_raw(
1092                access::DEPTH_STENCIL_ATTACHMENT_WRITE.as_raw()
1093                    | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ.as_raw(),
1094            ),
1095        ),
1096        ty::ComputeShaderWrite => (stage::COMPUTE_SHADER, access::SHADER_WRITE),
1097        ty::ComputeShaderReadWrite => (
1098            stage::COMPUTE_SHADER,
1099            access::from_raw(access::SHADER_WRITE.as_raw() | access::SHADER_READ.as_raw()),
1100        ),
1101        ty::AnyShaderWrite => (stage::ALL_COMMANDS, access::SHADER_WRITE),
1102        ty::TransferWrite => (stage::TRANSFER, access::TRANSFER_WRITE),
1103        ty::HostWrite => (stage::HOST, access::HOST_WRITE),
1104        ty::ColorAttachmentReadWrite => (
1105            stage::COLOR_ATTACHMENT_OUTPUT,
1106            access::from_raw(
1107                access::COLOR_ATTACHMENT_READ.as_raw()
1108                    | vk::AccessFlags::COLOR_ATTACHMENT_WRITE.as_raw(),
1109            ),
1110        ),
1111        ty::General => (
1112            stage::ALL_COMMANDS,
1113            access::from_raw(access::MEMORY_READ.as_raw() | vk::AccessFlags::MEMORY_WRITE.as_raw()),
1114        ),
1115        ty::RayTracingShaderReadSampledImageOrUniformTexelBuffer => {
1116            (stage::RAY_TRACING_SHADER_KHR, access::SHADER_READ)
1117        }
1118        ty::RayTracingShaderReadColorInputAttachment => {
1119            (stage::RAY_TRACING_SHADER_KHR, access::INPUT_ATTACHMENT_READ)
1120        }
1121        ty::RayTracingShaderReadDepthStencilInputAttachment => {
1122            (stage::RAY_TRACING_SHADER_KHR, access::INPUT_ATTACHMENT_READ)
1123        }
1124        ty::RayTracingShaderReadAccelerationStructure => (
1125            stage::RAY_TRACING_SHADER_KHR,
1126            access::ACCELERATION_STRUCTURE_READ_KHR,
1127        ),
1128        ty::RayTracingShaderReadOther => (stage::RAY_TRACING_SHADER_KHR, access::SHADER_READ),
1129        ty::AccelerationStructureBuildWrite => (
1130            stage::ACCELERATION_STRUCTURE_BUILD_KHR,
1131            access::ACCELERATION_STRUCTURE_WRITE_KHR,
1132        ),
1133        ty::AccelerationStructureBuildRead => (
1134            stage::ACCELERATION_STRUCTURE_BUILD_KHR,
1135            access::ACCELERATION_STRUCTURE_READ_KHR,
1136        ),
1137        ty::AccelerationStructureBufferWrite => (
1138            stage::ACCELERATION_STRUCTURE_BUILD_KHR,
1139            access::TRANSFER_WRITE,
1140        ),
1141        ty::MeshShaderReadUniformBuffer => (stage::MESH_SHADER_EXT, access::SHADER_READ),
1142        ty::MeshShaderReadSampledImageOrUniformTexelBuffer => {
1143            (stage::MESH_SHADER_EXT, access::SHADER_READ)
1144        }
1145        ty::MeshShaderReadOther => (stage::MESH_SHADER_EXT, access::SHADER_READ),
1146        ty::TaskShaderReadUniformBuffer => (stage::TASK_SHADER_EXT, access::SHADER_READ),
1147        ty::TaskShaderReadSampledImageOrUniformTexelBuffer => {
1148            (stage::TASK_SHADER_EXT, access::SHADER_READ)
1149        }
1150        ty::TaskShaderReadOther => (stage::TASK_SHADER_EXT, access::SHADER_READ),
1151        ty::MeshShaderWrite => (stage::MESH_SHADER_EXT, access::SHADER_WRITE),
1152        ty::TaskShaderWrite => (stage::TASK_SHADER_EXT, access::SHADER_WRITE),
1153    }
1154}
1155
1156/// Describes the general category of all graphics driver failure cases.
1157///
1158/// In the event of a failure you should follow the _vk-graph_ code to the responsible Vulkan API
1159/// and then to the `ash` function call; it will generally contain a link to the appropriate
1160/// specification. The specifications provide a table of possible error conditions which can be a
1161/// good starting point to debug the issue.
1162///
1163/// Feel free to open an [issue on GitHub](https://github.com/attackgoat/vk-graph/issues) for help
1164/// debugging the issue.
1165#[derive(Clone, Copy, Debug)]
1166pub enum DriverError {
1167    /// The input data, or referenced data, is not valid for the current state.
1168    InvalidData,
1169
1170    /// The requested feature, or input configuration, is not supported for the current state.
1171    Unsupported,
1172
1173    /// The device has run out of physical memory.
1174    ///
1175    /// Many drivers return this value for generic or unhandled error conditions.
1176    OutOfMemory,
1177}
1178
1179impl DriverError {
1180    fn from_alloc_err(err: AllocationError) -> Self {
1181        match err {
1182            AllocationError::OutOfMemory => Self::OutOfMemory,
1183            AllocationError::InvalidAllocationCreateDesc
1184            | AllocationError::InvalidAllocatorCreateDesc(_) => Self::InvalidData,
1185            AllocationError::FailedToMap(_)
1186            | AllocationError::NoCompatibleMemoryTypeFound
1187            | AllocationError::Internal(_)
1188            | AllocationError::BarrierLayoutNeedsDevice10
1189            | AllocationError::CastableFormatsRequiresEnhancedBarriers
1190            | AllocationError::CastableFormatsRequiresAtLeastDevice12 => Self::Unsupported,
1191        }
1192    }
1193}
1194
1195impl From<Infallible> for DriverError {
1196    fn from(value: Infallible) -> Self {
1197        match value {}
1198    }
1199}
1200
1201impl Display for DriverError {
1202    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1203        write!(f, "{:?}", self)
1204    }
1205}
1206
1207impl Error for DriverError {}
1208
1209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1210pub(super) enum SharingMode {
1211    Concurrent,
1212    Exclusive(Option<(u32, u32)>),
1213}
1214
1215impl SharingMode {
1216    const MODE_CONCURRENT: u64 = u64::MAX;
1217    const MODE_UNKNOWN: u64 = u64::MAX - 1;
1218
1219    pub(super) const fn decode(val: u64) -> Self {
1220        if val == Self::MODE_CONCURRENT {
1221            Self::Concurrent
1222        } else if val == Self::MODE_UNKNOWN {
1223            Self::Exclusive(None)
1224        } else {
1225            Self::Exclusive(Some(((val >> 32) as u32, val as u32)))
1226        }
1227    }
1228
1229    pub(super) const fn encode(self) -> u64 {
1230        match self {
1231            SharingMode::Concurrent => Self::MODE_CONCURRENT,
1232            SharingMode::Exclusive(None) => Self::MODE_UNKNOWN,
1233            SharingMode::Exclusive(Some((family, index))) => (family as u64) << 32 | index as u64,
1234        }
1235    }
1236}
1237
1238#[cfg(test)]
1239mod test {
1240    use {super::merge_push_constant_ranges, ash::vk};
1241
1242    macro_rules! assert_pcr_eq {
1243        ($lhs: expr, $rhs: expr,) => {
1244            assert_eq!($lhs.stage_flags, $rhs.stage_flags, "Stages flags not equal");
1245            assert_eq!($lhs.offset, $rhs.offset, "Offset not equal");
1246            assert_eq!($lhs.size, $rhs.size, "Size not equal");
1247        };
1248    }
1249
1250    fn reference_merge_push_constant_ranges(
1251        pcr: &[vk::PushConstantRange],
1252    ) -> Vec<vk::PushConstantRange> {
1253        if pcr.is_empty() {
1254            return vec![];
1255        }
1256        let end = pcr.iter().map(|r| r.offset + r.size).max().unwrap();
1257        let mut per_byte = vec![0u32; end as usize];
1258        for r in pcr {
1259            let raw = r.stage_flags.as_raw();
1260            let range_end = r.offset + r.size;
1261            for byte in per_byte[r.offset as usize..range_end as usize].iter_mut() {
1262                *byte |= raw;
1263            }
1264        }
1265        let mut result = Vec::new();
1266        let mut i = 0usize;
1267        while (i as u32) < end {
1268            let flags = per_byte[i];
1269            if flags == 0 {
1270                i += 1;
1271                continue;
1272            }
1273            let start = i as u32;
1274            while (i as u32) < end && per_byte[i] == flags {
1275                i += 1;
1276            }
1277            result.push(vk::PushConstantRange {
1278                stage_flags: vk::ShaderStageFlags::from_raw(flags),
1279                offset: start,
1280                size: (i as u32) - start,
1281            });
1282        }
1283        result
1284    }
1285
1286    fn assert_merge_invariants(input: &[vk::PushConstantRange], output: &[vk::PushConstantRange]) {
1287        let expected = reference_merge_push_constant_ranges(input);
1288        assert_eq!(
1289            output.len(),
1290            expected.len(),
1291            "length mismatch\n  input: {input:?}\n  got: {output:?}\n  expected: {expected:?}"
1292        );
1293        for (idx, (got, exp)) in output.iter().zip(expected.iter()).enumerate() {
1294            assert_eq!(
1295                got.stage_flags, exp.stage_flags,
1296                "result[{idx}] stage_flags mismatch\n  input: {input:?}\n  got: {output:?}\n  expected: {expected:?}"
1297            );
1298            assert_eq!(
1299                got.offset, exp.offset,
1300                "result[{idx}] offset mismatch\n  input: {input:?}\n  got: {output:?}\n  expected: {expected:?}"
1301            );
1302            assert_eq!(
1303                got.size, exp.size,
1304                "result[{idx}] size mismatch\n  input: {input:?}\n  got: {output:?}\n  expected: {expected:?}"
1305            );
1306        }
1307    }
1308
1309    #[test]
1310    pub fn push_constant_ranges_complex() {
1311        let res = merge_push_constant_ranges(&[
1312            vk::PushConstantRange {
1313                stage_flags: vk::ShaderStageFlags::VERTEX,
1314                offset: 8,
1315                size: 16,
1316            },
1317            vk::PushConstantRange {
1318                stage_flags: vk::ShaderStageFlags::GEOMETRY,
1319                offset: 20,
1320                size: 48,
1321            },
1322            vk::PushConstantRange {
1323                stage_flags: vk::ShaderStageFlags::TESSELLATION_CONTROL,
1324                offset: 24,
1325                size: 8,
1326            },
1327            vk::PushConstantRange {
1328                stage_flags: vk::ShaderStageFlags::TESSELLATION_EVALUATION,
1329                offset: 28,
1330                size: 32,
1331            },
1332            vk::PushConstantRange {
1333                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1334                offset: 40,
1335                size: 128,
1336            },
1337        ]);
1338
1339        assert_eq!(res.len(), 8);
1340        assert_pcr_eq!(
1341            res[0],
1342            vk::PushConstantRange {
1343                stage_flags: vk::ShaderStageFlags::VERTEX,
1344                offset: 8,
1345                size: 12,
1346            },
1347        );
1348        assert_pcr_eq!(
1349            res[1],
1350            vk::PushConstantRange {
1351                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::GEOMETRY,
1352                offset: 20,
1353                size: 4,
1354            },
1355        );
1356        assert_pcr_eq!(
1357            res[2],
1358            vk::PushConstantRange {
1359                stage_flags: vk::ShaderStageFlags::TESSELLATION_CONTROL
1360                    | vk::ShaderStageFlags::GEOMETRY,
1361                offset: 24,
1362                size: 4,
1363            },
1364        );
1365        assert_pcr_eq!(
1366            res[3],
1367            vk::PushConstantRange {
1368                stage_flags: vk::ShaderStageFlags::TESSELLATION_CONTROL
1369                    | vk::ShaderStageFlags::TESSELLATION_EVALUATION
1370                    | vk::ShaderStageFlags::GEOMETRY,
1371                offset: 28,
1372                size: 4,
1373            },
1374        );
1375        assert_pcr_eq!(
1376            res[4],
1377            vk::PushConstantRange {
1378                stage_flags: vk::ShaderStageFlags::GEOMETRY
1379                    | vk::ShaderStageFlags::TESSELLATION_EVALUATION,
1380                offset: 32,
1381                size: 8,
1382            },
1383        );
1384        assert_pcr_eq!(
1385            res[5],
1386            vk::PushConstantRange {
1387                stage_flags: vk::ShaderStageFlags::GEOMETRY
1388                    | vk::ShaderStageFlags::TESSELLATION_EVALUATION
1389                    | vk::ShaderStageFlags::FRAGMENT,
1390                offset: 40,
1391                size: 20,
1392            },
1393        );
1394        assert_pcr_eq!(
1395            res[6],
1396            vk::PushConstantRange {
1397                stage_flags: vk::ShaderStageFlags::FRAGMENT | vk::ShaderStageFlags::GEOMETRY,
1398                offset: 60,
1399                size: 8,
1400            },
1401        );
1402        assert_pcr_eq!(
1403            res[7],
1404            vk::PushConstantRange {
1405                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1406                offset: 68,
1407                size: 100,
1408            },
1409        );
1410    }
1411
1412    #[test]
1413    pub fn push_constant_ranges_disjoint() {
1414        let res = merge_push_constant_ranges(&[
1415            vk::PushConstantRange {
1416                stage_flags: vk::ShaderStageFlags::VERTEX,
1417                offset: 0,
1418                size: 32,
1419            },
1420            vk::PushConstantRange {
1421                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1422                offset: 32,
1423                size: 64,
1424            },
1425        ]);
1426
1427        assert_eq!(res.len(), 2);
1428        assert_pcr_eq!(
1429            res[0],
1430            vk::PushConstantRange {
1431                stage_flags: vk::ShaderStageFlags::VERTEX,
1432                offset: 0,
1433                size: 32,
1434            },
1435        );
1436        assert_pcr_eq!(
1437            res[1],
1438            vk::PushConstantRange {
1439                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1440                offset: 32,
1441                size: 64,
1442            },
1443        );
1444    }
1445
1446    #[test]
1447    pub fn push_constant_ranges_equal() {
1448        let res = merge_push_constant_ranges(&[
1449            vk::PushConstantRange {
1450                stage_flags: vk::ShaderStageFlags::VERTEX,
1451                offset: 0,
1452                size: 32,
1453            },
1454            vk::PushConstantRange {
1455                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1456                offset: 0,
1457                size: 32,
1458            },
1459        ]);
1460
1461        assert_eq!(res.len(), 1);
1462        assert_pcr_eq!(
1463            res[0],
1464            vk::PushConstantRange {
1465                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
1466                offset: 0,
1467                size: 32,
1468            },
1469        );
1470    }
1471
1472    #[test]
1473    pub fn push_constant_ranges_overlap() {
1474        let res = merge_push_constant_ranges(&[
1475            vk::PushConstantRange {
1476                stage_flags: vk::ShaderStageFlags::VERTEX,
1477                offset: 0,
1478                size: 24,
1479            },
1480            vk::PushConstantRange {
1481                stage_flags: vk::ShaderStageFlags::GEOMETRY,
1482                offset: 8,
1483                size: 24,
1484            },
1485            vk::PushConstantRange {
1486                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1487                offset: 20,
1488                size: 28,
1489            },
1490        ]);
1491
1492        assert_eq!(res.len(), 5);
1493        assert_pcr_eq!(
1494            res[0],
1495            vk::PushConstantRange {
1496                stage_flags: vk::ShaderStageFlags::VERTEX,
1497                offset: 0,
1498                size: 8,
1499            },
1500        );
1501        assert_pcr_eq!(
1502            res[1],
1503            vk::PushConstantRange {
1504                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::GEOMETRY,
1505                offset: 8,
1506                size: 12,
1507            },
1508        );
1509        assert_pcr_eq!(
1510            res[2],
1511            vk::PushConstantRange {
1512                stage_flags: vk::ShaderStageFlags::VERTEX
1513                    | vk::ShaderStageFlags::GEOMETRY
1514                    | vk::ShaderStageFlags::FRAGMENT,
1515                offset: 20,
1516                size: 4,
1517            },
1518        );
1519        assert_pcr_eq!(
1520            res[3],
1521            vk::PushConstantRange {
1522                stage_flags: vk::ShaderStageFlags::GEOMETRY | vk::ShaderStageFlags::FRAGMENT,
1523                offset: 24,
1524                size: 8,
1525            },
1526        );
1527        assert_pcr_eq!(
1528            res[4],
1529            vk::PushConstantRange {
1530                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1531                offset: 32,
1532                size: 16,
1533            },
1534        );
1535    }
1536
1537    #[test]
1538    pub fn push_constant_ranges_subset() {
1539        let res = merge_push_constant_ranges(&[
1540            vk::PushConstantRange {
1541                stage_flags: vk::ShaderStageFlags::VERTEX,
1542                offset: 0,
1543                size: 64,
1544            },
1545            vk::PushConstantRange {
1546                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1547                offset: 16,
1548                size: 8,
1549            },
1550        ]);
1551
1552        assert_eq!(res.len(), 3);
1553        assert_pcr_eq!(
1554            res[0],
1555            vk::PushConstantRange {
1556                stage_flags: vk::ShaderStageFlags::VERTEX,
1557                offset: 0,
1558                size: 16,
1559            },
1560        );
1561        assert_pcr_eq!(
1562            res[1],
1563            vk::PushConstantRange {
1564                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
1565                offset: 16,
1566                size: 8,
1567            },
1568        );
1569        assert_pcr_eq!(
1570            res[2],
1571            vk::PushConstantRange {
1572                stage_flags: vk::ShaderStageFlags::VERTEX,
1573                offset: 24,
1574                size: 40,
1575            },
1576        );
1577    }
1578
1579    #[test]
1580    pub fn push_constant_ranges_superset() {
1581        let res = merge_push_constant_ranges(&[
1582            vk::PushConstantRange {
1583                stage_flags: vk::ShaderStageFlags::VERTEX,
1584                offset: 0,
1585                size: 64,
1586            },
1587            vk::PushConstantRange {
1588                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1589                offset: 0,
1590                size: 80,
1591            },
1592        ]);
1593
1594        assert_eq!(res.len(), 2);
1595        assert_pcr_eq!(
1596            res[0],
1597            vk::PushConstantRange {
1598                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
1599                offset: 0,
1600                size: 64,
1601            },
1602        );
1603        assert_pcr_eq!(
1604            res[1],
1605            vk::PushConstantRange {
1606                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1607                offset: 64,
1608                size: 16,
1609            },
1610        );
1611    }
1612
1613    #[test]
1614    pub fn push_constant_ranges_single() {
1615        let input = [vk::PushConstantRange {
1616            stage_flags: vk::ShaderStageFlags::VERTEX,
1617            offset: 16,
1618            size: 32,
1619        }];
1620        let res = merge_push_constant_ranges(&input);
1621        assert_eq!(res.len(), 1);
1622        assert_pcr_eq!(
1623            res[0],
1624            vk::PushConstantRange {
1625                stage_flags: vk::ShaderStageFlags::VERTEX,
1626                offset: 16,
1627                size: 32,
1628            },
1629        );
1630        assert_merge_invariants(&input, &res);
1631    }
1632
1633    #[test]
1634    pub fn push_constant_ranges_three_identical() {
1635        let input = [
1636            vk::PushConstantRange {
1637                stage_flags: vk::ShaderStageFlags::VERTEX,
1638                offset: 0,
1639                size: 32,
1640            },
1641            vk::PushConstantRange {
1642                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1643                offset: 0,
1644                size: 32,
1645            },
1646            vk::PushConstantRange {
1647                stage_flags: vk::ShaderStageFlags::COMPUTE,
1648                offset: 0,
1649                size: 32,
1650            },
1651        ];
1652        let res = merge_push_constant_ranges(&input);
1653        assert_eq!(res.len(), 1);
1654        assert_pcr_eq!(
1655            res[0],
1656            vk::PushConstantRange {
1657                stage_flags: vk::ShaderStageFlags::VERTEX
1658                    | vk::ShaderStageFlags::FRAGMENT
1659                    | vk::ShaderStageFlags::COMPUTE,
1660                offset: 0,
1661                size: 32,
1662            },
1663        );
1664        assert_merge_invariants(&input, &res);
1665    }
1666
1667    #[test]
1668    pub fn push_constant_ranges_three_same_offset() {
1669        let input = [
1670            vk::PushConstantRange {
1671                stage_flags: vk::ShaderStageFlags::VERTEX,
1672                offset: 0,
1673                size: 8,
1674            },
1675            vk::PushConstantRange {
1676                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1677                offset: 0,
1678                size: 16,
1679            },
1680            vk::PushConstantRange {
1681                stage_flags: vk::ShaderStageFlags::COMPUTE,
1682                offset: 0,
1683                size: 32,
1684            },
1685        ];
1686        let res = merge_push_constant_ranges(&input);
1687        assert_eq!(res.len(), 3);
1688        assert_pcr_eq!(
1689            res[0],
1690            vk::PushConstantRange {
1691                stage_flags: vk::ShaderStageFlags::VERTEX
1692                    | vk::ShaderStageFlags::FRAGMENT
1693                    | vk::ShaderStageFlags::COMPUTE,
1694                offset: 0,
1695                size: 8,
1696            },
1697        );
1698        assert_pcr_eq!(
1699            res[1],
1700            vk::PushConstantRange {
1701                stage_flags: vk::ShaderStageFlags::FRAGMENT | vk::ShaderStageFlags::COMPUTE,
1702                offset: 8,
1703                size: 8,
1704            },
1705        );
1706        assert_pcr_eq!(
1707            res[2],
1708            vk::PushConstantRange {
1709                stage_flags: vk::ShaderStageFlags::COMPUTE,
1710                offset: 16,
1711                size: 16,
1712            },
1713        );
1714        assert_merge_invariants(&input, &res);
1715    }
1716
1717    #[test]
1718    pub fn push_constant_ranges_nested_chain() {
1719        let input = [
1720            vk::PushConstantRange {
1721                stage_flags: vk::ShaderStageFlags::VERTEX,
1722                offset: 0,
1723                size: 64,
1724            },
1725            vk::PushConstantRange {
1726                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1727                offset: 8,
1728                size: 48,
1729            },
1730            vk::PushConstantRange {
1731                stage_flags: vk::ShaderStageFlags::COMPUTE,
1732                offset: 16,
1733                size: 32,
1734            },
1735        ];
1736        let res = merge_push_constant_ranges(&input);
1737        assert_eq!(res.len(), 5);
1738        assert_pcr_eq!(
1739            res[0],
1740            vk::PushConstantRange {
1741                stage_flags: vk::ShaderStageFlags::VERTEX,
1742                offset: 0,
1743                size: 8,
1744            },
1745        );
1746        assert_pcr_eq!(
1747            res[1],
1748            vk::PushConstantRange {
1749                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
1750                offset: 8,
1751                size: 8,
1752            },
1753        );
1754        assert_pcr_eq!(
1755            res[2],
1756            vk::PushConstantRange {
1757                stage_flags: vk::ShaderStageFlags::VERTEX
1758                    | vk::ShaderStageFlags::FRAGMENT
1759                    | vk::ShaderStageFlags::COMPUTE,
1760                offset: 16,
1761                size: 32,
1762            },
1763        );
1764        assert_pcr_eq!(
1765            res[3],
1766            vk::PushConstantRange {
1767                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
1768                offset: 48,
1769                size: 8,
1770            },
1771        );
1772        assert_pcr_eq!(
1773            res[4],
1774            vk::PushConstantRange {
1775                stage_flags: vk::ShaderStageFlags::VERTEX,
1776                offset: 56,
1777                size: 8,
1778            },
1779        );
1780        assert_merge_invariants(&input, &res);
1781    }
1782
1783    #[test]
1784    pub fn push_constant_ranges_touching() {
1785        let input = [
1786            vk::PushConstantRange {
1787                stage_flags: vk::ShaderStageFlags::VERTEX,
1788                offset: 0,
1789                size: 16,
1790            },
1791            vk::PushConstantRange {
1792                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1793                offset: 16,
1794                size: 16,
1795            },
1796            vk::PushConstantRange {
1797                stage_flags: vk::ShaderStageFlags::COMPUTE,
1798                offset: 32,
1799                size: 16,
1800            },
1801        ];
1802        let res = merge_push_constant_ranges(&input);
1803        assert_eq!(res.len(), 3);
1804        assert_pcr_eq!(
1805            res[0],
1806            vk::PushConstantRange {
1807                stage_flags: vk::ShaderStageFlags::VERTEX,
1808                offset: 0,
1809                size: 16,
1810            },
1811        );
1812        assert_pcr_eq!(
1813            res[1],
1814            vk::PushConstantRange {
1815                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1816                offset: 16,
1817                size: 16,
1818            },
1819        );
1820        assert_pcr_eq!(
1821            res[2],
1822            vk::PushConstantRange {
1823                stage_flags: vk::ShaderStageFlags::COMPUTE,
1824                offset: 32,
1825                size: 16,
1826            },
1827        );
1828        assert_merge_invariants(&input, &res);
1829    }
1830
1831    #[test]
1832    pub fn push_constant_ranges_complex_interleave() {
1833        let input = [
1834            vk::PushConstantRange {
1835                stage_flags: vk::ShaderStageFlags::VERTEX,
1836                offset: 0,
1837                size: 24,
1838            },
1839            vk::PushConstantRange {
1840                stage_flags: vk::ShaderStageFlags::GEOMETRY,
1841                offset: 8,
1842                size: 24,
1843            },
1844            vk::PushConstantRange {
1845                stage_flags: vk::ShaderStageFlags::COMPUTE,
1846                offset: 16,
1847                size: 24,
1848            },
1849            vk::PushConstantRange {
1850                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1851                offset: 32,
1852                size: 24,
1853            },
1854        ];
1855        let res = merge_push_constant_ranges(&input);
1856        assert_eq!(res.len(), 6);
1857        assert_pcr_eq!(
1858            res[0],
1859            vk::PushConstantRange {
1860                stage_flags: vk::ShaderStageFlags::VERTEX,
1861                offset: 0,
1862                size: 8,
1863            },
1864        );
1865        assert_pcr_eq!(
1866            res[1],
1867            vk::PushConstantRange {
1868                stage_flags: vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::GEOMETRY,
1869                offset: 8,
1870                size: 8,
1871            },
1872        );
1873        assert_pcr_eq!(
1874            res[2],
1875            vk::PushConstantRange {
1876                stage_flags: vk::ShaderStageFlags::VERTEX
1877                    | vk::ShaderStageFlags::GEOMETRY
1878                    | vk::ShaderStageFlags::COMPUTE,
1879                offset: 16,
1880                size: 8,
1881            },
1882        );
1883        assert_pcr_eq!(
1884            res[3],
1885            vk::PushConstantRange {
1886                stage_flags: vk::ShaderStageFlags::GEOMETRY | vk::ShaderStageFlags::COMPUTE,
1887                offset: 24,
1888                size: 8,
1889            },
1890        );
1891        assert_pcr_eq!(
1892            res[4],
1893            vk::PushConstantRange {
1894                stage_flags: vk::ShaderStageFlags::COMPUTE | vk::ShaderStageFlags::FRAGMENT,
1895                offset: 32,
1896                size: 8,
1897            },
1898        );
1899        assert_pcr_eq!(
1900            res[5],
1901            vk::PushConstantRange {
1902                stage_flags: vk::ShaderStageFlags::FRAGMENT,
1903                offset: 40,
1904                size: 16,
1905            },
1906        );
1907        assert_merge_invariants(&input, &res);
1908    }
1909
1910    #[test]
1911    pub fn push_constant_ranges_fuzz() {
1912        use rand::Rng;
1913        use rand::SeedableRng;
1914        use rand::rngs::StdRng;
1915
1916        let stages = [
1917            vk::ShaderStageFlags::VERTEX,
1918            vk::ShaderStageFlags::FRAGMENT,
1919            vk::ShaderStageFlags::GEOMETRY,
1920            vk::ShaderStageFlags::TESSELLATION_CONTROL,
1921            vk::ShaderStageFlags::TESSELLATION_EVALUATION,
1922            vk::ShaderStageFlags::COMPUTE,
1923        ];
1924
1925        for seed in 0..10000 {
1926            let mut rng = StdRng::seed_from_u64(seed);
1927            let count = rng.random_range(0..=stages.len());
1928
1929            let mut available: Vec<usize> = (0..stages.len()).collect();
1930            for i in (1..available.len()).rev() {
1931                let j = rng.random_range(0..=i);
1932                available.swap(i, j);
1933            }
1934
1935            let input: Vec<vk::PushConstantRange> = available
1936                .iter()
1937                .take(count)
1938                .map(|&idx| {
1939                    let offset = rng.random_range(0u32..128);
1940                    let size = rng.random_range(1u32..64);
1941                    vk::PushConstantRange {
1942                        stage_flags: stages[idx],
1943                        offset,
1944                        size,
1945                    }
1946                })
1947                .collect();
1948
1949            let result = merge_push_constant_ranges(&input);
1950            assert_merge_invariants(&input, &result);
1951        }
1952    }
1953}