code wiki / _hdl_build / nx_rd_intra_gate.nx
nx_rd_intra_gate.nx source
↩ module page · 62 lines · 3808 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"
10
11func 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 {
12 var bits: i64 = 0
13 var by: i64 = 0
14 while by < H/4 {
15 var bx: i64 = 0
16 while bx < W/4 {
17 let cx: i64 = bx*4; let cy: i64 = by*4
18 var ht: i64 = 0; var hl: i64 = 0
19 if use_pred == 1 {
20 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 } }
21 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 } }
22 }
23 // load block pixels
24 let src: *i64 = sys_mmap(16*8) as *i64
25 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 }
26 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 } }
27 // residual -> transform -> quant -> entropy ; then reconstruct
28 var i2: i64=0; while i2<16 { blk[i2] = src[i2] - pred[i2]; i2=i2+1 }
29 vt_fwd(blk); vt_quant(blk, qp)
30 bits = bits + ve_encode(blk, ebuf)
31 vt_dequant(blk, qp); vt_inv(blk)
32 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 }
33 bx = bx + 1
34 }
35 by = by + 1
36 }
37 return bits
38}
39
40func main() -> i64 {
41 g_puts("nx_rd_intra gate (RD gain from intra prediction, MEASURED)\n" as *u8)
42 var pass: i64 = 0; var total: i64 = 0
43 let W: i64 = 32; let H: i64 = 32; let n: i64 = W*H; let QP: i64 = 12
44 let orig: *u8 = sys_mmap(n); let rN: *u8 = sys_mmap(n); let rP: *u8 = sys_mmap(n)
45 let ebuf: *u8 = sys_mmap(256); let blk: *i64 = sys_mmap(16*8) as *i64; let pred: *i64 = sys_mmap(16*8) as *i64
46 let top: *i64 = sys_mmap(4*8) as *i64; let left: *i64 = sys_mmap(4*8) as *i64
47 // a structured frame: vertical stripes (varies with x, constant down columns) -> intra VERTICAL predicts it well
48 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 }
49
50 let naive_bits: i64 = code_frame(orig, rN, W, H, QP, 0, ebuf, blk, pred, top, left)
51 let pred_bits: i64 = code_frame(orig, rP, W, H, QP, 1, ebuf, blk, pred, top, left)
52 let nb: i64 = (naive_bits+7)/8; let pb: i64 = (pred_bits+7)/8
53 let np: i64 = qm_psnr_cdb(orig, rN, n); let pp: i64 = qm_psnr_cdb(orig, rP, n)
54 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)
55
56 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
57 pass = pass + g_check("both reconstruct (PSNR sane)" as *u8, (np > 2000) & (pp > 2000)); total=total+1
58
59 g_puts("---- rd-intra gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
60 if pass == total { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
61 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
62}