code wiki / _hdl_build / nx_vcodec_compound_ceil.nx
nx_vcodec_compound_ceil.nx source
↩ module page · 120 lines · 6402 B
1// nx_vcodec_compound_ceil.nx -- GEN-2 RUNG-0 PROBE P0a: compound-from-past AVERAGING ceiling (SAD domain).
2// Question: on P-frames, does predicting a coded MB as the AVERAGE of two motion-compensated PAST references
3// (latency-safe: no future frame) beat the single-ref prediction we ship? Compound averaging cancels independent
4// quant noise between refs (up to ~sqrt(2) on static) and covers occlusion flips -- multi-ref SELECTION measured
5// only 1.5%, but AVERAGING is unmeasured and is gen-2's biggest open lever. Method: build the recon chain with
6// the REAL shipped encoder (vv_enc_rct8, emode 681); per coded (non-skip-threshold) MB, compare full-pel ME SAD:
7// single = vm_search vs prev1; compound = avg(MC(prev1,mv1), MC(prev2,mv2)) with mv2 = vm_search vs prev2.
8// Both arms full-pel (equal granularity = fair relative). Reports total SADs + the per-mille cut + the share of
9// MBs where compound wins. ⚠SAD->bits is SUBLINEAR (measured: an 18% SAD cut -> 3.7% bits at qp8) -- read the
10// result as an UPPER-bound direction gate for building compound syntax, not as BD-rate. license: ORIGINAL
11import "nx_syscalls.nx"
12import "nx_video_codec_wasm.nx"
13
14const SW: i64 = 352
15const SH: i64 = 288
16const NF: i64 = 48
17
18func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
19func gn(v: i64) -> i64 {
20 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
21 let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
22 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
23func cpb(d: *u8, s: *u8, n: i64) -> i64 { var i: i64=0; while i<n { d[i]=s[i]; i=i+1 } return 0 }
24
25func frames(yuv: *u8, hi: i64, total: i64, fp: *i64, fdata: i64) -> i64 {
26 var nf: i64=0; var p: i64=hi
27 while nf < NF { if p>=total { break }
28 var q: i64=p; while q<total { if (yuv[q]&0xff)==10 { break } q=q+1 } q=q+1
29 if q+fdata>total { break } fp[nf]=(yuv as i64)+q; nf=nf+1; p=q+fdata }
30 return nf }
31
32// SAD of cur MB vs the AVERAGE of two full-pel MC blocks
33func sad_avg2(cur: *u8, r1: *u8, r2: *u8, W: i64, cx: i64, cy: i64, m1x: i64, m1y: i64, m2x: i64, m2y: i64) -> i64 {
34 var sad: i64 = 0
35 var y: i64 = 0
36 while y < 16 {
37 var x: i64 = 0
38 while x < 16 {
39 let a: i64 = r1[(cy+m1y+y)*W + cx+m1x+x] as i64
40 let b: i64 = r2[(cy+m2y+y)*W + cx+m2x+x] as i64
41 let d: i64 = (cur[(cy+y)*W + cx+x] as i64) - ((a + b + 1) >> 1)
42 if d < 0 { sad = sad - d } else { sad = sad + d }
43 x = x + 1 }
44 y = y + 1 }
45 return sad
46}
47
48func runv(fp: *i64, qp: i64, sz: i64, out: *i64) -> i64 {
49 let prevE: *u8=sys_mmap(sz+64); let reconE: *u8=sys_mmap(sz+64); let prev2: *u8=sys_mmap(sz+64)
50 let wire: *u8=sys_mmap(4194304); let blk: *i64=sys_mmap(512) as *i64; let mv: *i64=sys_mmap(128) as *i64
51 let est: *i64=sys_mmap(64) as *i64; let probs: *i64=sys_mmap(32*8) as *i64; let rcb: *u8=sys_mmap(4194304)
52 let t8c: *i64=sys_mmap(5120) as *i64; let rctx: *i64=sys_mmap(64) as *i64
53 let dmv1: *i64=sys_mmap(32) as *i64; let dmv2: *i64=sys_mmap(32) as *i64
54 vc_t8_init(t8c)
55 var z: i64=0; while z<sz { prevE[z]=0 as u8; prev2[z]=0 as u8; z=z+1 }
56 rctx[1]=est as i64; rctx[2]=probs as i64; rctx[3]=rcb as i64; rctx[4]=t8c as i64; rctx[5]=0; rctx[6]=0; rctx[7]=0
57 out[0]=0; out[1]=0; out[2]=0; out[3]=0
58 let BW: i64 = SW/16; let BH: i64 = SH/16
59 var f: i64=0
60 while f < NF {
61 let cur: *u8=fp[f] as *u8
62 var key: i64=0; if f==0 { key=1 }
63 // side-measure BEFORE encoding this frame (prev/prev2 are the refs an encoder would use for frame f)
64 if f >= 2 {
65 var by: i64=0
66 while by < BH {
67 var bx: i64=0
68 while bx < BW {
69 let zsad: i64 = vm_sad_zero(cur, prevE, SW, bx, by, 16)
70 if zsad >= qp*30 { // the shipped skip gate: only CODED MBs matter
71 let s1: i64 = vm_search(cur, prevE, SW, SH, bx, by, 16, 8, dmv1, vmscr3)
72 vm_search(cur, prev2, SW, SH, bx, by, 16, 8, dmv2, vmscr3)
73 let sc: i64 = sad_avg2(cur, prevE, prev2, SW, bx*16, by*16, dmv1[0], dmv1[1], dmv2[0], dmv2[1])
74 out[0] = out[0] + s1
75 var best: i64 = s1
76 if sc < best { best = sc; out[3] = out[3] + 1 }
77 out[1] = out[1] + best
78 out[2] = out[2] + 1
79 }
80 bx = bx + 1 }
81 by = by + 1 }
82 }
83 rctx[0]=681
84 let nb: i64 = vv_enc_rct8(cur, prevE, reconE, SW, SH, qp, key, qp*30, wire, 4194304, blk, mv, rctx)
85 if nb<=0 { return 1 }
86 cpb(prev2, prevE, sz)
87 cpb(prevE, reconE, sz)
88 f=f+1
89 }
90 return 0 }
91
92func sweepqp(fp: *i64, sz: i64, qp: i64) -> i64 {
93 let o: *i64=sys_mmap(40) as *i64
94 runv(fp, qp, sz, o)
95 gw(" qp=" as *u8); gn(qp)
96 gw(" codedMBs=" as *u8); gn(o[2])
97 gw(" singleSAD=" as *u8); gn(o[0])
98 gw(" min(single,compound)=" as *u8); gn(o[1])
99 if o[0] > 0 { gw(" SADcut=" as *u8); gn((o[0]-o[1])*1000/o[0]); gw(" permille" as *u8) }
100 if o[2] > 0 { gw(" compound-wins=" as *u8); gn(o[3]*1000/o[2]); gw(" permille-of-MBs" as *u8) }
101 gw("\n" as *u8)
102 return 0 }
103
104func main() -> i64 {
105 let vmscr3: *i64 = sys_mmap(32) as *i64 // vm_search scratch (2026-07-29: hoisted ONE alloc; the per-call sys_mmap inside vm_search was the wasm 0-stub + native map-leak class)
106 gw("=== nx_vcodec_compound_ceil: GEN-2 P0a compound-from-past averaging ceiling (SAD, full-pel both arms) ===\n" as *u8)
107 let box: *i64 = sys_mmap(16) as *i64
108 let yuv: *u8 = sys_read_file("/tmp/seq.y4m" as *u8, box)
109 if (yuv as i64)==0 { gw("cannot read /tmp/seq.y4m -> RED\n" as *u8); return 1 }
110 let total: i64=box[0]
111 var hi: i64=0; while hi<total { if (yuv[hi]&0xff)==10 { break } hi=hi+1 } hi=hi+1
112 let C2: i64=(SW/2)*(SH/2); let fdata: i64=SW*SH+2*C2; let sz: i64=fdata
113 let fp: *i64=sys_mmap(128*8) as *i64
114 let nf: i64=frames(yuv, hi, total, fp, fdata)
115 if nf < NF { gw("too few frames -> RED\n" as *u8); return 1 }
116 sweepqp(fp, sz, 8)
117 sweepqp(fp, sz, 20)
118 sweepqp(fp, sz, 32)
119 gw("COMPOUND: DONE\n" as *u8)
120 return 0 }