nx_h264_idct.nx source
↩ module page · 77 lines · 2939 B
1// nx_h264_idct.nx -- H.264 4x4 inverse integer transform (rung 5-core, built
2// bottom-up). THE deterministic DSP kernel at the base of pixel reconstruction:
3// dequantized transform coefficients -> residual samples. Spec ITU-T H.264
4// section 8.5.12.2 (residual 4x4): two butterfly passes (rows then columns) then
5// r = (h + 32) >> 6. Reusable regardless of the entropy layer above.
6//
7// Arithmetic right shift (floor, sign-preserving) is REQUIRED on negatives. We
8// implement asr() to shift only non-negative magnitudes, so correctness does NOT
9// depend on whether the language '>>' is arithmetic or logical -- the gate's
10// negative outputs (e.g. -1) prove it.
11//
12// genealogy_id: itu_t_h264_sec8_5_residual_transform + malvar_2003_low_complexity_transform
13// lineage_id: integer_butterfly_2pass + round_shift6
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16
17// arithmetic shift right by n (floor toward -inf), shift-semantics-independent
18func asr(x: i64, n: i64) -> i64 {
19 if x >= 0 { return x >> n }
20 let p: i64 = 0 - x
21 return 0 - ((p + ((1 << n) - 1)) >> n)
22}
23
24// in-place inverse transform of a 16-element row-major 4x4 coefficient block
25// LEAK FIX 2026-08-01: this mmapped a 16-word scratch PER CALL and runs once per
26// 4x4 block (~196,000 calls per 1080p frame) with page-granular mmap and no free.
27// The _s variant takes caller-provided scratch; the old wrapper is kept so the 10
28// cold callers (gates/tests) need no change.
29func nx_idct4x4(d: *i64) -> i64 { let f: *i64 = sys_mmap(16 * 8) as *i64; return nx_idct4x4_s(d, f) }
30func nx_idct4x4_s(d: *i64, f: *i64) -> i64 {
31 var i: i64 = 0
32 while i < 4 {
33 let z0: i64 = d[i * 4 + 0]
34 let z1: i64 = d[i * 4 + 1]
35 let z2: i64 = d[i * 4 + 2]
36 let z3: i64 = d[i * 4 + 3]
37 let e0: i64 = z0 + z2
38 let e1: i64 = z0 - z2
39 let e2: i64 = asr(z1, 1) - z3
40 let e3: i64 = z1 + asr(z3, 1)
41 f[i * 4 + 0] = e0 + e3
42 f[i * 4 + 1] = e1 + e2
43 f[i * 4 + 2] = e1 - e2
44 f[i * 4 + 3] = e0 - e3
45 i = i + 1
46 }
47 var j: i64 = 0
48 while j < 4 {
49 let z0: i64 = f[0 * 4 + j]
50 let z1: i64 = f[1 * 4 + j]
51 let z2: i64 = f[2 * 4 + j]
52 let z3: i64 = f[3 * 4 + j]
53 let g0: i64 = z0 + z2
54 let g1: i64 = z0 - z2
55 let g2: i64 = asr(z1, 1) - z3
56 let g3: i64 = z1 + asr(z3, 1)
57 d[0 * 4 + j] = asr(g0 + g3 + 32, 6)
58 d[1 * 4 + j] = asr(g1 + g2 + 32, 6)
59 d[2 * 4 + j] = asr(g1 - g2 + 32, 6)
60 d[3 * 4 + j] = asr(g0 - g3 + 32, 6)
61 j = j + 1
62 }
63 return 0
64}
65
66// reconstruct: out[i] = clip(pred[i] + residual[i], 0, 255)
67func nx_idct_add_clip(pred: *u8, res: *i64, out: *u8, n: i64) -> i64 {
68 var i: i64 = 0
69 while i < n {
70 var v: i64 = (pred[i] as i64) + res[i]
71 if v < 0 { v = 0 }
72 if v > 255 { v = 255 }
73 out[i] = v as u8
74 i = i + 1
75 }
76 return 0
77}