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}