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}