nx_wgsl_gate.nx
buildroot/runtime/nx_wgsl_gate.nx
about
nx_wgsl_gate.nx -- IS THE SHADER BACKEND REAL, OR A RUBBER STAMP?
SUBJECT: ./nx_wgsl.elf by default, or ./nx_wgsl.sov.elf.new with `staged`.
Both modes execute the actual binary; e2e fork, never an in-process re-derive -- an
in-process gate would prove the SOURCE compiles, not that the SHIPPED artifact behaves).
THE PRE-DECLARED ACCEPT RULE (written before the backend was built): the SAME NishiLang source
compiled to BOTH dialects must produce the SAME RESULT. On this box that cannot be proven at the
pixel level -- headless WebGPU wedges inside requestAdapter/createShaderModule (measured; it is
why nx_game_page_emit carries a GPU_BOOT_MS race at all) -- so equivalence is asserted at the
EMITTED-IR level and the pixel gap is DECLARED, never papered over:
* TRACE IDENTITY: each backend records the node ids it emits, in order. Two backends that
consumed the same source completely produce identical traces.
* NON-VACUITY: a module with one statement removed must NOT trace the same. Without this leg
trace identity would be satisfied by two backends that both emit nothing.
* REFUSAL: a construct outside the covered subset must refuse BY NAME. A silent
mistranslation in a shader backend compiles, links, runs, and draws the wrong picture.
* DIALECT SEPARATION: the GLSL output must carry GLSL's own spelling and the WGSL output
WGSL's -- proving each backend emitted its dialect rather than copying the other.
* SHIPPING EQUIVALENCE: the emitted GLSL must carry the same operators and operands as the
hand-written VSH that ships in nx_game_page_emit today, which is the migration reference.
* DECLARATION REFUSALS (S1, 2026-09-04): a texture-typed uniform, a K_ATTRIB and a fragment K_VARY
each REFUSE BY NAME in WGSL (they used to be emitted wrong with no refusal), and a scalar uniform
is still ADMITTED by the same pass -- the positive control a deny-guard must carry.
* UNIFORM QUALIFICATION (S2, 2026-09-04): WGSL reads a uniform as `u.<name>` (it lives in struct U),
GLSL reads it bare; a parameter or local of the same name shadows the uniform and stays bare in
both. Trace identity must survive a uniform being in play.
* TEXTURES ARE THEIR OWN KIND (S3, 2026-09-04): K_TEXTURE emits a @group/@binding var OUTSIDE struct U
in WGSL and a sampler uniform in GLSL, read bare in both; the deprecated texture-typed K_UNIFORM
refuses in BOTH dialects naming K_TEXTURE; texture_2d<f32> and a binding collision refuse by name.
* DERIVED FRAGMENT SIGNATURE (S4, 2026-09-04): a sir_param_position parameter yields
`@fragment fn main(@builtin(position) pos:vec4f)->@location(0) vec4f{` and GLSL reads it as gl_FragCoord;
zero parameters derive to the old literal exactly; a position READ with no declared parameter and a
plain (unbound) fragment parameter refuse by name -- an undeclared input is never a placeholder.
WHAT THIS GATE DOES NOT MEASURE, STATED SO IT CANNOT BE MISREAD: no tooth renders a frame.
GREEN here means the two dialects are emitted from one source and agree structurally. It does
NOT mean a GPU drew the same pixels from both. That is nx_wgsl_pixel_gate, and it is OWED.
dependencies 3 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nxnx_gatekit_lib.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 44 | const WGG_ELF: *u8 = "./nx_wgsl.elf" |
| 52 | const WGG_CAP: i64 = 1048576 |
| 57 | const WGG_PACKER_FLOATS: i64 = 96 |
| 58 | const WGG_PACKER_PAL_F: i64 = 28 |
| 59 | const WGG_PACKER_PALF_F: i64 = 76 |
| 60 | const WGG_FLOAT_BYTES: i64 = 4 |
| 64 | const WGG_R_TEXUNIFORM: *u8 = "texuniform_named=wgsl: texture-typed uniform" |
| 68 | const WGG_R_ATTRIB: *u8 = "attrib_named=wgsl: vertex attribute declaration (K_ATTRIB)" |
| 69 | const WGG_R_FRAGVARY: *u8 = "fragvary_named=wgsl: varying declaration (K_VARY) reached in a fragment stage" |
| 74 | const WGG_TEX_LAYOUT: *u8 = "struct U{\nscale:f32,\n}\n@group(0)@binding(0)var<uniform> u:U;\n@group(0)@binding(1)var vox:texture_3d<u32>;\n" |
| 75 | const WGG_TEX_WGSL_DECL: *u8 = "@group(0)@binding(1)var vox:texture_3d<u32>;\n" |
| 76 | const WGG_TEX_GLSL_DECL: *u8 = "uniform highp usampler3D vox;\n" |
| 77 | const WGG_TEX_WGSL_READ: *u8 = "return textureLoad(vox,vec3i(x,y,z),0).x;\n" |
| 78 | const WGG_TEX_GLSL_READ: *u8 = "return texelFetch(vox,ivec3(x,y,z),0).x;\n" |
| 79 | const WGG_R_TEXUNIFORM_GL: *u8 = "texuniform_glsl_named=glsl: texture-typed uniform" |
| 80 | const WGG_R_TEX2D_WG: *u8 = "tex2d_wgsl_named=wgsl: texture type outside the covered subset" |
| 81 | const WGG_R_TEX2D_GL: *u8 = "tex2d_glsl_named=glsl: texture type outside the covered subset" |
| 82 | const WGG_R_TEXCOLLIDE: *u8 = "texcollide_named=wgsl: derived texture binding collides" |
| 85 | const WGG_FRAGPOS_SIG: *u8 = "@fragment fn main(@builtin(position) pos:vec4f)->@location(0) vec4f{\n" |
| 86 | const WGG_FRAGPOS_WGSL_BODY: *u8 = "return vec4f(pos.x,pos.y,0.0,1.0);\n" |
| 87 | const WGG_FRAGPOS_GLSL_BODY: *u8 = "vec4(gl_FragCoord.x,gl_FragCoord.y,0.0,1.0)" |
| 88 | const WGG_FRAGCONST_SIG: *u8 = "@fragment fn main()->@location(0) vec4f{\n" |
| 89 | const WGG_R_FRAGUNDECL: *u8 = "fragundecl_named=wgsl: @builtin(position) read without a declared entry parameter" |
| 90 | const WGG_R_FRAGPLAIN_WG: *u8 = "fragplain_wgsl_named=wgsl: fragment entry parameter that is not the @builtin(position) input" |
| 91 | const WGG_R_FRAGPLAIN_GL: *u8 = "fragplain_glsl_named=glsl: entry-point parameter that is not the @builtin(position) input" |
| 98 | const WGG_FRAGOUT_GLSL: *u8 = "out vec4 fc;\nvoid main(){\nfc=vec4(1.0,0.0,0.0,1.0);\n}\n" |
| 99 | const WGG_FRAGOUT_GLSL_DECL: *u8 = "out vec4 fc;\n" |
| 101 | const WGG_FRAGOUT_WGSL: *u8 = "@fragment fn main()->@location(0) vec4f{\nreturn vec4f(1.0,0.0,0.0,1.0);\n}\n" |
| 103 | const WGG_FRAGLOC2_GLSL: *u8 = "layout(location=2) out vec4 fc;\n" |
| 104 | const WGG_FRAGLOC2_WGSL: *u8 = "@fragment fn main()->@location(2) vec4f{\n" |
| 106 | const WGG_FRAGDISCARD_WGSL: *u8 = "@fragment fn main(){\ndiscard;\n}\n" |
| 107 | const WGG_FRAGDISCARD_GLSL: *u8 = "void main(){\ndiscard;\n}\n" |
| 108 | const WGG_R_FRAGNOOUT_GL: *u8 = "fragnoout_glsl_named=glsl: fragment entry returns a value with no declared fragment output" |
| 109 | const WGG_R_FRAGNOOUT_WG: *u8 = "fragnoout_wgsl_named=wgsl: fragment entry returns a value with no declared fragment output" |
| 110 | const WGG_R_VERTFRAGOUT_GL: *u8 = "vertfragout_glsl_named=glsl: fragment output declaration (K_FRAGOUT) outside a fragment stage" |
| 111 | const WGG_R_VERTFRAGOUT_WG: *u8 = "vertfragout_wgsl_named=wgsl: fragment output declaration (K_FRAGOUT) outside a fragment stage" |
| 112 | const WGG_R_TWOOUT_GL: *u8 = "fragtwoout_glsl_named=glsl: more than one fragment output declared" |
| 113 | const WGG_R_TWOOUT_WG: *u8 = "fragtwoout_wgsl_named=wgsl: more than one fragment output declared" |
| 116 | const WGG_R_TEXSAMPLE_WG: *u8 = "texsample_wgsl_named=wgsl: sampled texture read (E_TEXSAMPLE)" |
| 117 | const WGG_TEXSAMPLE_GLSL: *u8 = "return texture(vox,uv);\n" |
| 201 | const WGG_C_TILDE: i64 = 126 |
| 202 | const WGG_C_BANG: i64 = 33 |
functions
| 119 | func wgg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 121 | func wgg_has(buf: *u8, n: i64, ned: *u8) -> i64 |
| 139 | func wgg_count(buf: *u8, n: i64, ned: *u8) -> i64 |
| 158 | func wgg_num_after(buf: *u8, n: i64, key: *u8) -> i64 |
| 203 | func wgg_bang(s: *u8) -> *u8 |
| 218 | func main(argc: i64, argv: *i64) -> i64 |