diff --git a/lp-gfx/lp-gfx-wgpu/src/assembly.rs b/lp-gfx/lp-gfx-wgpu/src/assembly.rs index 41e9be636..c6ae6847f 100644 --- a/lp-gfx/lp-gfx-wgpu/src/assembly.rs +++ b/lp-gfx/lp-gfx-wgpu/src/assembly.rs @@ -10,15 +10,22 @@ //! (dependency) order. Driving naga `glsl-in` directly means `lpfn_` is //! not a reserved prefix here, so the prelude functions resolve as plain //! local GLSL functions with canonical float semantics; -//! 2. **generated prototypes** for every authored function — naga `glsl-in` +//! 2. **hoisted signature dependencies** ([`hoist_declarations`]) — the +//! authored top-level `struct` definitions and `const` declarations, +//! moved above the generated prototypes so signatures referencing them +//! (`Point make_point(float)`, `float f(float a[N])`) resolve; authored +//! function prototypes are stripped in the same pass (the generated +//! prototype set below covers every defined function, and naga rejects +//! duplicate prototypes); +//! 3. **generated prototypes** for every authored function — naga `glsl-in` //! resolves calls in source order (declaration-before-use), while the //! engine's `lps-glsl` frontend accepts out-of-order definitions, so //! authored content may rely on it; -//! 3. **texture call lowering** ([`crate::texture_lowering`]) — every +//! 4. **texture call lowering** ([`crate::texture_lowering`]) — every //! `texture()` / `texelFetch()` site on a spec'd sampler is rewritten to //! a generated helper implementing the CPU tier's sampling semantics //! (index-space wrap, `texelFetch` edge clamp) over `textureLoad`; -//! 4. a **generated fragment `main()`** wrapping +//! 5. a **generated fragment `main()`** wrapping //! `render(floor(gl_FragCoord.xy))` — matching the CPU path's `pos` //! convention (the synthesised render-texture loop passes integer pixel //! coordinates without a half-pixel offset). @@ -49,13 +56,15 @@ pub fn assemble_fragment_glsl( textures: &TextureBindingSpecs, ) -> Result { let lowered = lower_texture_calls(authored, textures)?; + let (hoisted, remainder) = hoist_declarations(&lowered.rewritten); let mut out = String::from("#version 450 core\n"); out.push_str(&assemble_prelude(authored)); + out.push_str(&hoisted); out.push_str(&lowered.shared_helpers); out.push_str(&lowered.helper_prototypes); out.push_str(&authored_prototypes(authored)); - out.push_str(&lowered.rewritten); + out.push_str(&remainder); // Helper definitions come after the authored text so the sampler // uniform declarations they reference are already in scope for naga's // declaration-before-use resolution (call sites resolve through the @@ -178,6 +187,110 @@ pub fn authored_prototypes(authored: &str) -> String { out } +/// Split out the top-level declarations that must precede the generated +/// prototypes: `struct` definitions and `const` declarations (prototype +/// signatures may reference the types and array sizes they define). +/// Authored function prototypes are stripped in the same pass — the +/// generated prototype set covers every defined function in callee-first +/// order, and naga rejects duplicate prototypes. (Merely *skipping* +/// generation for authored-prototyped functions would not do: their arena +/// slot would then be assigned at the authored prototype's position, after +/// every generated prototype, breaking callee-first order for their +/// callers.) +/// +/// Returns `(hoisted, remainder)`: the hoisted declarations concatenated in +/// source order, and `src` with the hoisted and stripped spans blanked +/// (newlines preserved, so diagnostics keep their line numbers). +pub fn hoist_declarations(src: &str) -> (String, String) { + let clean = strip_comments_and_directives(src); + let (hoist, strip) = hoist_and_strip_spans(&clean); + + let mut hoisted = String::new(); + for span in &hoist { + hoisted.push_str(src[span.clone()].trim_end()); + hoisted.push('\n'); + } + let mut remainder = src.as_bytes().to_vec(); + for span in hoist.iter().chain(strip.iter()) { + for b in &mut remainder[span.clone()] { + if *b != b'\n' { + *b = b' '; + } + } + } + let remainder = + String::from_utf8(remainder).expect("blanking replaces bytes with ASCII spaces"); + (hoisted, remainder) +} + +/// Scan comment-stripped source for top-level spans to hoist (struct/const +/// declarations) and to strip (authored function prototypes). Spans are +/// byte ranges valid in the original source (comment stripping is +/// byte-for-byte). +fn hoist_and_strip_spans( + clean: &str, +) -> (Vec>, Vec>) { + let bytes = clean.as_bytes(); + let mut hoist = Vec::new(); + let mut strip = Vec::new(); + let mut depth = 0usize; + let mut stmt_start = 0usize; + // Start of a struct/const statement whose terminating `;` is pending + // (its braced body — struct members or an initializer list — spans one + // or more `{}` groups before the semicolon). + let mut hoist_pending: Option = None; + for (i, &b) in bytes.iter().enumerate() { + match b { + b'{' => { + if depth == 0 && hoist_pending.is_none() { + let raw = &clean[stmt_start..i]; + let segment = raw.trim_start(); + if starts_with_keyword(segment, "struct") + || starts_with_keyword(segment, "const") + { + hoist_pending = Some(stmt_start + (raw.len() - segment.len())); + } + } + depth += 1; + } + b'}' => { + depth = depth.saturating_sub(1); + if depth == 0 && hoist_pending.is_none() { + stmt_start = i + 1; + } + } + b';' if depth == 0 => { + if let Some(start) = hoist_pending.take() { + hoist.push(start..i + 1); + } else { + let raw = &clean[stmt_start..i]; + let start = stmt_start + (raw.len() - raw.trim_start().len()); + let segment = raw.trim(); + if starts_with_keyword(segment, "struct") + || starts_with_keyword(segment, "const") + { + hoist.push(start..i + 1); + } else if !segment.contains('=') && function_signature(segment).is_some() { + // A `;`-terminated function signature with no + // initializer is an authored prototype (the `=` + // guard keeps globals like `float x = f(1.0);`). + strip.push(start..i + 1); + } + } + stmt_start = i + 1; + } + _ => {} + } + } + (hoist, strip) +} + +/// True when `s` starts with `keyword` at an identifier boundary. +fn starts_with_keyword(s: &str, keyword: &str) -> bool { + s.strip_prefix(keyword) + .is_some_and(|rest| rest.as_bytes().first().is_none_or(|&b| !is_ident_byte(b))) +} + /// One top-level function definition found in comment-stripped source. struct AuthoredFunction { name: String, @@ -489,6 +602,67 @@ float f(float x) { return x; } ); } + #[test] + fn hoists_structs_and_consts_above_prototypes() { + let authored = r#" +const int N = 2; +vec4 render(vec2 pos) { Point p = make_point(pos.x); return vec4(p.x); } +struct Point { float x; float y; }; +Point make_point(float x) { return Point(x, x); } +float sum(float arr[N]) { return arr[0] + arr[1]; } +"#; + let unit = + assemble_fragment_glsl(authored, &TextureBindingSpecs::new()).expect("assembles"); + let struct_at = unit.find("struct Point").expect("struct hoisted"); + let const_at = unit.find("const int N = 2;").expect("const hoisted"); + let proto_at = unit.find("Point make_point(float x);").expect("prototype"); + assert!(struct_at < proto_at && const_at < proto_at); + assert!(unit.contains("float sum(float arr[N]);")); + // Hoisted, not duplicated. + assert_eq!(unit.matches("struct Point").count(), 1); + assert_eq!(unit.matches("const int N").count(), 1); + } + + #[test] + fn strips_authored_prototypes_but_not_globals() { + let authored = "float helper(float x);\n\ + float scale = 2.0;\n\ + vec4 render(vec2 pos) { return vec4(helper(pos.x)); }\n\ + float helper(float x) { return x * scale; }\n"; + let unit = + assemble_fragment_glsl(authored, &TextureBindingSpecs::new()).expect("assembles"); + // Only the generated prototype survives (naga rejects duplicates), + // and it precedes render's per callee-first ordering. + assert_eq!(unit.matches("float helper(float x);").count(), 1); + let helper_proto = unit.find("float helper(float x);").expect("prototype"); + let render_proto = unit.find("vec4 render(vec2 pos);").expect("prototype"); + assert!(helper_proto < render_proto); + assert!(unit.contains("float scale = 2.0;")); + } + + #[test] + fn hoist_preserves_line_count_in_remainder() { + let src = "struct P { float x; };\nconst int N = 1;\nfloat f(float a);\nfloat f(float a) { return a; }\n"; + let (hoisted, remainder) = hoist_declarations(src); + assert!(hoisted.contains("struct P")); + assert!(hoisted.contains("const int N = 1;")); + assert!(!remainder.contains("struct P")); + assert!(!remainder.contains("float f(float a);")); + assert!(remainder.contains("float f(float a) { return a; }")); + assert_eq!(src.lines().count(), remainder.lines().count()); + } + + #[test] + fn hoist_strips_struct_returning_prototypes() { + let src = "struct Point { float x; };\n\ + Point make_point(float x);\n\ + Point make_point(float x) { return Point(x); }\n"; + let (hoisted, remainder) = hoist_declarations(src); + assert!(hoisted.contains("struct Point")); + assert!(!remainder.contains("Point make_point(float x);")); + assert!(remainder.contains("Point make_point(float x) {")); + } + #[test] fn assembled_unit_has_version_prelude_prototypes_and_wrapper() { let authored = "layout(binding = 0) uniform vec2 outputSize;\n\ diff --git a/lp-gfx/lp-gfx-wgpu/tests/util/reference.rs b/lp-gfx/lp-gfx-wgpu/tests/util/reference.rs index e9946af2d..316486e32 100644 --- a/lp-gfx/lp-gfx-wgpu/tests/util/reference.rs +++ b/lp-gfx/lp-gfx-wgpu/tests/util/reference.rs @@ -4,7 +4,7 @@ use std::time::{Duration, Instant}; -use lp_gfx_wgpu::assembly::authored_prototypes; +use lp_gfx_wgpu::assembly::{authored_prototypes, hoist_declarations}; use lp_shader::{CompilePxDesc, LpsEngine, LpsPxShader, ShaderFrontend, TextureBuffer}; use lps_shared::{LpsValueF32, TextureStorageFormat}; use lpvm_wasm::WasmOptions; @@ -36,12 +36,14 @@ impl ReferenceRenderer { /// the device compile path: `lpfn_*` calls resolve to the Q32 builtin /// impls) at the default device Q32 config. /// - /// Prototypes are spliced ahead of the source for the same reason as on - /// the GPU path: naga glsl-in resolves calls in source order (the spike - /// hand-declared `worley_demo` for basic2; here the production - /// prototype generator covers every authored function). + /// Struct/const declarations are hoisted and prototypes spliced ahead + /// of the source for the same reason as on the GPU path: naga glsl-in + /// resolves calls in source order (the spike hand-declared + /// `worley_demo` for basic2; here the production hoist + prototype + /// generator covers every authored declaration). pub fn compile(&self, shader: &CorpusShader) -> Result { - let source = format!("{}{}", authored_prototypes(shader.source), shader.source); + let (hoisted, remainder) = hoist_declarations(shader.source); + let source = format!("{hoisted}{}{remainder}", authored_prototypes(shader.source)); let start = Instant::now(); let compiled = self .engine diff --git a/lp-shader/lps-filetests/filetests/array/of-struct/inout-param.glsl b/lp-shader/lps-filetests/filetests/array/of-struct/inout-param.glsl index 82f0d92e4..9372da338 100644 --- a/lp-shader/lps-filetests/filetests/array/of-struct/inout-param.glsl +++ b/lp-shader/lps-filetests/filetests/array/of-struct/inout-param.glsl @@ -18,6 +18,4 @@ vec2 test_aos_inout_param() { return vec2(ps[0].x, ps[0].y); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_aos_inout_param() ~= vec2(10.0, 20.0) diff --git a/lp-shader/lps-filetests/filetests/array/of-struct/out-param.glsl b/lp-shader/lps-filetests/filetests/array/of-struct/out-param.glsl index a3feb2dfc..6ec7ce598 100644 --- a/lp-shader/lps-filetests/filetests/array/of-struct/out-param.glsl +++ b/lp-shader/lps-filetests/filetests/array/of-struct/out-param.glsl @@ -15,6 +15,4 @@ vec2 test_aos_out_param() { return vec2(ps[0].x, ps[0].y); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_aos_out_param() ~= vec2(30.0, 40.0) diff --git a/lp-shader/lps-filetests/filetests/const/array-size/param.glsl b/lp-shader/lps-filetests/filetests/const/array-size/param.glsl index 97a878242..9acb4ca4c 100644 --- a/lp-shader/lps-filetests/filetests/const/array-size/param.glsl +++ b/lp-shader/lps-filetests/filetests/const/array-size/param.glsl @@ -19,7 +19,6 @@ float test_param_array_call() { return test_param_array(test_arr); } -// @unsupported(wgpu.f32) // run: test_param_array_call() == 0.0 vec2 test_nested_calls(vec2 arr[NESTED_SIZE]) { @@ -31,6 +30,4 @@ vec2 test_nested_calls_call() { return test_nested_calls(test_arr); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_nested_calls_call() ~= vec2(0.0, 0.0) diff --git a/lp-shader/lps-filetests/filetests/function/access-lvalue-local-out-inout.glsl b/lp-shader/lps-filetests/filetests/function/access-lvalue-local-out-inout.glsl index 108003a48..5e59ee804 100644 --- a/lp-shader/lps-filetests/filetests/function/access-lvalue-local-out-inout.glsl +++ b/lp-shader/lps-filetests/filetests/function/access-lvalue-local-out-inout.glsl @@ -11,6 +11,7 @@ float test_access_index_vector_lane_out() { return v[1]; } +// wgpu.f32: WGSL forbids taking the address of a vector component; naga wgsl-out emits `&v[i]` for vector-lane out/inout args, and the probe compiles the whole file per directive, so every directive fails (tracked follow-up) // @unsupported(wgpu.f32) // run: test_access_index_vector_lane_out() ~= 21.0 @@ -188,6 +189,5 @@ float test_pointer_arg_nested_struct_field_out() { return o.inner.value; } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) // @unsupported(wgpu.f32) // run: test_pointer_arg_nested_struct_field_out() ~= 7.0 diff --git a/lp-shader/lps-filetests/filetests/function/declare-prototype.glsl b/lp-shader/lps-filetests/filetests/function/declare-prototype.glsl index 9fe1fce79..6154ad8c3 100644 --- a/lp-shader/lps-filetests/filetests/function/declare-prototype.glsl +++ b/lp-shader/lps-filetests/filetests/function/declare-prototype.glsl @@ -18,7 +18,6 @@ float test_declare_prototype_simple() { return add_two_floats(3.0, 4.0); } -// @unsupported(wgpu.f32) // run: test_declare_prototype_simple() ~= 7.0 void test_declare_prototype_void(); @@ -29,7 +28,6 @@ void test_declare_prototype_void() { void_func(); } -// @unsupported(wgpu.f32) // run: test_declare_prototype_void() == 0.0 vec4 test_declare_prototype_vector(vec4 a, vec4 b); @@ -39,7 +37,6 @@ vec4 test_declare_prototype_vector(vec4 a, vec4 b) { return add_vectors(a, b); } -// @unsupported(wgpu.f32) // run: test_declare_prototype_vector(vec4(1.0), vec4(2.0)) ~= vec4(3.0) float test_declare_prototype_multiple(); @@ -51,8 +48,6 @@ float test_declare_prototype_multiple() { return multiply_by_two(5.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_declare_prototype_multiple() ~= 10.0 // ============================================================================ diff --git a/lp-shader/lps-filetests/filetests/function/edge-const-out-error.glsl b/lp-shader/lps-filetests/filetests/function/edge-const-out-error.glsl index 8c1c2f079..8c8648862 100644 --- a/lp-shader/lps-filetests/filetests/function/edge-const-out-error.glsl +++ b/lp-shader/lps-filetests/filetests/function/edge-const-out-error.glsl @@ -20,6 +20,7 @@ float test_edge_const_out_error() { return 1.0; } +// wgpu.f32: naga glsl-in rejects the `const in` parameter qualifier ("Expected Void, Struct or a type, found In"); the probe compiles the whole file per directive, so every directive fails (tracked follow-up) // @unsupported(wgpu.f32) // run: test_edge_const_out_error() ~= 1.0 @@ -113,6 +114,5 @@ float test_edge_const_struct() { return 5.0; } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) // @unsupported(wgpu.f32) // run: test_edge_const_struct() ~= 5.0 diff --git a/lp-shader/lps-filetests/filetests/function/edge-return-type-match.glsl b/lp-shader/lps-filetests/filetests/function/edge-return-type-match.glsl index 06e2ee0a8..7c41e3a5b 100644 --- a/lp-shader/lps-filetests/filetests/function/edge-return-type-match.glsl +++ b/lp-shader/lps-filetests/filetests/function/edge-return-type-match.glsl @@ -13,7 +13,6 @@ float test_edge_return_type_match_float() { return get_pi(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_match_float() ~= 3.14159 int get_answer() { @@ -25,7 +24,6 @@ int test_edge_return_type_match_int() { return get_answer(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_match_int() == 42 vec2 get_origin() { @@ -37,7 +35,6 @@ vec2 test_edge_return_type_match_vector() { return get_origin(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_match_vector() ~= vec2(0.0, 0.0) void do_nothing() { @@ -49,7 +46,6 @@ void test_edge_return_type_match_void() { do_nothing(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_match_void() == 0.0 /* @@ -73,7 +69,6 @@ float test_edge_return_type_convertible() { return int_to_float(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_convertible() ~= 42.0 /* @@ -97,7 +92,6 @@ float test_edge_return_type_array() { return arr[0] + arr[1] + arr[2]; } -// @unsupported(wgpu.f32) // run: test_edge_return_type_array() ~= 6.0 /* @@ -125,7 +119,6 @@ Point test_edge_return_type_struct() { return p; } -// @unsupported(wgpu.f32) // run: test_edge_return_type_struct() ~= Point(1.0, 2.0) mat2 get_identity() { @@ -137,7 +130,6 @@ mat2 test_edge_return_type_matrix() { return get_identity(); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_matrix() ~= mat2(1.0, 0.0, 0.0, 1.0) bool is_even(int x) { @@ -149,7 +141,6 @@ bool test_edge_return_type_bool() { return is_even(4); } -// @unsupported(wgpu.f32) // run: test_edge_return_type_bool() == true float absolute_value(float x) { @@ -165,6 +156,4 @@ float test_edge_return_type_multiple_returns() { return absolute_value(-5.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_edge_return_type_multiple_returns() ~= 5.0 diff --git a/lp-shader/lps-filetests/filetests/function/forward-declare.glsl b/lp-shader/lps-filetests/filetests/function/forward-declare.glsl index bdb4f6cd0..e7115730d 100644 --- a/lp-shader/lps-filetests/filetests/function/forward-declare.glsl +++ b/lp-shader/lps-filetests/filetests/function/forward-declare.glsl @@ -14,7 +14,6 @@ float test_forward_declare_simple() { return compute_area(4.0, 5.0); } -// @unsupported(wgpu.f32) // run: test_forward_declare_simple() ~= 20.0 vec2 test_forward_declare_vector() { @@ -24,7 +23,6 @@ vec2 test_forward_declare_vector() { return transform_point(point, transform); } -// @unsupported(wgpu.f32) // run: test_forward_declare_vector() ~= vec2(1.0, 2.0) void test_forward_declare_array() { @@ -34,7 +32,6 @@ void test_forward_declare_array() { // Data should be initialized to [1.0, 2.0, 3.0] } -// @unsupported(wgpu.f32) // run: test_forward_declare_array() == 0.0 float test_forward_declare_multiple_calls() { @@ -44,7 +41,6 @@ float test_forward_declare_multiple_calls() { return area1 + area2; } -// @unsupported(wgpu.f32) // run: test_forward_declare_multiple_calls() ~= 36.0 float test_forward_declare_in_expression() { @@ -52,7 +48,6 @@ float test_forward_declare_in_expression() { return compute_area(3.0, 4.0) * 2.0; } -// @unsupported(wgpu.f32) // run: test_forward_declare_in_expression() ~= 24.0 // Multiple identical prototypes: valid in GLSL, but our parser rejects duplicates in one file. @@ -62,7 +57,6 @@ float test_forward_declare_duplicate() { return add_numbers(7.0, 8.0); } -// @unsupported(wgpu.f32) // run: test_forward_declare_duplicate() ~= 15.0 // Forward declaration with different parameter names (OK) @@ -73,8 +67,6 @@ vec2 test_forward_declare_different_names() { return scale_vector(v, 2.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_forward_declare_different_names() ~= vec2(4.0, 6.0) // ============================================================================ diff --git a/lp-shader/lps-filetests/filetests/function/param-default-in.glsl b/lp-shader/lps-filetests/filetests/function/param-default-in.glsl index b0cb30310..2484fa623 100644 --- a/lp-shader/lps-filetests/filetests/function/param-default-in.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-default-in.glsl @@ -13,7 +13,6 @@ float test_param_default_explicit_in() { return add_explicit(2.0, 3.0); } -// @unsupported(wgpu.f32) // run: test_param_default_explicit_in() ~= 5.0 float add_implicit(float a, float b) { @@ -25,7 +24,6 @@ float test_param_default_implicit_in() { return add_implicit(2.0, 3.0); } -// @unsupported(wgpu.f32) // run: test_param_default_implicit_in() ~= 5.0 float process(in float a, float b, in float c) { @@ -37,7 +35,6 @@ float test_param_default_mixed() { return process(1.0, 2.0, 3.0); } -// @unsupported(wgpu.f32) // run: test_param_default_mixed() ~= 6.0 vec2 combine_vectors(vec2 a, vec2 b) { @@ -49,7 +46,6 @@ float test_param_default_vector() { return length(combine_vectors(vec2(1.0, 2.0), vec2(3.0, 4.0))); } -// @unsupported(wgpu.f32) // run: test_param_default_vector() ~= 7.2111 int multiply(int x, int y) { @@ -61,7 +57,6 @@ int test_param_default_int() { return multiply(6, 7); } -// @unsupported(wgpu.f32) // run: test_param_default_int() == 42 bool logical_and(bool a, bool b) { @@ -73,7 +68,6 @@ bool test_param_default_bool() { return logical_and(true, true); } -// @unsupported(wgpu.f32) // run: test_param_default_bool() == true float modify_local(float x) { @@ -88,7 +82,6 @@ float test_param_default_modification() { return result; // Should be 15.0, original unchanged } -// @unsupported(wgpu.f32) // run: test_param_default_modification() ~= 15.0 mat2 multiply_matrices(mat2 a, mat2 b) { @@ -103,7 +96,6 @@ mat2 test_param_default_matrix() { return result; } -// @unsupported(wgpu.f32) // run: test_param_default_matrix() ~= mat2(2.0, 4.0, 6.0, 8.0) float sum_elements(float[3] arr) { @@ -116,7 +108,6 @@ float test_param_default_array() { return sum_elements(data); } -// @unsupported(wgpu.f32) // run: test_param_default_array() ~= 6.0 struct Point { @@ -133,6 +124,4 @@ Point test_param_default_struct() { return move_point(p, 3.0, 4.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_default_struct() ~= Point(4.0, 6.0) diff --git a/lp-shader/lps-filetests/filetests/function/param-struct.glsl b/lp-shader/lps-filetests/filetests/function/param-struct.glsl index 3046a1187..ebf947174 100644 --- a/lp-shader/lps-filetests/filetests/function/param-struct.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-struct.glsl @@ -28,7 +28,6 @@ float test_param_struct_simple() { return distance_from_origin(origin); } -// @unsupported(wgpu.f32) // run: test_param_struct_simple() ~= 5.0 void move_point(inout Point p, float dx, float dy) { @@ -43,7 +42,6 @@ void test_param_struct_modify() { // p should now be (6.0, 5.0) } -// @unsupported(wgpu.f32) // run: test_param_struct_modify() == 0.0 float circle_area(Circle c) { @@ -56,7 +54,6 @@ float test_param_struct_nested() { return circle_area(circle); } -// @unsupported(wgpu.f32) // run: test_param_struct_nested() ~= 12.56636 Color blend_colors(Color c1, Color c2, float factor) { @@ -70,7 +67,6 @@ Color test_param_struct_return() { return blend_colors(red, blue, 0.5); } -// @unsupported(wgpu.f32) // run: test_param_struct_return() ~= Color(vec3(0.5, 0.0, 0.5), 0.9) void create_circle(out Circle c, Point center, float radius) { @@ -85,7 +81,6 @@ void test_param_struct_out() { // circle should be properly initialized } -// @unsupported(wgpu.f32) // run: test_param_struct_out() == 0.0 float get_alpha(const Color c) { @@ -98,7 +93,6 @@ float test_param_struct_const() { return get_alpha(color); } -// @unsupported(wgpu.f32) // run: test_param_struct_const() ~= 0.7 void process_circle(in Circle input, out Circle output, inout Point center) { @@ -117,7 +111,6 @@ float test_param_struct_mixed_qualifiers() { return out_circle.radius + center.x + center.y; // 6.0 + 11.0 + 11.0 = 28.0 } -// @unsupported(wgpu.f32) // run: test_param_struct_mixed_qualifiers() ~= 28.0 struct Triangle { @@ -141,6 +134,4 @@ float test_param_struct_complex() { return triangle_perimeter(triangle); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_struct_complex() ~= 12.0 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/bool.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/bool.glsl index 4fa59d671..6a87af1c7 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/bool.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/bool.glsl @@ -10,6 +10,4 @@ bool test_param_unnamed_bool() { return both_true(true, false); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_bool() == false diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/compute.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/compute.glsl index 2e42bac1b..af589744e 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/compute.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/compute.glsl @@ -10,6 +10,4 @@ float test_param_unnamed_all_unnamed() { return compute(2.0, 3.0, 4.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_all_unnamed() ~= 10.0 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/forward.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/forward.glsl index 32c9c7838..363bb1a85 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/forward.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/forward.glsl @@ -17,6 +17,4 @@ float test_param_unnamed_forward_declare() { return result1 + result2; } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_forward_declare() ~= 16.0 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/int.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/int.glsl index c7925d984..0c501037e 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/int.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/int.glsl @@ -10,6 +10,4 @@ int test_param_unnamed_int() { return max_value(5, 8); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_int() == 8 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/mixed.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/mixed.glsl index f8fd8561e..c1f3c444b 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/mixed.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/mixed.glsl @@ -14,6 +14,4 @@ float test_param_unnamed_mixed() { return multiply(2.0, 3); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_mixed() ~= 8.0 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/simple.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/simple.glsl index 66a510b42..a3dc1d9db 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/simple.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/simple.glsl @@ -13,6 +13,4 @@ float test_param_unnamed_simple() { return add(3.0, 4.0); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_simple() ~= 7.0 diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/vector.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/vector.glsl index 6328d7e10..8b683a144 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/vector.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/vector.glsl @@ -10,6 +10,4 @@ vec2 test_param_unnamed_vector() { return combine(vec2(1.0, 2.0), vec2(3.0, 4.0)); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_vector() ~= vec2(4.0, 6.0) diff --git a/lp-shader/lps-filetests/filetests/function/param-unnamed/void.glsl b/lp-shader/lps-filetests/filetests/function/param-unnamed/void.glsl index 3c43fa1f5..c2ef287e3 100644 --- a/lp-shader/lps-filetests/filetests/function/param-unnamed/void.glsl +++ b/lp-shader/lps-filetests/filetests/function/param-unnamed/void.glsl @@ -8,6 +8,4 @@ void test_param_unnamed_void() { process(5.0, 3); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_param_unnamed_void() == 0.0 diff --git a/lp-shader/lps-filetests/filetests/function/return-struct.glsl b/lp-shader/lps-filetests/filetests/function/return-struct.glsl index 83d2030eb..dcff6f968 100644 --- a/lp-shader/lps-filetests/filetests/function/return-struct.glsl +++ b/lp-shader/lps-filetests/filetests/function/return-struct.glsl @@ -29,7 +29,6 @@ Point2D test_return_struct_simple() { return get_origin(); } -// @unsupported(wgpu.f32) // run: test_return_struct_simple() ~= Point2D(0.0, 0.0) Color get_red() { @@ -41,7 +40,6 @@ Color test_return_struct_color() { return get_red(); } -// @unsupported(wgpu.f32) // run: test_return_struct_color() ~= Color(vec3(1.0, 0.0, 0.0), 1.0) Point2D add_points(Point2D p1, Point2D p2) { @@ -55,7 +53,6 @@ Point2D test_return_struct_calculated() { return add_points(a, b); } -// @unsupported(wgpu.f32) // run: test_return_struct_calculated() ~= Point2D(4.0, 6.0) Color blend_colors(Color c1, Color c2, float factor) { @@ -71,7 +68,6 @@ Color test_return_struct_mixed() { return blend_colors(red, blue, 0.5); } -// @unsupported(wgpu.f32) // run: test_return_struct_mixed() ~= Color(vec3(0.5, 0.0, 0.5), 0.9) Triangle get_equilateral_triangle(float side) { @@ -88,7 +84,6 @@ Triangle test_return_struct_nested() { return get_equilateral_triangle(2.0); } -// @unsupported(wgpu.f32) // run: test_return_struct_nested() ~= Triangle(Point2D(0.0, 0.0), Point2D(2.0, 0.0), Point2D(1.0, 1.732)) Point2D scale_point(Point2D p, float scale) { @@ -101,7 +96,6 @@ Point2D test_return_struct_modified() { return scale_point(original, 2.0); } -// @unsupported(wgpu.f32) // run: test_return_struct_modified() ~= Point2D(6.0, 8.0) Color make_color(float r, float g, float b) { @@ -113,7 +107,6 @@ Color test_return_struct_constructor() { return make_color(0.5, 0.7, 0.9); } -// @unsupported(wgpu.f32) // run: test_return_struct_constructor() ~= Color(vec3(0.5, 0.7, 0.9), 1.0) struct Vector3D { @@ -129,6 +122,4 @@ Vector3D test_return_struct_compact() { return get_up_vector(); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_return_struct_compact() ~= Vector3D(0.0, 1.0, 0.0) diff --git a/lp-shader/lps-filetests/filetests/function/scope-local.glsl b/lp-shader/lps-filetests/filetests/function/scope-local.glsl index e71f8e45e..5844bcd82 100644 --- a/lp-shader/lps-filetests/filetests/function/scope-local.glsl +++ b/lp-shader/lps-filetests/filetests/function/scope-local.glsl @@ -16,7 +16,6 @@ float test_scope_local_simple() { return local_func(); } -// @unsupported(wgpu.f32) // run: test_scope_local_simple() ~= 42.0 float access_global() { @@ -29,7 +28,6 @@ float test_scope_local_shadow_global() { return access_global(); } -// @unsupported(wgpu.f32) // run: test_scope_local_shadow_global() ~= 200.0 float process_locals() { @@ -44,7 +42,6 @@ float test_scope_local_multiple() { return process_locals(); } -// @unsupported(wgpu.f32) // run: test_scope_local_multiple() ~= 3.0 float sum_loop(int n) { @@ -61,7 +58,6 @@ float test_scope_local_in_loop() { return sum_loop(5); } -// @unsupported(wgpu.f32) // run: test_scope_local_in_loop() ~= 10.0 float inner_func() { @@ -79,7 +75,6 @@ float test_scope_local_nested() { return outer_func(); } -// @unsupported(wgpu.f32) // run: test_scope_local_nested() ~= 30.0 float use_params(float param1, float param2) { @@ -92,7 +87,6 @@ float test_scope_local_parameters() { return use_params(2.0, 3.0); } -// @unsupported(wgpu.f32) // run: test_scope_local_parameters() ~= 13.0 float mixed_types() { @@ -109,7 +103,6 @@ float test_scope_local_types() { return mixed_types(); } -// @unsupported(wgpu.f32) // run: test_scope_local_types() ~= 12.14 float sum_local_array() { @@ -122,7 +115,6 @@ float test_scope_local_arrays() { return sum_local_array(); } -// @unsupported(wgpu.f32) // run: test_scope_local_arrays() ~= 6.0 struct LocalStruct { @@ -139,7 +131,6 @@ LocalStruct test_scope_local_struct() { return create_local_struct(); } -// @unsupported(wgpu.f32) // run: test_scope_local_struct() ~= LocalStruct(5.0, 10.0) float modify_local() { @@ -154,6 +145,4 @@ float test_scope_local_modification() { return modify_local(); } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_scope_local_modification() ~= 13.0 diff --git a/lp-shader/lps-filetests/filetests/lps-glsl/basic2-render.glsl b/lp-shader/lps-filetests/filetests/lps-glsl/basic2-render.glsl index 24e940a66..e3733ce59 100644 --- a/lp-shader/lps-filetests/filetests/lps-glsl/basic2-render.glsl +++ b/lp-shader/lps-filetests/filetests/lps-glsl/basic2-render.glsl @@ -40,6 +40,4 @@ vec4 worley_demo(vec2 scaledCoord, float time) { // run[q32]: render(vec2(4.0, 8.0)) ~= vec4(0.0, 0.14434814, 1.0, 1.0) (tolerance: 0.002) // set_uniform: outputSize = vec2(32.0, 32.0) // set_uniform: time = 1.25 -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run[f32]: render(vec2(4.0, 8.0)) ~= vec4(0.0, 0.14105844, 1.0, 1.0) (tolerance: 0.002) diff --git a/lp-shader/lps-filetests/filetests/struct/array-of-struct.glsl b/lp-shader/lps-filetests/filetests/struct/array-of-struct.glsl index 6521a1421..dc924dd33 100644 --- a/lp-shader/lps-filetests/filetests/struct/array-of-struct.glsl +++ b/lp-shader/lps-filetests/filetests/struct/array-of-struct.glsl @@ -30,7 +30,6 @@ float test_arrstruct_declare() { return 1.0; } -// @unsupported(wgpu.f32) // run: test_arrstruct_declare() == 1.0 float test_arrstruct_construct_literal() { @@ -38,7 +37,6 @@ float test_arrstruct_construct_literal() { return points[0].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_construct_literal() ~= 1.0 float test_arrstruct_construct_element_access() { @@ -46,7 +44,6 @@ float test_arrstruct_construct_element_access() { return points[2].y; } -// @unsupported(wgpu.f32) // run: test_arrstruct_construct_element_access() ~= 6.0 // ============================================================================ @@ -60,7 +57,6 @@ float test_arrstruct_read_scalar_member() { return points[1].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_read_scalar_member() ~= 30.0 float test_arrstruct_read_vector_member() { @@ -70,7 +66,6 @@ float test_arrstruct_read_vector_member() { return mats[0].shininess; } -// @unsupported(wgpu.f32) // run: test_arrstruct_read_vector_member() ~= 32.0 vec3 test_arrstruct_read_vec3_member() { @@ -79,7 +74,6 @@ vec3 test_arrstruct_read_vec3_member() { return mats[0].ambient; } -// @unsupported(wgpu.f32) // run: test_arrstruct_read_vec3_member() ~= vec3(0.1, 0.2, 0.3) // ============================================================================ @@ -94,7 +88,6 @@ float test_arrstruct_write_scalar_member() { return points[1].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_write_scalar_member() ~= 99.0 float test_arrstruct_write_vector_component() { @@ -105,7 +98,6 @@ float test_arrstruct_write_vector_component() { return mats[0].ambient.x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_write_vector_component() ~= 0.5 // ============================================================================ @@ -121,7 +113,6 @@ float test_arrstruct_element_assign() { return points[0].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_element_assign() ~= 3.0 // ============================================================================ @@ -136,11 +127,8 @@ float test_arrstruct_dynamic_index(int idx) { return points[idx].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_dynamic_index(0) ~= 10.0 -// @unsupported(wgpu.f32) // run: test_arrstruct_dynamic_index(1) ~= 20.0 -// @unsupported(wgpu.f32) // run: test_arrstruct_dynamic_index(2) ~= 30.0 // ============================================================================ @@ -160,7 +148,6 @@ float test_arrstruct_loop_sum() { return sum; } -// @unsupported(wgpu.f32) // run: test_arrstruct_loop_sum() ~= 6.0 // ============================================================================ @@ -179,7 +166,6 @@ float test_arrstruct_param_byval() { return sum_point_x_vals(points); } -// @unsupported(wgpu.f32) // run: test_arrstruct_param_byval() ~= 6.0 // ============================================================================ @@ -200,7 +186,6 @@ float test_arrstruct_return() { return pts[2].y; } -// @unsupported(wgpu.f32) // run: test_arrstruct_return() ~= 6.0 // ============================================================================ @@ -223,7 +208,6 @@ float test_arrstruct_inout() { return points[1].x; } -// @unsupported(wgpu.f32) // run: test_arrstruct_inout() ~= 6.0 // ============================================================================ @@ -245,7 +229,6 @@ float test_arrstruct_nested_struct_member() { return lines[1].by; } -// @unsupported(wgpu.f32) // run: test_arrstruct_nested_struct_member() ~= 8.0 float test_arrstruct_nested_deep_access() { @@ -256,7 +239,6 @@ float test_arrstruct_nested_deep_access() { return lines[1].bx; } -// @unsupported(wgpu.f32) // run: test_arrstruct_nested_deep_access() ~= 99.0 // ============================================================================ @@ -268,6 +250,4 @@ float test_arrstruct_zerofill() { return points[0].x; } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_arrstruct_zerofill() ~= 0.0 diff --git a/lp-shader/lps-filetests/filetests/struct/deep-nested.glsl b/lp-shader/lps-filetests/filetests/struct/deep-nested.glsl index 982adb53e..592f3eb88 100644 --- a/lp-shader/lps-filetests/filetests/struct/deep-nested.glsl +++ b/lp-shader/lps-filetests/filetests/struct/deep-nested.glsl @@ -60,7 +60,6 @@ float test_deep_declare_panel_grid() { return 1.0; } -// @unsupported(wgpu.f32) // run: test_deep_declare_panel_grid() ~= 1.0 float test_deep_construct_read_path_4level() { @@ -69,7 +68,6 @@ float test_deep_construct_read_path_4level() { return panel_grid.header.top.start.x; } -// @unsupported(wgpu.f32) // run: test_deep_construct_read_path_4level() ~= 0.0 float test_deep_path_read_tagged_header() { @@ -77,7 +75,6 @@ float test_deep_path_read_tagged_header() { return panel_grid.header.top.start.y; } -// @unsupported(wgpu.f32) // run: test_deep_path_read_tagged_header() ~= 10.0 float test_deep_path_read_content_bottom_end_x() { @@ -85,7 +82,6 @@ float test_deep_path_read_content_bottom_end_x() { return panel_grid.content.bottom.end.x; } -// @unsupported(wgpu.f32) // run: test_deep_path_read_content_bottom_end_x() ~= 1.0 float test_deep_path_write_content_top_end_y() { @@ -94,7 +90,6 @@ float test_deep_path_write_content_top_end_y() { return panel_grid.content.top.end.y; } -// @unsupported(wgpu.f32) // run: test_deep_path_write_content_top_end_y() ~= 100.0 float test_deep_path_write_footer_left_start_x() { @@ -103,7 +98,6 @@ float test_deep_path_write_footer_left_start_x() { return panel_grid.footer.left.start.x; } -// @unsupported(wgpu.f32) // run: test_deep_path_write_footer_left_start_x() ~= -3.5 // Same final shape as `panel_grid.header = replacement` after deep_mk_panel_grid(1,2,3). @@ -115,7 +109,6 @@ float test_deep_partial_assign_header_via_constructor() { return panel_grid.header.top.start.y; } -// @unsupported(wgpu.f32) // run: test_deep_partial_assign_header_via_constructor() ~= 7.0 float test_deep_read_after_header_construct_and_write() { @@ -125,7 +118,6 @@ float test_deep_read_after_header_construct_and_write() { return panel_grid.header.right.end.x; } -// @unsupported(wgpu.f32) // run: test_deep_read_after_header_construct_and_write() ~= 9.0 // --- Compact 4-level chain: Outer → Middle → Inner → Coord ------------------- @@ -151,7 +143,6 @@ float test_deep_chain_declare_outer() { return 1.0; } -// @unsupported(wgpu.f32) // run: test_deep_chain_declare_outer() ~= 1.0 float test_deep_chain_construct_read_4deep() { @@ -159,7 +150,6 @@ float test_deep_chain_construct_read_4deep() { return o.m.i.c.x; } -// @unsupported(wgpu.f32) // run: test_deep_chain_construct_read_4deep() ~= 5.0 float test_deep_chain_write_inner_coord() { @@ -168,7 +158,6 @@ float test_deep_chain_write_inner_coord() { return o.m.i.c.x; } -// @unsupported(wgpu.f32) // run: test_deep_chain_write_inner_coord() ~= 42.0 // `o.m = Middle(...)` hits nested aggregate assign (not phase 04); use whole-struct rebuild. @@ -177,7 +166,6 @@ float test_deep_chain_rebuild_outer_with_middle() { return o.m.i.c.x; } -// @unsupported(wgpu.f32) // run: test_deep_chain_rebuild_outer_with_middle() ~= 8.0 float test_deep_chain_whole_outer_assign() { @@ -187,7 +175,6 @@ float test_deep_chain_whole_outer_assign() { return a.m.i.c.x; } -// @unsupported(wgpu.f32) // run: test_deep_chain_whole_outer_assign() ~= 99.0 float test_deep_mixed_panel_grid_and_chain() { @@ -198,6 +185,4 @@ float test_deep_mixed_panel_grid_and_chain() { return a + b; } -// wgpu.f32: GPU assembly splices prototypes above the authored text; struct-typed signatures / authored prototypes break naga declaration order (tracked follow-up) -// @unsupported(wgpu.f32) // run: test_deep_mixed_panel_grid_and_chain() ~= 3.0