code wiki / _hdl_build / nx_vcodec_tile_gate.nx

nx_vcodec_tile_gate.nx source

↩ module page · 92 lines · 6661 B

1import "nx_gate_base.nx" 2// nx_vcodec_tile_gate.nx -- TILE-PARALLEL proof (task #47 rung 1). Splits a luma plane into K row-tiles and 3// encodes/decodes each as a self-contained stream via vc_enc/dec_frame_packed_region. The cardinal proofs: 4// T1 keyframe: decode the K tiles in REVERSE order (K-1..0) and still reconstruct byte-exact -> no tile 5// depends on any other (the whole point: each can run on its own core/GPU-workgroup). 6// T2 untiled region == the original full-frame codec (the primitive reduces cleanly; no regression). 7// T3 P-frame tiles: same reverse-order bit-exactness (motion reads the full prev, which is shared+ready). 8// T4 measured per-tile encode time -> the parallel speedup a K-core / GPU dispatch would realize. 9// license_tier: ORIGINAL 10import "nx_syscalls.nx" 11import "nx_vcodec.nx" 12 13func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 14" as *u8); return ok } 15func gn(v: i64) -> i64 { 16 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} 17 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} 18 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 19func ck(name: *u8, ok: i64, p: *i64, t: *i64) -> i64 { 20 t[0]=t[0]+1; gw(" " as *u8); gw(name); if ok==1 { gw(" PASS\n" as *u8); p[0]=p[0]+1 } else { gw(" FAIL\n" as *u8) } return 0 } 21 22func fillY(y: *u8, W: i64, H: i64, sh: i64) -> i64 { 23 var r: i64=0 24 while r<H { var c: i64=0 25 while c<W { let sc: i64=c+sh; var v: i64=(sc*255)/W + (((sc/2+r/3)%7)*20-60); if sc>W/2 { v=v+45 } 26 if v<0 {v=0} if v>255 {v=255}; y[r*W+c]=v as u8; c=c+1 } r=r+1 } 27 return 0 } 28func eqbytes(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if (a[i]&0xff)!=(b[i]&0xff) { return 0 } i=i+1 } return 1 } 29 30func main() -> i64 { 31 gw("=== nx_vcodec_tile_gate: tile-parallel independence + bit-exactness (rung 1 toward 4K@60) ===\n" as *u8) 32 let p: *i64=sys_mmap(16) as *i64; let t: *i64=sys_mmap(16) as *i64 33 let W: i64=256; let H: i64=192; let q: i64=16; let N: i64=W*H 34 let K: i64=4 // 4 tiles; BH=12 MB rows -> 3 MB rows (48px) per tile 35 let BH: i64=H/16; let trows: i64=BH/K 36 let cur: *u8=sys_mmap(N); let prev: *u8=sys_mmap(N) 37 let reconE: *u8=sys_mmap(N); let reconD: *u8=sys_mmap(N); let reconF: *u8=sys_mmap(N) 38 let blk: *i64=sys_mmap(512) as *i64; let mv: *i64=sys_mmap(128) as *i64 39 let full: *u8=sys_mmap(262144) 40 // per-tile independent stream buffers 41 let ts0: *u8=sys_mmap(131072); let ts1: *u8=sys_mmap(131072); let ts2: *u8=sys_mmap(131072); let ts3: *u8=sys_mmap(131072) 42 var z: i64=0; while z<N { prev[z]=0 as u8; z=z+1 } 43 fillY(cur, W, H, 0) 44 45 // ---- T1: KEYFRAME, encode 4 tiles, decode in REVERSE order ---- 46 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 0*trows, 1*trows, q, 1, 6016, ts0, blk, mv, 0) 47 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 1*trows, 2*trows, q, 1, 6016, ts1, blk, mv, 0) 48 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 2*trows, 3*trows, q, 1, 6016, ts2, blk, mv, 0) 49 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 3*trows, 4*trows, q, 1, 6016, ts3, blk, mv, 0) 50 // decode 3,2,1,0 -- reverse order proves NO tile depends on an earlier one 51 vc_dec_frame_packed_region(prev, reconD, W, H, 3*trows, 4*trows, q, ts3, blk, mv, 0) 52 vc_dec_frame_packed_region(prev, reconD, W, H, 2*trows, 3*trows, q, ts2, blk, mv, 0) 53 vc_dec_frame_packed_region(prev, reconD, W, H, 1*trows, 2*trows, q, ts1, blk, mv, 0) 54 vc_dec_frame_packed_region(prev, reconD, W, H, 0*trows, 1*trows, q, ts0, blk, mv, 0) 55 ck("T1 keyframe: 4 tiles decode REVERSE-order byte-exact (independent)\x00" as *u8, eqbytes(reconE, reconD, N), p, t) 56 57 // ---- T2: untiled region [0,BH) == original full-frame codec (no regression) ---- 58 let fb: i64 = vc_enc_frame_packed(cur, prev, reconF, W, H, q, 1, 6016, full, blk, mv) 59 let rb: *u8=sys_mmap(262144) 60 let reconR: *u8=sys_mmap(N) 61 vc_enc_frame_packed_region(cur, prev, reconR, W, H, 0, BH, q, 1, 6016, rb, blk, mv, 0) 62 ck("T2 region[0,BH) recon == full-frame codec recon (untiled reduces cleanly)\x00" as *u8, eqbytes(reconF, reconR, N), p, t) 63 64 // ---- T3: P-FRAME tiles (motion reads full prev), reverse-order bit-exact ---- 65 fillY(prev, W, H, 0) // prev = last frame 66 fillY(cur, W, H, 4) // cur panned 4px -> real motion 67 var z2: i64=0; while z2<N { reconD[z2]=0xEE as u8; reconE[z2]=0xEE as u8; z2=z2+1 } 68 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 0, 1*trows, q, 0, 6016, ts0, blk, mv, 0) 69 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 1*trows, 2*trows, q, 0, 6016, ts1, blk, mv, 0) 70 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 2*trows, 3*trows, q, 0, 6016, ts2, blk, mv, 0) 71 vc_enc_frame_packed_region(cur, prev, reconE, W, H, 3*trows, 4*trows, q, 0, 6016, ts3, blk, mv, 0) 72 vc_dec_frame_packed_region(prev, reconD, W, H, 1*trows, 2*trows, q, ts1, blk, mv, 0) 73 vc_dec_frame_packed_region(prev, reconD, W, H, 3*trows, 4*trows, q, ts3, blk, mv, 0) 74 vc_dec_frame_packed_region(prev, reconD, W, H, 0, 1*trows, q, ts0, blk, mv, 0) 75 vc_dec_frame_packed_region(prev, reconD, W, H, 2*trows, 3*trows, q, ts2, blk, mv, 0) 76 ck("T3 P-frame: tiles decode out-of-order byte-exact (motion via shared prev)\x00" as *u8, eqbytes(reconE, reconD, N), p, t) 77 78 // ---- T4: per-tile encode time -> parallel speedup a K-core / GPU dispatch realizes ---- 79 let ITER: i64=40 80 let t0: i64=sys_now_us(); var it: i64=0 81 while it<ITER { vc_enc_frame_packed(cur, prev, reconF, W, H, q, 0, 6016, full, blk, mv); it=it+1 } 82 let serial: i64=(sys_now_us()-t0)/ITER 83 let t1: i64=sys_now_us(); it=0 84 while it<ITER { vc_enc_frame_packed_region(cur, prev, reconE, W, H, 0, trows, q, 0, 6016, ts0, blk, mv, 0); it=it+1 } 85 let onetile: i64=(sys_now_us()-t1)/ITER 86 gw(" serial whole-frame enc=" as *u8); gn(serial); gw("us one-of-" as *u8); gn(K); gw("-tiles=" as *u8); gn(onetile) 87 gw("us => " as *u8); gn(K); gw(" cores ~= " as *u8); gn(serial/(onetile+1)); gw("x speedup (wall-clock = slowest tile)\n" as *u8) 88 ck("T4 tiling adds no serial overhead (K tiles ~= 1 frame of work)\x00" as *u8, (onetile*K < serial*13/10 + 200) as i64, p, t) 89 90 gw("TILE-GATE: " as *u8); gn(p[0]); gw("/" as *u8); gn(t[0]) 91 if p[0]==t[0] { gw(" GREEN -- tiles are INDEPENDENT + bit-exact -> the codec is now parallelizable (CPU cores now, GPU later)\n" as *u8); return 0 } 92 gw(" RED\n" as *u8); return 1 }