nx_gpu_graphics_gate.nx source
↩ module page · 170 lines · 11794 B
1// nx_gpu_graphics_gate.nx -- GOAL-GPU-NATIVE rung-2: a GRAPHICS engine on the sovereign GPFIFO pipeline.
2// Synthesis the operator asked for -- hardware rung up + game ecosystem + consume/produce, all sovereign.
3// Builds on the RESEARCHED NVIDIA command model embodied in the BM-GPU organs (GF100 method-header decode +
4// NVC56F class-binding via SET_OBJECT@0x0, spec-faithful). Adds a GRAPHICS class: a game/driver PRODUCES a
5// draw-command pushbuffer (SET_OBJECT graphics, SET_FB/W/H, CLEAR, per-triangle state, DRAW), the modeled
6// GPU host/FIFO CONSUMES the ring, and the GRAPHICS engine (our rung-1 rasterizer) PRODUCES pixels into GPU
7// VRAM with a Z-buffer. This is the same submit->execute loop as compute, now driving the screen.
8// produce (draw cmds) -> GPFIFO ring -> consume (FIFO decode) -> graphics engine -> produce (pixels in VRAM)
9// KAT: the scene renders THROUGH the command stream; the Z-buffer is correct through the pipeline (a far
10// triangle submitted LAST does not overwrite the near one); a TAMPER pushbuffer with NO SET_OBJECT renders
11// NOTHING (dispatch gated on class-bind, faithful to the FIFO spec); the produced frame exports to BMP.
12// HONEST SCOPE: spec-faithful FIFO decode + class-bind LOGIC; method offsets for the graphics class are
13// representative; real silicon exec = the bare-metal PCIe/doorbell last mile (BM-GPU-6/7). No hw writes (Rule 26).
14// expect_exit: 0 license_tier: ORIGINAL
15import "nx_fb.nx"
16import "nx_gate_verdict.nx"
17
18const GRAPHICS_CLASS: i64 = 0xC397 // representative Ampere 3D class id
19
20func gg_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
21func gg_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
22func gg_rd32(b: *u8, o: i64) -> i64 { return (b[o] as i64)|((b[o+1] as i64)<<8)|((b[o+2] as i64)<<16)|((b[o+3] as i64)<<24) }
23func gg_wr32(b: *u8, o: i64, v: i64) -> i64 { b[o]=(v&0xff) as u8; b[o+1]=((v>>8)&0xff) as u8; b[o+2]=((v>>16)&0xff) as u8; b[o+3]=((v>>24)&0xff) as u8; return 0 }
24func gg_edge(ax: i64, ay: i64, bx: i64, by: i64, px: i64, py: i64) -> i64 { return (bx-ax)*(py-ay) - (by-ay)*(px-ax) }
25func gg_min3(a: i64, b: i64, c: i64) -> i64 { var m: i64=a; if b<m {m=b} if c<m {m=c} return m }
26func gg_max3(a: i64, b: i64, c: i64) -> i64 { var m: i64=a; if b>m {m=b} if c>m {m=c} return m }
27func gg_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v }
28
29// GPU GRAPHICS engine: rasterize the triangle held in gs[3..18] into the framebuffer at fb_va in gmem, z-tested.
30func gg_rast(gmem: *u8, zbuf: *i64, gs: *i64) -> i64 {
31 let fb_va: i64=gs[0]; let W: i64=gs[1]; let H: i64=gs[2]
32 let x0: i64=gs[3]; let y0: i64=gs[4]; let x1: i64=gs[5]; let y1: i64=gs[6]; let x2: i64=gs[7]; let y2: i64=gs[8]; let z: i64=gs[9]
33 let area: i64=gg_edge(x0,y0,x1,y1,x2,y2)
34 if area==0 { return 0 }
35 let minx: i64=gg_clamp(gg_min3(x0,x1,x2),0,W-1); let maxx: i64=gg_clamp(gg_max3(x0,x1,x2),0,W-1)
36 let miny: i64=gg_clamp(gg_min3(y0,y1,y2),0,H-1); let maxy: i64=gg_clamp(gg_max3(y0,y1,y2),0,H-1)
37 var py: i64=miny
38 while py<=maxy {
39 var px: i64=minx
40 while px<=maxx {
41 let w0: i64=gg_edge(x1,y1,x2,y2,px,py); let w1: i64=gg_edge(x2,y2,x0,y0,px,py); let w2: i64=gg_edge(x0,y0,x1,y1,px,py)
42 var inside: i64=0
43 if area>0 { if w0>=0 { if w1>=0 { if w2>=0 { inside=1 } } } } else { if w0<=0 { if w1<=0 { if w2<=0 { inside=1 } } } }
44 if inside==1 { let idx: i64=py*W+px; if z<zbuf[idx] { zbuf[idx]=z
45 let r: i64=(w0*gs[10]+w1*gs[13]+w2*gs[16])/area; let g: i64=(w0*gs[11]+w1*gs[14]+w2*gs[17])/area; let b: i64=(w0*gs[12]+w1*gs[15]+w2*gs[18])/area
46 let o: i64=fb_va+idx*3; gmem[o]=r as u8; gmem[o+1]=g as u8; gmem[o+2]=b as u8 } }
47 px=px+1
48 }
49 py=py+1
50 }
51 return 0
52}
53func gg_clear(gmem: *u8, zbuf: *i64, gs: *i64, color: i64) -> i64 {
54 let fb_va: i64=gs[0]; let W: i64=gs[1]; let H: i64=gs[2]; let FAR: i64=1<<30
55 let r: i64=(color>>16)&0xff; let g: i64=(color>>8)&0xff; let b: i64=color&0xff
56 var i: i64=0
57 while i<W*H { let o: i64=fb_va+i*3; gmem[o]=r as u8; gmem[o+1]=g as u8; gmem[o+2]=b as u8; zbuf[i]=FAR; i=i+1 }
58 return 0
59}
60// the modeled GPU host/FIFO: walk the pushbuffer, decode method headers (GF100), class-gate + dispatch graphics methods.
61func gpfifo_run_graphics(gmem: *u8, pb_off: i64, pb_dwords: i64, gs: *i64, zbuf: *i64) -> i64 {
62 var i: i64=0
63 while i<pb_dwords {
64 let hdr: i64=gg_rd32(gmem, pb_off+i*4)
65 let mode: i64=(hdr>>29)&0x7; let count: i64=(hdr>>16)&0x1fff; let method0: i64=(hdr&0xfff)<<2
66 i=i+1
67 var j: i64=0
68 while j<count {
69 let data: i64=gg_rd32(gmem, pb_off+i*4); i=i+1
70 var m: i64=method0; if mode==1 { m=method0+j*4 }
71 if m==0x0 { gs[19]=data } else { if gs[19]==GRAPHICS_CLASS {
72 if m==0x200 { gs[0]=data }
73 if m==0x204 { gs[1]=data }
74 if m==0x208 { gs[2]=data }
75 if m==0x210 { gg_clear(gmem, zbuf, gs, data) }
76 if m>=0x220 { if m<=0x25c { gs[3 + ((m-0x220)>>2)]=data } }
77 if m==0x260 { gg_rast(gmem, zbuf, gs) }
78 } }
79 j=j+1
80 }
81 }
82 return 0
83}
84func gg_emit1(gmem: *u8, off: i64, method: i64, data: i64) -> i64 { gg_wr32(gmem, off, (1<<29)|(1<<16)|((method>>2)&0xfff)); gg_wr32(gmem, off+4, data); return off+8 }
85func gg_emit_tri(gmem: *u8, off: i64, x0: i64, y0: i64, x1: i64, y1: i64, x2: i64, y2: i64, z: i64, c: *i64) -> i64 {
86 var o: i64=off
87 o=gg_emit1(gmem,o,0x220,x0); o=gg_emit1(gmem,o,0x224,y0); o=gg_emit1(gmem,o,0x228,x1); o=gg_emit1(gmem,o,0x22c,y1); o=gg_emit1(gmem,o,0x230,x2); o=gg_emit1(gmem,o,0x234,y2); o=gg_emit1(gmem,o,0x238,z)
88 o=gg_emit1(gmem,o,0x23c,c[0]); o=gg_emit1(gmem,o,0x240,c[1]); o=gg_emit1(gmem,o,0x244,c[2]); o=gg_emit1(gmem,o,0x248,c[3]); o=gg_emit1(gmem,o,0x24c,c[4]); o=gg_emit1(gmem,o,0x250,c[5]); o=gg_emit1(gmem,o,0x254,c[6]); o=gg_emit1(gmem,o,0x258,c[7]); o=gg_emit1(gmem,o,0x25c,c[8])
89 o=gg_emit1(gmem,o,0x260,0) // DRAW
90 return o
91}
92
93// build the scene pushbuffer; with_obj=0 omits SET_OBJECT (the tamper). returns pb_dwords.
94func build_scene(gmem: *u8, pb_off: i64, fb_va: i64, W: i64, H: i64, with_obj: i64) -> i64 {
95 var po: i64=pb_off
96 if with_obj==1 { po=gg_emit1(gmem,po,0x0,GRAPHICS_CLASS) }
97 po=gg_emit1(gmem,po,0x200,fb_va); po=gg_emit1(gmem,po,0x204,W); po=gg_emit1(gmem,po,0x208,H)
98 po=gg_emit1(gmem,po,0x210,0x141e20) // CLEAR dark
99 let cf: *i64=sys_mmap(8*9); cf[0]=220;cf[1]=40;cf[2]=40;cf[3]=40;cf[4]=220;cf[5]=40;cf[6]=40;cf[7]=40;cf[8]=220
100 po=gg_emit_tri(gmem,po, 18,14, 150,34, 38,112, 100, cf) // FAR gradient
101 let cy: *i64=sys_mmap(8*9); cy[0]=230;cy[1]=210;cy[2]=50;cy[3]=230;cy[4]=210;cy[5]=50;cy[6]=230;cy[7]=210;cy[8]=50
102 po=gg_emit_tri(gmem,po, 70,30, 156,86, 64,106, 40, cy) // NEAR yellow
103 let cc: *i64=sys_mmap(8*9); cc[0]=40;cc[1]=200;cc[2]=200;cc[3]=40;cc[4]=200;cc[5]=200;cc[6]=40;cc[7]=200;cc[8]=200
104 po=gg_emit_tri(gmem,po, 74,40, 140,80, 68,100, 100, cc) // FAR2 cyan, submitted LAST
105 return (po-pb_off)/4
106}
107
108func count_scene(gmem: *u8, fb_va: i64, W: i64, H: i64, zbuf: *i64) -> i64 {
109 var c: i64=0; var i: i64=0; while i<W*H { if zbuf[i]<(1<<30) { c=c+1 } i=i+1 } return c
110}
111
112func main() -> i64 {
113 gg_puts("GOAL-GPU-NATIVE rung-2: GRAPHICS engine on the sovereign GPFIFO pipeline (game produces -> GPU consumes -> pixels)\n" as *u8)
114 let W: i64=160
115 let H: i64=120
116 let gmem: *u8 = sys_mmap(131072)
117 let fb_va: i64=16384
118 let pb_off: i64=4096
119 let zbuf: *i64 = sys_mmap(W*H*8) as *i64
120 let gs: *i64 = sys_mmap(8*24) as *i64
121 var gi: i64=0
122 while gi<24 { gs[gi]=0; gi=gi+1 }
123
124 // PRODUCE the draw-command pushbuffer (what a game submits), CONSUME via the FIFO, PRODUCE pixels
125 let pbd: i64 = build_scene(gmem, pb_off, fb_va, W, H, 1)
126 gpfifo_run_graphics(gmem, pb_off, pbd, gs, zbuf)
127 let covered: i64 = count_scene(gmem, fb_va, W, H, zbuf)
128
129 // z-buffer through the pipeline: near pixels must survive the far triangle submitted LAST
130 var near_px: i64=0
131 var near_yellow: i64=0
132 var p: i64=0
133 while p<W*H { if zbuf[p]==40 { near_px=near_px+1; let o: i64=fb_va+p*3; if (gmem[o] as i64)==230 { if (gmem[o+1] as i64)==210 { if (gmem[o+2] as i64)==50 { near_yellow=near_yellow+1 } } } } p=p+1 }
134
135 // TAMPER: same scene with NO SET_OBJECT -> class never bound -> engine must render NOTHING
136 let gmem2: *u8 = sys_mmap(131072)
137 let zbuf2: *i64 = sys_mmap(W*H*8) as *i64
138 var zz: i64=0
139 while zz<W*H { zbuf2[zz]=1<<30; zz=zz+1 }
140 let gs2: *i64 = sys_mmap(8*24) as *i64
141 var gj: i64=0
142 while gj<24 { gs2[gj]=0; gj=gj+1 }
143 let pbd2: i64 = build_scene(gmem2, pb_off, fb_va, W, H, 0)
144 gpfifo_run_graphics(gmem2, pb_off, pbd2, gs2, zbuf2)
145 let tamper_covered: i64 = count_scene(gmem2, fb_va, W, H, zbuf2)
146
147 let sz: i64 = fb_bmp_save(((gmem as i64)+fb_va) as *u8, W, H, "knowledge/status/nishios_gpu.bmp\x00" as *u8)
148 let hd: i64 = sys_openat_wr("knowledge/status/nishios_gpu.html\x00" as *u8, 0x1a4)
149 if hd>0 { let html: *u8 = "<!doctype html><html><body style=\x27background:#0a0a12;color:#8af;font-family:monospace;text-align:center\x27><h3>NishiOS sovereign GPU: scene rendered THROUGH the GPFIFO command pipeline</h3><img src=\x27nishios_gpu.bmp\x27 style=\x27image-rendering:pixelated;width:640px;border:1px solid #333\x27><div>game produces draw cmds -> GPFIFO ring -> GPU consumes -> rasterizer produces pixels</div></body></html>\x00"; var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) }
150
151 gg_puts(" pushbuffer dwords="); gg_num(pbd); gg_puts(" -> rendered covered="); gg_num(covered); gg_puts(" near(z=40)="); gg_num(near_px); gg_puts(" yellow="); gg_num(near_yellow); gg_puts(" | TAMPER(no SET_OBJECT) covered="); gg_num(tamper_covered); gg_puts("\n" as *u8)
152
153 var pass: i64=0
154 var ttl: i64=0
155 ttl=ttl+1; gg_puts(" T1 scene rendered THROUGH the GPFIFO command stream (covered>1500): " as *u8); if covered>1500 { pass=pass+1; gg_puts("PASS\n" as *u8) } else { gg_puts("FAIL\n" as *u8) }
156 ttl=ttl+1; gg_puts(" T2 Z-buffer correct through the pipeline (near survives far-submitted-LAST): " as *u8); if near_px>0 { if near_yellow==near_px { pass=pass+1; gg_puts("PASS\n" as *u8) } else { gg_puts("FAIL\n" as *u8) } } else { gg_puts("FAIL\n" as *u8) }
157 ttl=ttl+1; gg_puts(" T3 TAMPER: no SET_OBJECT class-bind => engine renders NOTHING (dispatch gated): " as *u8); if tamper_covered==0 { pass=pass+1; gg_puts("PASS\n" as *u8) } else { gg_puts("FAIL\n" as *u8) }
158 ttl=ttl+1; gg_puts(" T4 produced frame exported to BMP: " as *u8); if sz>0 { pass=pass+1; gg_puts("PASS\n" as *u8) } else { gg_puts("FAIL\n" as *u8) }
159
160 gg_puts("NISHIOS-GPU-GFX-GATE passed "); gg_num(pass); gg_puts("/"); gg_num(ttl)
161 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
162 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
163 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
164 let ctr__dry: *i64 = gv_ctr()
165 ctr__dry[0] = pass
166 ctr__dry[1] = ttl
167 let rc__dry: i64 = gv_verdict("GPU-GRAPHICS-GATE" as *u8, ctr__dry, "graphics drawn THROUGH the sovereign GPFIFO pipeline: produce->consume->produce, hardware-rung-up)" as *u8)
168 sys_exit(rc__dry)
169 return rc__dry
170}