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