mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 17:21:49 -10:00
Shader packs: struct types without a name
GLSL lets a declaration define its struct type in place without naming it
(GLSL 4.60, 4.1.8): `shared struct { uint sum; uint tile[8][8]; } lds;`.
naga's frontend wants a name ("Expected identifier, found LeftBrace"), which
RenderPearl v2.7.2's compute programs (deferred, deferred1, composite,
composite3) hit. Each such type now gets one (`hz_struct<n>`) before the
stages are read.
Part of #7171
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
fbb17c980e
commit
5e2c8f5641
2 files changed
+71
-2
No files matched your search
@@ -0,0 +1,44 @@
|
||||
//! Struct types without a name. GLSL lets a declaration define its struct type in place without
|
||||
//! naming it (GLSL 4.60, 4.1.8: `shared struct { uint sum; uint tile[64]; } lds;`); naga's
|
||||
//! frontend wants a name there ("Expected identifier, found LeftBrace"). Each such type gets
|
||||
//! one, `hz_struct<n>`; nothing else changes.
|
||||
|
||||
use super::scan::significant;
|
||||
use crate::macros::lex;
|
||||
|
||||
/// `code` with a name for each struct type declared without one, or `None` when it has none.
|
||||
pub(super) fn name(code: &str) -> Option<String> {
|
||||
let tokens = lex(code);
|
||||
let mut out = String::with_capacity(code.len() + 64);
|
||||
let mut named = 0;
|
||||
for (i, t) in tokens.iter().enumerate() {
|
||||
out.push_str(t);
|
||||
let opens = (i + 1..tokens.len())
|
||||
.find(|&j| significant(tokens[j]))
|
||||
.is_some_and(|j| tokens[j] == "{");
|
||||
if *t == "struct" && opens {
|
||||
out.push_str(&format!(" hz_struct{named}"));
|
||||
named += 1;
|
||||
}
|
||||
}
|
||||
(named > 0).then_some(out)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::name;
|
||||
|
||||
#[test]
|
||||
fn struct_types_without_a_name_get_one() {
|
||||
let code = "shared struct {\n uint sum;\n} lds;\nstruct Light { vec3 c; };\n\
|
||||
struct\n{ float a; } x, y[2];\n";
|
||||
assert_eq!(
|
||||
name(code).as_deref(),
|
||||
Some(
|
||||
"shared struct hz_struct0 {\n uint sum;\n} lds;\nstruct Light { vec3 c; };\n\
|
||||
struct hz_struct1\n{ float a; } x, y[2];\n"
|
||||
)
|
||||
);
|
||||
assert_eq!(name("struct Light { vec3 c; };\n"), None);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ use naga::valid::{Capabilities, ValidationFlags, Validator};
|
||||
|
||||
use crate::Preprocessed;
|
||||
|
||||
mod anonymous_structs;
|
||||
mod atomic_vectors;
|
||||
mod geometry;
|
||||
mod image_parameters;
|
||||
@@ -239,9 +240,14 @@ fn translate(
|
||||
} else {
|
||||
GBUFFERS_MATRICES.to_owned()
|
||||
};
|
||||
// Interface blocks travel as plain varyings (`interface_blocks`).
|
||||
// Struct types without a name get one (`anonymous_structs`), and interface blocks travel
|
||||
// as plain varyings (`interface_blocks`).
|
||||
let flat = |pp: &Preprocessed| {
|
||||
interface_blocks::flatten(&pp.code).map(|code| Preprocessed { code, ..pp.clone() })
|
||||
let named = anonymous_structs::name(&pp.code);
|
||||
let code = named.as_deref().unwrap_or(&pp.code);
|
||||
interface_blocks::flatten(code)
|
||||
.or(named)
|
||||
.map(|code| Preprocessed { code, ..pp.clone() })
|
||||
};
|
||||
let (vertex_flat, fragment_flat) = (flat(vertex), flat(fragment));
|
||||
let vertex = vertex_flat.as_ref().unwrap_or(vertex);
|
||||
@@ -625,6 +631,11 @@ fn resources(
|
||||
|
||||
/// Translates a compute program (`.csh`).
|
||||
pub fn translate_compute(compute: &Preprocessed) -> Result<ComputeProgram, Vec<Error>> {
|
||||
let named = anonymous_structs::name(&compute.code).map(|code| Preprocessed {
|
||||
code,
|
||||
..compute.clone()
|
||||
});
|
||||
let compute = named.as_ref().unwrap_or(compute);
|
||||
let split = atomic_vectors::rewrite(compute);
|
||||
let compute = split.as_ref().unwrap_or(compute);
|
||||
let mut c = Stage::scan(compute, ShaderStage::Compute);
|
||||
@@ -2157,6 +2168,20 @@ mod tests {
|
||||
}));
|
||||
}
|
||||
|
||||
/// A `shared` variable whose struct type has no name (GLSL 4.60, 4.1.8), as compute
|
||||
/// programs keep their work group's tiles.
|
||||
#[test]
|
||||
fn a_shared_struct_without_a_type_name_compiles() {
|
||||
let csh = "#version 460\nlayout(local_size_x = 8, local_size_y = 8) in;\n\
|
||||
shared struct {\n uint sum;\n uint tile[gl_WorkGroupSize.x][gl_WorkGroupSize.y];\n} lds;\n\
|
||||
layout(r32ui) uniform uimage2D colorimg4;\nvoid main() {\n \
|
||||
lds.tile[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = gl_LocalInvocationIndex;\n \
|
||||
barrier();\n imageStore(colorimg4, ivec2(gl_GlobalInvocationID.xy), uvec4(lds.tile[1][1]));\n}\n";
|
||||
let pack = Pack::from_zip_bytes("P.zip", zip(&[("shaders/deferred_a.csh", csh)])).unwrap();
|
||||
translate_compute(&preprocess(&pack, "deferred_a.csh", &Macros::standard()))
|
||||
.unwrap_or_else(|e| panic!("{e:?}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_blocks_bind_at_their_binding() {
|
||||
let csh = "#version 430\nlayout(local_size_x = 1) in;\n\
|
||||
|
||||
Reference in new issue
Block a user