code wiki / _hdl_build / nx_rd_intra_gate.nx
nx_rd_intra_gate.nx source
↩ module page · 70 lines · 4250 B
1// nx_rd_intra_gate.nx -- MEASURES the rate-distortion gain of intra prediction: code one structured frame two ways
2// (naive pixels-128 vs neighbour-predicted, raster order) at the same QP and compare bytes + PSNR. Proves V-R7
3// shifts the RD curve left (fewer bytes at equal quality). Composes nx_intra+nx_vtransform+nx_ventropy+nx_quality_metric.
4import "nx_syscalls.nx"
5import "nx_gate_emit_lib.nx"
6import "nx_intra.nx"
7import "nx_vtransform.nx"
8import "nx_ventropy.nx"
9import "nx_quality_metric.nx"
10import "nx_gate_verdict.nx"
11
12func code_frame(orig: *u8, recon: *u8, W: i64, H: i64, qp: i64, use_pred: i64, ebuf: *u8, blk: *i64, pred: *i64, top: *i64, left: *i64) -> i64 {
13 var bits: i64 = 0
14 var by: i64 = 0
15 while by < H/4 {
16 var bx: i64 = 0
17 while bx < W/4 {
18 let cx: i64 = bx*4; let cy: i64 = by*4
19 var ht: i64 = 0; var hl: i64 = 0
20 if use_pred == 1 {
21 if cy > 0 { ht = 1; var x: i64=0; while x<4 { top[x] = recon[(cy-1)*W + (cx+x)] as i64; x=x+1 } }
22 if cx > 0 { hl = 1; var y: i64=0; while y<4 { left[y] = recon[(cy+y)*W + (cx-1)] as i64; y=y+1 } }
23 }
24 // load block pixels
25 let src: *i64 = sys_mmap(16*8) as *i64
26 var yy: i64=0; while yy<4 { var xx: i64=0; while xx<4 { src[yy*4+xx] = orig[(cy+yy)*W+(cx+xx)] as i64; xx=xx+1 } yy=yy+1 }
27 if use_pred == 1 { in_best(src, top, left, ht, hl, pred) } else { var i: i64=0; while i<16 { pred[i]=128; i=i+1 } }
28 // residual -> transform -> quant -> entropy ; then reconstruct
29 var i2: i64=0; while i2<16 { blk[i2] = src[i2] - pred[i2]; i2=i2+1 }
30 vt_fwd(blk); vt_quant(blk, qp)
31 bits = bits + ve_encode(blk, ebuf)
32 vt_dequant(blk, qp); vt_inv(blk)
33 yy=0; while yy<4 { var xx: i64=0; while xx<4 { var v: i64 = pred[yy*4+xx] + blk[yy*4+xx]; if v<0 {v=0} if v>255 {v=255} recon[(cy+yy)*W+(cx+xx)] = v as u8; xx=xx+1 } yy=yy+1 }
34 bx = bx + 1
35 }
36 by = by + 1
37 }
38 return bits
39}
40
41func main() -> i64 {
42 g_puts("nx_rd_intra gate (RD gain from intra prediction, MEASURED)\n" as *u8)
43 var pass: i64 = 0; var total: i64 = 0
44 let W: i64 = 32; let H: i64 = 32; let n: i64 = W*H; let QP: i64 = 12
45 let orig: *u8 = sys_mmap(n); let rN: *u8 = sys_mmap(n); let rP: *u8 = sys_mmap(n)
46 let ebuf: *u8 = sys_mmap(256); let blk: *i64 = sys_mmap(16*8) as *i64; let pred: *i64 = sys_mmap(16*8) as *i64
47 let top: *i64 = sys_mmap(4*8) as *i64; let left: *i64 = sys_mmap(4*8) as *i64
48 // a structured frame: vertical stripes (varies with x, constant down columns) -> intra VERTICAL predicts it well
49 var y: i64=0; while y<H { var x: i64=0; while x<W { orig[y*W+x] = (50 + x*5) as u8; x=x+1 } y=y+1 }
50
51 let naive_bits: i64 = code_frame(orig, rN, W, H, QP, 0, ebuf, blk, pred, top, left)
52 let pred_bits: i64 = code_frame(orig, rP, W, H, QP, 1, ebuf, blk, pred, top, left)
53 let nb: i64 = (naive_bits+7)/8; let pb: i64 = (pred_bits+7)/8
54 let np: i64 = qm_psnr_cdb(orig, rN, n); let pp: i64 = qm_psnr_cdb(orig, rP, n)
55 g_puts(" [measure] naive: " as *u8); g_pn(nb); g_puts(" B @ PSNR " as *u8); g_pn(np); g_puts(" intra-pred: " as *u8); g_pn(pb); g_puts(" B @ PSNR " as *u8); g_pn(pp); g_puts("\n" as *u8)
56
57 pass = pass + g_check("intra prediction uses FEWER bytes at >= the quality (RD curve shifts left)" as *u8, (pb < nb) & (pp >= np - 50)); total=total+1
58 pass = pass + g_check("both reconstruct (PSNR sane)" as *u8, (np > 2000) & (pp > 2000)); total=total+1
59
60 g_puts("---- rd-intra gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
61 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
62 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
63 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
64 let ctr__dry: *i64 = gv_ctr()
65 ctr__dry[0] = pass
66 ctr__dry[1] = total
67 let rc__dry: i64 = gv_verdict("RD-INTRA-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
68 sys_exit(rc__dry)
69 return rc__dry
70}