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