nx_wgsl_front_candidate_t217.nx
buildroot/runtime/nx_wgsl_front_candidate_t217.nx
about
nx_wgsl.nx -- THE SHADER BACKENDS: NishiLang in, GLSL and WGSL out.
CONTRACT SYMBOL: wgsl_emit_module (declared _ABSENT_ on the graphics compare board until now).
THE SOURCE IS NISHILANG, NOT GLSL (operator 2026-08-23). This organ is NOT a GLSL->WGSL
transpiler. A shader is authored ONCE against the nx_shader_ir representation; glsl_emit_module
and wgsl_emit_module are two BACKENDS over that one source, exactly as nx_compile_x86 and the
WAT lane are two backends over one NishiLang front-end. Neither dialect is authored, so neither
can drift from the other -- disagreement is impossible BY CONSTRUCTION rather than by discipline.
RUNG 1, SHIPPED HERE: the fullscreen-triangle VERTEX STAGE. It is not a toy -- it is the exact
stage that ships TODAY, hand-written TWICE in nx_game_page_emit:
GLSL VSH : void main(){vec2 v=vec2((gl_VertexID<<1)&2,gl_VertexID&2);gl_Position=vec4(v*2.-1.,0.,1.);}
WGSL vs : @vertex fn vs(@builtin(vertex_index) vi:u32)->@builtin(position) vec4f{...}
Those two hand copies are the duplication this rung deletes: below, ONE NishiLang source
(shsrc_fullscreen_tri) emits both.
WHY THIS STAGE PROVES THE THESIS. The two dialects are not spelling variants of each other:
* GLSL ASSIGNS gl_Position; WGSL RETURNS @builtin(position). Different STRUCTURE.
* GLSL gl_VertexID is i32; WGSL vertex_index is u32 and must be converted before i32 maths.
* WGSL requires a u32 shift amount (1u); GLSL takes a plain int.
* WGSL requires 0.0, never 0. ; GLSL accepts either.
Every one of those is dialect knowledge the BACKEND owns. A translator would have to rediscover
them from GLSL text; a backend simply knows them, once.
COVERED SUBSET (rung 1) -- anything outside REFUSES BY NAME via sir_refuse and returns -1.
A NAMED REFUSAL IS A CONTRACT; A SILENT MISTRANSLATION IN A SHADER BACKEND IS THE WORST
AVAILABLE FAILURE: it compiles, it links, it runs, and it draws the wrong picture forever.
decls : uniform (scalar + array); attribute and varying are GLSL-covered and, since S1
(2026-09-04), WGSL-REFUSED BY NAME (K_ATTRIB anywhere, K_VARY in a fragment stage) until
the entry-parameter derivation that WGSL needs for them lands; a texture-typed uniform
refuses in WGSL too -- it was being emitted INSIDE struct U
S3 (2026-09-04): a TEXTURE is its own kind (K_TEXTURE / sir_texture) in BOTH backends: GLSL
`uniform highp usampler3D`, WGSL a @group/@binding var OUTSIDE struct U with its binding
DERIVED from declaration order; only texture_3d<u32> is covered, other texture types refuse
S4 (2026-09-04): the FRAGMENT entry signature is DERIVED from the declared parameters (no
longer a literal): a sir_param_position parameter is `@builtin(position) name:vec4f` in WGSL and
gl_FragCoord in GLSL; a position READ with no such parameter, and any entry parameter a backend
cannot bind (plain fragment params, any vertex/compute param), refuse by name
stmts : var, assign, return, if/else, discard
dependencies 11 imports · 0 importers
diagram shows first 10 each side; +1 more imports, +0 more importers in the complete lists below.
imports: nx_syscalls.nxnx_shader_ir.nxnx_cast_shader_src.nxnx_world_shader_src.nxnx_types.nxnx_lex_kinds.nxnx_ir.nxnx_tokenizer.nxnx_parse.nxnx_opt.nxnx_import.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 78 | const STAGE_PLAIN: i64 = 0 |
| 79 | const STAGE_VERTEX: i64 = 1 |
| 80 | const STAGE_FRAGMENT: i64 = 2 |
| 82 | const STAGE_COMPUTE: i64 = 3 |
| 87 | const WG_WORKGROUP: i64 = 64 |
| 91 | const WG_TRACE_CAP: i64 = SIR_MAXNODE |
| 95 | const WG_EMIT_CAP: i64 = SIR_MAXNODE * 16 |
| 97 | const WG_C_BANG: i64 = 33 |
| 99 | const WG_NUMBUF: i64 = 32 |
| 107 | const WG_MSGBUF: i64 = 128 |
| 114 | const WG_BIND_GROUP: i64 = 0 |
| 119 | const WG_BIND_UNIFORM: i64 = 0 |
| 120 | const WG_BIND_TEX_FIRST: i64 = WG_BIND_UNIFORM + 1 |
| 264 | const WG_F32ARR_LANES: i64 = 4 |
| 2007 | const WG_UNIFORM_STRIDE_MULTIPLE: i64 = 16 |
| 2141 | const WG_MODE_0644: i64 = 420 |
| 2794 | const SHL_EXPAND_CAP: i64 = 4194304 |
| 2795 | const SHL_LEX_CAP: i64 = 262144 |
functions
| 118 | func wg_group(m: *i64) -> i64 { return WG_BIND_GROUP + m[M_BINDGROUP] } |
| 123 | func gl_ty(t: i64) -> *u8 |
| 142 | func wg_ty(t: i64) -> *u8 |
| 165 | func gl_tyname(m: *i64, t: i64) -> *u8 |
| 170 | func wg_tyname(m: *i64, t: i64) -> *u8 |
| 179 | func wg_is_texty(t: i64) -> i64 |
| 192 | func wg_name_is(m: *i64, id: i64, name: *u8) -> i64 |
| 196 | func wg_fn_param(m: *i64, fn: i64, name: *u8) -> i64 |
| 206 | func wg_fn_position_param(m: *i64, fn: i64) -> i64 |
| 216 | func wg_chain_local(m: *i64, head: i64, name: *u8) -> i64 |
| 231 | func wg_decl_named(m: *i64, kind: i64, name: *u8) -> i64 |
| 241 | func wg_resolves_to_uniform(m: *i64, name: *u8) -> i64 |
| 251 | func wg_resolves_to_varying(m: *i64, name: *u8) -> i64 |
| 265 | func wg_f32arr_vec4n(n: i64) -> i64 { return (n + WG_F32ARR_LANES - 1) / WG_F32ARR_LANES } |
| 267 | func wg_f32arr_len(m: *i64, name: *u8) -> i64 |
| 277 | func wg_decl_kind_first(m: *i64, kind: i64) -> i64 |
| 286 | func wg_decl_kind_count(m: *i64, kind: i64) -> i64 |
| 297 | func wg_fragout(m: *i64) -> i64 { return wg_decl_kind_first(m, K_FRAGOUT) } |
| 302 | func wg_chain_returns_value(m: *i64, head: i64) -> i64 |
| 319 | func wg_chain_assigns(m: *i64, head: i64, name: *u8) -> i64 |
| 337 | func wg_chain_last_is_return(m: *i64, head: i64) -> i64 |
| 347 | func wg_tex_binding(m: *i64, tex: i64) -> i64 |
| 358 | func wg_storage_at(m: *i64, binding: i64) -> i64 |
| 370 | func wg_front_contract(m:*i64,stage:i64)->i64 |
| 386 | func gl_expr(m: *i64, id: i64, out: *u8, pos: i64, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 521 | func gl_stmts(m: *i64, head: i64, out: *u8, pos: i64, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 598 | func glsl_emit_module(m: *i64, stage: i64, out: *u8, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 789 | func wg_fn_is_plain(m: *i64, f: i64, stage: i64) -> i64 |
| 797 | func wg_rev(out: *u8, a: i64, b: i64) -> i64 |
| 816 | func wg_splat_callee(n: *u8) -> i64 |
| 825 | func wg_vec_arg_ty(m: *i64, id: i64) -> i64 |
| 837 | func wg_expr(m: *i64, id: i64, out: *u8, pos: i64, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 1051 | func wg_is_position(m: *i64, id: i64) -> i64 |
| 1059 | func wg_stmts(m: *i64, head: i64, out: *u8, pos: i64, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 1164 | func wgsl_compute_stage(m: *i64, f: i64, out: *u8, pos: i64, cap: i64) -> i64 |
| 1175 | func wgsl_emit_module(m: *i64, stage: i64, out: *u8, cap: i64, trace: *i64, tcap: i64, tn: *i64) -> i64 |
| 1545 | func shsrc_fullscreen_tri(m: *i64) -> i64 |
| 1575 | func shsrc_depth_min(m: *i64) -> i64 |
| 1587 | func wg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 1589 | func wg_streq(a: *u8, b: *u8) -> i64 |
| 1598 | func wg_compute_demo() -> i64 |
| 1650 | func wg_probe(m: *i64, stage: i64, label: *u8, dialect_wgsl: i64, trace: *i64, tn: *i64) -> i64 |
| 1669 | func wg_trace_eq(a: *i64, an: i64, b: *i64, bn: i64) -> i64 |
| 1679 | func shsrc_frag_const(m: *i64) -> i64 |
| 1697 | func shsrc_fullscreen_tri_scaled(m: *i64) -> i64 |
| 1714 | func shsrc_fullscreen_tri_shadowlocal(m: *i64) -> i64 |
| 1732 | func shsrc_plain_shadowparam(m: *i64) -> i64 |
| 1748 | func shsrc_private_demo(m: *i64) -> i64 |
| 1765 | func shsrc_tex2d_sample(m: *i64) -> i64 |
| 1773 | func shsrc_tex_plain(m: *i64) -> i64 |
| 1793 | func shsrc_frag_pos(m: *i64) -> i64 |
| 1809 | func shsrc_frag_pos_undeclared(m: *i64) -> i64 |
| 1824 | func shsrc_frag_plainparam(m: *i64) -> i64 |
| 1842 | func shsrc_frag_discard(m: *i64) -> i64 |
| 1852 | func shsrc_frag_noout(m: *i64) -> i64 |
| 1866 | func shsrc_frag_loc2(m: *i64) -> i64 |
| 1880 | func shsrc_vert_fragout(m: *i64) -> i64 |
| 1887 | func shsrc_frag_twoout(m: *i64) -> i64 |
| 1894 | func shsrc_frag_const_body(m: *i64) -> i64 |
| 1910 | func shsrc_texsample(m: *i64) -> i64 |
| 1921 | func shsrc_select_let(m: *i64) -> i64 |
| 1936 | func shsrc_for_until(m: *i64) -> i64 |
| 1952 | func shsrc_struct(m: *i64) -> i64 |
| 1975 | func shsrc_struct_ret(m: *i64) -> i64 |
| 2008 | func wg_round_up(al: i64, n: i64) -> i64 { return ((n + al - 1) / al) * al } |
| 2009 | func wg_align_of(t: i64) -> i64 |
| 2021 | func wg_size_of(t: i64) -> i64 |
| 2038 | func wg_uniform_layout(m: *i64, out: *u8, pos: i64, cap: i64) -> i64 { return wg_uniform_layout_k(m, out, pos, cap, "struct_u_size=" as *u8) } |
| 2039 | func wg_uniform_layout_k(m: *i64, out: *u8, pos: i64, cap: i64, key: *u8) -> i64 |
| 2092 | func shsrc_world_uniforms(m: *i64) -> i64 |
| 2104 | func shsrc_neg_uninit(m: *i64) -> i64 |
| 2115 | func wg_world_demo() -> i64 |
| 2143 | func wg_glsl_to_path(m: *i64, stage: i64, outp: *u8, label: *u8) -> i64 |
| 2161 | func wg_cast_demo(outp: *u8, outf: *u8) -> i64 |
| 2232 | func wg_layout_demo() -> i64 |
| 2301 | func gl_call_name(name: *u8) -> *u8 |
| 2312 | func wg_decls_demo() -> i64 |
| 2800 | func shl_ty(t: *Type) -> i64 |
| 2810 | func shl_op(op: i64) -> *u8 |
| 2833 | func shl_val(m2: *i64, f: *Function, vid: i64, nb: *u8) -> i64 |
| 2859 | func shl_blk(m2: *i64, f: *Function, fn2: i64, bb: *BasicBlock, nb: *u8, msg: *u8, seen: *i64) -> i64 |
| 2936 | func shl_bid(f: *Function, id: i64) -> *BasicBlock |
| 2949 | func shl_reaches(f: *Function, from: i64, to: i64, mark: *i64, wl: *i64) -> i64 |
| 2979 | func shl_reaches_avoid(f: *Function, from: i64, to: i64, avoid: i64, mark: *i64, wl: *i64) -> i64 |
| 3008 | func shl_dominates(f: *Function, b: i64, p: i64, mark: *i64, wl: *i64) -> i64 |
| 3023 | func shl_is_header(f: *Function, bb: *BasicBlock, mark: *i64, wl: *i64) -> i64 |
| 3052 | func shl_region(m2: *i64, f: *Function, fn2: i64, eid: i64, stop: i64, nb: *u8, msg: *u8, seen: *i64, mark: *i64, wl: *i64, depth: i64) -> i64 |
| 3169 | func shl_lower(m2: *i64, f: *Function, fname: *u8) -> i64 |
| 3235 | func main(argc: i64, argv: *i64) -> i64 |