Skip to main content

rusty_h264_accel/
mectx.rs

1//! H-14 R3: `MeCtx` — the per-search motion-estimation evaluation context.
2//!
3//! The reconciliation (WHYS H-14 R2) measured ~23 ns/eval of GLUE around a
4//! 16-18 ns SATD kernel: per-candidate slice re-derivation, bounds asserts,
5//! phase match ladder, wrapper hops. This context collects that chain: the
6//! plane geometry is validated ONCE at construction, the kernel function
7//! pointers are chosen ONCE (size × ISA), and `eval` does only integer bounds,
8//! a phase pick, one offset multiply, and the raw kernel call.
9//!
10//! The `unsafe` stays quarantined in this crate; the encoder remains
11//! `#![forbid(unsafe_code)]`. Every value returned is EXACTLY what the safe
12//! path computes (`2·WelsSampleSatd` for full/half phases, `Σ|H·d|` fused-avg
13//! for quarter phases), so an eval served here instead of there cannot change
14//! the bitstream — pinned by `mectx_matches_safe_path`.
15
16use crate::satd_avg::{satd_avg_w16, satd_avg_w8};
17
18type WelsSatd = unsafe extern "C" fn(*const u8, i32, *const u8, i32) -> i32;
19type AvgSatd = unsafe fn(*const u8, usize, *const u8, *const u8, usize, usize) -> u32;
20
21/// Plane indices into [`MeCtx::planes`].
22const PF: usize = 0;
23const PH: usize = 1;
24const PV: usize = 2;
25const PC: usize = 3;
26
27pub struct MeCtx<'a> {
28    src: &'a [u8],
29    cw: usize,
30    planes: [&'a [u8]; 4], // f, h, v, c — each pw×ph, stride == pw
31    stride: usize,
32    pad: isize,
33    /// Valid top-left range for a candidate's padded plane position, precomputed
34    /// with the same `+1` slack the safe `hpel_ref`/`hpel_qpel_refs` guards use
35    /// (the quarter phases read one sample past the block on either axis).
36    px_max: isize,
37    py_max: isize,
38    lx: isize,
39    ly: isize,
40    w: usize,
41    h: usize,
42    satd: WelsSatd,
43    avg: AvgSatd,
44}
45
46impl<'a> MeCtx<'a> {
47    /// Validates the whole search geometry once. Returns `None` when AVX2 is
48    /// unavailable, the shape is uncovered, or any slice is short — the caller
49    /// then uses the safe per-eval path for the entire search.
50    #[allow(clippy::too_many_arguments)]
51    pub fn new(
52        src: &'a [u8],
53        cw: usize,
54        f: &'a [u8],
55        h_pl: &'a [u8],
56        v: &'a [u8],
57        c: &'a [u8],
58        stride: usize,
59        pad: usize,
60        pw: usize,
61        ph: usize,
62        lx: usize,
63        ly: usize,
64        w: usize,
65        h: usize,
66    ) -> Option<Self> {
67        if !crate::has_avx2() || stride != pw {
68            return None;
69        }
70        let (satd, avg): (WelsSatd, AvgSatd) = match (w, h) {
71            (16, 16) => (crate::WelsSampleSatd16x16_avx2 as WelsSatd, satd_avg_w16 as AvgSatd),
72            (16, 8) => (crate::WelsSampleSatd16x8_avx2 as WelsSatd, satd_avg_w16 as AvgSatd),
73            (8, 16) => (crate::WelsSampleSatd8x16_avx2 as WelsSatd, satd_avg_w8 as AvgSatd),
74            (8, 8) => (crate::WelsSampleSatd8x8_avx2 as WelsSatd, satd_avg_w8 as AvgSatd),
75            _ => return None,
76        };
77        if src.len() < (h - 1) * cw + w {
78            return None;
79        }
80        let need = pw.checked_mul(ph)?;
81        if f.len() < need || h_pl.len() < need || v.len() < need || c.len() < need {
82            return None;
83        }
84        // px/py are padded-plane coordinates of the candidate's top-left sample;
85        // the +1 covers the quarter phases' shifted operand (offset 1 or stride).
86        let px_max = pw as isize - w as isize - 1;
87        let py_max = ph as isize - h as isize - 1;
88        if px_max < 0 || py_max < 0 {
89            return None;
90        }
91        Some(MeCtx {
92            src,
93            cw,
94            planes: [f, h_pl, v, c],
95            stride,
96            pad: pad as isize,
97            px_max,
98            py_max,
99            lx: lx as isize,
100            ly: ly as isize,
101            w,
102            h,
103            satd,
104            avg,
105        })
106    }
107
108    /// SATD distortion of candidate `(mvx, mvy)` (quarter-pel units) — the exact
109    /// value the safe dispatch computes — or `None` when the candidate leaves the
110    /// validated window (caller falls back; identical value there too).
111    #[inline]
112    pub fn eval(&self, mvx: i32, mvy: i32) -> Option<u32> {
113        let px = self.lx + (mvx >> 2) as isize + self.pad;
114        let py = self.ly + (mvy >> 2) as isize + self.pad;
115        if px < 0 || py < 0 || px > self.px_max || py > self.py_max {
116            return None;
117        }
118        let base = py as usize * self.stride + px as usize;
119        let (fx, fy) = (mvx & 3, mvy & 3);
120        let st = self.stride;
121        // SAFETY (whole match): `base + oa/ob + (h-1)·stride + w (+1 slack)` is
122        // inside every plane by the constructor's `pw·ph` length check together
123        // with the px/py window test above; `src` covers `(h-1)·cw + w`.
124        unsafe {
125            if fx & 1 == 0 && fy & 1 == 0 {
126                // Full- and half-pel: one plane, read in place.
127                let p = match (fx, fy) {
128                    (0, 0) => self.planes[PF],
129                    (2, 0) => self.planes[PH],
130                    (0, 2) => self.planes[PV],
131                    _ => self.planes[PC], // (2, 2)
132                };
133                let v = (self.satd)(
134                    self.src.as_ptr(),
135                    self.cw as i32,
136                    p.as_ptr().add(base),
137                    st as i32,
138                );
139                return Some(2 * v as u32);
140            }
141            // Quarter phases: the spec's (a+b+1)>>1 of two planes, operand table
142            // identical to `hpel_qpel_refs` (pinned by the oracle test).
143            let (pa, oa, pb, ob) = match (fx, fy) {
144                (1, 0) => (PF, 0, PH, 0),
145                (3, 0) => (PF, 1, PH, 0),
146                (0, 1) => (PF, 0, PV, 0),
147                (0, 3) => (PF, st, PV, 0),
148                (1, 1) => (PH, 0, PV, 0),
149                (3, 1) => (PH, 0, PV, 1),
150                (1, 3) => (PH, st, PV, 0),
151                (3, 3) => (PH, st, PV, 1),
152                (2, 1) => (PH, 0, PC, 0),
153                (2, 3) => (PH, st, PC, 0),
154                (1, 2) => (PV, 0, PC, 0),
155                _ => (PV, 1, PC, 0), // (3, 2)
156            };
157            Some((self.avg)(
158                self.src.as_ptr(),
159                self.cw,
160                self.planes[pa].as_ptr().add(base + oa),
161                self.planes[pb].as_ptr().add(base + ob),
162                st,
163                self.h,
164            ))
165        }
166    }
167}