code wiki / _hdl_build / nx_d3d_persp_gate.nx

nx_d3d_persp_gate.nx source

↩ module page · 102 lines · 6031 B

1// nx_d3d_persp_gate.nx -- D3c: PERSPECTIVE-CORRECT attribute interpolation conformance vs WARP. Same screen triangle 2// as the gradient test, but each vertex has a different clip-space w (1,2,4). WARP interpolates color hyperbolically 3// (perspective-correct); a naive AFFINE rasterizer gets it visibly WRONG. We do the real per-fragment divide-by-w and 4// grade pixel-for-pixel vs Microsoft (knowledge/warp_persp.ppm). This is the honest, non-flattering rung -- the one a 5// real GPU pipeline must pass to run a game. Integer-exact hyperbolic weights; WARP = benchmark oracle. license_tier: ORIGINAL expect_exit: 0 6import "nx_syscalls.nx" 7 8func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 9func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 10func edge(ax: i64, ay: i64, bx: i64, by: i64, px: i64, py: i64) -> i64 { return (bx-ax)*(py-ay) - (by-ay)*(px-ax) } 11func iabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 12func rnd_div(num: i64, den: i64) -> i64 { return (num + den/2) / den } 13 14func main() -> i64 { 15 hw("=== nx_d3d_persp_gate -- D3c: PERSPECTIVE-CORRECT interpolation vs WARP (per-vertex w = 1,2,4) ===\n" as *u8) 16 var fails: i64 = 0 17 let szp: *i64 = sys_mmap(16) as *i64 18 let ppm: *u8 = sys_read_file("knowledge/warp_persp.ppm" as *u8, szp) 19 if (ppm as i64) == 0 { hw("FAIL no warp_persp.ppm\n" as *u8); sys_exit(1); return 1 } 20 var hdr: i64 = 0; var nl: i64 = 0; var i: i64 = 0 21 while i < 40 { if ppm[i] == (10 as u8) { nl = nl + 1; if nl == 3 { hdr = i + 1; i = 40 } } i = i + 1 } 22 23 // 2x screen verts: v0(32,96) red W=1, v1(64,32) green W=2, v2(96,96) blue W=4 24 // hyperbolic weight a_i = w_i / W_i, scaled by Wprod=8 to stay integer: mult = {8,4,2} 25 var sgn: i64 = 1 26 if edge(32,96,64,32,96,96) < 0 { sgn = 0 - 1 } 27 28 let out: *u8 = sys_mmap(64*64*3 + 32) 29 var exact: i64 = 0 30 var within1: i64 = 0 31 var within2: i64 = 0 32 var cov: i64 = 0 33 var y: i64 = 0 34 while y < 64 { 35 var x: i64 = 0 36 while x < 64 { 37 let sx: i64 = 2*x + 1 38 let sy: i64 = 2*y + 1 39 let w0: i64 = edge(64,32,96,96,sx,sy) * sgn 40 let w1: i64 = edge(96,96,32,96,sx,sy) * sgn 41 let w2: i64 = edge(32,96,64,32,sx,sy) * sgn 42 var orr: i64 = 0; var ogg: i64 = 0; var obb: i64 = 0 43 var inside: i64 = 0 44 if w0 >= 0 { if w1 >= 0 { if w2 >= 0 { inside = 1 } } } 45 if inside == 1 { 46 let a0: i64 = w0 * 8 // /1 47 let a1: i64 = w1 * 4 // /2 48 let a2: i64 = w2 * 2 // /4 49 let den: i64 = a0 + a1 + a2 50 orr = rnd_div(a0 * 255, den) // red weight = v0 51 ogg = rnd_div(a1 * 255, den) // green weight = v1 52 obb = rnd_div(a2 * 255, den) // blue weight = v2 53 cov = cov + 1 54 } 55 let o3: i64 = (y*64 + x)*3 56 out[o3] = orr as u8; out[o3+1] = ogg as u8; out[o3+2] = obb as u8 57 let wr: i64 = ppm[hdr + o3] as i64 58 let wg: i64 = ppm[hdr + o3 + 1] as i64 59 let wb: i64 = ppm[hdr + o3 + 2] as i64 60 let dr: i64 = iabs(orr - wr) 61 let dg: i64 = iabs(ogg - wg) 62 let db: i64 = iabs(obb - wb) 63 if dr == 0 { if dg == 0 { if db == 0 { exact = exact + 1 } } } 64 if dr <= 1 { if dg <= 1 { if db <= 1 { within1 = within1 + 1 } } } 65 if dr <= 2 { if dg <= 2 { if db <= 2 { within2 = within2 + 1 } } } 66 x = x + 1 67 } 68 y = y + 1 69 } 70 hw(" coverage="); pn(cov); hw(" exact="); pn(exact); hw("/4096 within-1="); pn(within1); hw("/4096 within-2="); pn(within2); hw("/4096\n" as *u8) 71 72 // sanity: prove we are NOT doing affine. Affine center(32,32) would be (62,124,70); pers-correct is (112,112,32). 73 let cc: i64 = (32*64 + 32)*3 74 hw(" our center(32,32)=("); pn(out[cc] as i64); hw(","); pn(out[cc+1] as i64); hw(","); pn(out[cc+2] as i64) 75 hw(") WARP=("); pn(ppm[hdr+cc] as i64); hw(","); pn(ppm[hdr+cc+1] as i64); hw(","); pn(ppm[hdr+cc+2] as i64); hw(")\n" as *u8) 76 77 var t1: i64 = 0 78 if cov >= 500 { if cov <= 524 { t1 = 1 } } 79 if t1 == 1 { hw("T1 PASS coverage matches (~512)\n" as *u8) } else { fails=fails+1; hw("T1 FAIL cov="); pn(cov); hw("\n" as *u8) } 80 var t2: i64 = 0 81 if within1 >= 4090 { t2 = 1 } 82 if t2 == 1 { hw("T2 PASS perspective-correct color within 1 LSB of WARP on >=4090/4096 pixels\n" as *u8) } else { fails=fails+1; hw("T2 FAIL within1="); pn(within1); hw("\n" as *u8) } 83 var t3: i64 = 0 84 if within2 == 4096 { t3 = 1 } 85 if t3 == 1 { hw("T3 PASS every pixel within 2 LSB of WARP (no gross error)\n" as *u8) } else { fails=fails+1; hw("T3 FAIL within2="); pn(within2); hw("\n" as *u8) } 86 // T4 proves the divide actually happened: our center must be perspective (112,112,32), NOT affine (62,124,70) 87 var t4: i64 = 0 88 if (out[cc] as i64) == 112 { if (out[cc+2] as i64) == 32 { t4 = 1 } } 89 if t4 == 1 { hw("T4 PASS center is perspective-correct (112,112,32), not affine (62,124,70) -- the divide is real\n" as *u8) } else { fails=fails+1; hw("T4 FAIL center not perspective-correct\n" as *u8) } 90 91 let fd: i64 = sys_openat_wr("knowledge/nx_d3d_persp.ppm\x00" as *u8, 0x1a4) 92 let h6: *u8 = "P6\n64 64\n255\n" as *u8 93 var hn: i64 = 0 94 while h6[hn] != (0 as u8) { hn = hn + 1 } 95 sys_write(fd, h6, hn); sys_write(fd, out, 64*64*3); sys_close(fd) 96 hw("T5 artifact -> knowledge/nx_d3d_persp.ppm\n" as *u8) 97 98 if fails == 0 { hw("NX-D3D-PERSP GREEN -- perspective-correct interpolation matches Microsoft WARP (real GPU pipeline conformance)\n" as *u8); sys_exit(0); return 0 } 99 hw("NX-D3D-PERSP RED fails="); pn(fails); hw("\n" as *u8) 100 sys_exit(1) 101 return 1 102}