Skip to main content

concinnity_core/render/slang_programs/
vk.rs

1// Single-source engine shader programs for the Vulkan backend.
2//
3// Each program compiles a `.slang` file under `src/shaders/` (the
4// backend-neutral single-source directory) to SPIR-V, at build time where the
5// host has slangc and at renderer init otherwise, cached in the
6// content-addressed shader cache. The runtime `POOL_SIZE` / `MAX_PROBES`
7// values are injected as `#define` lines into the source text, so the cache
8// keys them.
9//
10// The `[[vk::binding]]` annotations (and ParameterBlock member order) in the
11// sources are the engine's descriptor-set layouts. slangc names every
12// single-entry SPIR-V entry point `main`, which is what pipeline stage creation
13// asks for.
14
15/// Which runtime capacities a program bakes into its source as `#define`s.
16/// They ride the source text rather than a command line so the shader cache
17/// keys them.
18#[derive(Clone, Copy, PartialEq, Eq)]
19pub enum Sizes {
20    /// No size defines.
21    None,
22    /// The reflection-probe array length only: the SSR resolve binds the
23    /// forward global set's probe cubes but none of the texture pool.
24    Probes,
25    /// The bindless texture-pool capacity and the probe array length.
26    PoolAndProbes,
27}
28
29/// One SPIR-V program: which shader file, which entry point, under which
30/// variant gates and baked capacities.
31pub struct SlangProgram {
32    /// File name under `src/shaders/` for the `cn debug` disk-first resolve;
33    /// also the embedded fallback's origin.
34    pub file: &'static str,
35    /// Entry point compiled out of that file.
36    pub entry: &'static str,
37    /// Diagnostic label (compile errors + cache miss logs + export report).
38    pub label: &'static str,
39    /// Fixed variant gates (e.g. HIZ_INIT_MSAA), each injected as
40    /// `#define <gate> 1`. More than one where a variant is the intersection of
41    /// two, like the textured ray-traced glass fragment.
42    pub gates: &'static [&'static str],
43    /// Runtime capacities injected from the context.
44    pub sizes: Sizes,
45    /// Inject `#define USE_MSAA {0|1}` from `Ctx::msaa`. A HOST difference
46    /// rather than a target one: only the fog fragment declares its depth source
47    /// by the main pass's sample count.
48    pub msaa: bool,
49}
50
51/// `vertex_main_bindless` from `main_bindless.slang`.
52pub static MAIN_BINDLESS_VERT: SlangProgram = SlangProgram {
53    file: "main_bindless.slang",
54    entry: "vertex_main_bindless",
55    label: "vert_bindless.slang",
56    gates: &[],
57    sizes: Sizes::PoolAndProbes,
58    msaa: false,
59};
60/// `fragment_main_bindless` from `main_bindless.slang`.
61pub static MAIN_BINDLESS_FRAG: SlangProgram = SlangProgram {
62    file: "main_bindless.slang",
63    entry: "fragment_main_bindless",
64    label: "frag_bindless.slang",
65    gates: &[],
66    sizes: Sizes::PoolAndProbes,
67    msaa: false,
68};
69/// `cull_kernel` from `cull.slang`: phase-1 draw cull.
70pub static CULL: SlangProgram = SlangProgram {
71    file: "cull.slang",
72    entry: "cull_kernel",
73    label: "cull.slang",
74    gates: &[],
75    sizes: Sizes::None,
76    msaa: false,
77};
78/// `cull_kernel` from `cull.slang` under `CULL_PHASE2`: the two-pass occlusion
79/// re-test against the rebuilt Hi-Z pyramid.
80pub static CULL_PHASE2: SlangProgram = SlangProgram {
81    file: "cull.slang",
82    entry: "cull_kernel",
83    label: "cull_phase2.slang",
84    gates: &["CULL_PHASE2"],
85    sizes: Sizes::None,
86    msaa: false,
87};
88/// `cull_kernel` from `cull.slang` under `SHADOW_CULL`: light-frustum only,
89/// against the lean three-binding shadow cull set.
90pub static CULL_SHADOW: SlangProgram = SlangProgram {
91    file: "cull.slang",
92    entry: "cull_kernel",
93    label: "cull_shadow.slang",
94    gates: &["SHADOW_CULL"],
95    sizes: Sizes::None,
96    msaa: false,
97};
98/// `model_history_kernel` from `model_history.slang`: this frame's model
99/// snapshot for the next frame's motion vectors.
100pub static MODEL_HISTORY: SlangProgram = SlangProgram {
101    file: "model_history.slang",
102    entry: "model_history_kernel",
103    label: "model_history.slang",
104    gates: &[],
105    sizes: Sizes::None,
106    msaa: false,
107};
108/// `light_cull_kernel` from `light_cull.slang`.
109pub static LIGHT_CULL: SlangProgram = SlangProgram {
110    file: "light_cull.slang",
111    entry: "light_cull_kernel",
112    label: "light_cull.slang",
113    gates: &[],
114    sizes: Sizes::None,
115    msaa: false,
116};
117/// `hiz_init_msaa` from `hiz_build.slang`.
118pub static HIZ_INIT_MSAA: SlangProgram = SlangProgram {
119    file: "hiz_build.slang",
120    entry: "hiz_init_msaa",
121    label: "hiz_init_msaa.slang",
122    gates: &["HIZ_INIT_MSAA"],
123    sizes: Sizes::None,
124    msaa: false,
125};
126/// `hiz_init_single` from `hiz_build.slang`.
127pub static HIZ_INIT_SINGLE: SlangProgram = SlangProgram {
128    file: "hiz_build.slang",
129    entry: "hiz_init_single",
130    label: "hiz_init_single.slang",
131    gates: &["HIZ_INIT_SINGLE"],
132    sizes: Sizes::None,
133    msaa: false,
134};
135/// `hiz_downsample` from `hiz_build.slang`.
136pub static HIZ_DOWNSAMPLE: SlangProgram = SlangProgram {
137    file: "hiz_build.slang",
138    entry: "hiz_downsample",
139    label: "hiz_downsample.slang",
140    gates: &["HIZ_DOWNSAMPLE"],
141    sizes: Sizes::None,
142    msaa: false,
143};
144/// `hiz_spd_msaa` from `hiz_build.slang`.
145pub static HIZ_SPD_MSAA: SlangProgram = SlangProgram {
146    file: "hiz_build.slang",
147    entry: "hiz_spd_msaa",
148    label: "hiz_spd_msaa.slang",
149    gates: &["HIZ_SPD_MSAA"],
150    sizes: Sizes::None,
151    msaa: false,
152};
153/// `hiz_spd_single` from `hiz_build.slang`.
154pub static HIZ_SPD_SINGLE: SlangProgram = SlangProgram {
155    file: "hiz_build.slang",
156    entry: "hiz_spd_single",
157    label: "hiz_spd_single.slang",
158    gates: &["HIZ_SPD_SINGLE"],
159    sizes: Sizes::None,
160    msaa: false,
161};
162/// `hiz_spd_tail` from `hiz_build.slang`.
163pub static HIZ_SPD_TAIL: SlangProgram = SlangProgram {
164    file: "hiz_build.slang",
165    entry: "hiz_spd_tail",
166    label: "hiz_spd_tail.slang",
167    gates: &["HIZ_SPD_TAIL"],
168    sizes: Sizes::None,
169    msaa: false,
170};
171
172/// `probe_mip0` from `probe_prefilter.slang`.
173pub static PROBE_MIP0: SlangProgram = SlangProgram {
174    file: "probe_prefilter.slang",
175    entry: "probe_mip0",
176    label: "probe_mip0.slang",
177    gates: &["PROBE_MIP0"],
178    sizes: Sizes::None,
179    msaa: false,
180};
181/// `probe_downsample` from `probe_prefilter.slang`.
182pub static PROBE_DOWNSAMPLE: SlangProgram = SlangProgram {
183    file: "probe_prefilter.slang",
184    entry: "probe_downsample",
185    label: "probe_downsample.slang",
186    gates: &["PROBE_DOWNSAMPLE"],
187    sizes: Sizes::None,
188    msaa: false,
189};
190/// `probe_ggx` from `probe_prefilter.slang`.
191pub static PROBE_GGX: SlangProgram = SlangProgram {
192    file: "probe_prefilter.slang",
193    entry: "probe_ggx",
194    label: "probe_ggx.slang",
195    gates: &["PROBE_GGX"],
196    sizes: Sizes::None,
197    msaa: false,
198};
199
200// The G-buffer pre-pass and shadow families. Every entry is its own program so
201// it declares only the resources it binds; the `[[vk::binding]]` annotations
202// reproduce the descriptor sets the GLSL declared, so the SPIR-V is a drop-in
203// against the untouched pipeline layouts.
204/// `gbuffer_prepass_vertex_bindless` from `gbuffer_prepass.slang`.
205pub static GBUFFER_BINDLESS_VERT: SlangProgram = SlangProgram {
206    file: "gbuffer_prepass.slang",
207    entry: "gbuffer_prepass_vertex_bindless",
208    label: "gbuffer_prepass_vert_bindless.slang",
209    gates: &["GB_BINDLESS"],
210    sizes: Sizes::None,
211    msaa: false,
212};
213/// `gbuffer_prepass_fragment_bindless` from `gbuffer_prepass.slang`.
214pub static GBUFFER_BINDLESS_FRAG: SlangProgram = SlangProgram {
215    file: "gbuffer_prepass.slang",
216    entry: "gbuffer_prepass_fragment_bindless",
217    label: "gbuffer_prepass_frag_bindless.slang",
218    gates: &["GB_FRAGMENT_BINDLESS"],
219    sizes: Sizes::None,
220    msaa: false,
221};
222/// `shadow_vertex_main` from `shadow.slang`.
223pub static SHADOW_VERT: SlangProgram = SlangProgram {
224    file: "shadow.slang",
225    entry: "shadow_vertex_main",
226    label: "shadow_vert.slang",
227    gates: &["SHADOW_STATIC"],
228    sizes: Sizes::None,
229    msaa: false,
230};
231/// `shadow_vertex_main_skinned` from `shadow.slang`.
232pub static SKINNED_SHADOW_VERT: SlangProgram = SlangProgram {
233    file: "shadow.slang",
234    entry: "shadow_vertex_main_skinned",
235    label: "shadow_vert_skinned.slang",
236    gates: &["SHADOW_SKINNED"],
237    sizes: Sizes::None,
238    msaa: false,
239};
240/// `shadow_vertex_bindless` from `shadow.slang`.
241pub static SHADOW_BINDLESS_VERT: SlangProgram = SlangProgram {
242    file: "shadow.slang",
243    entry: "shadow_vertex_bindless",
244    label: "shadow_vert_bindless.slang",
245    gates: &["SHADOW_BINDLESS"],
246    sizes: Sizes::None,
247    msaa: false,
248};
249
250// The fullscreen-triangle vertex stage every ported post pass pairs with; one
251// module serves them all, the way `composite.vert` served the GLSL ones.
252/// `fullscreen_vertex` from `fullscreen.slang`.
253pub static FULLSCREEN_VERT: SlangProgram = SlangProgram {
254    file: "fullscreen.slang",
255    entry: "fullscreen_vertex",
256    label: "fullscreen_vert.slang",
257    gates: &[],
258    sizes: Sizes::None,
259    msaa: false,
260};
261/// `taa_fragment_main` from `taa.slang`.
262pub static TAA_FRAG: SlangProgram = SlangProgram {
263    file: "taa.slang",
264    entry: "taa_fragment_main",
265    label: "taa_frag.slang",
266    gates: &[],
267    sizes: Sizes::None,
268    msaa: false,
269};
270/// `bloom_prefilter_fragment` from `bloom.slang`.
271pub static BLOOM_PREFILTER: SlangProgram = SlangProgram {
272    file: "bloom.slang",
273    entry: "bloom_prefilter_fragment",
274    label: "bloom_prefilter.slang",
275    gates: &["BLOOM_PREFILTER"],
276    sizes: Sizes::None,
277    msaa: false,
278};
279/// `bloom_downsample_fragment` from `bloom.slang`.
280pub static BLOOM_DOWNSAMPLE: SlangProgram = SlangProgram {
281    file: "bloom.slang",
282    entry: "bloom_downsample_fragment",
283    label: "bloom_downsample.slang",
284    gates: &["BLOOM_DOWNSAMPLE"],
285    sizes: Sizes::None,
286    msaa: false,
287};
288/// `bloom_upsample_fragment` from `bloom.slang`.
289pub static BLOOM_UPSAMPLE: SlangProgram = SlangProgram {
290    file: "bloom.slang",
291    entry: "bloom_upsample_fragment",
292    label: "bloom_upsample.slang",
293    gates: &["BLOOM_UPSAMPLE"],
294    sizes: Sizes::None,
295    msaa: false,
296};
297/// `composite_fragment` from `composite.slang`.
298pub static COMPOSITE_FRAG: SlangProgram = SlangProgram {
299    file: "composite.slang",
300    entry: "composite_fragment",
301    label: "composite_frag.slang",
302    gates: &[],
303    sizes: Sizes::None,
304    msaa: false,
305};
306/// `ssao_kernel_fragment` from `ssao.slang`.
307pub static SSAO_KERNEL: SlangProgram = SlangProgram {
308    file: "ssao.slang",
309    entry: "ssao_kernel_fragment",
310    label: "ssao_kernel.slang",
311    gates: &["SSAO_KERNEL"],
312    sizes: Sizes::None,
313    msaa: false,
314};
315/// `ssao_blur_fragment` from `ssao.slang`.
316pub static SSAO_BLUR: SlangProgram = SlangProgram {
317    file: "ssao.slang",
318    entry: "ssao_blur_fragment",
319    label: "ssao_blur.slang",
320    gates: &["SSAO_BLUR"],
321    sizes: Sizes::None,
322    msaa: false,
323};
324/// `ssr_resolve_fragment` from `ssr.slang`.
325pub static SSR_RESOLVE: SlangProgram = SlangProgram {
326    file: "ssr.slang",
327    entry: "ssr_resolve_fragment",
328    label: "ssr_resolve.slang",
329    gates: &[],
330    sizes: Sizes::Probes,
331    msaa: false,
332};
333/// `ssgi_gather_fragment` from `ssgi.slang`.
334pub static SSGI_GATHER: SlangProgram = SlangProgram {
335    file: "ssgi.slang",
336    entry: "ssgi_gather_fragment",
337    label: "ssgi_gather.slang",
338    gates: &["SSGI_GATHER"],
339    sizes: Sizes::None,
340    msaa: false,
341};
342/// `ssgi_composite_fragment` from `ssgi.slang`.
343pub static SSGI_COMPOSITE: SlangProgram = SlangProgram {
344    file: "ssgi.slang",
345    entry: "ssgi_composite_fragment",
346    label: "ssgi_composite.slang",
347    gates: &["SSGI_COMPOSITE"],
348    sizes: Sizes::None,
349    msaa: false,
350};
351/// `reflection_blur_fragment` from `reflection.slang`.
352pub static REFLECTION_BLUR: SlangProgram = SlangProgram {
353    file: "reflection.slang",
354    entry: "reflection_blur_fragment",
355    label: "reflection_blur.slang",
356    gates: &["REFLECTION_BLUR"],
357    sizes: Sizes::None,
358    msaa: false,
359};
360/// `reflection_composite_fragment` from `reflection.slang`.
361pub static REFLECTION_COMPOSITE: SlangProgram = SlangProgram {
362    file: "reflection.slang",
363    entry: "reflection_composite_fragment",
364    label: "reflection_composite.slang",
365    gates: &["REFLECTION_COMPOSITE"],
366    sizes: Sizes::None,
367    msaa: false,
368};
369
370// The compute kernels and the fog family. The fog fragment is the only program
371// whose assembly depends on the host's MSAA mode.
372/// `fog_froxel_kernel` from `fog.slang`.
373pub static FOG_FROXEL: SlangProgram = SlangProgram {
374    file: "fog.slang",
375    entry: "fog_froxel_kernel",
376    label: "fog_froxel.slang",
377    gates: &["FOG_FROXEL"],
378    sizes: Sizes::None,
379    msaa: false,
380};
381/// `fog_fragment` from `fog.slang`.
382pub static FOG_FRAG: SlangProgram = SlangProgram {
383    file: "fog.slang",
384    entry: "fog_fragment",
385    label: "fog_frag.slang",
386    gates: &[],
387    sizes: Sizes::None,
388    msaa: true,
389};
390/// `histogram_build` from `auto_exposure.slang`.
391pub static AUTO_EXPOSURE_BUILD: SlangProgram = SlangProgram {
392    file: "auto_exposure.slang",
393    entry: "histogram_build",
394    label: "auto_exposure_build.slang",
395    gates: &["AE_BUILD"],
396    sizes: Sizes::None,
397    msaa: false,
398};
399/// `histogram_average` from `auto_exposure.slang`.
400pub static AUTO_EXPOSURE_AVERAGE: SlangProgram = SlangProgram {
401    file: "auto_exposure.slang",
402    entry: "histogram_average",
403    label: "auto_exposure_average.slang",
404    gates: &["AE_AVERAGE"],
405    sizes: Sizes::None,
406    msaa: false,
407};
408/// `rt_skin` from `rt_skin.slang`.
409pub static RT_SKIN: SlangProgram = SlangProgram {
410    file: "rt_skin.slang",
411    entry: "rt_skin",
412    label: "rt_skin.slang",
413    gates: &[],
414    sizes: Sizes::None,
415    msaa: false,
416};
417/// `particle_simulate` from `particle_simulate.slang`.
418pub static PARTICLE_SIMULATE: SlangProgram = SlangProgram {
419    file: "particle_simulate.slang",
420    entry: "particle_simulate",
421    label: "particle_simulate.slang",
422    gates: &[],
423    sizes: Sizes::None,
424    msaa: false,
425};
426
427// The remaining raster families: the particle billboard pair, the projected
428// decal, world-space lines and the text / sprite overlay. Each has real vertex
429// geometry, so unlike the post passes they keep their own vertex entry rather
430// than pairing with `fullscreen.slang`. Only the two depth-reading fragments
431// take the host's sample count; their vertex stages never name the depth source.
432/// `particle_vertex` from `particle.slang`.
433pub static PARTICLE_VERT: SlangProgram = SlangProgram {
434    file: "particle.slang",
435    entry: "particle_vertex",
436    label: "particle_vert.slang",
437    gates: &[],
438    sizes: Sizes::None,
439    msaa: false,
440};
441/// `particle_fragment` from `particle.slang`.
442pub static PARTICLE_FRAG: SlangProgram = SlangProgram {
443    file: "particle.slang",
444    entry: "particle_fragment",
445    label: "particle_frag.slang",
446    gates: &[],
447    sizes: Sizes::None,
448    msaa: false,
449};
450/// `decal_vertex` from `decal.slang`.
451pub static DECAL_VERT: SlangProgram = SlangProgram {
452    file: "decal.slang",
453    entry: "decal_vertex",
454    label: "decal_vert.slang",
455    gates: &[],
456    sizes: Sizes::None,
457    msaa: false,
458};
459/// `decal_fragment` from `decal.slang`.
460pub static DECAL_FRAG: SlangProgram = SlangProgram {
461    file: "decal.slang",
462    entry: "decal_fragment",
463    label: "decal_frag.slang",
464    gates: &[],
465    sizes: Sizes::None,
466    msaa: true,
467};
468/// `line_vertex` from `line.slang`.
469pub static LINE_VERT: SlangProgram = SlangProgram {
470    file: "line.slang",
471    entry: "line_vertex",
472    label: "line_vert.slang",
473    gates: &[],
474    sizes: Sizes::None,
475    msaa: false,
476};
477/// `line_fragment` from `line.slang`.
478pub static LINE_FRAG: SlangProgram = SlangProgram {
479    file: "line.slang",
480    entry: "line_fragment",
481    label: "line_frag.slang",
482    gates: &[],
483    sizes: Sizes::None,
484    msaa: true,
485};
486/// `text_vertex_main` from `text.slang`.
487pub static TEXT_VERT: SlangProgram = SlangProgram {
488    file: "text.slang",
489    entry: "text_vertex_main",
490    label: "text_vert.slang",
491    gates: &[],
492    sizes: Sizes::None,
493    msaa: false,
494};
495/// `text_fragment_main` from `text.slang`.
496pub static TEXT_FRAG: SlangProgram = SlangProgram {
497    file: "text.slang",
498    entry: "text_fragment_main",
499    label: "text_frag.slang",
500    gates: &[],
501    sizes: Sizes::None,
502    msaa: false,
503};
504
505// Every declared program, iterated by the export-time precompile. Both Hi-Z
506// init variants are enumerated: which one a device runs depends on its MSAA
507// The ray-traced families, compiled only where `VK_KHR_ray_query` is present:
508// slangc emits `SPV_KHR_ray_query` (SPIR-V 1.5), so these need the Vulkan 1.2
509// device the extension already implies. The flat variants declare no bindless
510// pool at all, which is what keeps a non-bindless world from binding one.
511/// `rt_reflections_fragment` from `rt_reflections.slang`.
512pub static RT_REFLECTIONS_FRAG: SlangProgram = SlangProgram {
513    file: "rt_reflections.slang",
514    entry: "rt_reflections_fragment",
515    label: "rt_reflections.slang",
516    gates: &[],
517    sizes: Sizes::Probes,
518    msaa: false,
519};
520/// `rt_reflections_fragment` from `rt_reflections.slang`.
521pub static RT_REFLECTIONS_FRAG_TEXTURED: SlangProgram = SlangProgram {
522    file: "rt_reflections.slang",
523    entry: "rt_reflections_fragment",
524    label: "rt_reflections_textured.slang",
525    gates: &["RT_TEXTURED"],
526    sizes: Sizes::PoolAndProbes,
527    msaa: false,
528};
529/// `glass_vertex` from `glass.slang`.
530pub static GLASS_VERT: SlangProgram = SlangProgram {
531    file: "glass.slang",
532    entry: "glass_vertex",
533    label: "glass_vert.slang",
534    gates: &[],
535    sizes: Sizes::Probes,
536    msaa: true,
537};
538/// `glass_fragment` from `glass.slang`.
539pub static GLASS_FRAG: SlangProgram = SlangProgram {
540    file: "glass.slang",
541    entry: "glass_fragment",
542    label: "glass_frag.slang",
543    gates: &[],
544    sizes: Sizes::Probes,
545    msaa: true,
546};
547/// `glass_rt_fragment` from `glass.slang`.
548pub static GLASS_FRAG_RT: SlangProgram = SlangProgram {
549    file: "glass.slang",
550    entry: "glass_rt_fragment",
551    label: "glass_frag_rt.slang",
552    gates: &["GLASS_RT"],
553    sizes: Sizes::Probes,
554    msaa: true,
555};
556/// `glass_rt_fragment` from `glass.slang`.
557pub static GLASS_FRAG_RT_TEXTURED: SlangProgram = SlangProgram {
558    file: "glass.slang",
559    entry: "glass_rt_fragment",
560    label: "glass_frag_rt_textured.slang",
561    gates: &["GLASS_RT", "RT_TEXTURED"],
562    sizes: Sizes::PoolAndProbes,
563    msaa: true,
564};
565
566// The see-through glass MESH family, the transparent pass's third producer.
567// Ray-traced only -- the per-pixel trace is what makes the mesh see-through
568// rather than the opaque reflective glass the main pass draws -- so there is no
569// base pair. Its vertex stage is its own (it applies the per-draw model matrix)
570// but shares every descriptor binding with the rest of the pass.
571/// `glass_mesh_vertex` from `glass_mesh.slang`.
572pub static GLASS_MESH_VERT: SlangProgram = SlangProgram {
573    file: "glass_mesh.slang",
574    entry: "glass_mesh_vertex",
575    label: "glass_mesh_vert.slang",
576    gates: &[],
577    sizes: Sizes::Probes,
578    msaa: true,
579};
580/// `glass_mesh_rt_fragment` from `glass_mesh.slang`.
581pub static GLASS_MESH_FRAG_RT: SlangProgram = SlangProgram {
582    file: "glass_mesh.slang",
583    entry: "glass_mesh_rt_fragment",
584    label: "glass_mesh_frag_rt.slang",
585    gates: &[],
586    sizes: Sizes::Probes,
587    msaa: true,
588};
589/// `glass_mesh_rt_fragment` from `glass_mesh.slang`.
590pub static GLASS_MESH_FRAG_RT_TEXTURED: SlangProgram = SlangProgram {
591    file: "glass_mesh.slang",
592    entry: "glass_mesh_rt_fragment",
593    label: "glass_mesh_frag_rt_textured.slang",
594    gates: &["RT_TEXTURED"],
595    sizes: Sizes::PoolAndProbes,
596    msaa: true,
597};
598
599// The water surface family, the transparent pass's other producer. Same shape as
600// the glass table above, and deliberately the same descriptor bindings, so
601// `transparent.rs` builds one set of set layouts and both producers draw under
602// them.
603/// `water_vertex` from `water.slang`.
604pub static WATER_VERT: SlangProgram = SlangProgram {
605    file: "water.slang",
606    entry: "water_vertex",
607    label: "water_vert.slang",
608    gates: &[],
609    sizes: Sizes::Probes,
610    msaa: true,
611};
612/// `water_fragment` from `water.slang`.
613pub static WATER_FRAG: SlangProgram = SlangProgram {
614    file: "water.slang",
615    entry: "water_fragment",
616    label: "water_frag.slang",
617    gates: &[],
618    sizes: Sizes::Probes,
619    msaa: true,
620};
621/// `water_rt_fragment` from `water.slang`.
622pub static WATER_FRAG_RT: SlangProgram = SlangProgram {
623    file: "water.slang",
624    entry: "water_rt_fragment",
625    label: "water_frag_rt.slang",
626    gates: &["WATER_RT"],
627    sizes: Sizes::Probes,
628    msaa: true,
629};
630/// `water_rt_fragment` from `water.slang`.
631pub static WATER_FRAG_RT_TEXTURED: SlangProgram = SlangProgram {
632    file: "water.slang",
633    entry: "water_rt_fragment",
634    label: "water_frag_rt_textured.slang",
635    gates: &["WATER_RT", "RT_TEXTURED"],
636    sizes: Sizes::PoolAndProbes,
637    msaa: true,
638};
639
640// mode, and a bundle should be warm for either.
641/// Every declared program, which the renderer and the build script both
642/// iterate: one compiles them at init, the other ahead of time.
643pub static ALL: &[&SlangProgram] = &[
644    &MAIN_BINDLESS_VERT,
645    &MAIN_BINDLESS_FRAG,
646    &LIGHT_CULL,
647    &MODEL_HISTORY,
648    &CULL,
649    &CULL_PHASE2,
650    &CULL_SHADOW,
651    &RT_SKIN,
652    &HIZ_INIT_MSAA,
653    &HIZ_INIT_SINGLE,
654    &HIZ_DOWNSAMPLE,
655    &PROBE_MIP0,
656    &PROBE_DOWNSAMPLE,
657    &PROBE_GGX,
658    &GBUFFER_BINDLESS_VERT,
659    &GBUFFER_BINDLESS_FRAG,
660    &SHADOW_VERT,
661    &SKINNED_SHADOW_VERT,
662    &SHADOW_BINDLESS_VERT,
663    &FULLSCREEN_VERT,
664    &TAA_FRAG,
665    &BLOOM_PREFILTER,
666    &BLOOM_DOWNSAMPLE,
667    &BLOOM_UPSAMPLE,
668    &COMPOSITE_FRAG,
669    &SSAO_KERNEL,
670    &SSAO_BLUR,
671    &SSR_RESOLVE,
672    &SSGI_GATHER,
673    &SSGI_COMPOSITE,
674    &REFLECTION_BLUR,
675    &REFLECTION_COMPOSITE,
676    &FOG_FROXEL,
677    &FOG_FRAG,
678    &AUTO_EXPOSURE_BUILD,
679    &AUTO_EXPOSURE_AVERAGE,
680    &PARTICLE_SIMULATE,
681    &PARTICLE_VERT,
682    &PARTICLE_FRAG,
683    &DECAL_VERT,
684    &DECAL_FRAG,
685    &LINE_VERT,
686    &LINE_FRAG,
687    &TEXT_VERT,
688    &TEXT_FRAG,
689    &RT_REFLECTIONS_FRAG,
690    &RT_REFLECTIONS_FRAG_TEXTURED,
691    &GLASS_VERT,
692    &GLASS_FRAG,
693    &GLASS_FRAG_RT,
694    &GLASS_FRAG_RT_TEXTURED,
695    &GLASS_MESH_VERT,
696    &GLASS_MESH_FRAG_RT,
697    &GLASS_MESH_FRAG_RT_TEXTURED,
698    &WATER_VERT,
699    &WATER_FRAG,
700    &WATER_FRAG_RT,
701    &WATER_FRAG_RT_TEXTURED,
702];
703
704#[cfg(test)]
705mod tests {
706    use super::*;
707    use alloc::vec::Vec;
708
709    // `label` keys each precompiled SPIR-V artifact, paired with the sample
710    // count for the programs that read it, so two programs sharing a label
711    // would hand one's bytes to the other.
712    #[test]
713    fn every_program_has_a_distinct_label() {
714        let mut labels: Vec<&str> = ALL.iter().map(|p| p.label).collect();
715        let declared = labels.len();
716        labels.sort_unstable();
717        labels.dedup();
718        assert_eq!(
719            labels.len(),
720            declared,
721            "two programs share a label, so they would share a precompiled artifact"
722        );
723    }
724
725    #[test]
726    fn every_program_names_an_embedded_shader() {
727        for p in ALL {
728            assert!(
729                crate::render::shaders::embedded(p.file).is_some(),
730                "{}: no embedded {}",
731                p.label,
732                p.file
733            );
734        }
735    }
736
737    // Only the sample count varies per host among the enumerable dimensions;
738    // the sizes are baked at their ceilings. A program that gained a dimension
739    // the build script does not enumerate would leave that variant uncovered.
740    #[test]
741    fn the_only_per_host_variant_is_the_sample_count() {
742        let sampled = ALL.iter().filter(|p| p.msaa).count();
743        assert!(sampled > 0, "the MSAA dimension went missing");
744        assert!(sampled < ALL.len(), "every program cannot read the depth");
745        for p in ALL {
746            assert!(!p.entry.is_empty(), "{}", p.label);
747        }
748    }
749}