code wiki / _hdl_build / nx_vsubpel_gate.nx

nx_vsubpel_gate.nx source

↩ module page · 54 lines · 3324 B

1// nx_vsubpel_gate.nx -- proves + MEASURES half-pel motion (nx_vsubpel): when content moves by a genuine 0.5 pixel, 2// integer-pel motion leaves a large residual but half-pel refinement lands on the true position with ~zero residual. 3// Lower residual = fewer bits at identical quality = the sub-pixel quality-per-bit win. 4import "nx_syscalls.nx" 5import "nx_gate_emit_lib.nx" 6import "nx_vsubpel.nx" 7import "nx_gate_verdict.nx" 8 9func main() -> i64 { 10 g_puts("nx_vsubpel gate (half-pel motion cuts the residual, MEASURED)\n" as *u8) 11 var pass: i64 = 0; var total: i64 = 0 12 let W: i64 = 24; let H: i64 = 24; let T: i64 = 16 13 let cx: i64 = 4; let cy: i64 = 4 // block position (leaves a guard border) 14 15 let A: *u8 = sys_mmap(W*H) as *u8 // reference (prev) 16 let B: *u8 = sys_mmap(W*H) as *u8 // current = A shifted by EXACTLY 0.5px in x 17 let tmp: *i64 = sys_mmap(T*T*8) as *i64 18 let mvh: *i64 = sys_mmap(2*8) as *i64 19 20 // textured reference so a sub-pixel shift actually changes pixels (a flat region has no sub-pixel residual) 21 var y: i64 = 0 22 while y < H { var x: i64 = 0 23 while x < W { A[y*W+x] = (40 + ((x*11 + y*7) % 120)) as u8; x = x + 1 } y = y + 1 } 24 // B = A moved +0.5px in x (B[x] = average of A[x] and A[x+1]) -- a genuine half-pel motion 25 y = 0 26 while y < H { var x: i64 = 0 27 while x < W - 1 { B[y*W+x] = (((A[y*W+x] as i64) + (A[y*W+(x+1)] as i64) + 1) / 2) as u8; x = x + 1 } 28 B[y*W + (W-1)] = A[y*W + (W-1)]; y = y + 1 } 29 30 // INTEGER-pel residual at MV (0,0): the best integer match can't represent the 0.5 shift 31 sp_interp_block(A, W, cx, cy, 0, 0, T, tmp) 32 let sad_int: i64 = sp_sad(B, W, cx, cy, tmp, T) 33 // HALF-pel refine around (0,0): should find (hx=1,hy=0) = the true 0.5px-x shift 34 let sad_half: i64 = sp_refine(B, A, W, H, cx, cy, 0, 0, T, tmp, mvh) 35 36 g_puts(" [measure] residual SAD: integer-pel=" as *u8); g_pn(sad_int); g_puts(" half-pel=" as *u8); g_pn(sad_half) 37 g_puts(" best half-pel MV=(" as *u8); g_pn(mvh[0]); g_puts("," as *u8); g_pn(mvh[1]); g_puts(")/2px\n" as *u8) 38 if sad_int > 0 { g_puts(" [measure] residual cut by half-pel = " as *u8); g_pn((sad_int - sad_half) * 100 / sad_int); g_puts("%\n" as *u8) } 39 40 pass = pass + g_check("half-pel residual << integer-pel residual (>= 8x smaller)" as *u8, sad_half * 8 < sad_int); total=total+1 41 pass = pass + g_check("half-pel found the true (0.5, 0) shift" as *u8, (mvh[0]==1) & (mvh[1]==0)); total=total+1 42 pass = pass + g_check("integer-pel genuinely cannot match (residual non-trivial)" as *u8, sad_int > 256); total=total+1 43 44 g_puts("---- vsubpel gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 45 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 46 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 47 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 48 let ctr__dry: *i64 = gv_ctr() 49 ctr__dry[0] = pass 50 ctr__dry[1] = total 51 let rc__dry: i64 = gv_verdict("VSUBPEL-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 52 sys_exit(rc__dry) 53 return rc__dry 54}