code wiki / (root) / nx_av1_intra_gate.nx

nx_av1_intra_gate.nx source

↩ module page · 257 lines · 9750 B

1// nx_av1_intra_gate.nx -- proves AV1/AV2 non-directional intra prediction. 2// 3// T2 pins DC's FOUR availability cases. With NEITHER edge the answer is 4// mid-grey 1 << (bitdepth-1), not zero. A decoder that treats a missing edge 5// as zeros predicts black along the top and left of every frame -- which 6// reads as a vignette, not as a bug. 7// 8// T5 is the strongest structural check for the smooth family: with CONSTANT 9// neighbours every smooth predictor must return exactly that constant. That 10// holds only if each weight and its complement sum to 256 and the rounding 11// matches. Using 255 as the complement produces almost-right constants -- a 12// fraction of a level per pixel, accumulating across a frame as a gradient. 13// 14// T4 pins Paeth's TIE ORDER and that it SELECTS rather than averages: over 15// 300 random triples the result must always be one of its three inputs. 16// 17// license_tier: ORIGINAL 18import "nx_syscalls.nx" 19import "nx_av1_intra.nx" 20 21func g_puts(s: *u8) -> i64 { 22 var i: i64 = 0 23 while s[i] != (0 as u8) { i = i + 1 } 24 sys_write(1, s, i) 25 return i 26} 27 28func g_putn(v: i64) -> i64 { 29 let buf: *u8 = sys_mmap(32) 30 var x: i64 = v 31 if x < 0 { g_puts("-" as *u8); x = 0 - x } 32 if x == 0 { buf[0] = 0x30 as u8; sys_write(1, buf, 1); return 1 } 33 let tmp: *u8 = sys_mmap(32) 34 var d: i64 = 0 35 while x > 0 { tmp[d] = ((x % 10) + 0x30) as u8; x = x / 10; d = d + 1 } 36 var i: i64 = 0 37 while i < d { buf[i] = tmp[d - 1 - i]; i = i + 1 } 38 sys_write(1, buf, d) 39 return d 40} 41 42func main() -> i64 { 43 var fails: i64 = 0 44 var mark: i64 = 0 45 46 let above: *i64 = sys_mmap(64 * 8) as *i64 47 let left: *i64 = sys_mmap(64 * 8) as *i64 48 let out: *i64 = sys_mmap(512 * 8) as *i64 49 let p: *i64 = sys_mmap(64 * 8) as *i64 50 51 var i: i64 = 0 52 var r: i64 = 0 53 var c: i64 = 0 54 var bad: i64 = 0 55 var n: i64 = 0 56 var v: i64 = 0 57 var m: i64 = 0 58 59 // ---- T1: the smooth weight tables ---- 60 if nx_intra_sm_weight(4, 0) != 255 { fails = fails + 1 } 61 if nx_intra_sm_weight(4, 3) != 64 { fails = fails + 1 } 62 if nx_intra_sm_weight(8, 0) != 255 { fails = fails + 1 } 63 if nx_intra_sm_weight(8, 7) != 32 { fails = fails + 1 } 64 if nx_intra_sm_weight(16, 0) != 255 { fails = fails + 1 } 65 if nx_intra_sm_weight(16, 15) != 16 { fails = fails + 1 } 66 bad = 0 67 i = 1 68 while i < 8 { 69 if nx_intra_sm_weight(8, i) >= nx_intra_sm_weight(8, i - 1) { bad = bad + 1 } 70 i = i + 1 71 } 72 if bad != 0 { fails = fails + 1 } 73 if nx_intra_sm_weight(8, 8) != (0 - 1) { fails = fails + 1 } 74 if nx_intra_sm_weight(5, 0) != (0 - 1) { fails = fails + 1 } 75 if fails > 0 { if mark == 0 { mark = 1 } } 76 77 // ---- T2: DC's FOUR availability cases ---- 78 i = 0 79 while i < 16 { above[i] = 100; left[i] = 200; i = i + 1 } 80 p[NX_INTRA_P_ABOVELEFT] = 0 81 p[NX_INTRA_P_W] = 4 82 p[NX_INTRA_P_H] = 4 83 p[NX_INTRA_P_BITDEPTH] = 8 84 // both edges: (4*100 + 4*200 + 4) / 8 = 150 85 p[NX_INTRA_P_HAVE_A] = 1; p[NX_INTRA_P_HAVE_L] = 1 86 if nx_intra_dc_value(above, left, p) != 150 { fails = fails + 1 } 87 // above only 88 p[NX_INTRA_P_HAVE_A] = 1; p[NX_INTRA_P_HAVE_L] = 0 89 if nx_intra_dc_value(above, left, p) != 100 { fails = fails + 1 } 90 // left only 91 p[NX_INTRA_P_HAVE_A] = 0; p[NX_INTRA_P_HAVE_L] = 1 92 if nx_intra_dc_value(above, left, p) != 200 { fails = fails + 1 } 93 // NEITHER: mid-grey, not zero 94 p[NX_INTRA_P_HAVE_A] = 0; p[NX_INTRA_P_HAVE_L] = 0 95 if nx_intra_dc_value(above, left, p) != 128 { fails = fails + 1 } 96 p[NX_INTRA_P_BITDEPTH] = 10 97 if nx_intra_dc_value(above, left, p) != 512 { fails = fails + 1 } 98 p[NX_INTRA_P_BITDEPTH] = 12 99 if nx_intra_dc_value(above, left, p) != 2048 { fails = fails + 1 } 100 // a bit depth below 8 is refused 101 p[NX_INTRA_P_BITDEPTH] = 4 102 if nx_intra_dc_value(above, left, p) != (0 - 1) { fails = fails + 1 } 103 // non-square 8x4 with both edges: (8*100 + 4*200 + 6)/12 = 133 104 p[NX_INTRA_P_BITDEPTH] = 8 105 p[NX_INTRA_P_W] = 8; p[NX_INTRA_P_H] = 4 106 p[NX_INTRA_P_HAVE_A] = 1; p[NX_INTRA_P_HAVE_L] = 1 107 if nx_intra_dc_value(above, left, p) != 133 { fails = fails + 1 } 108 if fails > 0 { if mark == 0 { mark = 2 } } 109 110 // ---- T3: V copies columns, H copies rows ---- 111 i = 0 112 while i < 16 { above[i] = 10 + i; left[i] = 90 + i; i = i + 1 } 113 p[NX_INTRA_P_W] = 4; p[NX_INTRA_P_H] = 4 114 p[NX_INTRA_P_HAVE_A] = 1; p[NX_INTRA_P_HAVE_L] = 1 115 bad = 0 116 if nx_intra_predict(NX_INTRA_V, out, above, left, p) != 1 { fails = fails + 1 } else { 117 r = 0 118 while r < 4 { 119 c = 0 120 while c < 4 { 121 if out[r * 4 + c] != above[c] { bad = bad + 1 } 122 c = c + 1 123 } 124 r = r + 1 125 } 126 } 127 if nx_intra_predict(NX_INTRA_H, out, above, left, p) != 1 { fails = fails + 1 } else { 128 r = 0 129 while r < 4 { 130 c = 0 131 while c < 4 { 132 if out[r * 4 + c] != left[r] { bad = bad + 1 } 133 c = c + 1 134 } 135 r = r + 1 136 } 137 } 138 if bad != 0 { fails = fails + 1 } 139 if fails > 0 { if mark == 0 { mark = 3 } } 140 141 // ---- T4: Paeth SELECTS, and its TIE ORDER ---- 142 if nx_intra_paeth_pick(10, 20, 15) != 15 { fails = fails + 1 } 143 if nx_intra_paeth_pick(10, 50, 10) != 50 { fails = fails + 1 } 144 if nx_intra_paeth_pick(70, 20, 20) != 70 { fails = fails + 1 } 145 if nx_intra_paeth_pick(33, 33, 33) != 33 { fails = fails + 1 } 146 var seed: i64 = 4242 147 var l1: i64 = 0 148 var a1: i64 = 0 149 var al1: i64 = 0 150 var pk: i64 = 0 151 bad = 0 152 i = 0 153 while i < 300 { 154 seed = (seed * 1103515245 + 12345) & 0x7fffffff 155 l1 = (seed >> 5) & 255 156 seed = (seed * 1103515245 + 12345) & 0x7fffffff 157 a1 = (seed >> 5) & 255 158 seed = (seed * 1103515245 + 12345) & 0x7fffffff 159 al1 = (seed >> 5) & 255 160 pk = nx_intra_paeth_pick(l1, a1, al1) 161 if pk != l1 { if pk != a1 { if pk != al1 { bad = bad + 1 } } } 162 i = i + 1 163 } 164 if bad != 0 { fails = fails + 1 } 165 if fails > 0 { if mark == 0 { mark = 4 } } 166 167 // ---- T5: CONSTANT neighbours -> CONSTANT output, all three smooths ---- 168 let consts: *i64 = sys_mmap(64) as *i64 169 consts[0] = 0; consts[1] = 1; consts[2] = 77 170 consts[3] = 128; consts[4] = 254; consts[5] = 255 171 let sizes: *i64 = sys_mmap(64) as *i64 172 sizes[0] = 4; sizes[1] = 8; sizes[2] = 16 173 let modes: *i64 = sys_mmap(64) as *i64 174 modes[0] = NX_INTRA_SMOOTH; modes[1] = NX_INTRA_SMOOTH_V; modes[2] = NX_INTRA_SMOOTH_H 175 176 bad = 0 177 var ci: i64 = 0 178 var si: i64 = 0 179 var mi: i64 = 0 180 var k: i64 = 0 181 while ci < 6 { 182 v = consts[ci] 183 si = 0 184 while si < 3 { 185 n = sizes[si] 186 k = 0 187 while k < n { above[k] = v; left[k] = v; k = k + 1 } 188 p[NX_INTRA_P_W] = n 189 p[NX_INTRA_P_H] = n 190 p[NX_INTRA_P_ABOVELEFT] = v 191 mi = 0 192 while mi < 3 { 193 if nx_intra_predict(modes[mi], out, above, left, p) != 1 { 194 bad = bad + 1 195 } else { 196 k = 0 197 while k < n * n { 198 if out[k] != v { bad = bad + 1 } 199 k = k + 1 200 } 201 } 202 mi = mi + 1 203 } 204 si = si + 1 205 } 206 ci = ci + 1 207 } 208 if bad != 0 { fails = fails + 1 } 209 if fails > 0 { if mark == 0 { mark = 5 } } 210 211 // ---- T6: constant neighbours through DC, V, H and Paeth too ---- 212 k = 0 213 while k < 8 { above[k] = 77; left[k] = 77; k = k + 1 } 214 p[NX_INTRA_P_W] = 8; p[NX_INTRA_P_H] = 8 215 p[NX_INTRA_P_ABOVELEFT] = 77 216 p[NX_INTRA_P_HAVE_A] = 1; p[NX_INTRA_P_HAVE_L] = 1 217 p[NX_INTRA_P_BITDEPTH] = 8 218 bad = 0 219 m = 0 220 while m < 4 { 221 if nx_intra_predict(m, out, above, left, p) != 1 { bad = bad + 1 } else { 222 k = 0 223 while k < 64 { 224 if out[k] != 77 { bad = bad + 1 } 225 k = k + 1 226 } 227 } 228 m = m + 1 229 } 230 if bad != 0 { fails = fails + 1 } 231 if fails > 0 { if mark == 0 { mark = 6 } } 232 233 // ---- T7 NEG: refusals ---- 234 if nx_intra_predict(0 - 1, out, above, left, p) != 0 { fails = fails + 1 } 235 if nx_intra_predict(7, out, above, left, p) != 0 { fails = fails + 1 } 236 p[NX_INTRA_P_W] = 0 237 if nx_intra_predict(NX_INTRA_DC, out, above, left, p) != 0 { fails = fails + 1 } 238 p[NX_INTRA_P_W] = 8; p[NX_INTRA_P_H] = 0 239 if nx_intra_predict(NX_INTRA_DC, out, above, left, p) != 0 { fails = fails + 1 } 240 // an unsupported smooth size is REFUSED rather than approximated 241 p[NX_INTRA_P_W] = 5; p[NX_INTRA_P_H] = 5 242 if nx_intra_predict(NX_INTRA_SMOOTH, out, above, left, p) != 0 { fails = fails + 1 } 243 if fails > 0 { if mark == 0 { mark = 7 } } 244 245 if fails == 0 { 246 g_puts("GATE nx_av1_intra verdict=GREEN pass=7/7 (smooth weight tables 4/8/16 monotonic, bad size+index refused; DC all FOUR availability cases -- both/above/left/NEITHER where neither gives mid-grey 128/512/2048 NOT zero -- plus non-square 8x4 and a sub-8 bitdepth refused; V copies columns, H copies rows; Paeth SELECTS one of its three inputs over 300 random triples with tie order pinned; CONSTANT-IN-CONSTANT-OUT for all three smooth modes at 6 constants x 3 sizes, which holds only if weight+complement==256; DC/V/H/Paeth constant too; NEG bad mode/zero dims/unsupported smooth size refused)\n" as *u8) 247 sys_exit(0) 248 return 0 249 } 250 g_puts("GATE nx_av1_intra verdict=RED fails=" as *u8) 251 g_putn(fails) 252 g_puts(" first_stage=" as *u8) 253 g_putn(mark) 254 g_puts("\n" as *u8) 255 sys_exit(1) 256 return 1 257}