collective

Browse / github.com/storytold/filmcraft / patch

h264: const-generic MC kernels, i16 first pass, inline window row copy

h264: MC filters with compile-time block width and i16 first pass Found while auditing `crates/h264` at upstream/main bfc23840 (Ryzen 7800X3D, single thread, `perf stat -e instructions:u,cycles:u` and a flat `perf record` profile; fixtures: x264 1080p CRF 20 long-GOP B, CAVLC, intra-only, and a 3840x2160 high-bitrate stream, each with an ffmpeg md5). Gains marked "estimated" were not measured. Today: 1080p long-GOP ~152 M instructions/frame (~100 fps single thread), 1080p intra 342 M (39 fps), 2160p high-bitrate 2340 M (5 fps). **MC filters use runtime block widths and i32 intermediates** (`inter.rs:116-229` `mc_luma_win`, `248-264` `mc_chroma_win`). The wi

Status
open
Score
0.00
Adopters
0 other operators
Author
vangel76 (imported from pull request #3183, open)
Base
bfc23840b603e69c782302c6ed04d4a9f6ec26a8
Size
+133 −74 in 2 files
Review
pending
Shared
2026-10-28
Id
a444d323d73a0d19efae4c1b

How it went

No other operator has reported using it yet.

Diff

raw · crates/h264/src/inter.rs crates/h264/src/picture.rs

diff --git a/crates/h264/src/inter.rs b/crates/h264/src/inter.rs--- a/crates/h264/src/inter.rs+++ b/crates/h264/src/inter.rs@@ -72,21 +72,41 @@ fn avg(a: u8, b: u8) -> u8 {     ((a as u16 + b as u16 + 1) >> 1) as u8 } -/// Horizontal 6-tap (unclipped) at every position of `row` for `n` outputs: out[c] uses row[c..c + 6].+/// 6-tap filter in i16: the unclipped result of a first pass lies in -2550..=10710. #[inline(always)]-fn htap_row(row: &[u8], out: &mut [i32], n: usize) {-    let row = &row[..n + 5];-    for (o, w) in out[..n].iter_mut().zip(row.windows(6)) {-        *o = tap6(w[0] as i32, w[1] as i32, w[2] as i32, w[3] as i32, w[4] as i32, w[5] as i32);+fn tap6_16(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> i16 {+    let [a, b, c, d, e, f] = [a, b, c, d, e, f].map(i16::from);+    a - 5 * b + 20 * c + 20 * d - 5 * e + f+}++/// Round and clip a first-pass value: Clip1((v + 16) >> 5).+#[inline(always)]+fn round5(v: i16) -> u8 {+    ((v + 16) >> 5).clamp(0, 255) as u8+}++/// Horizontal 6-tap (unclipped) for `BW` outputs: out[c] uses row[c..c + 6].+#[inline(always)]+fn htap_row<const BW: usize>(row: &[u8], out: &mut [i16; 16]) {+    let row = &row[..BW + 5];+    for c in 0..BW {+        out[c] = tap6_16(row[c], row[c + 1], row[c + 2], row[c + 3], row[c + 4], row[c + 5]);+    }+}++/// Vertical 6-tap (unclipped) over six rows at columns 0..BW.+#[inline(always)]+fn vtap_row<const BW: usize>(rows: [&[u8]; 6], out: &mut [i16; 16]) {+    let [a, b, c, d, e, f] = rows.map(|r| &r[..BW]);+    for i in 0..BW {+        out[i] = tap6_16(a[i], b[i], c[i], d[i], e[i], f[i]);     } } -/// Vertical 6-tap (unclipped) over six rows at columns 0..n. #[inline(always)]-fn vtap_row(rows: [&[u8]; 6], out: &mut [i32], n: usize) {-    let [a, b, c, d, e, f] = rows.map(|r| &r[..n]);-    for i in 0..n {-        out[i] = tap6(a[i] as i32, b[i] as i32, c[i] as i32, d[i] as i32, e[i] as i32, f[i] as i32);+fn copy_fixed<const BW: usize>(dst: &mut [u8], src: &[u8]) {+    if let (Some(d), Some(s)) = (dst.first_chunk_mut::<BW>(), src.first_chunk::<BW>()) {+        *d = *s;     } } @@ -108,90 +128,90 @@ pub fn mc_luma(p: PlaneRef, x: i32, y: i32, fx: u32, fy: u32, bw: usize, bh: usi }  /// Luma interpolation from a prepared window: `src[0]` is the sample at (x - 2, y - 2) and `ss` the-/// window stride; the window covers (bw + 5) x (bh + 5) samples.+/// window stride; the window covers (bw + 5) x (bh + 5) samples. `bw` is 4, 8 or 16. #[allow(clippy::too_many_arguments)] pub fn mc_luma_win(src: &[u8], ss: usize, fx: u32, fy: u32, bw: usize, bh: usize, out: &mut [u8], os: usize) {+    match bw {+        16 => luma_win::<16>(src, ss, fx, fy, bh, out, os),+        8 => luma_win::<8>(src, ss, fx, fy, bh, out, os),+        _ => luma_win::<4>(src, ss, fx, fy, bh, out, os),+    }+}++#[inline(always)]+fn luma_win<const BW: usize>(src: &[u8], ss: usize, fx: u32, fy: u32, bh: usize, out: &mut [u8], os: usize) {     // window row r (0..bh+5) starts at src[r * ss]; sample G of block (r, c) is at window (r + 2, c + 2)-    let wrow = |r: usize| &src[r * ss..r * ss + bw + 5];-    let mut t = [0i32; 16];+    let wrow = |r: usize| &src[r * ss..r * ss + BW + 5];+    let rows6 = |r: usize, off: usize| [wrow(r), wrow(r + 1), wrow(r + 2), wrow(r + 3), wrow(r + 4), wrow(r + 5)].map(|x| &x[off..]);+    let mut t = [0i16; 16];     match (fx, fy) {         (0, 0) => {             for r in 0..bh {-                copy_n(&mut out[r * os..], &wrow(r + 2)[2..], bw);+                copy_fixed::<BW>(&mut out[r * os..], &wrow(r + 2)[2..]);             }         }         (_, 0) => {+            let g = if fx == 1 { 2 } else { 3 };             for r in 0..bh {                 let row = wrow(r + 2);-                htap_row(row, &mut t, bw);-                let o = &mut out[r * os..r * os + bw];-                match fx {-                    1 => {-                        for c in 0..bw {-                            o[c] = avg(row[c + 2], clip1((t[c] + 16) >> 5));-                        }-                    }-                    2 => {-                        for c in 0..bw {-                            o[c] = clip1((t[c] + 16) >> 5);-                        }+                htap_row::<BW>(row, &mut t);+                let o = &mut out[r * os..r * os + BW];+                if fx == 2 {+                    for c in 0..BW {+                        o[c] = round5(t[c]);                     }-                    _ => {-                        for c in 0..bw {-                            o[c] = avg(row[c + 3], clip1((t[c] + 16) >> 5));-                        }+                } else {+                    let g = &row[g..g + BW];+                    for c in 0..BW {+                        o[c] = avg(g[c], round5(t[c]));                     }                 }             }         }         (0, _) => {             for r in 0..bh {-                let rows = [wrow(r), wrow(r + 1), wrow(r + 2), wrow(r + 3), wrow(r + 4), wrow(r + 5)].map(|x| &x[2..]);-                vtap_row(rows, &mut t, bw);-                let g = if fy == 1 { rows[2] } else { rows[3] };-                let o = &mut out[r * os..r * os + bw];+                let rows = rows6(r, 2);+                vtap_row::<BW>(rows, &mut t);+                let o = &mut out[r * os..r * os + BW];                 if fy == 2 {-                    for c in 0..bw {-                        o[c] = clip1((t[c] + 16) >> 5);+                    for c in 0..BW {+                        o[c] = round5(t[c]);                     }                 } else {-                    for c in 0..bw {-                        o[c] = avg(g[c], clip1((t[c] + 16) >> 5));+                    let g = &(if fy == 1 { rows[2] } else { rows[3] })[..BW];+                    for c in 0..BW {+                        o[c] = avg(g[c], round5(t[c]));                     }                 }             }         }         (2, _) | (_, 2) => {             // unclipped horizontal half samples b1 for window rows 0..bh+5-            let mut b1 = [[0i32; 16]; WIN];+            let mut b1 = [[0i16; 16]; WIN];             for (r, bt) in b1.iter_mut().enumerate().take(bh + 5) {-                htap_row(wrow(r), bt, bw);+                htap_row::<BW>(wrow(r), bt);             }-            let mut v = [0i32; 16];+            let mut j = [0u8; 16];+            let mut v = [0i16; 16];             for r in 0..bh {-                let o = &mut out[r * os..r * os + bw];-                let (b0, b1r, b2, b3, b4, b5) = (&b1[r], &b1[r + 1], &b1[r + 2], &b1[r + 3], &b1[r + 4], &b1[r + 5]);-                for c in 0..bw {-                    t[c] = tap6(b0[c], b1r[c], b2[c], b3[c], b4[c], b5[c]);+                let o = &mut out[r * os..r * os + BW];+                let [b0, b1r, b2, b3, b4, b5] = [&b1[r], &b1[r + 1], &b1[r + 2], &b1[r + 3], &b1[r + 4], &b1[r + 5]];+                for c in 0..BW {+                    let [a, b, cc, d, e, f] = [b0[c], b1r[c], b2[c], b3[c], b4[c], b5[c]].map(i32::from);+                    j[c] = clip1((tap6(a, b, cc, d, e, f) + 512) >> 10);                 }                 match (fx, fy) {-                    (2, 2) => {-                        for c in 0..bw {-                            o[c] = clip1((t[c] + 512) >> 10);-                        }-                    }+                    (2, 2) => o.copy_from_slice(&j[..BW]),                     (2, 1) | (2, 3) => {                         let bh_ = if fy == 1 { b2 } else { b3 };-                        for c in 0..bw {-                            o[c] = avg(clip1((bh_[c] + 16) >> 5), clip1((t[c] + 512) >> 10));+                        for c in 0..BW {+                            o[c] = avg(round5(bh_[c]), j[c]);                         }                     }                     _ => {-                        let off = if fx == 1 { 2 } else { 3 };-                        let rows = [wrow(r), wrow(r + 1), wrow(r + 2), wrow(r + 3), wrow(r + 4), wrow(r + 5)].map(|x| &x[off..]);-                        vtap_row(rows, &mut v, bw);-                        for c in 0..bw {-                            o[c] = avg(clip1((v[c] + 16) >> 5), clip1((t[c] + 512) >> 10));+                        vtap_row::<BW>(rows6(r, if fx == 1 { 2 } else { 3 }), &mut v);+                        for c in 0..BW {+                            o[c] = avg(round5(v[c]), j[c]);                         }                     }                 }@@ -201,14 +221,13 @@ pub fn mc_luma_win(src: &[u8], ss: usize, fx: u32, fy: u32, bw: usize, bh: usize             // e, g, p, r: average of a horizontal half sample (row r or r + 1) and a vertical one (col c or c + 1)             let hoff = if fy == 1 { 2 } else { 3 };             let voff = if fx == 1 { 2 } else { 3 };-            let mut v = [0i32; 16];+            let mut v = [0i16; 16];             for r in 0..bh {-                htap_row(wrow(r + hoff), &mut t, bw);-                let rows = [wrow(r), wrow(r + 1), wrow(r + 2), wrow(r + 3), wrow(r + 4), wrow(r + 5)].map(|x| &x[voff..]);-                vtap_row(rows, &mut v, bw);-                let o = &mut out[r * os..r * os + bw];-                for c in 0..bw {-                    o[c] = avg(clip1((t[c] + 16) >> 5), clip1((v[c] + 16) >> 5));+                htap_row::<BW>(wrow(r + hoff), &mut t);+                vtap_row::<BW>(rows6(r, voff), &mut v);+                let o = &mut out[r * os..r * os + BW];+                for c in 0..BW {+                    o[c] = avg(round5(t[c]), round5(v[c]));                 }             }         }@@ -240,24 +259,33 @@ pub fn mc_chroma(p: PlaneRef, x: i32, y: i32, fx: u32, fy: u32, bw: usize, bh: u }  /// Chroma interpolation from a prepared (bw + 1) x (bh + 1) window whose first sample is the integer-/// position of the block.+/// position of the block. `bw` is 2, 4 or 8. #[allow(clippy::too_many_arguments)] pub fn mc_chroma_win(src: &[u8], ss: usize, fx: u32, fy: u32, bw: usize, bh: usize, out: &mut [u8], os: usize) {-    let (fx, fy) = (fx as u16, fy as u16);-    let (w00, w10, w01, w11) = ((8 - fx) * (8 - fy), fx * (8 - fy), (8 - fx) * fy, fx * fy);+    match bw {+        8 => chroma_win::<8>(src, ss, fx, fy, bh, out, os),+        4 => chroma_win::<4>(src, ss, fx, fy, bh, out, os),+        _ => chroma_win::<2>(src, ss, fx, fy, bh, out, os),+    }+}++#[inline(always)]+fn chroma_win<const BW: usize>(src: &[u8], ss: usize, fx: u32, fy: u32, bh: usize, out: &mut [u8], os: usize) {     if fx == 0 && fy == 0 {         for r in 0..bh {-            copy_n(&mut out[r * os..], &src[r * ss..], bw);+            copy_fixed::<BW>(&mut out[r * os..], &src[r * ss..]);         }         return;     }+    let (fx, fy) = (fx as u16, fy as u16);+    let (w00, w10, w01, w11) = ((8 - fx) * (8 - fy), fx * (8 - fy), (8 - fx) * fy, fx * fy);     for r in 0..bh {-        let r0 = &src[r * ss..r * ss + bw + 1];-        let r1 = &src[(r + 1) * ss..(r + 1) * ss + bw + 1];-        let o = &mut out[r * os..r * os + bw];-        for (c, o) in o.iter_mut().enumerate() {+        let r0 = &src[r * ss..r * ss + BW + 1];+        let r1 = &src[(r + 1) * ss..(r + 1) * ss + BW + 1];+        let o = &mut out[r * os..r * os + BW];+        for c in 0..BW {             let v = w00 * r0[c] as u16 + w10 * r0[c + 1] as u16 + w01 * r1[c] as u16 + w11 * r1[c + 1] as u16;-            *o = ((v + 32) >> 6) as u8;+            o[c] = ((v + 32) >> 6) as u8;         }     } }@@ -500,6 +528,34 @@ mod tests {         }     } +    #[test]+    fn chroma_matches_formula() {+        let mut seed = 11u32;+        let src: Vec<u8> = (0..9 * 9)+            .map(|_| {+                seed = seed.wrapping_mul(1664525).wrapping_add(1013904223);+                (seed >> 24) as u8+            })+            .collect();+        for bw in [2, 4, 8] {+            for bh in [2, 4, 8] {+                for fx in 0..8 {+                    for fy in 0..8 {+                        let mut out = [0u8; 64];+                        mc_chroma_win(&src, 9, fx, fy, bw, bh, &mut out, 8);+                        for r in 0..bh {+                            for c in 0..bw {+                                let s = |dr: usize, dc: usize| src[(r + dr) * 9 + c + dc] as u32;+                                let want = ((8 - fx) * (8 - fy) * s(0, 0) + fx * (8 - fy) * s(0, 1) + (8 - fx) * fy * s(1, 0) + fx * fy * s(1, 1) + 32) >> 6;+                                assert_eq!(out[r * 8 + c] as u32, want, "{bw}x{bh} frac {fx},{fy} at {r},{c}");+                            }+                        }+                    }+                }+            }+        }+    }+     #[test]     fn weighting() {         let a = [100u8; 4];diff --git a/crates/h264/src/picture.rs b/crates/h264/src/picture.rs--- a/crates/h264/src/picture.rs+++ b/crates/h264/src/picture.rs@@ -302,7 +302,10 @@ fn copy_line<const N: usize>(line: &[u8], x0: i32, out: &mut [u8], w: usize) { }  /// Copy `out.len()` samples of `line` starting at x0, replicating edge samples outside the line.-#[inline(always)]+/// Kept out of line so the fixed-size path of `copy_line` stays an inline move rather than being+/// merged with this variable-length copy into a libc memcpy call.+#[cold]+#[inline(never)] fn copy_clamped(line: &[u8], x0: i32, out: &mut [u8]) {     let w = out.len();     if x0 >= 0 && x0 as usize + w <= line.len() {