code wiki / (root) / nx_gpu_graphics_gate.nx

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}