concinnity_core/render/vulkan/uniforms.rs
1//! repr(C) uniform / push-constant structs only the Vulkan frame encoders bind
2//! (std140 / std430 / push-constant layouts). Each is mirrored field-for-field
3//! in a `.glsl`/`.vert`/`.frag`/`.comp` shader under `vulkan/shaders/`, or in
4//! the one `.slang` block Vulkan alone declares.
5//!
6//! Blocks whose shader counterpart is a single-source `.slang` declaration are
7//! declared once for every backend in `crate::render::uniforms`; what is left here is
8//! what only this backend binds. Their layouts are checked by `shader_layout` in
9//! concinnity-device, which reads the expected offsets out of slangc's
10//! reflection per target. The hand-written asserts below are for the families
11//! whose shaders are still per backend -- the cull kernel, the skinning and
12//! morph kernels, the raymarch SDF templates, the velocity pass, and Metal's
13//! water.
14
15/// Byte size of the auto-exposure push-constant range. Pins the struct size to
16/// what the pipeline layout declares.
17pub const AUTO_EXPOSURE_PUSH_BYTES: u32 = 16;
18
19/// The GPU-cull push constant (cull.slang): six already-normalised frustum
20/// planes (xyz = normal, w = d), the camera position sharing its 16-byte slot with
21/// the build-time object count, then the shader-bucket routing (120 B total).
22#[derive(Copy, Clone)]
23#[repr(C)]
24pub struct CullParams {
25 /// Frustum planes, each `(normal.xyz, d)`.
26 pub planes: [[f32; 4]; 6],
27 /// World-space camera position.
28 pub cam_pos: [f32; 3],
29 /// Draw records the kernel iterates.
30 pub object_count: u32,
31 /// Shader-bucket command regions in the indirect buffer. The kernel writes
32 /// every record's slot in all `bucket_count` regions (a draw in the record's
33 /// own bucket, a no-op everywhere else); region `b` starts at command
34 /// `b * bucket_stride`. `bucket_count = 1` degenerates to a single region.
35 pub bucket_count: u32,
36 /// `u32` slots one bucket occupies in the output list.
37 pub bucket_stride: u32,
38}
39
40/// Cull-side Hi-Z uniforms (cull.slang, 80 bytes): the previous frame's
41/// un-jittered view-projection, the Hi-Z mip-0 dimensions, the mip count, and an
42/// enable flag. Mirrors the Metal / DirectX CullUniforms tail.
43#[derive(Copy, Clone)]
44#[repr(C)]
45pub struct CullHizParams {
46 /// Previous frame's un-jittered view-projection. Projects each AABB into the
47 /// depth space the Hi-Z pyramid was reduced from (`M * v`).
48 pub prev_view_proj: [[f32; 4]; 4],
49 /// Hi-Z mip-0 dimensions (in texels).
50 pub hiz_size: [f32; 2],
51 /// How many mip levels live in the bound texture.
52 pub hiz_mip_count: u32,
53 /// 0 skips the Hi-Z test entirely (first frame / after a resize, before a
54 /// valid pyramid exists).
55 pub hiz_enabled: u32,
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use core::mem::{offset_of, size_of};
62
63 // CullParams must match the `CullParams` push-constant block in cull.slang:
64 // six frustum planes, then cam_pos sharing its 16-byte slot with
65 // object_count. `shader_layout` in concinnity-device reflects the same
66 // source; this is the copy that runs without slangc.
67 #[test]
68 fn cull_params_layout_matches_the_shader() {
69 assert_eq!(size_of::<CullParams>(), 120);
70 assert_eq!(offset_of!(CullParams, planes), 0);
71 assert_eq!(offset_of!(CullParams, cam_pos), 96);
72 assert_eq!(offset_of!(CullParams, object_count), 108);
73 assert_eq!(offset_of!(CullParams, bucket_count), 112);
74 assert_eq!(offset_of!(CullParams, bucket_stride), 116);
75 }
76
77 // CullHizParams in cull.slang: mat4 (64) + float2 (8) + two uints. Total 80
78 // bytes, tightly packed after the mat4.
79 #[test]
80 fn cull_hiz_params_layout_matches_the_shader() {
81 assert_eq!(size_of::<CullHizParams>(), 80);
82 assert_eq!(offset_of!(CullHizParams, prev_view_proj), 0);
83 assert_eq!(offset_of!(CullHizParams, hiz_size), 64);
84 assert_eq!(offset_of!(CullHizParams, hiz_mip_count), 72);
85 assert_eq!(offset_of!(CullHizParams, hiz_enabled), 76);
86 }
87}