code wiki / _hdl_build / nx_faithdiff_probe.nx
nx_faithdiff_probe.nx source
↩ module page · 180 lines · 11077 B
1// nx_faithdiff_probe.nx -- functions UNDER wat-faithfulness test. NO main -> the WAT target exports each.
2// Imports the REAL codec so the probe tests the SHIPPING functions (not copies) + a FULL encode->decode
3// roundtrip -> a divergence VM-vs-native here == the identical divergence in the deployed wasm. license: ORIGINAL
4import "nx_video_codec_wasm.nx" // brings vv_enc/vv_dec (+ vc_* incl AQ/tile/deblock) exactly as shipped
5const K_MAGIC_16384: i64 = 16384
6const K_MAGIC_20480: i64 = 20480
7const K_MAGIC_6016: i64 = 6016
8const K_MAGIC_4096: i64 = 4096
9const K_MAGIC_8192: i64 = 8192
10const K_MAGIC_90000: i64 = 90000
11const K_MAGIC_90128: i64 = 90128
12const K_MAGIC_90256: i64 = 90256
13const K_MAGIC_130000: i64 = 130000
14const K_MAGIC_52000: i64 = 52000
15const K_MAGIC_89000: i64 = 89000
16const K_MAGIC_16777216: i64 = 16777216
17const K_MAGIC_57008: i64 = 57008
18const K_MAGIC_57500: i64 = 57500
19const K_MAGIC_57692: i64 = 57692
20const K_MAGIC_58400: i64 = 58400
21
22// the TILE integration pattern (isolated): tfy pack/unpack + the variable-bound compare
23func fd_tile(tfy: i64, sy: i64) -> i64 {
24 let tf: i64 = tfy & 1; let ytop: i64 = tfy >> 1
25 var r: i64 = tf
26 if sy > ytop { r = r + 1000 }
27 return r }
28
29// FULL codec roundtrip at a caller-provided memory base (native = real alloc; VM = mod.mem offset). Fills a
30// 64x64 frame from seed, vv_enc (key) then vv_dec, returns a checksum of the decoded recon + bitcount. If VM
31// and native return the same value, the ENTIRE encode->decode path (AQ + tile + deblock + transform +
32// entropy) lowered to wasm faithfully. W=64,H=64 is codec-safe (chroma 32x32, both /16).
33func fd_roundtrip(membase: i64, seed: i64) -> i64 {
34 let W: i64 = 64; let H: i64 = 64
35 let N: i64 = W*H; let C: i64 = (W/2)*(H/2); let sz: i64 = N + 2*C
36 let cur: *u8 = membase as *u8
37 let prevE: *u8 = (membase + sz) as *u8; let reconE: *u8 = (membase + 2*sz) as *u8
38 let prevD: *u8 = (membase + 3*sz) as *u8; let reconD: *u8 = (membase + 4*sz) as *u8
39 let stream: *u8 = (membase + 5*sz) as *u8
40 let blk: *i64 = (membase + 5*sz + K_MAGIC_16384) as *i64
41 let mv: *i64 = (membase + 5*sz + K_MAGIC_20480) as *i64
42 var i: i64 = 0
43 while i < sz { prevE[i] = 0 as u8; prevD[i] = 0 as u8; i = i + 1 }
44 i = 0
45 while i < N { let x: i64 = i & 63; let y: i64 = i >> 6
46 var v: i64 = (x + y) * 2 + (seed & 63); if x > 31 { v = v + 40 }; if v > 255 { v = 255 }
47 cur[i] = v as u8; i = i + 1 }
48 i = N; while i < sz { cur[i] = 128 as u8; i = i + 1 }
49 let kb: i64 = vv_enc(cur, prevE, reconE, W, H, 20, 1, K_MAGIC_6016, stream, K_MAGIC_16384, blk, mv)
50 vv_dec(prevD, reconD, W, H, 20, stream, kb, blk, mv)
51 var sum: i64 = 0; i = 0
52 while i < sz { sum = sum + (reconD[i] & 0xff) * (i + 1); i = i + 1 }
53 return (sum & 0xffffff) * K_MAGIC_4096 + (kb & 0xfff) }
54
55// full BANDED roundtrip (the tile-parallel path): 2 bands via vv_enc_band/vv_dec_band, decode reverse.
56func fd_band_roundtrip(membase: i64, seed: i64) -> i64 {
57 let W: i64 = 64; let H: i64 = 64
58 let N: i64 = W*H; let C: i64 = (W/2)*(H/2); let sz: i64 = N + 2*C
59 let cur: *u8 = membase as *u8
60 let prev: *u8 = (membase + sz) as *u8; let reconE: *u8 = (membase + 2*sz) as *u8; let reconD: *u8 = (membase + 3*sz) as *u8
61 let s0: *u8 = (membase + 4*sz) as *u8; let s1: *u8 = (membase + 4*sz + K_MAGIC_8192) as *u8
62 let blk: *i64 = (membase + 4*sz + K_MAGIC_16384) as *i64; let mv: *i64 = (membase + 4*sz + K_MAGIC_20480) as *i64
63 var i: i64 = 0
64 while i < sz { prev[i] = 0 as u8; i = i + 1 }
65 i = 0
66 while i < N { let x: i64 = i & 63; let y: i64 = i >> 6
67 var v: i64 = (x + y) * 2 + (seed & 63); if x > 31 { v = v + 40 }; if v > 255 { v = 255 }
68 cur[i] = v as u8; i = i + 1 }
69 i = N; while i < sz { cur[i] = 128 as u8; i = i + 1 }
70 let l0: i64 = vv_enc_band(cur, prev, reconE, W, H, 0, 2, 20, 1, K_MAGIC_6016, s0, K_MAGIC_8192, blk, mv) // BH=4, 2 bands x 2 rows
71 let l1: i64 = vv_enc_band(cur, prev, reconE, W, H, 2, 4, 20, 1, K_MAGIC_6016, s1, K_MAGIC_8192, blk, mv)
72 vv_dec_band(prev, reconD, W, H, 2, 4, 20, s1, l1, blk, mv)
73 vv_dec_band(prev, reconD, W, H, 0, 2, 20, s0, l0, blk, mv)
74 var sum: i64 = 0; i = 0
75 while i < sz { sum = sum + (reconD[i] & 0xff) * (i + 1); i = i + 1 }
76 return (sum & 0xffffff) * K_MAGIC_4096 + ((l0 + l1) & 0xfff) }
77
78// RANGE-CODED full-frame roundtrip (task #31): vv_enc_rc -> vv_dec_rc through the LZMA range coder. A VM-vs-
79// native divergence here == the identical divergence in the deployed wasm -> catches any range-coder lowering
80// bug BEFORE it ships. rctx buffers laid out high in membase to avoid the codec scratch below.
81func fd_rc_roundtrip(membase: i64, seed: i64) -> i64 {
82 let W: i64 = 64; let H: i64 = 64
83 let N: i64 = W*H; let C: i64 = (W/2)*(H/2); let sz: i64 = N + 2*C
84 let cur: *u8 = membase as *u8
85 let prevE: *u8 = (membase + sz) as *u8; let reconE: *u8 = (membase + 2*sz) as *u8
86 let prevD: *u8 = (membase + 3*sz) as *u8; let reconD: *u8 = (membase + 4*sz) as *u8
87 let stream: *u8 = (membase + 5*sz) as *u8
88 let blk: *i64 = (membase + 5*sz + K_MAGIC_16384) as *i64
89 let mv: *i64 = (membase + 5*sz + K_MAGIC_20480) as *i64
90 let est: *i64 = (membase + K_MAGIC_90000) as *i64
91 let probs: *i64 = (membase + K_MAGIC_90128) as *i64
92 let rcbuf: *u8 = (membase + K_MAGIC_90256) as *u8
93 let rctx: *i64 = (membase + K_MAGIC_130000) as *i64
94 var i: i64 = 0
95 while i < sz { prevE[i] = 0 as u8; prevD[i] = 0 as u8; i = i + 1 }
96 i = 0
97 while i < N { let x: i64 = i & 63; let y: i64 = i >> 6
98 var v: i64 = (x + y) * 2 + (seed & 63); if x > 31 { v = v + 40 }; if v > 255 { v = 255 }
99 cur[i] = v as u8; i = i + 1 }
100 i = N; while i < sz { cur[i] = 128 as u8; i = i + 1 }
101 rctx[0] = 1; rctx[1] = est as i64; rctx[2] = probs as i64; rctx[3] = rcbuf as i64
102 let kb: i64 = vv_enc_rc(cur, prevE, reconE, W, H, 20, 1, K_MAGIC_6016, stream, K_MAGIC_16384, blk, mv, rctx)
103 rctx[0] = 1; rctx[1] = est as i64; rctx[2] = probs as i64; rctx[3] = rcbuf as i64
104 vv_dec_rc(prevD, reconD, W, H, 20, stream, kb, blk, mv, rctx)
105 var sum: i64 = 0; i = 0
106 while i < sz { sum = sum + (reconD[i] & 0xff) * (i + 1); i = i + 1 }
107 return (sum & 0xffffff) * K_MAGIC_4096 + (kb & 0xfff) }
108
109// VARIABLE-TRANSFORM (t8) roundtrip (task #46 rung 2): vv_enc_t8 -> vv_dec_t8, KEYFRAME then a P-FRAME
110// (right half changed -> left half SKIPs, right half codes inter residuals) so the 8x8 intra AND inter
111// paths + the 1 bit/MB select all execute IN THE VM. t8 buffers live in a fresh region (membase+52000..)
112// clear of the other probes' layouts. Checksums the P recon + both bitcounts.
113func fd_t8_roundtrip(membase: i64, seed: i64) -> i64 {
114 let W: i64 = 64; let H: i64 = 64
115 let N: i64 = W*H; let C: i64 = (W/2)*(H/2); let sz: i64 = N + 2*C
116 let cur: *u8 = membase as *u8
117 let prevE: *u8 = (membase + sz) as *u8; let reconE: *u8 = (membase + 2*sz) as *u8
118 let prevD: *u8 = (membase + 3*sz) as *u8; let reconD: *u8 = (membase + 4*sz) as *u8
119 let stream: *u8 = (membase + 5*sz) as *u8
120 let blk: *i64 = (membase + 5*sz + K_MAGIC_16384) as *i64
121 let mv: *i64 = (membase + 5*sz + K_MAGIC_20480) as *i64
122 let t8c: *i64 = (membase + K_MAGIC_52000) as *i64
123 let rctx: *i64 = (membase + K_MAGIC_89000) as *i64
124 vc_t8_init(t8c)
125 var i: i64 = 0
126 while i < sz { prevE[i] = 0 as u8; prevD[i] = 0 as u8; i = i + 1 }
127 i = 0
128 while i < N { let x: i64 = i & 63; let y: i64 = i >> 6
129 var v: i64 = (x + y) * 2 + (seed & 63); if x > 31 { v = v + 40 }; if v > 255 { v = 255 }
130 cur[i] = v as u8; i = i + 1 }
131 i = N; while i < sz { cur[i] = 128 as u8; i = i + 1 }
132 rctx[0] = 0; rctx[1] = 0; rctx[2] = 0; rctx[3] = 0; rctx[4] = t8c as i64
133 let kb: i64 = vv_enc_t8(cur, prevE, reconE, W, H, 20, 1, K_MAGIC_6016, stream, K_MAGIC_16384, blk, mv, rctx)
134 rctx[0] = 0; rctx[1] = 0; rctx[2] = 0; rctx[3] = 0; rctx[4] = t8c as i64
135 vv_dec_t8(prevD, reconD, W, H, 20, stream, kb, blk, mv, rctx)
136 i = 0
137 while i < sz { prevE[i] = reconE[i]; prevD[i] = reconD[i]; i = i + 1 }
138 i = 0
139 while i < N { let x: i64 = i & 63
140 if x > 31 { var v2: i64 = (cur[i] as i64) + 25; if v2 > 255 { v2 = 255 }; cur[i] = v2 as u8 }
141 i = i + 1 }
142 rctx[0] = 4; rctx[1] = 0; rctx[2] = 0; rctx[3] = 0; rctx[4] = t8c as i64; rctx[5] = 0 // emode 4 = CAVLC + RD-AUTO: the P-frame exercises vc_rd_t8_inter + bit-patch in the VM
143 let pb: i64 = vv_enc_t8(cur, prevE, reconE, W, H, 20, 0, K_MAGIC_6016, stream, K_MAGIC_16384, blk, mv, rctx)
144 rctx[0] = 0; rctx[1] = 0; rctx[2] = 0; rctx[3] = 0; rctx[4] = t8c as i64 // decoder never sees the auto flag
145 vv_dec_t8(prevD, reconD, W, H, 20, stream, pb, blk, mv, rctx)
146 var sum: i64 = 0; i = 0
147 while i < sz { sum = sum + (reconD[i] & 0xff) * (i + 1); i = i + 1 }
148 return (sum & 0xfffff) * K_MAGIC_16777216 + (kb & 0xfff) * K_MAGIC_4096 + (pb & 0xfff) }
149
150// RANGE-CODED + t8 roundtrip: vv_enc_rct8 -> vv_dec_rct8 (rc_block64 contexts + the two-section frame),
151// keyframe only (the rc+inter interaction is fd_rc's + fd_t8's job; this pins the rct8 composition).
152func fd_rct8_roundtrip(membase: i64, seed: i64) -> i64 {
153 let W: i64 = 64; let H: i64 = 64
154 let N: i64 = W*H; let C: i64 = (W/2)*(H/2); let sz: i64 = N + 2*C
155 let cur: *u8 = membase as *u8
156 let prevE: *u8 = (membase + sz) as *u8; let reconE: *u8 = (membase + 2*sz) as *u8
157 let prevD: *u8 = (membase + 3*sz) as *u8; let reconD: *u8 = (membase + 4*sz) as *u8
158 let stream: *u8 = (membase + 5*sz) as *u8
159 let blk: *i64 = (membase + 5*sz + K_MAGIC_16384) as *i64
160 let mv: *i64 = (membase + 5*sz + K_MAGIC_20480) as *i64
161 let t8c: *i64 = (membase + K_MAGIC_52000) as *i64 // VC_T8_SIZE*8 = 5008B, ends K_MAGIC_57008
162 let est: *i64 = (membase + K_MAGIC_57500) as *i64
163 let probs: *i64 = (membase + K_MAGIC_57692) as *i64 // 24 contexts (RC_NCTX8) fit here with room
164 let rcbuf: *u8 = (membase + K_MAGIC_58400) as *u8 // ~30000B rc section scratch, ends < K_MAGIC_89000
165 let rctx: *i64 = (membase + K_MAGIC_89000) as *i64
166 vc_t8_init(t8c)
167 var i: i64 = 0
168 while i < sz { prevE[i] = 0 as u8; prevD[i] = 0 as u8; i = i + 1 }
169 i = 0
170 while i < N { let x: i64 = i & 63; let y: i64 = i >> 6
171 var v: i64 = (x + y) * 2 + (seed & 63); if x > 31 { v = v + 40 }; if v > 255 { v = 255 }
172 cur[i] = v as u8; i = i + 1 }
173 i = N; while i < sz { cur[i] = 128 as u8; i = i + 1 }
174 rctx[0] = 1; rctx[1] = est as i64; rctx[2] = probs as i64; rctx[3] = rcbuf as i64; rctx[4] = t8c as i64
175 let kb: i64 = vv_enc_rct8(cur, prevE, reconE, W, H, 20, 1, K_MAGIC_6016, stream, K_MAGIC_16384, blk, mv, rctx)
176 rctx[0] = 1; rctx[1] = est as i64; rctx[2] = probs as i64; rctx[3] = rcbuf as i64; rctx[4] = t8c as i64
177 vv_dec_rct8(prevD, reconD, W, H, 20, stream, kb, blk, mv, rctx)
178 var sum: i64 = 0; i = 0
179 while i < sz { sum = sum + (reconD[i] & 0xff) * (i + 1); i = i + 1 }
180 return (sum & 0xffffff) * K_MAGIC_4096 + (kb & 0xfff) }