Expand description
SIMD acceleration for rusty_h264 — pure Rust, no assembly. The vendored
openh264 NASM this crate grew around was fully ripped on 2026-08-12; every
kernel is now portable Rust (x86-64 SSE2/AVX2 intrinsics + aarch64 NEON +
scalar oracles), no nasm, no build script, no FFI.
This crate is deliberately not #![forbid(unsafe_code)]: it is the one place
unsafe lives, behind safe wrappers, so the codec core stays forbid(unsafe).
§Structure, and where it is going
docs/add_SIMD_rip_ASM.md is ripping the assembly out kernel by kernel. Two things
follow from that, and this file is arranged around them:
x86_asmholds everything still backed by openh264 NASM. It is gated ontarget_arch = "x86_64"and shrinks with every phase of the campaign.- Portable modules (
chroma_mc, …) hold Rust intrinsics with an x86-64 path, an aarch64 NEON path, and a scalar reference that all three are tested bit-identical against. These compile and run on every architecture.
Until the campaign finishes, the crate is a mix. The whole crate used to be
#![cfg(target_arch = "x86_64")] — compiled to nothing on ARM, which is why aarch64
ran fully scalar. That gate now sits on the x86_asm module alone, so portable
kernels reach ARM as they land.
Order matters: replace, then rip. The vendored assembly measures ~1.94x on decode (paired, N=5, 34/35 reps above 1.0), so deleting a kernel before its portable replacement is bit-identical and no slower would ship a real regression.
openh264 asm is BSD-2 licensed; attribution lives in vendor/LICENSE.openh264.
Structs§
Functions§
- bs_
motion_ masks - Safe dispatcher: AVX2 when present, else the SSE2 twin — never
Noneon x86-64 since 2026-08-27 (audit site 18): SSE2 is the x86-64 BASELINE, so before the twin existed, a hypervisor masking AVX2 (or a pre-Haswell CPU) silently dropped the packed-bS arm and everything routed on it back to the scalar per-edge walk. TheOptionshape is kept for the callers. - bs_
motion_ masks_ two_ list - Safe dispatcher for the two-list masks kernel;
Nonewhen AVX2 is absent. - chroma8x8_
pred - 8x8 chroma prediction into
pred(>= 64 bytes).mode: 2=Vertical, 3(=else)=Plane — the only modes the asm served; DC/Horizontal stay with the caller’s scalar, exactly the old wrapper’s contract. - dct_
four_ t4 - Forward 4x4 transform of an 8x8 region’s residual (four blocks,
SUBBLOCKSorder). Seedct_four_t4_scalarfor the reference semantics. - dct_
four_ t4_ scalar - Forward-transform the residual of four 4x4 blocks covering an 8x8 region.
- deblock_
chroma_ eq4_ h - Chroma (both planes), vertical edge, bS==4.
- deblock_
chroma_ eq4_ v - Chroma (both planes), horizontal edge, bS==4.
- deblock_
chroma_ lt4_ h - Chroma (both planes), vertical edge, bS<4.
*_p1point at column p1 of row 0 (q0 is at column 2). NOTE: scalar for now — a vertical chroma edge is 8 rows x 2 planes, and the transpose needed to vectorise it costs more than the 4 filtered samples per row save. Measured before leaving it this way. - deblock_
chroma_ lt4_ v - Chroma (both planes), horizontal edge, bS<4.
*_p1point at the p1 row. - deblock_
luma_ eq4_ h - Luma, vertical edge, bS==4.
- deblock_
luma_ eq4_ v - Luma, horizontal edge, bS==4.
- deblock_
luma_ lt4_ h - Luma, vertical edge (filter horizontally), bS<4.
p4points at column p3 of row 0. - deblock_
luma_ lt4_ v - Luma, horizontal edge (filter vertically), bS<4.
p3points at the p3 row. - dequant_
4x4 - Safe dispatcher.
None= no AVX2, caller keeps its scalar twin (the oracle). - hpel_
fused - Builds the three half-pel planes from the edge-padded full-pel plane
f(pw×ph, row stridepw). Returnsfalse(no work done) when no SIMD arm applies (x86-64 without AVX2, other ISAs, or a plane too narrow for the vector interior) — the caller falls back to its scalar/tile path. - i16x16_
luma_ pred - 16x16 luma prediction into
pred(>= 256 bytes).rec[base]is the MB top-left; the top row isrec[base - stride ..], the left columnrec[base - 1 + y*stride].mode: 0=V, 1=H, 2=DC, 3=Plane — the caller guarantees the needed neighbours exist (both for DC/Plane), exactly the contract the asm wrapper had. - idct_
four_ t4_ rec - Inverse 4x4 transform + reconstruct of an 8x8 region. See
idct_four_t4_rec_scalarfor the reference semantics. - idct_
four_ t4_ rec_ scalar - Inverse-transform four 4x4 coefficient blocks and add them to
pred, writing the reconstruction intorec. - mb_
uniform - Safe dispatcher for the uniform-motion test: AVX2 when present, else the
SSE2 twin — never
Noneon x86-64 since 2026-08-27 (audit site 18). This test runs on ALL macroblocks (9.5x the masks kernel’s work, per the counts above), so it is the arm a masked-AVX2 VM was losing most of. - mc_
centre - Centre half-pel plane:
clip((6tap applied twice + 512) >> 10),win {8, 16}. - mc_
centre_ hq - Fused centre-adjacent quarter-pel, horizontal flavour ((2,1) fdr=0, (2,3) fdr=1): ONE pass-1 + one fused pass-2/avg instead of the 3-kernel 2-staging compose. Byte-identical by construction: the hor-half is the rounded form of the pass-1 rows the centre already computes.
- mc_
centre_ vq - Fused centre-adjacent quarter-pel, vertical flavour ((1,2) fdc=0, (3,2) fdc=1): vertical-first pass 1, then fused horizontal pass-2/avg.
- mc_
chroma_ w4 - Eighth-pel chroma bilinear MC, 4 pixels wide,
heightrows. - mc_
chroma_ w8 - Eighth-pel chroma bilinear MC, 8 pixels wide,
heightrows. - mc_
hor20 - Horizontal half-pel plane:
clip((6tap_h + 16) >> 5),win {8, 16}. - mc_
hor_ qpel - One-filter horizontal qpel (
McHorVer10/30): half-pel 6-tap thenpavgbvs full-pel at column+fdc, in one pass (no 256 B scratch store).fdc∈ {0,1}. - mc_
hv_ qpel - Fused HV-diagonal qpel: hor-half at
(hdr, hdc), ver-half at(vdr, vdc), averaged — one loop, no staging. Offsets followavg_full’s convention. - mc_
ver02 - Vertical half-pel plane:
clip((6tap_v + 16) >> 5),win {8, 16}. - mc_
ver_ qpel - One-filter vertical qpel (
McHorVer01/03): half-pel 6-tap thenpavgbvs full-pel at row+fdr, in one pass.fdr∈ {0,1}. - pixel_
avg (a + b + 1) >> 1of two planes — the quarter-pel average.win {4, 8, 16}.- quant_
four_ 4x4 - openh264
WELS_NEW_QUANTover four 4x4 blocks, in place. Seequant_four_4x4_scalarfor the reference semantics. - quant_
four_ 4x4_ scalar - openh264’s
WELS_NEW_QUANTover four 4x4 blocks, in place. - sad_
8x16 - SAD of two 8x16 blocks.
- sad_
16x8 - SAD of two 16x8 blocks.
- sad_
16x16 - SAD of two 16x16 blocks.
- sad_x4
- SADs of one
w×hsource block vs four offsetsointobase(striders), for every ME partition shape. Values are exactlyΣ|a−b|per candidate.Nonewithout AVX2 or for an uncovered shape. - satd_
4x4 - SATD of two 4x4 blocks. Too small for the band kernel (which does four at once).
- satd_
8x8 - SATD of two 8x8 blocks:
Σ_4x4 ((Σ|H·d| + 1) >> 1). - satd_
8x16 - SATD of two 8x16 blocks:
Σ_4x4 ((Σ|H·d| + 1) >> 1). - satd_
16x8 - SATD of two 16x8 blocks:
Σ_4x4 ((Σ|H·d| + 1) >> 1). - satd_
16x16 - SATD of two 16x16 blocks:
Σ_4x4 ((Σ|H·d| + 1) >> 1). - satd_
avg - Fused
SATD(src, (a+b+1)>>1)of aw×hblock —Σ|H·d|, the SAME valuesatd_pxcomputes on the materialized average (NOT the(Σ+1)>>1theWelsSampleSatd*wrappers return).Nonewhen AVX2 is unavailable or the size is unsupported — the caller then materializes and takes the old path, so a non-AVX2 machine is byte-identical by construction. - satd_
avg_ x4 - Four fused avg+SATDs of one
w×hsource block:(plane_a, off_a, plane_b, off_b)per candidate, shared stride — the quarter-pel ring for every ME partition shape.Nonewithout AVX2 or for an uncovered shape. - satd_x4
Σ|H·d|SATDs of onew×hsource block vs four offsetsointobase(striders) — the diamond’s shape, for every ME partition. The exact scalar-Hadamard value (satd_pxdomain, NOT the(Σ+1)>>1the Wels wrappers return).Nonewithout AVX2 or for an uncovered shape.- satd_
x4p - Four SATDs (
Σ|H·d|) of onew×hsource block vs four INDEPENDENT plane operands (shared stride) — the sub-pel ring’s shape, now for every ME partition.Nonewithout AVX2 or for an uncovered shape. - tq_
scalar_ forced - ORACLE ARM (
RFF_TQ_SCALAR=1): pin the three transform/quant dispatchers to their scalar twins at RUNTIME — the differential/bisection anchor the campaign method requires of every kernel family (add_SIMD_rip_ASM.md§3 step 1), previously satisfied here only inside#[cfg(test)](H10). Output is byte-identical either way — this is a correctness knob, not a speed knob; same cached-atomic shape and cost class asabl_reconabove.