Skip to main content

rusty_h264_encoder/
mb16.rs

1//! I_16x16 macroblock encoding (DC prediction) — the compressing intra path.
2//!
3//! Index-based loops below drive pixel/block-position arithmetic and read
4//! clearer than iterator adapters for this raster math.
5#![allow(clippy::needless_range_loop)]
6//!
7//! Each macroblock is DC-predicted from already-reconstructed neighbors, the
8//! residual is transformed/quantized (luma DC via the secondary Hadamard), the
9//! coefficients are CAVLC-coded, and the macroblock is reconstructed so the next
10//! one can predict from it. `nnz` grids feed the CAVLC `nC` context exactly as a
11//! conforming decoder derives it.
12
13use crate::cabac::CabacEncoder;
14use crate::config::EncoderConfig;
15use crate::signals::{self, FrameSignals};
16use rusty_h264_common::cavlc::{
17    encode_residual_block, scan_4x4_ac, scan_4x4_dcac, write_cbp_inter, write_cbp_intra,
18};
19use rusty_h264_common::inter::{
20    inter_partitions, mc_chroma, mc_luma, predict_mv, predict_partition_mv, MvNeighbor,
21};
22#[cfg(not(accel))]
23use rusty_h264_common::predict::add_residual_4x4;
24use rusty_h264_common::predict::{
25    add_residual_8x8, chroma8x8_pred, chroma_mode_available, chroma_qp, reconstruct_4x4_into,
26    intra4x4_pred, intra8x8_pred, luma16x16_pred, reconstruct_4x4, I16Mode, CHROMA_4X4_SCAN_XY,
27    LUMA_4X4_SCAN_XY,
28};
29#[cfg(not(accel))]
30use rusty_h264_common::transform::inverse_dct_blocks;
31use rusty_h264_common::transform::{
32    dequantize, forward_core, forward_core_8x8, forward_dct_blocks, forward_quant_chroma_dc,
33    forward_quant_luma_dc, inverse_quant_8x8, inverse_quant_chroma_dc,
34    inverse_quant_luma_dc, quantize, quantize_8x8, satd_4x4_sum,
35};
36use rusty_h264_common::aligned::AlignedBytes;
37use rusty_h264_common::{BitWriter, YuvFrame};
38
39/// A/B switch for the batched full-pel rescue grid (`RFF_ME_BATCH=0` disables).
40///
41/// Read ONCE per process, not per call: this sits inside the motion-search rescue
42/// path, and `std::env::var` allocates a `String` and takes the process-wide
43/// environment lock every time. A runtime switch inside a hot loop is its own
44/// measurable tax — cache it.
45
46
47/// λ-normalised threshold for the partition-split search gate (U2).
48///
49/// The existing `split_gate` is a function of qstep ALONE, so it does not scale with
50/// the rate/distortion trade the search is actually making. Normalising the null arm
51/// by λ — the king feature for any search-skip gate — makes one constant transfer
52/// across content AND the whole QP ladder, and in the SAFE direction: the feature is
53/// small exactly where the 16×16 null arm is already good, so easy content skips more.
54///
55/// Harvested over 36 k gated macroblocks (4 clips): at T = 400 the split search is
56/// skipped on 2.9–22.5% of them while keeping **100.00%** of the achievable cost gain
57/// on every clip; T = 600 skips 11–79% for 93–99% kept. `RFF_SPLIT_T=0` disables.
58pub(crate) static DEFER_SUBPEL: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
59
60pub(crate) static SPLIT_T: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
61
62/// Observe-only HARVEST for the sub-8x8 dispatch fit (Great Gate P3.3 gate —
63/// docs/gate-ledger.md sub8x8-split). One CSV row per P_8x8 quad decision:
64/// the 8x8 arm's J, the best SPLIT arm's J (tracked even when 8x8 wins), the
65/// chosen sub_mb_type, lme (for margin normalization — the null-arm-over-λ
66/// king-feature law), and the MB's variance. `RFF_SUB8_HARVEST=<path>`.
67/// R1 PRE-CHECK instrument (docs/gate-repair-plan.md): the SIGNED RD regret of the
68/// SATD split decision, per macroblock, in lambda units.
69///
70/// The census says RD overturns the SATD split pick on 33.8-81.4% of the macroblocks
71/// where SATD chose to split. A RATE cannot justify refitting the proxy: `prom_av1e004`
72/// was a 3x more accurate cost model that measured DEAD NEUTRAL because its error was
73/// rank-invariant near the argmin. What decides R1 is the MAGNITUDE of the disagreement,
74/// and the existing harvest throws it away -- `split_gain` is recorded only when the
75/// split is KEPT and zeroed on revert.
76///
77/// So record one signed number:
78///
79/// ```text
80/// dj = (j_split - j_flat) / lambda
81///
82///   dj > 0  RD reverted: following SATD would have cost `dj` lambda-units. REGRET.
83///   dj < 0  RD kept it:  the split saved `-dj`. GAIN.
84/// ```
85///
86/// If the regret mass sits near zero, SATD's false positives are near-ties, the RD pass
87/// is expensive insurance against nothing, and R1 closes without touching the proxy.
88/// A fat regret tail is the only thing that justifies a refit.
89///
90///   RFF_SUB8_REGRET=<path>   zero cost when unset (OnceLock + Option, as sub8_harvest)
91mod sub8_regret {
92    use std::io::Write;
93    use std::sync::{Mutex, OnceLock};
94
95    fn sink() -> &'static Option<Mutex<std::fs::File>> {
96        static S: OnceLock<Option<Mutex<std::fs::File>>> = OnceLock::new();
97        S.get_or_init(|| {
98            std::env::var("RFF_SUB8_REGRET").ok().and_then(|p| {
99                let mut f = std::fs::File::create(p).ok()?;
100                let _ = writeln!(f, "reverted,j_split,j_flat,lambda,dj_lambda,split_quads");
101                Some(Mutex::new(f))
102            })
103        })
104    }
105
106    #[inline]
107    pub fn enabled() -> bool {
108        sink().is_some()
109    }
110
111    /// One macroblock's RD trial outcome. `ja`/`jb` are the split and flat J values.
112    pub fn record(ja: f64, jb: f64, lambda: f64, split_quads: usize) {
113        if let Some(m) = sink() {
114            if let Ok(mut f) = m.lock() {
115                let dj = (ja - jb) / lambda.max(1e-9);
116                let _ = writeln!(
117                    f, "{},{:.1},{:.1},{:.4},{:.4},{}",
118                    (jb <= ja) as u8, ja, jb, lambda, dj, split_quads
119                );
120            }
121        }
122    }
123}
124
125mod sub8_harvest {
126    use std::io::Write;
127    use std::sync::{Mutex, OnceLock};
128
129    fn sink() -> &'static Option<Mutex<std::fs::File>> {
130        static S: OnceLock<Option<Mutex<std::fs::File>>> = OnceLock::new();
131        S.get_or_init(|| {
132            std::env::var("RFF_SUB8_HARVEST").ok().and_then(|p| {
133                let mut f = std::fs::File::create(p).ok()?;
134                // `j8_lme` and `mbvar` are PRE-SEARCH: both are known before the
135                // 8 extra motion searches this gate would skip. `st`/`jsplit` are
136                // post-search (kept for context), `rd_kept` is the label — did the
137                // macroblock's RD trial ultimately KEEP the split?
138                let _ = writeln!(f, "j8,jsplit,st,lme,mbvar,j8_lme,mvdiv,rd_kept");
139                Some(Mutex::new(f))
140            })
141        })
142    }
143
144    /// One quad's row, buffered until the macroblock's RD trial resolves (the
145    /// label is only known then).
146    pub struct Row {
147        pub j8: i64,
148        pub jsplit: i64,
149        pub st: u8,
150        pub lme: f64,
151        pub mbvar: i64,
152        /// PRE-SEARCH motion divergence: |mv_quad - mv16| in quarter-pel. Known
153        /// after the ONE 8x8 search we always run, before the EIGHT sub-searches
154        /// this gate would skip. Unlike `j8_lme` (difficulty) and `mbvar`
155        /// (texture) — both refuted — this measures the thing splitting actually
156        /// exploits: a motion BOUNDARY inside the quad. A quad moving with its
157        /// parent has nothing to split.
158        pub mvdiv: i32,
159    }
160
161    #[inline]
162    pub fn enabled() -> bool {
163        sink().is_some()
164    }
165
166    /// Flushes a macroblock's buffered quad rows with the RD outcome attached.
167    pub fn flush(rows: &[Row], rd_kept: bool) {
168        if let Some(m) = sink() {
169            if let Ok(mut f) = m.lock() {
170                for r in rows {
171                    let jl = r.j8 as f64 / r.lme.max(1e-9);
172                    let _ = writeln!(
173                        f,
174                        "{},{},{},{:.3},{},{:.2},{},{}",
175                        r.j8, r.jsplit, r.st, r.lme, r.mbvar, jl, r.mvdiv, rd_kept as u8
176                    );
177                }
178            }
179        }
180    }
181}
182
183/// P3 RD-pricing probe #2: price the INTRA-vs-INTER decision in the RD
184/// currency instead of the SATD proxy + fitted `tune_intra_penalty`.
185/// `RFF_INTRA_RD=1`.
186///
187/// Today: `c_intra = best_i16_satd + lme*tune_intra_penalty` vs the inter
188/// arm's SATD cost. Both sides are prediction-error proxies, and the penalty
189/// constant exists precisely to correct the proxy's bias — a fitted patch over
190/// a wrong-sign currency (the same defect the sub-8x8 probe confirmed, where
191/// re-pricing moved the worst clip 4.3 points AND improved the winners). The
192/// evaluator needed here already existed and had ZERO callers
193/// (`trial_intra`): snapshot -> encode into scratch -> real bits + recon SSD
194/// -> restore. "Exported != wired", the same law as the SATD asm kernel that
195/// sat uncalled for months.
196fn intra_rd_on() -> bool {
197    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
198    *ON.get_or_init(|| std::env::var("RFF_INTRA_RD").map(|v| v == "1").unwrap_or(false))
199}
200
201/// P3 RD-pricing probe #3: price the PARTITION SHAPE decision (16x16 vs 16x8
202/// vs 8x16 vs P_8x8) in the RD currency. `RFF_SHAPE_RD=1`.
203///
204/// The third and last SATD-priced DEFAULT-ON site. The shapes are compared on
205/// `best_part`'s SATD+lambda*mvbits costs today; finer shapes always reduce
206/// prediction error, so the same wrong-sign bias that made sub-8x8 a net loser
207/// should bias this decision toward over-splitting too — mildly, since 16x8
208/// has far less freedom to fit noise than 4x4. Probe, do not assume.
209/// Weight applied to chroma SSD inside the inter RD trials. 1.0 = the original
210/// equal-weight sum (byte-identical).
211fn chroma_ssd_weight() -> f64 {
212    static V: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
213    *V.get_or_init(|| {
214        std::env::var("RFF_RD_CHROMA_W")
215            .ok()
216            .and_then(|v| v.parse().ok())
217            .unwrap_or(1.0)
218    })
219}
220
221/// Texture ceiling above which shape-RD is vetoed (see the call site).
222fn shape_rd_tex_max() -> i64 {
223    static V: std::sync::OnceLock<i64> = std::sync::OnceLock::new();
224    *V.get_or_init(|| {
225        std::env::var("RFF_SHAPE_RD_TEXMAX")
226            .ok()
227            .and_then(|v| v.parse().ok())
228            // REFIT 1000 -> 2000 on 2026-08-08. The original 1000 was placed in the
229            // open gap of a 24-clip 4x4-era table, below mobile_cif (1494) because
230            // mobile then LOST +1.99% BD-SSIM with the shape-RD pass on. Re-measured
231            // on the current encoder, mobile now WINS -0.90% (I+P) / -0.45% (I+P+B)
232            // unvetoed — a ~2.9-point sign flip on the same clip and the same knob.
233            // The threshold-transfer law, exactly: a threshold is only valid for the
234            // encoder it was fitted against, and this one went stale.
235            //
236            // NOT removed, because the above-the-line HOLDOUT refuted removal:
237            // maxtex_plaid (median_var 2962) regresses +3.50% unvetoed. Both
238            // above-the-line clips flipped sign since the fit, in OPPOSITE
239            // directions, so `median_var` still ORDERS them — the line was just in
240            // the wrong place. 2000 sits in the open gap between them (1499 .. 2962):
241            // mobile is released, plaid stays guarded, and every other clip in the
242            // corpus is under 1000 and therefore byte-identical either way.
243            //
244            // The fit rests on TWO above-the-line points. Content landing in the new
245            // (1000, 2000] band is unmeasured; re-run bench/gate_refit.py when a
246            // clip appears there.
247            .unwrap_or(2000)
248    })
249}
250
251/// Shape-RD override: `Some(true/false)` from `RFF_SHAPE_RD=1/0`, `None` when unset.
252///
253/// This USED to return `bool` and be consumed as `shape_rd_on() || cfg.tune_shape_rd`
254/// — an OR, which meant `RFF_SHAPE_RD=0` could not turn the gate OFF. shape-RD was
255/// therefore the one shipped gate with NO ESCAPE HATCH: it could not be neutralised at
256/// runtime, could not be Tier-0 tested by `gatecheck` (whose contract is "every gate's
257/// neutral setting still reproduces the un-gated bytes"), and could not be A/B'd against
258/// the `fast`-preset regression it is the leading suspect for. Returning an Option makes
259/// the env an OVERRIDE in both directions.
260fn shape_rd_on() -> Option<bool> {
261    static ON: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
262    *ON.get_or_init(|| std::env::var("RFF_SHAPE_RD").ok().map(|v| v == "1"))
263}
264
265/// `RFF_INTRA_RD_ALL=1` removes the grain gate from the intra RD probe (i.e.
266/// price EVERY macroblock by RD) — the arm the 1.71x-for-nothing measurement
267/// was taken on. Default: gated to grain.
268fn intra_rd_grain_gate() -> bool {
269    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
270    *ON.get_or_init(|| std::env::var("RFF_INTRA_RD_ALL").map(|v| v != "1").unwrap_or(true))
271}
272
273/// ONLINE SPLIT-PAYOFF CENSUS (best_part campaign, centre 2). The per-QUAD skip
274/// gate was pruned with three varied pre-search probes — `j8/lambda`
275/// (difficulty), `mbvar` (texture) and `mvdiv` (motion boundary) all lose wins
276/// at ~the rate they skip searches (ratios 0.87-1.00), because whether a quad
277/// benefits from splitting is a property of its RESIDUAL, which does not exist
278/// until you split. No cheap signal predicts it.
279///
280/// But the same harvest shows the payoff varies 2.4x BY CONTENT — the fraction
281/// of quads sitting in a macroblock whose split survived the RD trial:
282/// harbour 13.7%, bus 27.7%, foreman 32.5%, mobile 33.2%. So the dispatch grain
283/// is the FRAME, not the quad: measure the survival rate online over this
284/// frame's first macroblocks and stop searching splits for the remainder if the
285/// content is not paying. Same shape as the free-skip census that gates RD-skip
286/// and greedy-skip, and me_wide's online payoff learner — within-frame, so it
287/// stays deterministic under GOP-parallel encode.
288///
289/// ⚠ VALUE-WEIGHTED, not a count. The first cut of this census gated on the
290/// PERCENTAGE of macroblocks whose split survived, and on crowd_run that threw
291/// away 78% of a -2.43% BD-SSIM win to buy its speed: a frame where only a tenth
292/// of splits survive can still carry a large win if those few save a lot of
293/// bits. Counting decisions instead of weighting them by what they are worth is
294/// exactly the objective error the suppressor campaign names as cardinal
295/// (unit-weighted net gain, never classification accuracy). The census now
296/// accumulates the RD J the surviving splits actually SAVE, in lambda units,
297/// and requires a mean saving per searched macroblock.
298///
299/// `RFF_SUB8_MINPAY` = required mean J saved per searched MB, in lambda units
300/// (0 disables the census); `RFF_SUB8_LEARN` = MBs observed before it may act.
301fn sub8_pay_cfg() -> (usize, usize) {
302    static C: std::sync::OnceLock<(usize, usize)> = std::sync::OnceLock::new();
303    *C.get_or_init(|| {
304        let p = std::env::var("RFF_SUB8_MINPAY").ok().and_then(|v| v.parse().ok()).unwrap_or(0);
305        let l = std::env::var("RFF_SUB8_LEARN").ok().and_then(|v| v.parse().ok()).unwrap_or(64);
306        (p, l)
307    })
308}
309
310/// `RFF_SUB8_GRAIN=0` disables the sub-8x8 grain veto (bisection anchor).
311fn sub8_grain_veto_on() -> bool {
312    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
313    *ON.get_or_init(|| std::env::var("RFF_SUB8_GRAIN").map(|v| v != "0").unwrap_or(true))
314}
315
316/// P3.3 gate probe: re-price the SPLIT-vs-8x8 decision in the RD currency
317/// (`J = SSD_recon + lambda*bits`) instead of the SATD proxy `best_part`
318/// returns. `RFF_SUB8_RD=1`. See docs/gate-ledger.md sub8x8-split: SATD prices
319/// PREDICTION error, which always falls as partitions get finer, while the
320/// quantizer would have zeroed that detail anyway -- the wrong-sign-proxy law.
321/// This trials both arms through the real transform+quantize+reconstruct and
322/// keeps the one the CODED macroblock actually prefers.
323/// Allow the I_8x8 candidate on INTRA macroblocks inside P/B slices?
324///
325/// MEASURED AND PRUNED 2026-08-08 — kept as a comparator, do not re-explore.
326/// Recovered only 0.03-0.05 BD points on the I+P losers (foreman +0.28 -> +0.23,
327/// harbour +0.12 -> +0.08) and COST grain I+P+B 0.21 (-0.45 -> -0.24). The census
328/// explains why: it touches 0.001-0.039% of bytes, because intra-8x8-in-P is rare.
329///
330/// Hypothesis under test: with inter-8x8 already off, the only 8x8 left in a P frame
331/// is on intra-in-P macroblocks, and every remaining 8x8 BD loss sits in a structure
332/// that contains P frames while all-intra is clean. Intra-in-P blocks are the ones
333/// inter prediction failed on, so they skew toward the fine detail 4x4 handles better.
334/// `RFF_I8_IN_P=0` withholds the candidate there.
335/// How much the I_8x8 candidate must BEAT I_4x4/I_16x16 by, in lambda units, before
336/// it is selected — instead of winning on any margin at all.
337///
338/// MEASURED AND PRUNED 2026-08-08 — margin 0 (any win) is OPTIMAL, do not re-explore.
339/// Sweep over the 21-cell table: margin 0 -> 7 losers, sum -6.72%; margin 8 -> 7
340/// losers, sum -2.30%; margin 24 -> 12 losers, sum +1.25%. It gives back akiyo's win
341/// (-1.90 -> -0.64 -> +0.06) far faster than it recovers foreman (+0.28 -> +0.22 ->
342/// +0.23). The premise was wrong: akiyo's win is an accumulation of MANY MARGINAL
343/// per-MB picks, not a few decisive ones, so a margin kills the win first. A per-MB
344/// RD margin is not a proxy for the clip-level decisiveness of a win.
345///
346/// Motivated by a measured propagation effect: an 8x8-coded I-frame is a worse
347/// PREDICTION SOURCE, and the damage grows monotonically with GOP length. BD of 8x8
348/// vs 4x4 at gop 1 / 10 / 30 / 60: foreman -0.06 / +0.01 / +0.28 / +0.84, harbour
349/// -0.37 / -0.12 / +0.12 / +0.31, and even akiyo's win decays -1.90 -> -1.26. Every
350/// clip moves the same direction, so this is a mechanism and not content noise.
351///
352/// The margin is the dispatch. Clips where 8x8 wins DECISIVELY (akiyo, -1.90% on the
353/// I-frame alone) clear any sane margin and keep their win; clips where it wins by a
354/// hair (foreman, -0.06%) are near-ties that flip on quantisation noise and then cost
355/// far more downstream than they saved. Cost margin as the axis, no new signal needed.
356/// GREAT GATE: withhold the 8x8 transform on SCREEN content for this frame.
357///
358/// The PPS still advertises `transform_8x8_mode_flag`; clearing it per frame simply
359/// means no macroblock sets `transform_size_8x8_flag`, which is legal and keeps the
360/// stream decodable by anything that accepted the sequence.
361///
362/// The win-signature to check when touching this: NATURAL clips must be
363/// BYTE-IDENTICAL with the veto compiled in, because it must abstain on them.
364fn apply_screen_t8_veto(fe: &mut FrameEncoder, sig: &crate::signals::FrameSignals) {
365    if fe.t8_pick && screen_t8_veto_on() && sig.is_screen() {
366        // VALUE, not presence: `transform_8x8` stays true so the flag keeps being
367        // written (the PPS advertises it); `t8_pick` false makes every macroblock
368        // write it as ZERO.
369        fe.t8_pick = false;
370    }
371}
372
373/// `RFF_T8_SCREEN=0` opts out of the screen veto (the comparator arm).
374fn screen_t8_veto_on() -> bool {
375    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
376    *ON.get_or_init(|| std::env::var("RFF_T8_SCREEN").map(|v| v != "0").unwrap_or(true))
377}
378
379fn i8_margin() -> f64 {
380    static M: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
381    *M.get_or_init(|| {
382        std::env::var("RFF_I8_MARGIN").ok().and_then(|v| v.parse().ok()).unwrap_or(0.0)
383    })
384}
385
386fn i8_in_p_on() -> bool {
387    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
388    *ON.get_or_init(|| std::env::var("RFF_I8_IN_P").map(|v| v != "0").unwrap_or(true))
389}
390
391fn sub8_rd_on() -> bool {
392    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
393    *ON.get_or_init(|| std::env::var("RFF_SUB8_RD").map(|v| v == "1").unwrap_or(false))
394}
395
396/// Level-aware bit estimate for a planned inter macroblock: the same
397/// `sum rdoq_rate(|level|)` currency the inter-8x8-vs-4x4 decision already uses,
398/// plus the motion syntax (which does NOT cancel between a split arm and an
399/// 8x8 arm -- they carry a different NUMBER of mvds, and that difference is the
400/// whole point of the comparison).
401fn plan_rate_bits(plan: &InterPlan, sub_types: [u8; 4]) -> f64 {
402    let mut r = 0.0f64;
403    if plan.t8x8 {
404        for b in &plan.q8 {
405            for &l in b.iter() {
406                if l != 0 {
407                    r += rdoq_rate((l as i64).abs());
408                }
409            }
410        }
411    } else {
412        for b in &plan.q_blocks {
413            for &l in b.iter() {
414                if l != 0 {
415                    r += rdoq_rate((l as i64).abs());
416                }
417            }
418        }
419    }
420    for c in 0..2 {
421        for &l in &plan.c_dc_levels[c] {
422            if l != 0 {
423                r += rdoq_rate((l as i64).abs());
424            }
425        }
426        for b in &plan.c_q[c] {
427            for &l in b.iter() {
428                if l != 0 {
429                    r += rdoq_rate((l as i64).abs());
430                }
431            }
432        }
433    }
434    for m in plan.mvds.iter().take(plan.n_mvd) {
435        r += (mvd_bits(m.0) + mvd_bits(m.1)) as f64;
436    }
437    // sub_mb_type bins (1 for 8x8, 2 for 8x4, 3 for 4x8/4x4) + mb_type overhead.
438    for &st in &sub_types {
439        r += if st == 0 { 1.0 } else if st == 1 { 2.0 } else { 3.0 };
440    }
441    r + 16.0
442}
443
444/// P3.3 opt-in: search 8x4/4x8/4x4 sub-partitions inside P_8x8 (CABAC quality
445/// path, single-ref). `RFF_SUB8X8_SPLIT=1` enables; unset/0 = byte-identical.
446fn sub8x8_split_on() -> bool {
447    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
448    *ON.get_or_init(|| std::env::var("RFF_SUB8X8_SPLIT").map(|s| s == "1").unwrap_or(false))
449}
450
451fn split_t() -> f64 {
452    let v = SPLIT_T.load(std::sync::atomic::Ordering::Relaxed);
453    if v != u32::MAX {
454        return v as f64;
455    }
456    let d: u32 = std::env::var("RFF_SPLIT_T").ok().and_then(|s| s.parse().ok()).unwrap_or(0);
457    SPLIT_T.store(d, std::sync::atomic::Ordering::Relaxed);
458    d as f64
459}
460
461/// Observe-only HARVEST for the PARTITION-split gate (U2/U5).
462///
463/// The 16×16 search is the null arm and runs first; the 2-way splits and P_8x8 are
464/// the expensive arm (7 further `best_part` calls, each with its own full-pel search
465/// AND sub-pel refinement). Today they are gated by a fixed `split_gate` formula.
466/// Records the null-arm cost, the best split cost, and which won, so the
467/// skip-rate-vs-gain-kept ceiling can be swept before any threshold is touched.
468mod split_harvest {
469    use std::fs::File;
470    use std::io::Write;
471    use std::sync::{Mutex, OnceLock};
472
473    fn sink() -> &'static Option<Mutex<File>> {
474        static S: OnceLock<Option<Mutex<File>>> = OnceLock::new();
475        S.get_or_init(|| {
476            std::env::var("RFF_SPLIT_HARVEST").ok().and_then(|p| {
477                let mut f = File::create(p).ok()?;
478                let _ = writeln!(f, "c16,best,lambda,gate,won");
479                Some(Mutex::new(f))
480            })
481        })
482    }
483
484    #[inline]
485    pub fn enabled() -> bool {
486        sink().is_some()
487    }
488
489    pub fn record(c16: i64, best: i64, lambda: f64, gate: i64, won: u8) {
490        if let Some(m) = sink() {
491            if let Ok(mut f) = m.lock() {
492                let _ = writeln!(f, "{c16},{best},{lambda:.4},{gate},{won}");
493            }
494        }
495    }
496}
497
498/// Descent C escape hatch: `RFF_HPEL_REF=0` restores the copy-then-SATD half-pel path
499/// (byte-identical to it either way — this exists as a bisection anchor).
500fn hpel_ref_enabled() -> bool {
501    static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
502    *E.get_or_init(|| std::env::var("RFF_HPEL_REF").map(|v| v != "0").unwrap_or(true))
503}
504
505/// H-23: smooth (x264-shape) mvd cost table, in quarter-bit units scaled to the
506/// same magnitude as the Exp-Golomb model so λ stays calibrated. `RFF_MVCOST=1`.
507static MV_COST_TAB: std::sync::OnceLock<Vec<u16>> = std::sync::OnceLock::new();
508fn build_mv_cost() -> Vec<u16> {
509    (0..4096u32)
510        .map(|a| {
511            let c = 2.0 * ((a + 1) as f64).log2() + 0.718 + if a != 0 { 1.0 } else { 0.0 };
512            // Round to quarter-bits then express in the caller's integer "bits"
513            // domain by keeping 4× resolution — λ is rescaled to match below.
514            (c * 4.0).round() as u16
515        })
516        .collect()
517}
518/// H-24: 0 = off (Exp-Golomb step, byte-identical), 1 = DISPATCHED per frame by
519/// the `b2_mgain` motion probe, 2 = force-on. The BD sign-flip (bus −1.31 /
520/// football −0.24 vs foreman +0.23 / akiyo +0.11) tracks MOTION: the smooth
521/// curve pays where |mvd| is large enough to leave the first bracket, and only
522/// adds noise where every vector already sits inside it.
523static MV_SMOOTH: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
524pub fn set_mv_smooth(on: bool) {
525    MV_SMOOTH.store(if on { 2 } else { 0 }, core::sync::atomic::Ordering::Relaxed)
526}
527pub fn set_mv_smooth_mode(m: u32) {
528    MV_SMOOTH.store(m.min(3), core::sync::atomic::Ordering::Relaxed)
529}
530/// Dispatch threshold on the per-frame mgain probe (`RFF_MVCOST_T`, default 0.10).
531/// Calibrated on the DEPLOYED probe: bus min-frame 0.185 and football med 0.208
532/// route ON; foreman med 0.164 is the boundary case, akiyo ~0.00 routes OFF.
533/// H-26: the measured TRUE table plus a COHERENCE BIAS on every d≠0 entry —
534/// the cheap scalar form of the MV-field externality H-25 root-caused (a chosen
535/// vector that leaves the predictor degrades the neighbours' medians; truth
536/// per-vector under-prices that shared damage). `RFF_MVCOST_BIAS` in bits,
537/// read once at first use. DEFAULT 1.0 — mode 3 ships as the H-26 BIASED form
538/// (the original doc here said "default 0 = pure truth", contradicting the
539/// `unwrap_or(1.0)` shipped in the same commit; the code carries the intent —
540/// set `RFF_MVCOST_BIAS=0` explicitly for the H-25 pure-truth table).
541static MV_TRUE_BIASED: std::sync::OnceLock<Vec<u16>> = std::sync::OnceLock::new();
542fn build_true_biased() -> Vec<u16> {
543    let bias_q4 = (std::env::var("RFF_MVCOST_BIAS")
544        .ok()
545        .and_then(|v| v.parse::<f64>().ok())
546        .unwrap_or(1.0)
547        * 4.0)
548        .round() as u16;
549    crate::mvd_cost_tab::MVD_TRUE_COST4
550        .iter()
551        .enumerate()
552        .map(|(d, &c)| if d == 0 { c } else { c.saturating_add(bias_q4) })
553        .collect()
554}
555
556fn mv_smooth_t() -> f64 {
557    static T: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
558    *T.get_or_init(|| std::env::var("RFF_MVCOST_T").ok().and_then(|v| v.parse().ok()).unwrap_or(0.10))
559}
560/// 0 = step model, 1 = smooth (this frame routed on), 2 = smooth (forced),
561/// 3 = the MEASURED true-cost table (H-25) — no dispatch needed if it wins
562/// everywhere, since it is the truth both analytic models approximate.
563/// `frame_smooth` is the per-frame probe decision, carried on the frame state
564/// (like `sadfp`) — a process-global here races under the GOP-parallel encode.
565#[inline]
566fn mv_cost_kind(frame_smooth: bool) -> u32 {
567    match mv_smooth_mode() {
568        0 => 0,
569        // H-26 verdict: smooth/truth/truth+bias shuffle within ±0.2 BD fit-noise
570        // of each other at dispatch (bus prefers truth, football prefers smooth,
571        // none dominates), so the dispatch keeps its ORIGINALLY-GATED smooth
572        // ON-model; the measured/biased tables remain as modes 2/3 for research.
573        1 => frame_smooth as u32,
574        2 => 1, // archaeology: the x264 smooth curve, forced
575        _ => 2, // the biased-truth table, forced
576    }
577}
578#[inline]
579fn mv_smooth_mode() -> u32 {
580    match MV_SMOOTH.load(core::sync::atomic::Ordering::Relaxed) {
581        m @ 0..=3 => m,
582        _ => {
583            static E: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
584            // DEFAULT 1 = DISPATCHED (H-24). Owner's call: mean −0.27% BD is
585            // taken over minimax, accepting a known, bounded +0.16-0.18% on
586            // foreman-class content. `RFF_MVCOST=0` restores the pre-H-23 bytes.
587            *E.get_or_init(|| {
588                std::env::var("RFF_MVCOST").ok().and_then(|v| v.parse().ok()).unwrap_or(1)
589            })
590        }
591    }
592}
593
594/// Challenge-1 A3 escape hatch: `RFF_SATD_AVG=0` restores the materialize-then-SATD
595/// quarter-pel cost path (byte-identical either way — a bisection anchor, like
596/// `RFF_HPEL_REF`).
597/// H-14 R3 escape hatch: `RFF_MECTX=0` restores the per-eval safe dispatch
598/// (byte-identical either way — MeCtx returns exactly the safe path's values).
599#[cfg_attr(not(accel), allow(dead_code))] // caller is accel-gated
600fn mectx_enabled() -> bool {
601    static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
602    *E.get_or_init(|| std::env::var("RFF_MECTX").map(|v| v != "0").unwrap_or(true))
603}
604
605fn satd_avg_enabled() -> bool {
606    static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
607    *E.get_or_init(|| std::env::var("RFF_SATD_AVG").map(|v| v != "0").unwrap_or(true))
608}
609
610/// Track-B B2 (docs/lets-win-optimize.md): run the FULL-PEL phase of the non-fast
611/// motion search in the SAD domain (`psadbw`-class, ~3-4× cheaper per candidate) and
612/// reprice the winner in SATD before the rescue/sub-pel phases — the cost split
613/// every x264 preset uses (SAD fpel, SATD from subme≥2). ⚠ BITSTREAM-CHANGING (a
614/// different full-pel winner can emerge), so it ships opt-in until the per-clip
615/// 4-QP BD gate clears it. `set_me_sadfp` overrides; unset → `RFF_ME_SADFP` env,
616/// default OFF (off = byte-identical to the pre-B2 encoder).
617/// Modes: 0 = off (byte-identical), 1 = DISPATCHED per frame by the `b2_mgain`
618/// probe (the shipping shape), 2 = force-on everywhere (the truth-table A/B arm).
619static ME_SADFP: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
620pub fn set_me_sadfp(on: bool) {
621    // Harness semantics preserved: `true` = the force-on arm truth tables measure.
622    ME_SADFP.store(if on { 2 } else { 0 }, core::sync::atomic::Ordering::Relaxed)
623}
624pub fn set_me_sadfp_mode(m: u32) {
625    ME_SADFP.store(m.min(2), core::sync::atomic::Ordering::Relaxed)
626}
627fn me_sadfp_mode() -> u32 {
628    match ME_SADFP.load(core::sync::atomic::Ordering::Relaxed) {
629        u32::MAX => {
630            static INIT: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
631            // DEFAULT = 1 (dispatched) since the H-3 gate: 16-clip corpus mean
632            // −0.26% BD, wins bus −1.71 / football −1.84 / foreman −0.44 /
633            // shields −0.22, every former loss 0.00; residual tail (soccer +0.09,
634            // harbour +0.06) is BD-fit noise — it responds NON-monotonically to
635            // threshold changes (less B2 made soccer read WORSE, +0.18).
636            // `RFF_ME_SADFP=0` is the escape hatch reproducing the pre-B2 bytes.
637            *INIT.get_or_init(|| {
638                std::env::var("RFF_ME_SADFP").ok().and_then(|v| v.parse().ok()).unwrap_or(1)
639            })
640        }
641        m => m,
642    }
643}
644
645/// B2 dispatch threshold on the per-frame `b2_mgain` probe (`RFF_ME_SADT`).
646/// Calibrated on the DEPLOYED estimator (recon reference, sampled MBs), not the
647/// offline source-frame probe — the recurring R6 law.
648fn me_sadt() -> f64 {
649    static T: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
650    *T.get_or_init(|| std::env::var("RFF_ME_SADT").ok().and_then(|s| s.parse().ok()).unwrap_or(0.13))
651}
652fn me_sadt_dbg() -> bool {
653    static D: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
654    *D.get_or_init(|| std::env::var_os("RFF_ME_SADT_DBG").is_some())
655}
656
657/// Fixed-centre batched diamond passes on SAD-routed frames (`RFF_ME_FC=0` falls
658/// back to the cascading scalar walk — the bisection anchor). Fixed-centre differs
659/// from the cascade only when 2+ points improve in one pass, so it rides B2's BD
660/// gate; dispatched-OFF frames never take this path and stay byte-identical.
661/// ③ Sub-pel ring FC: fixed-centre argmin passes for the HALF-PEL step, batched
662/// through `satd_16x16_x4p` (two calls cover the 8-ring; candidates resolve to
663/// h/h/v/v and c/c/c/c plane reads from an integer centre). Quarter-step and any
664/// declined pass keep the cascading walk. Bitstream-changing → own gate
665/// (`AB_SPFC`), `RFF_SP_FC=0` anchor.
666static SP_FC: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
667pub fn set_sp_fc(on: bool) {
668    SP_FC.store(on as u32, core::sync::atomic::Ordering::Relaxed)
669}
670fn sp_fc_enabled() -> bool {
671    match SP_FC.load(core::sync::atomic::Ordering::Relaxed) {
672        0 => false,
673        1 => true,
674        _ => {
675            static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
676            *E.get_or_init(|| std::env::var("RFF_SP_FC").map(|v| v != "0").unwrap_or(false))
677        }
678    }
679}
680
681static ME_FC: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
682pub fn set_me_fc(on: bool) {
683    ME_FC.store(on as u32, core::sync::atomic::Ordering::Relaxed)
684}
685fn me_fc_enabled() -> bool {
686    match ME_FC.load(core::sync::atomic::Ordering::Relaxed) {
687        0 => false,
688        1 => true,
689        _ => {
690            static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
691            *E.get_or_init(|| std::env::var("RFF_ME_FC").map(|v| v != "0").unwrap_or(true))
692        }
693    }
694}
695
696/// H-13 SPLIT DISPATCH — measured and REFUTED as a free dispatch, shipped as an
697/// OPT-IN rung (default 0 = off = byte-identical). The premise "splits buy
698/// ~nothing on near-static frames" is FALSE: at T=0.03 akiyo read +2.45% BD,
699/// akiyo_qcif +2.02%, FourPeople +2.00% for only 1.10-1.15× — partition splits
700/// EARN BD on every measured content class (the third death of the split-gate
701/// idea: U2 T=400, the sum-weighted ceiling, now the mgain axis). foreman/bus
702/// route ON at any sane T (min frame mgain 0.061/0.185) and stay byte-identical.
703/// `RFF_SPLIT_MG` (fraction) / `set_split_mg` (milli): a priced speed rung, not
704/// a free lunch.
705static SPLIT_MG: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
706pub fn set_split_mg(milli: u32) {
707    SPLIT_MG.store(milli, core::sync::atomic::Ordering::Relaxed)
708}
709fn split_mg() -> f64 {
710    match SPLIT_MG.load(core::sync::atomic::Ordering::Relaxed) {
711        u32::MAX => {
712            static E: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
713            *E.get_or_init(|| {
714                std::env::var("RFF_SPLIT_MG").ok().and_then(|v| v.parse().ok()).unwrap_or(0.0)
715            })
716        }
717        m => m as f64 / 1000.0,
718    }
719}
720
721/// The flash veto: frames whose zero-MV residual is DC-shift-dominated beyond this
722/// fraction route OFF even at high mgain (`RFF_ME_SADDC`). Calibrated on the
723/// DEPLOYED per-frame values: crew's harmful ON-frames read dc 0.843–0.859 (the
724/// camera flashes) while every good ON-frame on bus/football/foreman reads ≤ 0.478
725/// — a 1.76× natural gap; 0.6 sits mid-gap with margin both ways.
726fn me_sad_dcmax() -> f64 {
727    static T: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
728    *T.get_or_init(|| std::env::var("RFF_ME_SADDC").ok().and_then(|s| s.parse().ok()).unwrap_or(0.6))
729}
730
731// The B2 dispatch signal `b2_mgain` (mgain + dcfrac) lives in `crate::signals`
732// (Great Gate P1) — read through `FrameSignals::mgain_dc`, whose doc carries the
733// 16-clip truth table and the crew-flash dcfrac rationale.
734
735/// Track-B B3: cap on sub-pel ring ITERATIONS per step (`RFF_SP_MAXIT` /
736/// `set_sp_maxit`). 0 = unlimited (the default — byte-identical to the walk-to-
737/// convergence encoder); N caps each step's walk at N passes, the bounded budget
738/// x264's subme levels have always had. Bitstream-changing when set → BD-gated.
739static SP_MAXIT: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
740pub fn set_sp_maxit(n: u32) {
741    SP_MAXIT.store(n, core::sync::atomic::Ordering::Relaxed)
742}
743fn sp_maxit() -> u32 {
744    match SP_MAXIT.load(core::sync::atomic::Ordering::Relaxed) {
745        u32::MAX => {
746            static INIT: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
747            *INIT.get_or_init(|| {
748                std::env::var("RFF_SP_MAXIT").ok().and_then(|v| v.parse().ok()).unwrap_or(0)
749            })
750        }
751        n => n,
752    }
753}
754
755/// B2 calibration: λ multiplier for the SAD-domain full-pel phase (`RFF_ME_SADL`,
756/// default 1.0). SATD distortion runs ~2× SAD's scale, so λ tuned for SATD weighs
757/// the rate term ~2× heavier in the SAD domain — 0.5 restores the SATD-era
758/// rate/distortion balance. Read once per process (hoisted per search).
759fn me_sadfp_lambda() -> f64 {
760    static E: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
761    // 0.5 = the calibrated default (SATD ≈ 2× SAD's scale; at 1.0 the rate term
762    // weighs double and foreman flips to a BD loss). Rides with the mode-1 default.
763    *E.get_or_init(|| {
764        std::env::var("RFF_ME_SADL").ok().and_then(|v| v.parse().ok()).unwrap_or(0.5)
765    })
766}
767
768/// Descent D: sub-pel ring census — evals/improvements by (step, ring position) and
769/// by loop ITERATION, so a position or an iteration that never pays is visible rather
770/// than assumed.
771#[cfg(feature = "profile")]
772pub mod spstats {
773    use core::sync::atomic::{AtomicU64, Ordering};
774    /// [step 0=half,1=quarter][position 0..8][0=evals,1=improvements]
775    pub static POS: [AtomicU64; 2 * 8 * 2] = [const { AtomicU64::new(0) }; 32];
776    /// [step][iteration 1..=6 clamped][0=evals,1=improvements]
777    pub static IT: [AtomicU64; 2 * 6 * 2] = [const { AtomicU64::new(0) }; 24];
778    #[inline]
779    pub fn ev(st: usize, pos: usize, it: u32) {
780        POS[(st * 8 + pos.min(7)) * 2].fetch_add(1, Ordering::Relaxed);
781        IT[(st * 6 + (it.max(1) as usize - 1).min(5)) * 2].fetch_add(1, Ordering::Relaxed);
782    }
783    #[inline]
784    pub fn imp(st: usize, pos: usize, it: u32) {
785        POS[(st * 8 + pos.min(7)) * 2 + 1].fetch_add(1, Ordering::Relaxed);
786        IT[(st * 6 + (it.max(1) as usize - 1).min(5)) * 2 + 1].fetch_add(1, Ordering::Relaxed);
787    }
788    /// Sub-pel evaluations that re-price an MV already evaluated in the SAME refinement.
789    pub static REDUNDANT: AtomicU64 = AtomicU64::new(0);
790    #[inline]
791    pub fn redundant() { REDUNDANT.fetch_add(1, Ordering::Relaxed); }
792    pub fn reset() {
793        for c in POS.iter() { c.store(0, Ordering::Relaxed); }
794        for c in IT.iter() { c.store(0, Ordering::Relaxed); }
795        REDUNDANT.store(0, Ordering::Relaxed);
796    }
797    pub fn snapshot() -> (Vec<u64>, Vec<u64>) {
798        (POS.iter().map(|c| c.load(Ordering::Relaxed)).collect(),
799         IT.iter().map(|c| c.load(Ordering::Relaxed)).collect())
800    }
801    pub fn redundant_count() -> u64 { REDUNDANT.load(Ordering::Relaxed) }
802}
803
804/// Descent B: which path does each ME cost evaluation actually take?
805#[cfg(feature = "profile")]
806pub mod satdpath {
807    use core::sync::atomic::{AtomicU64, Ordering};
808    pub static C: [AtomicU64; 3] = [const { AtomicU64::new(0) }; 3];
809    #[inline]
810    pub fn bump(i: usize) { C[i].fetch_add(1, Ordering::Relaxed); }
811    pub fn reset() { for c in C.iter() { c.store(0, Ordering::Relaxed); } }
812    pub fn snapshot() -> Vec<u64> { C.iter().map(|c| c.load(Ordering::Relaxed)).collect() }
813}
814
815/// The coarse-to-fine step ladder. DEFAULT `[16,8,4]` — the 64 and 32 rungs were
816/// REMOVED after the per-rung census showed they are ~39% of full-pel evaluations at a
817/// 0.05-0.84% hit rate, and the 20-clip 4-QP BD curve showed those rare hits are actively
818/// HARMFUL: a coarse jump finds a distant MV with marginally lower SATD, but it costs
819/// more mvd bits AND breaks the spatial coherence of the MV field, degrading every
820/// downstream neighbour's predictor. `lambda*mvbits` prices the first effect and is blind
821/// to the second. Dropping them is mean -0.93% BD-PSNR / -1.09% BD-SSIM with a WORST clip
822/// of +0.00%/+0.00% over 20 clips, and 1.15-1.57x fewer ME cost evaluations.
823///
824/// The 8 rung is load-bearing: `[16,4]` reads marginally better BD but makes football_cif
825/// do 1.55x MORE work, because the step-4 walk then has to crawl the distance the 8 rung
826/// covered in one hop. Reach and stride both matter; only the useless TOP is removed.
827///
828/// Bit i of the mask enables rung i of [64,32,16,8,4]. `RFF_DIA_LADDER=64,32,16,8,4`
829/// restores the pre-change ladder byte-for-byte; `set_dia_mask` overrides at runtime so a
830/// single process can measure several ladders.
831pub const DIA_RUNGS: [i32; 5] = [64, 32, 16, 8, 4];
832/// Rungs walked by default: `[16,8,4]`.
833pub const DIA_DEFAULT: u32 = 0b11100;
834
835/// SUB-PARTITION LADDER (best_part campaign, 2026-08-06). A sub-8x8 partition is
836/// seeded with its PARENT's already-converged MV (`extra = [mv16, mv_quad]`), so
837/// the coarse rungs a 16x16 block needs — to reach motion no predictor found —
838/// are near-pure toll here. Measured on foreman (quality, 30f, `mecost`):
839///
840/// | rung | reach | share of ALL ME evals | hit rate |
841/// |---|---|---|---|
842/// | s0 | 4 px | 30.0% | **0.97%** |
843/// | s1 | 2 px | 31.6% | 2.20% |
844/// | s2 | 1 px | 38.3% | 6.42% |
845///
846/// and the shares are IDENTICAL with the split search on or off — i.e. every
847/// 4x4 walks the same 4-pixel-reach ladder as an unpredicted 16x16. s0 alone is
848/// 863k evaluations to change 8,331 answers. The fine rung still reaches any
849/// distance (it walks to convergence), just in 1-px hops from a seed that is
850/// already right. `RFF_DIA_SUB` overrides (same `a,b,c` rung syntax as
851/// `RFF_DIA_LADDER`); `RFF_DIA_SUB=16,8,4` restores the pre-campaign behaviour.
852pub static DIA_SUB_MASK: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(u32::MAX);
853
854fn dia_sub_mask() -> u32 {
855    let m = DIA_SUB_MASK.load(core::sync::atomic::Ordering::Relaxed);
856    if m != u32::MAX {
857        return m;
858    }
859    static INIT: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
860    *INIT.get_or_init(|| match std::env::var("RFF_DIA_SUB") {
861        Ok(v) => {
862            let want: Vec<i32> = v.split(',').filter_map(|t| t.trim().parse().ok()).collect();
863            let mut m = 0u32;
864            for (i, r) in DIA_RUNGS.iter().enumerate() {
865                if want.contains(r) {
866                    m |= 1 << i;
867                }
868            }
869            m
870        }
871        // Default: the FINE rung alone (1 px, walked to convergence). Swept
872        // {[16,8,4], [8,4], [4]} on 6 clips as BD-rate vs no-splits — the short
873        // ladder is not a trade, it WINS on quality too, because coarse rungs on
874        // a 4x4 chase spurious far matches that fit the tiny block while
875        // wrecking the MV field its neighbours predict from (the same mechanism
876        // the diagonal-probe note above records, applied to rung REACH):
877        //
878        //   clip     full [16,8,4]      fine [4]        evals
879        //   foreman  -3.48 / -2.14      -3.59 / -2.21   -44.5%
880        //   harbour  -0.29 / +0.146     -0.36 / +0.073
881        //   mobile   -2.22 / -2.38      -2.42 / -2.57
882        //   tempete  -1.15 / -0.77      -1.25 / -0.89
883        //   bus      -6.61 / -5.53      -6.63 / -5.49   (tie)
884        //   screen   -11.98 / -12.40    -11.97 / -12.09 (gives back 0.31 of 12.4)
885        Err(_) => 0b10000,
886    })
887}
888pub static DIA_MASK: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(u32::MAX);
889pub fn set_dia_mask(m: u32) { DIA_MASK.store(m, core::sync::atomic::Ordering::Relaxed) }
890fn dia_mask() -> u32 {
891    let m = DIA_MASK.load(core::sync::atomic::Ordering::Relaxed);
892    if m != u32::MAX { return m; }
893    static INIT: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
894    *INIT.get_or_init(|| match std::env::var("RFF_DIA_LADDER") {
895        Ok(v) => {
896            let want: Vec<i32> = v.split(',').filter_map(|t| t.trim().parse().ok()).collect();
897            let mut m = 0u32;
898            for (i, r) in DIA_RUNGS.iter().enumerate() {
899                if want.contains(r) { m |= 1 << i; }
900            }
901            if m == 0 { DIA_DEFAULT } else { m }
902        }
903        Err(_) => DIA_DEFAULT,
904    })
905}
906
907/// Descent A: per-STEP-SIZE census of the coarse-to-fine diamond. The ladder is
908/// [64,32,16,8,4] quarter-pel (i.e. 16,8,4,2,1 full-pel) and each step walks until it
909/// stops improving. Counts evaluations AND improvements per step so a step that never
910/// pays can be identified rather than assumed.
911#[cfg(feature = "profile")]
912pub mod diastats {
913    use core::sync::atomic::{AtomicU64, Ordering};
914    /// [step_index][0]=evals, [1]=improvements
915    pub static C: [AtomicU64; 12] = [const { AtomicU64::new(0) }; 12];
916    #[inline]
917    pub fn ev(i: usize) { C[i * 2].fetch_add(1, Ordering::Relaxed); }
918    #[inline]
919    pub fn imp(i: usize) { C[i * 2 + 1].fetch_add(1, Ordering::Relaxed); }
920    pub fn reset() { for c in C.iter() { c.store(0, Ordering::Relaxed); } }
921    pub fn snapshot() -> Vec<(u64, u64)> {
922        (0..6).map(|i| (C[i * 2].load(Ordering::Relaxed), C[i * 2 + 1].load(Ordering::Relaxed))).collect()
923    }
924}
925
926/// Sub-pel refinement PATTERN (U1). Bit 0 = 4-point diamond ring instead of the
927/// 8-point square; bit 1 = single pass instead of walking to convergence.
928///
929/// Harvested from 280 k real refinements: ~29 evaluations each, but the LAST
930/// improvement lands at eval ~14–15 — **half of every refinement is spent confirming
931/// an answer already found** — and the first ring alone captures 64–72% of the total
932/// gain. An 8-point ring pays 8 evaluations for that confirmation; a 4-point diamond
933/// (what x264's subme uses) pays 4.
934///
935/// `RFF_SUBPEL_PAT`: 0 = 8-point + iterate (the pre-U1 default), 1 = 4-point +
936/// iterate, 2 = 8-point single pass, 3 = 4-point single pass.
937pub(crate) static SUBPEL_PAT: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
938
939/// Learning-window size and ring-1 threshold (percent) for the U1 online dispatcher.
940/// `RFF_SUBPEL_DISPATCH=0` disables it (pure `RFF_SUBPEL_PAT` behaviour).
941pub(crate) static SP_DISPATCH: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(u32::MAX);
942
943fn sp_dispatch_cfg() -> (u32, i64) {
944    use std::sync::OnceLock;
945    let forced = SP_DISPATCH.load(std::sync::atomic::Ordering::Relaxed);
946    if forced == 0 {
947        return (0, 0);
948    }
949    static C: OnceLock<(u32, i64)> = OnceLock::new();
950    *C.get_or_init(|| {
951        // DEFAULT OFF — measured and refuted (see the U1 entry in
952        // docs/WHYS-speed-gap.md). It only delivers speed where a blanket pattern
953        // change already would (bus 1.47x) while costing BD where it delivers none
954        // (foreman +0.97% for 1.04x, mobile +0.33% for 0.98x), and mixing refinement
955        // quality across frames measured WORSE than a uniform cut (bus +0.81%
956        // dispatched vs +0.30% pat2-always) — the refinement feeds the reference
957        // chain, so per-frame inconsistency propagates.
958        let on = std::env::var("RFF_SUBPEL_DISPATCH").map(|s| s != "0").unwrap_or(false);
959        if !on {
960            return (0, 0);
961        }
962        let k = std::env::var("RFF_SUBPEL_LEARN").ok().and_then(|s| s.parse().ok()).unwrap_or(200);
963        let t = std::env::var("RFF_SUBPEL_T").ok().and_then(|s| s.parse().ok()).unwrap_or(67);
964        (k, t)
965    })
966}
967
968/// Explicit override only; `None` means "use the preset's default".
969fn subpel_pattern_override() -> Option<u32> {
970    let v = SUBPEL_PAT.load(std::sync::atomic::Ordering::Relaxed);
971    if v != u32::MAX {
972        return Some(v);
973    }
974    if let Some(e) = std::env::var("RFF_SUBPEL_PAT").ok().and_then(|s| s.parse::<u32>().ok()) {
975        SUBPEL_PAT.store(e, std::sync::atomic::Ordering::Relaxed);
976        return Some(e);
977    }
978    None
979}
980
981/// Observe-only HARVEST for the sub-pel refinement skip-gate (U1).
982///
983/// `me-subpel` is 141 ms of a 320 ms quality encode — 44% — at 241 candidate
984/// evaluations per macroblock. This tap records, per refinement, the NULL-ARM cost
985/// (the full-pel winner, i.e. what we would keep if we skipped) against the cost the
986/// refinement actually reached, so the skip-rate-vs-gain-kept ceiling can be swept
987/// offline before any gate is written. Writes nothing unless `RFF_SUBPEL_HARVEST`
988/// names a file.
989mod subpel_harvest {
990    use std::fs::File;
991    use std::io::Write;
992    use std::sync::{Mutex, OnceLock};
993
994    fn sink() -> &'static Option<Mutex<File>> {
995        static S: OnceLock<Option<Mutex<File>>> = OnceLock::new();
996        S.get_or_init(|| {
997            std::env::var("RFF_SUBPEL_HARVEST").ok().and_then(|p| {
998                let mut f = File::create(p).ok()?;
999                let _ = writeln!(f, "pre,post,lambda,w,h,evals,to_best,ring1");
1000                Some(Mutex::new(f))
1001            })
1002        })
1003    }
1004
1005    #[inline]
1006    pub fn enabled() -> bool {
1007        sink().is_some()
1008    }
1009
1010    #[allow(clippy::too_many_arguments)]
1011    pub fn record(pre: i64, post: i64, lambda: f64, w: usize, h: usize, evals: u32, to_best: u32, ring1: i64) {
1012        if let Some(m) = sink() {
1013            if let Ok(mut f) = m.lock() {
1014                let _ = writeln!(f, "{pre},{post},{lambda:.4},{w},{h},{evals},{to_best},{ring1}");
1015            }
1016        }
1017    }
1018}
1019
1020/// A/B switch for serving B-direct 4×4 MC from the cached half-pel planes
1021/// (`RFF_BDIRECT_PLANES=0` restores the direct `mc_luma` 6-tap). Byte-identical
1022/// either way; the knob exists so the arm can be measured in one binary.
1023fn bdirect_planes_enabled() -> bool {
1024    use std::sync::OnceLock;
1025    static ON: OnceLock<bool> = OnceLock::new();
1026    *ON.get_or_init(|| std::env::var("RFF_BDIRECT_PLANES").map(|s| s != "0").unwrap_or(true))
1027}
1028
1029fn me_batch_enabled() -> bool {
1030    use std::sync::OnceLock;
1031    static ON: OnceLock<bool> = OnceLock::new();
1032    *ON.get_or_init(|| std::env::var("RFF_ME_BATCH").map(|s| s != "0").unwrap_or(true))
1033}
1034
1035/// A 16-byte-aligned 16×16 luma block — the aligned `op1` openh264's SSE2 SAD/SATD
1036/// kernels require (`movdqa`). Safe to construct (`forbid(unsafe)` holds); the asm
1037/// FFI that consumes it lives in `rusty_h264-accel`. Only used on the `asm` feature.
1038#[cfg(accel)]
1039#[repr(align(16))]
1040struct AlignedMb([u8; 256]);
1041
1042/// A B-slice 16×16 inter-coding spec: the prediction direction and the motion it
1043/// uses. `dir` 1 = `B_L0_16x16`, 2 = `B_L1_16x16`, 3 = `B_Bi_16x16` (spec Table
1044/// 7-14). List-0 is `refs[0]` (nearest past anchor); `l1` is List-1 (nearest
1045/// future anchor). `mv0`/`mv1` are the List-0/List-1 motion vectors (quarter-pel).
1046#[derive(Clone, Copy)]
1047struct BInter<'a> {
1048    dir: u8,
1049    l1: &'a crate::RefFrame,
1050    mv0: (i32, i32),
1051    mv1: (i32, i32),
1052    /// 0 = single 16x16 (use `dir`/`mv0`/`mv1`); 1 = 16x8; 2 = 8x16. When non-zero
1053    /// `parts2` carries `(pred, mv0, mv1)` per partition with pred 1=L0 / 2=L1 / 3=Bi.
1054    mvmode: u8,
1055    parts2: [(u8, (i32, i32), (i32, i32)); 2],
1056}
1057
1058/// 16-byte-aligned 256-`i16` DCT/coefficient buffer — the in-place `movdqa` quant
1059/// kernel (openh264 `WelsQuantFour4x4` heritage) requires aligned coefficients.
1060#[cfg(accel)]
1061#[repr(align(16))]
1062struct AlignedDct([i16; 256]);
1063
1064/// Luma variance of the 16×16 source MB at (mb_x, mb_y) — the content signal for
1065/// the adaptive SAD↔SATD cost dispatch (high variance = detail = SAD misprices).
1066/// `256·variance` scale (the /256 of the mean-square is kept integer); only the
1067/// RELATIVE ordering matters for the per-frame percentile, so the constant drops.
1068// `mb_variance` lives in `crate::signals` (Great Gate P1) — imported above; the
1069// per-MB raster vector is shared through `FrameSignals::mb_vars`.
1070
1071/// Adaptive-Quantization per-MB QP map: flat (low-variance) macroblocks get a FINER
1072/// QP (where blocking/banding is visible), busy ones a COARSER QP (where the eye
1073/// masks error) — moving bits to where they're seen. The shift is `strength ·
1074/// (log2 var − frame mean log2 var)`, so it's relative to THIS frame's texture
1075/// distribution (content-invariant), rounded to an integer QP step and clamped.
1076/// `strength == 0` → uniform base QP (byte-identical: every `mb_qp_delta` is 0).
1077/// `RFF_AQ_GRAIN=0` disables the grain veto below — the bisection anchor that
1078/// reproduces the pre-gate bytes exactly.
1079fn aq_grain_veto_on() -> bool {
1080    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1081    *ON.get_or_init(|| std::env::var("RFF_AQ_GRAIN").map(|s| s != "0").unwrap_or(true))
1082}
1083
1084fn aq_qp_map(sig: &FrameSignals, base_qp: u8, strength: f64) -> Vec<u8> {
1085    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncAq);
1086    const AQ_DQP_MAX: i32 = 4;
1087    let n = sig.n_mbs();
1088    if strength == 0.0 || n == 0 {
1089        return vec![base_qp; n];
1090    }
1091    // GRAIN VETO (Great Gate P2 — docs/gate-ledger.md "aq-grain-veto",
1092    // PROVISIONAL: fitted against one textured-grain exemplar). Grain breaks
1093    // AQ's premise from the side the lv_spread back-off cannot see: noise is
1094    // "busy" everywhere (spread stays LOW-to-mid), but it is not maskable
1095    // texture — coarsening it shifts bits into coding noise (measured
1096    // +29.45% BD-SSIM on grain_akiyo, the corpus's only catastrophic AQ loss).
1097    // Three clauses, each grain-physical, ANDed for precision and abstention:
1098    //   median_var < 200  — the residual is NOT explained by texture (protects
1099    //                       mobile 1346+, city 259+; grain reads ≤ 128);
1100    //   grain_floor > 5   — even the best-predicted MBs carry residual;
1101    //   mgain < 0.1       — a full-pel search cannot reduce it (not motion).
1102    // "Unexplained temporal residual: not texture, not motion → noise."
1103    // Per-frame firing on the 24-clip corpus: grain 58/58 frames, ONE frame of
1104    // one winner (stockholm 1/58); threshold-insensitive across var<150..250.
1105    // Misses (textured grain, var ≥ 200) fail OPEN to current behaviour.
1106    // Clause order = cost order: median_var and the probes are memoized in the
1107    // signal vector, and short-circuiting keeps the mgain probe off almost
1108    // every non-grain frame.
1109    let grain = aq_grain_veto_on() && sig.grain_signature();
1110    signals::census::bump(signals::census::AQ_GRAIN, grain);
1111    if grain {
1112        return vec![base_qp; n];
1113    }
1114    // Per-MB variance (the bit-cost weight) and its log2 (+1 avoids log2(0) on a flat
1115    // MB → reads as maximally flat → finest QP) — both read from the shared signal
1116    // vector (Great Gate P1: one variance walk per frame, N consumers).
1117    // (`(v+1) as f64` is converted on the fly at both consumers below, in the
1118    // same order the old materialized `var` Vec was read — identical sums,
1119    // one n-sized allocation per frame gone.)
1120    let lvs = sig.log_vars();
1121    let (lv, mean_lv) = (&lvs.0, lvs.1);
1122    // CONTENT-ADAPTIVE STRENGTH: back off where the log-variance SPREAD is high. A
1123    // wide/bimodal spread means synthetic-ish content (flat regions beside detailed
1124    // patterns) where "busy = maskable" FAILS and the patterns are salient — full AQ
1125    // there costs PSNR. Natural content's spread is ~1 (keeps full strength); a
1126    // synthetic pan's is ~6 (heavily reduced). Ramp 1.0→`AQ_SPREAD_MIN` over
1127    // [`AQ_SPREAD_LO`, `AQ_SPREAD_HI`].
1128    const AQ_SPREAD_LO: f64 = 1.5;
1129    const AQ_SPREAD_HI: f64 = 5.0;
1130    const AQ_SPREAD_MIN: f64 = 0.0; // extreme spread (pathological synthetic) → AQ OFF
1131    let std_lv = lvs.2; // the shared lv_spread — same formula, computed once
1132    let factor = (1.0 - (std_lv - AQ_SPREAD_LO) / (AQ_SPREAD_HI - AQ_SPREAD_LO)).clamp(AQ_SPREAD_MIN, 1.0);
1133    let eff_strength = strength * factor;
1134    // Per-MB QP shift (clamped): busy (log-var above mean) coarser, flat finer.
1135    // Site 7's ★★ arm (Round 10): the magic-number round frees this loop of
1136    // its libm `round` call. Ties-EVEN vs libm's ties-AWAY — differs only on
1137    // exact .5, which the corpus hash gate measures.
1138    let poly = crate::fastmath::polytier_on();
1139    let dqp: Vec<i32> = lv
1140        .iter()
1141        .map(|&l| {
1142            let x = eff_strength * (l - mean_lv);
1143            (if poly { crate::fastmath::round_ties_even_fast(x) } else { x.round() }) as i32
1144        })
1145        .map(|d| d.clamp(-AQ_DQP_MAX, AQ_DQP_MAX))
1146        .collect();
1147    // RATE COMPENSATION: AQ nets a rate change (coarsening a busy MB saves more bits
1148    // than fining a flat one adds), so shift the whole frame's QP by `c` to restore
1149    // the un-AQ rate — keeping `qp` meaningful. Bit model `bits_i ∝ var_i·2^(−qp_i/6)`
1150    // (variance as the per-MB cost proxy): `c = 6·log2(Σ var·2^(−dqp/6) / Σ var)`.
1151    let sum_v: f64 = sig.mb_vars().iter().map(|&v| (v + 1) as f64).sum();
1152    // `dqp` is clamped to [-AQ_DQP_MAX, AQ_DQP_MAX], so 2^(-d/6) has only nine
1153    // possible values — but it was being recomputed with a `powf` for every
1154    // macroblock of every frame, and after the per-call table fix it was still
1155    // NINE powf + divides per FRAME. It is a pure function of constants, so a
1156    // `OnceLock` evaluates the same expression once per PROCESS — the
1157    // `build_mv_cost` pattern, bit-identical by construction.
1158    static QSTEP: std::sync::OnceLock<[f64; (2 * AQ_DQP_MAX + 1) as usize]> =
1159        std::sync::OnceLock::new();
1160    let qstep = QSTEP.get_or_init(|| {
1161        std::array::from_fn(|i| 2f64.powf(-((i as i32 - AQ_DQP_MAX) as f64) / 6.0))
1162    });
1163    let sum_vs: f64 = sig
1164        .mb_vars()
1165        .iter()
1166        .map(|&v| (v + 1) as f64)
1167        .zip(&dqp)
1168        .map(|(v, &d)| v * qstep[(d + AQ_DQP_MAX) as usize])
1169        .sum();
1170    let c = (6.0 * (sum_vs / sum_v).log2()).round() as i32;
1171    dqp.iter()
1172        .map(|&d| (base_qp as i32 + c + d).clamp(0, 51) as u8)
1173        .collect()
1174}
1175
1176/// Mean per-sampled-pixel residual after GLOBAL-motion compensation of `sy` from
1177/// `ref_y` (coarse ±12 global ME + ±3 refine, subsampled interior). ~0 on a PURE pan
1178/// (a single MV predicts the whole frame) — precisely the content where the local ME
1179/// diamond never genuinely STALLS (its seed = the median = the pan MV is already
1180/// right), so the `me_wide` rescue can only find SPURIOUS MVs that wreck the B-frame
1181/// spatial-direct predictors. Gates `me_wide` off there — non-uniform content
1182/// (real stalls, where me_wide wins) reads well above 0.
1183/// Per-frame HEAD-ROOM probe for the `me_wide` rescue: on a small subsample of
1184/// blocks, how much does a WIDE full-pel search beat a PREDICTOR-LOCAL one?
1185///
1186/// This measures what the rescue actually buys, before the macroblock loop and
1187/// without committing any vector — unlike the online payoff gate, which scores its
1188/// own SATD cost-cut *after* committing MVs and so only ever separated static
1189/// content. Returns the mean relative SAD improvement, in percent.
1190///
1191/// Calibrated against the 20-clip per-clip BD truth table (docs/WHYS-speed-gap.md
1192/// R5): me_wide earns its 1.4–5.1× on high-head-room content (bus +4.57, blue_sky
1193/// +4.70, football +1.51, park_joy +0.91) and REGRESSES on low-head-room content
1194/// (foreman_qcif −1.08, foreman_cif −0.16, tempete −0.12, mobile −0.03).
1195///
1196/// Deliberately PER-FRAME, not per-clip: cross-frame adaptive state is
1197/// nondeterministic under the GOP-parallel encode path (a lesson already paid for
1198/// by the rescue's own learning window).
1199/// Head-room threshold (percent) for the `me_wide` frame gate. DEFAULT-ON at 16.
1200///
1201/// Calibrated on the DEPLOYED estimator (not the offline probe — they differ) and
1202/// gated on the full 20-clip `video-tests` corpus plus four synthesized boundary
1203/// clips, 4-QP BD-rate on PSNR and SSIM:
1204///
1205/// | | me_wide always-on | gated at 16 |
1206/// |---|---|---|
1207/// | real-corpus mean | +0.62% | +0.547% (88% retained) |
1208/// | **worst clip** | **−1.08%** (foreman_qcif) | **0.00%** |
1209/// | clips paying 1.1–3.6× for ~nothing | 13 | 0 |
1210///
1211/// Wins preserved: blue_sky +4.70, bus +4.37, park_joy +0.94, football +0.64,
1212/// shields +0.20; synthesized fast-pan +6.73, rotation +1.72, zoom +1.11.
1213/// Monotone non-regression — no clip is negative — which is what promotes this from
1214/// a speed trade to a default.
1215///
1216/// `RFF_ME_HR=0` disables the gate and reproduces the pre-gate bytes exactly (the
1217/// escape hatch / bisection anchor). Thresholds 13 and 16 both clear the boundary
1218/// clip (foreman_cif +0.07 / +0.03); 10 does NOT (−0.23) — the threshold is
1219/// calibrated on a narrow boundary pair, so treat it as re-tunable, not settled.
1220fn me_wide_hr_thresh() -> f64 {
1221    use std::sync::OnceLock;
1222    static T: OnceLock<f64> = OnceLock::new();
1223    *T.get_or_init(|| std::env::var("RFF_ME_HR").ok().and_then(|s| s.parse().ok()).unwrap_or(16.0))
1224}
1225
1226/// Cached, because it is read per frame — an `env::var` there is its own tax.
1227fn me_wide_hr_dbg() -> bool {
1228    use std::sync::OnceLock;
1229    static D: OnceLock<bool> = OnceLock::new();
1230    *D.get_or_init(|| std::env::var_os("RFF_ME_HR_DBG").is_some())
1231}
1232
1233// `me_wide_headroom` and `global_mc_residual` live in `crate::signals` (Great
1234// Gate P1) — read through `FrameSignals::headroom` / `FrameSignals::gmc_residual`,
1235// memoized so the CABAC-P driver's two consumers (the lme motion term and the
1236// me_wide coherence gate) share ONE computation per frame.
1237
1238/// Adds the mb-tree per-MB QP offset (TEMPORAL AQ — [`crate::mbtree`]) to the
1239/// spatial-AQ `aq_qp` map in place. An empty `qpo` (mb-tree off) or a length
1240/// mismatch is a no-op → byte-identical. Shared by the CAVLC and CABAC slice paths.
1241fn apply_mbtree_qpo(aq_qp: &mut [u8], qpo: &[i32]) {
1242    if qpo.len() == aq_qp.len() {
1243        for (q, &o) in aq_qp.iter_mut().zip(qpo) {
1244            *q = (*q as i32 + o).clamp(0, 51) as u8;
1245        }
1246    }
1247}
1248
1249/// IMPLICIT bi-prediction weights `(w0, w1)` from POC distances (spec §8.4.2.3.2,
1250/// `weighted_bipred_idc == 2`), IDENTICAL to the decoder's `implicit_weights`. The
1251/// closer anchor gets more weight; an equidistant B (`bframes == 1`) yields 32:32,
1252/// i.e. the plain average. `(32, 32)` fallback for the degenerate/out-of-range cases
1253/// the decoder also averages (no long-term refs here).
1254fn implicit_bi_weights(cur_poc: i32, l0_poc: i32, l1_poc: i32) -> (i32, i32) {
1255    let td = (l1_poc - l0_poc).clamp(-128, 127);
1256    let tb = (cur_poc - l0_poc).clamp(-128, 127);
1257    if td == 0 {
1258        return (32, 32);
1259    }
1260    // `(16384 + |td|/2) / td` for every clamped td, tabulated at compile time —
1261    // the one variable integer divide left in the B coding path (`td == 0` is
1262    // guarded above; its slot is unused). Same quotients: BIT-IDENTICAL.
1263    const TX: [i32; 256] = {
1264        let mut t = [0i32; 256];
1265        let mut i = 0usize;
1266        while i < 256 {
1267            let td = i as i32 - 128;
1268            if td != 0 {
1269                t[i] = (16384 + (if td < 0 { -td } else { td }) / 2) / td;
1270            }
1271            i += 1;
1272        }
1273        t
1274    };
1275    let tx = TX[(td + 128) as usize];
1276    let dsf = ((tb * tx + 32) >> 6).clamp(-1024, 1023);
1277    let w1 = dsf >> 2;
1278    if !(-64..=128).contains(&w1) {
1279        return (32, 32);
1280    }
1281    (64 - w1, w1)
1282}
1283
1284/// Bi-prediction blend of two motion-compensated samples `p` (List-0) and `q`
1285/// (List-1) under weights `(w0, w1)` — the decoder's `b_mc` blend. `(32, 32)` is the
1286/// plain `(p+q+1)>>1` average.
1287#[inline(always)]
1288fn bi_blend(p: i32, q: i32, w: (i32, i32)) -> u8 {
1289    ((p * w.0 + q * w.1 + 32) >> 6).clamp(0, 255) as u8
1290}
1291
1292/// Zig-zag scan of a raster i16 4×4 block into scan-order i32 — the fused-path
1293/// twin of `scan_4x4_dcac(&q_blocks[..])`, reading quantized levels straight from
1294/// the hot i16 DCT buffer. Byte-identical: the i16→i32 widening of a quant level
1295/// is exact (levels always fit i16, being the input to the i16 idct kernel).
1296#[cfg(accel)]
1297#[inline]
1298fn scan_4x4_dcac_i16(d: &[i16]) -> [i32; 16] {
1299    [
1300        d[0] as i32, d[1] as i32, d[4] as i32, d[8] as i32, d[5] as i32, d[2] as i32,
1301        d[3] as i32, d[6] as i32, d[9] as i32, d[12] as i32, d[13] as i32, d[10] as i32,
1302        d[7] as i32, d[11] as i32, d[14] as i32, d[15] as i32,
1303    ]
1304}
1305
1306
1307/// Per-frame intra encoder state: reconstructed planes (coded size) and the
1308/// per-4×4-block non-zero-coefficient counts used for CAVLC context.
1309pub struct FrameEncoder {
1310    mb_w: usize,
1311    mb_h: usize,
1312    qp: u8,  // the CURRENT macroblock's target QPy (AQ varies it per MB)
1313    qpc: u8, // chroma QP for `qp`
1314    /// Running QPy of the last macroblock that coded an `mb_qp_delta` (spec QPY_PREV).
1315    /// `mb_qp_delta = qp − cur_qp`; a skip / cbp==0 MB codes no delta and inherits it.
1316    cur_qp: u8,
1317    /// Implicit bi-prediction weights `(w0, w1)` for the current B-frame (from its
1318    /// L0/L1 anchor POC distances). `(32, 32)` = plain average (P/I frames, `bframes
1319    /// == 1`); unequal for `bframes > 1`.
1320    bi_w: (i32, i32),
1321    cw: usize, // coded luma width
1322    ccw: usize, // coded chroma width
1323    // 16-byte aligned (the openh264 deblock/MC/intra asm load aligned row chunks).
1324    rec_y: AlignedBytes,
1325    rec_u: AlignedBytes,
1326    rec_v: AlignedBytes,
1327    nnz_y: Vec<u8>,    // (mb_w*4) x (mb_h*4)
1328    nnz_c: [Vec<u8>; 2], // each (mb_w*2) x (mb_h*2)
1329    modes_y: Vec<u8>,  // intra4x4 mode per 4×4 block (2=DC for I_16x16 blocks)
1330    coded_y: Vec<bool>, // whether each 4×4 block is reconstructed (top-right avail)
1331    mv_y: Vec<(i32, i32)>, // motion vector per 4×4 block (quarter-pel) — List-0
1332    inter_y: Vec<bool>, // whether each 4×4 block is inter-coded
1333    ref_idx_y: Vec<i32>, // reference index per 4×4 block (-1 = intra/uncoded) — List-0
1334    // B-slice List-1 motion field (empty for P/I). B_L1/B_Bi commit here so a later
1335    // partition's List-1 median predictor sees it, mirroring the decoder's
1336    // `mv_neighbors_list(.., 1)` over `mv1`/`ref_idx1`.
1337    mv1_y: Vec<(i32, i32)>,
1338    ref_idx1_y: Vec<i32>,
1339    idz: i64, // intra dead-zone divisor: 2 for all-intra, 3 when frames reference each other
1340    rdoq_strength: f64, // CABAC trellis (RDOQ) strength; 0 = off (hard quantize, CAVLC path)
1341    // Explicit P weighted prediction (x264-parity weightp): per-reference LUMA
1342    // (weight, offset) at denom 6 for THIS slice; empty = off/identity. Set by
1343    // the P slice coders from the header's own table, applied post-MC at every
1344    // P prediction build — the same integer form, in the same place, as the
1345    // decoder's `weight_partition`, or decode(encode(x)) drifts on fades.
1346    wp: Vec<(i32, i32)>,
1347    transform_8x8: bool, // High-profile 8x8 transform enabled (transform_8x8_mode_flag)
1348    sub8x8: bool, // P_8x8 sub-partition motion (four 8x8 MVs per MB)
1349    me_wide: bool, // adaptive wide ME grid search rescue (diamond stalls on flat surfaces)
1350    /// Track-B B2 for THIS frame: SAD-domain full-pel phase. Set at construction
1351    /// (force mode), or per frame by the `b2_mgain` dispatcher (mode 1).
1352    sadfp: bool,
1353    /// H-24 mv-cost SHAPE routing for THIS frame (mv_smooth mode 1), set by the
1354    /// same `b2_mgain` probe. Per-frame state, NOT a global: the GOP-parallel
1355    /// encode runs frames concurrently and a global store races across workers.
1356    mv_smooth: bool,
1357    /// H-13: search partition splits this frame (routed off on near-static frames).
1358    do_splits: bool,
1359    me_wide_var: u64, // per-pixel source variance below which a block is "flat"
1360    me_rescue: i64, // per-pixel residual SATD (on a flat block) that flags a diamond stall
1361    me_wide_coh: f64, // gate me_wide off when the frame's global-MC residual is below this (pure pan)
1362    me_range: i32, // rescue grid half-range in px (16 = ±16; wider reaches FAST motion the diamond misses)
1363    me_fast: bool, // also fire the rescue on HIGH-VARIANCE high-residual blocks (fast-motion stalls, not just flat)
1364    // ONLINE per-frame rescue-payoff gate (adaptive; WITHIN-frame so it stays
1365    // deterministic under the frame-parallel encode). Run the real rescue on the
1366    // first `me_learn` stalls of a frame, count how many the fine grid improves by
1367    // ≥6.25%, and if that fraction is below `me_payoff_pct`% disable the rescue for
1368    // the rest of the frame. This separates genuine diamond stalls (tsrc/zoom fine
1369    // grid improves ~33% of fires) from IRREDUCIBLE residual (rotation/fractal ~5-8%)
1370    // using the ACTUAL neighbour-seeded diamond — the only faithful signal (a cheap
1371    // SAD proxy from (0,0) inverts it: rot reads as highest-payoff). Frame-level, so
1372    // no per-block selection concentrates the B-direct-poisoning spurious MVs.
1373    me_learn: u32,
1374    me_payoff_pct: u32,
1375    /// U1 online sub-pel dispatcher (within-frame, so it stays deterministic under
1376    /// GOP-parallel encode). For the first `SP_LEARN` refinements of a frame we run
1377    /// the full 8-point+iterate pattern and accumulate how much of the total gain the
1378    /// FIRST ring captured; once the window fills, a frame whose gain is concentrated
1379    /// in ring 1 switches to the single-pass pattern for the rest of the frame.
1380    ///
1381    /// Harvested justification: ring-1 captures 63.7% of the gain on foreman (which
1382    /// loses +2.34% BD to a blanket single-pass) against 69.9–71.9% on bus/mobile
1383    /// (which lose only +0.30/+0.74% and gain 1.08–1.31×). The fraction separates the
1384    /// content that can afford the cut from the content that cannot.
1385    sp_single_pass: bool,
1386    /// U5-struct: when set, `motion_search` returns its FULL-PEL winner and skips
1387    /// sub-pel refinement entirely. The partition driver uses this to search all
1388    /// candidate shapes cheaply, pick one, and refine ONLY the winner's sub-blocks.
1389    /// Measured ceiling: 3.4–6.4× less sub-pel work (the losing shapes' refinements
1390    /// are pure waste), i.e. ~1.42× whole-encode at 44% sub-pel share.
1391    sp_defer: std::cell::Cell<bool>,
1392    sp_learn_n: std::cell::Cell<u32>,
1393    sp_ring1: std::cell::Cell<i64>,
1394    sp_total: std::cell::Cell<i64>,
1395    sp_1pass: std::cell::Cell<bool>,
1396    resc_n: std::cell::Cell<u32>,   // stalls the fine grid ran on this frame (learning phase)
1397    resc_big: std::cell::Cell<u32>, // of those, how many it improved ≥6.25%
1398    resc_off: std::cell::Cell<bool>, // rescue disabled for the rest of this frame
1399    /// May a macroblock CHOOSE the 8x8 transform this frame?
1400    ///
1401    /// Deliberately separate from `transform_8x8`, which means "the PPS advertises
1402    /// transform_8x8_mode_flag, so the flag must be WRITTEN". Those are not the same
1403    /// thing, and conflating them is a desync: clearing `transform_8x8` per frame
1404    /// suppresses a bit the decoder is still reading. Presence is the PPS's business;
1405    /// value is the per-frame gate's. (Third instance of that confusion in one day —
1406    /// the sub-8x8 and B_Direct flag bugs were the other two.)
1407    t8_pick: bool,
1408    /// Margin, in lambda units, that the I_8x8 candidate must BEAT its rivals by.
1409    /// See `i8_margin()`.
1410    i8_margin: f64,
1411    /// True while planning an INTRA macroblock inside a P/B slice. Those blocks are
1412    /// a different population from intra MBs in an I slice -- they are the ones inter
1413    /// prediction FAILED on (occlusion, fine detail), which is exactly where 4x4
1414    /// adapts better than 8x8. Set per call site, never inferred.
1415    intra_in_p: bool,
1416    // Inter 8x8-transform dispatch: 0 = off (intra 8x8 only), 1 = always-RD.
1417    // There is no mode 2: the enum used to document "2 = content-adaptive" and the
1418    // only test of this field is `!= 0`, so mode 2 was never anything but mode 1 --
1419    // confirmed by a BD table that came back identical in all 21 cells.
1420    inter8x8: u8,
1421    inter8_pen: i64, // extra rate charge (nonzero-equiv) on the inter 8x8 candidate
1422    fast: bool, // Preset::Fast — SATD mode decision (no RDO), 16×16/I_16x16 only
1423    #[cfg_attr(not(accel), allow(dead_code))] // read in accel-gated blocks
1424    skip_accel_check: bool, // A/B knob: whole-MB psadbw gate in the P_Skip free-check
1425    coded_path_v2: bool,    // A/B knob: route inter coding through encode_inter_mb_v2
1426    tune_lambda_scale: f64, // tuning knob: scale on the RD λ (1.0 = standard)
1427    tune_intra_penalty: f64,
1428    satd_q: f64,               // adaptive: fraction of high-variance MBs routed to SATD cost
1429    subpel_force: bool,        // force sub-pel refinement even in the fast preset
1430    me_snap: bool,             // snap the diamond centre to integer-pel (see config)
1431    me_subpel_iter: bool,      // walk the sub-pel refine to convergence
1432    greedy_skip: bool,         // quality preset's SAD-thresholded P_Skip (PredictSadSkip)
1433    greedy_min_free: u32,      // online free-skip % gating greedy_skip on this frame
1434    rd_skip: bool,             // decide P_Skip by J = SSD + lambda*bits, not exact-zero residual
1435    rd_skip_min_free: u32,     // online free-skip % gating rd_skip on this frame
1436    rd_skip_fast_t: f64,       // skip-gate on SSD(skip)/lambda; <= 0 prices every candidate
1437    satd_var_thresh: i64,      // per-frame variance threshold for the routing (set in a pre-pass)
1438    aq_strength: f64,          // adaptive quantization: per-MB QP modulation strength (0 = off)
1439    mb_use_satd: bool,         // per-MB: this MB uses the SATD cost this decision
1440    // Per-MB luma nnz prediction cache (openh264 scan8 style): a padded 5×5 grid,
1441    // block (lbx,lby) at (lby+1)*5+(lbx+1); row 0 = top neighbours, col 0 = left.
1442    // Unavailable edges hold the sentinel 0x80, so the nnz predict is branchless.
1443    nnz_l_cache: [u8; 25],
1444    // Same, per chroma plane: a padded 3×3 grid for the 2×2 chroma blocks.
1445    nnz_c_cache: [[u8; 9]; 2],
1446    // openh264 predicted-SAD skip apparatus (per MB, mb_w×mb_h): the P_Skip
1447    // prediction's luma SAD, and whether the MB was actually skipped. The greedy
1448    // skip threshold for an MB is the median of its skip *neighbours'* skip SADs
1449    // (`PredictSadSkip`) — so skip propagates only from already-skip regions
1450    // (seeded by free skips) and self-limits, instead of a fixed bound that drifts.
1451    mb_skip_sad: Vec<u32>,
1452    mb_was_skip: Vec<bool>,
1453}
1454
1455/// A chosen inter coding for a macroblock: `mb_type` and, per partition, the
1456/// reference index and motion vector.
1457type InterChoice = (u8, Vec<(i32, (i32, i32))>);
1458
1459
1460
1461/// EXTERNAL MV SCORING (`RFF_MV_CMP=1`). Holds another encoder's motion field
1462/// (per frame, 4x4-block raster) so our own coder can price ITS vectors against
1463/// ours under REAL coded bits instead of SATD — the only way to tell a bad search
1464/// from a bad cost function.
1465pub static EXT_MV: std::sync::Mutex<Vec<Vec<(i32, i32)>>> = std::sync::Mutex::new(Vec::new());
1466/// [n, our bits, ext bits, our SSD, ext SSD, ext won on J, MVs differing]
1467pub static MVCMP: [std::sync::atomic::AtomicU64; 7] = {
1468    const Z: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1469    [Z; 7]
1470};
1471pub static MVCMP_FRAME: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
1472/// Replace our chosen vector with the external field's, for EVERY macroblock where
1473/// that field used a single 16x16 partition. Transplanting one vector in isolation
1474/// is meaningless — `mvd` is coded against the NEIGHBOURS' vectors, so a lone
1475/// foreign vector prices against the wrong predictor. Only a whole coherent field
1476/// can be compared fairly.
1477fn mv_force_on() -> bool {
1478    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1479    *ON.get_or_init(|| std::env::var("RFF_MV_FORCE").map_or(false, |v| v != "0"))
1480}
1481fn mv_cmp_on() -> bool {
1482    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1483    *ON.get_or_init(|| std::env::var("RFF_MV_CMP").map_or(false, |v| v != "0"))
1484}
1485
1486/// [n, sum our cost, sum oracle cost, blocks the oracle beat us on, cost() evals]
1487pub static ME_PROBE: [std::sync::atomic::AtomicU64; 7] = {
1488    const Z: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1489    [Z; 7]
1490};
1491
1492/// Cached — an `env::var` inside the ME loop inflated it 4x when probed naively.
1493fn me_oracle_on() -> bool {
1494    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1495    *ON.get_or_init(|| std::env::var("RFF_ME_ORACLE").map_or(false, |v| v != "0"))
1496}
1497
1498/// A snapshot of one macroblock's per-block grids and reconstruction region,
1499/// used to roll back a trial encode during RD mode decision.
1500///
1501/// Every field is a `Vec`, so building one from scratch is ten heap allocations.
1502/// The RD skip decision snapshots on EVERY candidate macroblock, which made that
1503/// allocation traffic the decision's dominant cost — hence
1504/// [`save_mb_into`](FrameEncoder::save_mb_into), which refills a reused buffer.
1505#[derive(Default)]
1506struct MbState {
1507    rec_y: Vec<u8>,
1508    rec_u: Vec<u8>,
1509    rec_v: Vec<u8>,
1510    nnz_y: Vec<u8>,
1511    nnz_c: [Vec<u8>; 2],
1512    mv_y: Vec<(i32, i32)>,
1513    inter_y: Vec<bool>,
1514    ref_idx_y: Vec<i32>,
1515    coded_y: Vec<bool>,
1516    modes_y: Vec<u8>,
1517    /// QPY_PREV. `qp_delta()` MUTATES this as a side effect of coding
1518    /// `mb_qp_delta`, so a trial encode advances it; without restoring it the
1519    /// real encode then codes its delta against the wrong predecessor and the
1520    /// decoder's QP diverges from the encoder's — a silent stream corruption,
1521    /// not a quality tweak.
1522    cur_qp: u8,
1523}
1524
1525/// Edge-clamped, coded-size source planes (luma, Cb, Cr).
1526/// Fast-preset pruned I4x4 mode search ({MPM, DC, V, H} instead of all 9 — the
1527/// x264-ultrafast-style candidate set). DEFAULT ON for the fast preset (gated:
1528/// +0.5% size at +0.02 dB on all-intra, +17% all-intra speed); RUSTY_FAST_INTRA=0
1529/// restores the exhaustive 9-mode search (the pre-flip bitstream).
1530fn fast_intra_enabled() -> bool {
1531    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1532    *ON.get_or_init(|| std::env::var("RUSTY_FAST_INTRA").map_or(true, |v| v != "0"))
1533}
1534
1535fn coded_source<'a>(
1536    cfg: &EncoderConfig,
1537    frame: &'a YuvFrame,
1538) -> (
1539    std::borrow::Cow<'a, [u8]>,
1540    std::borrow::Cow<'a, [u8]>,
1541    std::borrow::Cow<'a, [u8]>,
1542) {
1543    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncSource);
1544    let cw = cfg.mb_width() * 16;
1545    let ch = cfg.mb_height() * 16;
1546    // MB-aligned frame (the common case): the clamp is the identity, and the
1547    // drivers only READ the planes — borrow them. This was THREE full-plane
1548    // clones per slice (11.11); Cow keeps the padded path allocation intact.
1549    if frame.width == cw && frame.height == ch {
1550        return (
1551            std::borrow::Cow::Borrowed(&frame.y),
1552            std::borrow::Cow::Borrowed(&frame.u),
1553            std::borrow::Cow::Borrowed(&frame.v),
1554        );
1555    }
1556    let y = clamp_plane(&frame.y, frame.width, frame.height, cw, ch);
1557    let u = clamp_plane(&frame.u, frame.chroma_width(), frame.chroma_height(), cw / 2, ch / 2);
1558    let v = clamp_plane(&frame.v, frame.chroma_width(), frame.chroma_height(), cw / 2, ch / 2);
1559    (
1560        std::borrow::Cow::Owned(y),
1561        std::borrow::Cow::Owned(u),
1562        std::borrow::Cow::Owned(v),
1563    )
1564}
1565
1566/// 11.11: per-THREAD recycled slice scratch — the encoder twin of the decoder
1567/// GridPool's `sc_*` fields (D13's finding, never ported to the encoder until
1568/// now). GOP-parallel workers each hold their own copy, so reuse stays
1569/// deterministic. Every buffer is reset to its fresh-allocation contents
1570/// before use — byte-identical by construction.
1571mod enc_scratch {
1572    use std::cell::RefCell;
1573    thread_local! {
1574        static CS: RefCell<Option<super::CabacState>> = const { RefCell::new(None) };
1575        static QPY: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
1576        static REFID: RefCell<Vec<i32>> = const { RefCell::new(Vec::new()) };
1577        // The b-pyramid ref-B deblock tail needs BOTH lists' index grids alive
1578        // at once, so List-1 gets its own recycled slot.
1579        static REFID1: RefCell<Vec<i32>> = const { RefCell::new(Vec::new()) };
1580        static PAYLOAD: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
1581        static BITS: RefCell<super::BitWriter> = RefCell::new(super::BitWriter::new());
1582        static SNAP_A: RefCell<super::MbState> = RefCell::new(super::MbState::default());
1583        static SNAP_B: RefCell<super::MbState> = RefCell::new(super::MbState::default());
1584    }
1585    pub(super) fn take_cs() -> Option<super::CabacState> {
1586        CS.with(|c| c.borrow_mut().take())
1587    }
1588    pub(super) fn put_cs(v: super::CabacState) {
1589        CS.with(|c| *c.borrow_mut() = Some(v));
1590    }
1591    pub(super) fn take_qpy() -> Vec<u8> {
1592        QPY.with(|c| std::mem::take(&mut *c.borrow_mut()))
1593    }
1594    pub(super) fn put_qpy(v: Vec<u8>) {
1595        QPY.with(|c| *c.borrow_mut() = v);
1596    }
1597    pub(super) fn take_refid() -> Vec<i32> {
1598        REFID.with(|c| std::mem::take(&mut *c.borrow_mut()))
1599    }
1600    pub(super) fn put_refid(v: Vec<i32>) {
1601        REFID.with(|c| *c.borrow_mut() = v);
1602    }
1603    pub(super) fn take_refid1() -> Vec<i32> {
1604        REFID1.with(|c| std::mem::take(&mut *c.borrow_mut()))
1605    }
1606    pub(super) fn put_refid1(v: Vec<i32>) {
1607        REFID1.with(|c| *c.borrow_mut() = v);
1608    }
1609    pub(super) fn take_payload() -> Vec<u8> {
1610        PAYLOAD.with(|c| std::mem::take(&mut *c.borrow_mut()))
1611    }
1612    pub(super) fn put_payload(v: Vec<u8>) {
1613        PAYLOAD.with(|c| *c.borrow_mut() = v);
1614    }
1615    pub(super) fn take_bits() -> super::BitWriter {
1616        BITS.with(|c| std::mem::take(&mut *c.borrow_mut()))
1617    }
1618    pub(super) fn put_bits(v: super::BitWriter) {
1619        BITS.with(|c| *c.borrow_mut() = v);
1620    }
1621    // E11 dig (11.17): `save_mb()` built a DEFAULT MbState — ten empty Vecs
1622    // whose pushes then heap-allocate — per RD TRIAL. Two recycled slots: A for
1623    // the driver sites (their lifetimes are sequential), B for `trial_intra`,
1624    // which nests inside a shape-RD trial that still holds A.
1625    pub(super) fn take_snap_a() -> super::MbState {
1626        SNAP_A.with(|c| std::mem::take(&mut *c.borrow_mut()))
1627    }
1628    pub(super) fn put_snap_a(v: super::MbState) {
1629        SNAP_A.with(|c| *c.borrow_mut() = v);
1630    }
1631    pub(super) fn take_snap_b() -> super::MbState {
1632        SNAP_B.with(|c| std::mem::take(&mut *c.borrow_mut()))
1633    }
1634    pub(super) fn put_snap_b(v: super::MbState) {
1635        SNAP_B.with(|c| *c.borrow_mut() = v);
1636    }
1637}
1638
1639/// Edge-extends `plane` from `w`×`h` to the coded `ow`×`oh`, replicating the last
1640/// row/column — the source form the MB grid needs.
1641///
1642/// Row-wise, because the per-pixel form is O(pixels) of scalar `min`+multiply and is
1643/// the DOMINANT cost of `enc-source-copy`: every frame whose height is not a multiple
1644/// of 16 takes this path, which includes all 1080p content (1080/16 = 67.5 → coded
1645/// height 1088). The stage measured 579 ms over the corpus while the three plane
1646/// clones on the MB-aligned fast path account for only ~135 ms of it.
1647///
1648/// Byte-identical to the per-pixel form (`clamp_plane_per_pixel`, kept as the test
1649/// oracle): `x.min(w-1)` is the identity below `w` and pins to the last column above
1650/// it, so a row is a `copy_from_slice` plus a `fill`; `y.min(h-1)` makes the
1651/// overhanging rows copies of the final row. Both lower to memcpy/memset.
1652fn clamp_plane(plane: &[u8], w: usize, h: usize, ow: usize, oh: usize) -> Vec<u8> {
1653    let mut out = vec![0u8; ow * oh];
1654    for y in 0..oh {
1655        let sy = y.min(h - 1);
1656        let src = &plane[sy * w..sy * w + w];
1657        let dst = &mut out[y * ow..y * ow + ow];
1658        if ow <= w {
1659            dst.copy_from_slice(&src[..ow]);
1660        } else {
1661            dst[..w].copy_from_slice(src);
1662            dst[w..].fill(src[w - 1]);
1663        }
1664    }
1665    out
1666}
1667
1668/// The original per-pixel edge extension — kept as the correctness oracle for
1669/// [`clamp_plane`], per the scalar-twin discipline.
1670#[cfg(test)]
1671fn clamp_plane_per_pixel(plane: &[u8], w: usize, h: usize, ow: usize, oh: usize) -> Vec<u8> {
1672    let mut out = vec![0u8; ow * oh];
1673    for y in 0..oh {
1674        for x in 0..ow {
1675            out[y * ow + x] = plane[y.min(h - 1) * w + x.min(w - 1)];
1676        }
1677    }
1678    out
1679}
1680
1681#[cfg(test)]
1682mod source_tests {
1683    use super::*;
1684
1685    /// The ref_bits prune in `best_part` breaks out of the reference loop the
1686    /// moment `λ·ref_bits(r)` alone reaches the incumbent cost — which is only
1687    /// sound if `ref_bits` never DECREASES with `r`. Pinned here over every
1688    /// active-reference count the config admits.
1689    #[test]
1690    fn ref_bits_is_monotone() {
1691        for n in 1..=16usize {
1692            for r in 1..n {
1693                assert!(
1694                    ref_bits(r, n) >= ref_bits(r - 1, n),
1695                    "ref_bits({r},{n}) < ref_bits({},{n})",
1696                    r - 1
1697                );
1698            }
1699        }
1700        // And the coding facts the model encodes: no ref_idx with one ref,
1701        // one flag bit with two.
1702        assert_eq!(ref_bits(0, 1), 0);
1703        assert_eq!(ref_bits(0, 2), 1);
1704        assert_eq!(ref_bits(1, 2), 1);
1705    }
1706
1707    /// Bit-exact golden for the AQ map (site 7's function): flat top row
1708    /// (zero variance → the log2 shortcut arm), textured rest. Pins the whole
1709    /// pipeline — log_vars through the per-MB round loop and the rate
1710    /// compensation — at two strengths.
1711    #[test]
1712    fn aq_qp_map_golden() {
1713        let (cw, ch) = (160usize, 112usize);
1714        let (mb_w, mb_h) = (cw / 16, ch / 16);
1715        // Texture amplitude grows per MB COLUMN (variance gradient → the dqp
1716        // map varies), with exactly ONE flat MB (top-left) so the zero-variance
1717        // arm runs but the lv SPREAD stays inside AQ's active band — a whole
1718        // flat region reads as "pathological synthetic" and latches AQ off,
1719        // which is precisely the degenerate map the assert below refuses.
1720        let mut sy = vec![64u8; cw * ch];
1721        for j in 0..ch {
1722            for i in 0..cw {
1723                let k = 4 + (i / 16) * 12;
1724                sy[j * cw + i] = 80 + ((i * 7 + j * 13) % k) as u8;
1725            }
1726        }
1727        for j in 0..16 {
1728            for i in 0..16 {
1729                sy[j * cw + i] = 64;
1730            }
1731        }
1732        let mut h = 0xcbf2_9ce4_8422_2325u64;
1733        crate::fastmath::TEST_POLYTIER.with(|c| c.set(Some(false)));
1734        for strength in [1.0f64, 0.5] {
1735            let sig = signals::FrameSignals::new(&sy, cw, mb_w, mb_h, None);
1736            assert!(sig.mb_vars().iter().any(|&v| v == 0), "no zero-variance MB");
1737            let map = aq_qp_map(&sig, 26, strength);
1738            // The gate must prove the tool ran: a veto's early-out would pin
1739            // a constant map, not the arithmetic.
1740            assert!(map.iter().any(|&q| q != 26), "AQ map degenerate at {strength}");
1741            // Round 10 decision-identity: the whole AQ pipeline under the
1742            // POLY arm (poly log2 + ties-even round) must produce the
1743            // IDENTICAL u8 map — the integer decisions have fat margins and
1744            // exact .5 ties are measure-zero, and this asserts it rather
1745            // than argues it.
1746            crate::fastmath::TEST_POLYTIER.with(|c| c.set(Some(true)));
1747            let sigp = signals::FrameSignals::new(&sy, cw, mb_w, mb_h, None);
1748            assert_eq!(aq_qp_map(&sigp, 26, strength), map, "poly arm map differs at {strength}");
1749            crate::fastmath::TEST_POLYTIER.with(|c| c.set(Some(false)));
1750            for &q in &map {
1751                h ^= q as u64;
1752                h = h.wrapping_mul(0x100_0000_01b3);
1753            }
1754        }
1755        crate::fastmath::TEST_POLYTIER.with(|c| c.set(None));
1756        assert_eq!(h, 8641818917227936570, "aq_qp_map golden");
1757    }
1758
1759    #[test]
1760    fn clamp_plane_matches_per_pixel_oracle() {
1761        let mut s: u32 = 0xDEAD_BEEF;
1762        let mut rnd = || {
1763            s = s.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
1764            (s >> 24) as u8
1765        };
1766        // Real coded geometries plus adversarial ones: width-only overhang,
1767        // height-only overhang (the 1080p case), both, and neither.
1768        let cases = [
1769            (1920usize, 1080usize, 1920usize, 1088usize), // 1080p luma
1770            (960, 540, 960, 544),                         // 1080p chroma
1771            (352, 288, 352, 288),                         // exactly aligned
1772            (100, 100, 112, 112),                         // both axes overhang
1773            (37, 5, 48, 16),                              // tiny + ragged
1774            (16, 1, 16, 16),                              // single source row
1775            (1, 1, 16, 16),                               // single sample
1776        ];
1777        for (w, h, ow, oh) in cases {
1778            let plane: Vec<u8> = (0..w * h).map(|_| rnd()).collect();
1779            assert_eq!(
1780                clamp_plane(&plane, w, h, ow, oh),
1781                clamp_plane_per_pixel(&plane, w, h, ow, oh),
1782                "clamp mismatch for {w}x{h} -> {ow}x{oh}"
1783            );
1784        }
1785    }
1786}
1787
1788/// The constructor's fourteen env knobs, parsed ONCE per process (E20).
1789/// Fields mirror the exact expressions they replaced; `Option` where a cfg or
1790/// preset fallback applies, final value where the default is cfg-independent.
1791struct CtorEnv {
1792    sub8x8: Option<bool>,
1793    me_wide: Option<bool>,
1794    me_wide_var: u64,
1795    me_rescue: i64,
1796    me_wide_coh: f64,
1797    me_range: i32,
1798    me_fast: bool,
1799    me_learn: u32,
1800    me_payoff_pct: u32,
1801    defer_subpel: bool,
1802    inter8: u8,
1803    inter8_pen: i64,
1804    subpel: Option<bool>,
1805    rdskip_minfree: Option<u32>,
1806}
1807fn ctor_env() -> &'static CtorEnv {
1808    static E: std::sync::OnceLock<CtorEnv> = std::sync::OnceLock::new();
1809    E.get_or_init(|| CtorEnv {
1810        sub8x8: std::env::var("RFF_SUB8X8").ok().map(|s| s == "1"),
1811        me_wide: std::env::var("RFF_ME_WIDE").ok().map(|s| s == "1"),
1812        me_wide_var: std::env::var("RFF_ME_WIDE_VAR").ok().and_then(|s| s.parse().ok()).unwrap_or(800),
1813        me_rescue: std::env::var("RFF_ME_RESCUE").ok().and_then(|s| s.parse().ok()).unwrap_or(3),
1814        me_wide_coh: std::env::var("RFF_ME_COH").ok().and_then(|s| s.parse().ok()).unwrap_or(4.0),
1815        me_range: std::env::var("RFF_ME_RANGE").ok().and_then(|s| s.parse().ok()).unwrap_or(24),
1816        me_fast: std::env::var("RFF_ME_FASTMO").map(|s| s != "0").unwrap_or(true),
1817        me_learn: std::env::var("RFF_ME_LEARN").ok().and_then(|s| s.parse().ok()).unwrap_or(40),
1818        me_payoff_pct: std::env::var("RFF_ME_PAYOFF").ok().and_then(|s| s.parse().ok()).unwrap_or(15),
1819        defer_subpel: std::env::var("RFF_DEFER_SUBPEL").map(|v| v != "0").unwrap_or(false),
1820        inter8: std::env::var("RFF_INTER8").ok().and_then(|s| s.parse().ok()).unwrap_or(0),
1821        inter8_pen: std::env::var("RFF_INTER8_PEN").ok().and_then(|s| s.parse().ok()).unwrap_or(8),
1822        subpel: std::env::var("RFF_SUBPEL").ok().map(|v| v != "1"),
1823        rdskip_minfree: std::env::var("RFF_RDSKIP_MINFREE").ok().and_then(|v| v.parse().ok()),
1824    })
1825}
1826
1827impl FrameEncoder {
1828    fn new(cfg: &EncoderConfig) -> Self {
1829        // E20 (inline-execution.md 11.10): this constructor ran FOURTEEN raw
1830        // `std::env::var` reads - an OS query + String alloc + parse each - PER
1831        // SLICE, while every other knob in the tree caches its env read once.
1832        // All fourteen are process-constant by the same contract; `ctor_env()`
1833        // is their one read.
1834        let ke = ctor_env();
1835        let (mb_w, mb_h) = (cfg.mb_width(), cfg.mb_height());
1836        let (cw, ch) = (mb_w * 16, mb_h * 16);
1837        let (ccw, cch) = (cw / 2, ch / 2);
1838        Self {
1839            mb_w,
1840            mb_h,
1841            qp: cfg.qp,
1842            qpc: chroma_qp(cfg.qp),
1843            cur_qp: cfg.qp,
1844            bi_w: (32, 32),
1845            cw,
1846            ccw,
1847            rec_y: AlignedBytes::zeroed(cw * ch),
1848            rec_u: AlignedBytes::zeroed(ccw * cch),
1849            rec_v: AlignedBytes::zeroed(ccw * cch),
1850            nnz_y: vec![0; (mb_w * 4) * (mb_h * 4)],
1851            nnz_c: [vec![0; (mb_w * 2) * (mb_h * 2)], vec![0; (mb_w * 2) * (mb_h * 2)]],
1852            modes_y: vec![2; (mb_w * 4) * (mb_h * 4)],
1853            coded_y: vec![false; (mb_w * 4) * (mb_h * 4)],
1854            mv_y: vec![(0, 0); (mb_w * 4) * (mb_h * 4)],
1855            inter_y: vec![false; (mb_w * 4) * (mb_h * 4)],
1856            ref_idx_y: vec![-1; (mb_w * 4) * (mb_h * 4)],
1857            mv1_y: vec![(0, 0); (mb_w * 4) * (mb_h * 4)],
1858            ref_idx1_y: vec![-1; (mb_w * 4) * (mb_h * 4)],
1859            // All-intra (no inter references) tolerates the larger dead-zone; in
1860            // an I+P stream the IDR is a reference, so keep the standard offset.
1861            idz: if cfg.gop_size <= 1 { 2 } else { 3 },
1862            rdoq_strength: 0.0, // set >0 only in the CABAC slice coders
1863            wp: Vec::new(),
1864            transform_8x8: cfg.transform_8x8,
1865            // sub8x8 stays OPT-IN: the four P_8x8 sub-MVs feed the B-frames'
1866            // spatial-direct predictor, so on DIVERGENT motion (rotation/zoom/mixed)
1867            // it regresses with B-frames (mixed +0.24%, rot +0.42%, zoom +0.40%) —
1868            // a global effect its local RD gate can't see, and no clean dispatch
1869            // signal separates it yet (unlike me_wide's pure-pan coherence gate).
1870            // DEFAULT-ON for Quality (net real-content win; a 6-channel discovery
1871            // harvest proved no cheap gate beats always-on). Quality-only (Fast never
1872            // runs it). env RFF_SUB8X8 (0/1) > cfg.sub_8x8 (Some) > preset default.
1873            sub8x8: ke.sub8x8
1874                .or(cfg.sub_8x8)
1875                .unwrap_or(cfg.preset == crate::config::Preset::Quality),
1876            // me_wide is DEFAULT-ON for the Quality preset. VALIDATED 2026-07-27 on the
1877            // full 20-clip `video-tests` Derf corpus (4-QP BD-rate, PSNR+SSIM, anchor =
1878            // me_wide ON): **mean +0.62% BD-PSNR / +0.69% BD-SSIM**, i.e. turning it off
1879            // costs that much. Biggest wins blue_sky +4.70, bus +4.57, football +1.51,
1880            // park_joy +0.91; synthesized boundary content (smooth fast-pan / rotation /
1881            // zoom) reaches +2.6..+6.7%. The static clips (akiyo, FourPeople) sit at
1882            // exactly 0.00 at ~1.0x — the online payoff gate correctly disables it there.
1883            //
1884            // ⚠ UNFINISHED DISPATCH — the per-clip BD SIGN-FLIPS (+4.70 blue_sky ..
1885            // -1.08 foreman_qcif), and the cost when it fires is 1.0-5.1x. Worst value:
1886            // soccer_4cif 1.70x for +0.00, park_joy 5.08x for +0.91. `me_range` is NOT
1887            // the separating axis — it is a compromise dial (foreman_qcif loses at EVERY
1888            // range 24/16/8/4 = -1.08/-0.55/-0.50/-0.19 while blue_sky wins at every one
1889            // = +4.70/+3.10/+0.73), so shrinking it just trades the win away. The real
1890            // fix is a content signal that predicts the sign; the truth table for it is
1891            // in docs/WHYS-speed-gap.md.
1892            //
1893            // Quality-only (Fast never runs it). Precedence:
1894            // env RFF_ME_WIDE (0/1, for A/B) > cfg.me_wide (Some) > preset default.
1895            sadfp: me_sadfp_mode() == 2,
1896            mv_smooth: false,
1897            do_splits: true,
1898            me_wide: ke.me_wide
1899                .or(cfg.me_wide)
1900                .unwrap_or(cfg.preset == crate::config::Preset::Quality),
1901            me_wide_var: ke.me_wide_var,
1902            me_rescue: ke.me_rescue,
1903            me_wide_coh: ke.me_wide_coh,
1904            me_range: ke.me_range,
1905            me_fast: ke.me_fast,
1906            me_learn: ke.me_learn,
1907            me_payoff_pct: ke.me_payoff_pct,
1908            // U3: `balanced` runs SINGLE-PASS sub-pel. Measured on the 4-QP corpus,
1909            // a single pass captures 95.5–99.4% of the full refinement's BD benefit
1910            // (foreman −38.14 vs −39.94, mobile −49.38 vs −49.66, akiyo −26.10 vs
1911            // −26.43) for 1.03–1.31× less time — a straight Pareto improvement on the
1912            // preset. `RFF_SUBPEL_PAT=0` restores the full walk-to-convergence.
1913            sp_single_pass: cfg.preset == crate::config::Preset::Balanced,
1914            sp_defer: std::cell::Cell::new({
1915                let a = DEFER_SUBPEL.load(std::sync::atomic::Ordering::Relaxed) != 0
1916                    || ke.defer_subpel;
1917                // ONLY the Quality preset runs the multi-shape partition driver. On the
1918                // fast/balanced path there is a single 16×16 candidate, so there is no
1919                // losing shape to skip — deferring there does not save the refinement,
1920                // it DELETES it (measured +91..+145% BD before this guard).
1921                a && cfg.preset == crate::config::Preset::Quality
1922            }),
1923            sp_learn_n: std::cell::Cell::new(0),
1924            sp_ring1: std::cell::Cell::new(0),
1925            sp_total: std::cell::Cell::new(0),
1926            sp_1pass: std::cell::Cell::new(false),
1927            resc_n: std::cell::Cell::new(0),
1928            resc_big: std::cell::Cell::new(0),
1929            resc_off: std::cell::Cell::new(false),
1930            // DEFAULT 0 (intra 8x8 only). Inter 8x8 was the dominant regression in
1931            // the 8x8 default measurement: it turned foreman I+P from +0.28% to
1932            // +1.59% and harbour I+P from +0.12% to +1.62% BD-SSIM, the two largest
1933            // losses in the whole matrix, while its wins were <= 0.44%. `RFF_INTER8=1`
1934            // restores the always-RD arm as the comparator.
1935            t8_pick: cfg.transform_8x8,
1936            i8_margin: i8_margin(),
1937            intra_in_p: false,
1938            inter8x8: ke.inter8,
1939            // ~2 bits per 8x8 luma block (×4) of CAVLC-8x8 overhead the level-aware
1940            // rate still under-charges (no native 8x8 entropy model in CAVLC). Keeps
1941            // the per-MB transform RD from over-picking 8x8 on fine-texture MBs where
1942            // it doesn't compact — content-adaptive: only decisively-favorable MBs win.
1943            inter8_pen: ke.inter8_pen,
1944            // Balanced shares Fast's decision path; only sub-pel differs.
1945            //
1946            // `RFF_SUBPEL=1` forces the sub-pel path ON for a non-Quality preset. This
1947            // was the ONE preset-derived field with no override, which is exactly why
1948            // the fast/quality bisection stalled: the other three (sub8x8, me_wide,
1949            // shape-RD) are all byte-identical when toggled on `fast`, so this field
1950            // carries the whole 29% delta by elimination (docs/WHYS-p-frames.md D5d).
1951            // `== Fast`, NOT `!= Quality`. The old form gave Preset::Balanced
1952            // fast = true, i.e. NO sub-pel -- flatly contradicting Balanced's own doc
1953            // ("Fast's decision path plus sub-pel motion refinement, which Fast
1954            // omits"). Combined with a CLI that never parsed "balanced", the whole
1955            // preset was unreachable, which is why a speed harness once adopted it as
1956            // a deliberate NULL ARM.
1957            //
1958            // GRAIN CAVEAT, measured and NOT yet fixed: sub-pel interpolates, and on
1959            // grain it interpolates NOISE -- Balanced is +13.61% BD-SSIM there against
1960            // Fast (Quality is worse still, +18.79%). A per-frame veto on
1961            // `grain_signature()` was attempted at all three slice coders and did NOT
1962            // take: `fe.fast` is consumed before a per-frame mutation lands, so the
1963            // gate must move to FrameEncoder construction or into the ME itself.
1964            // Removed rather than shipped half-applied. Balanced is OPT-IN, so this is
1965            // a documented trade, not a silent regression.
1966            //
1967            // Sub-pel is the single biggest compression lever in the encoder:
1968            // -30.10 (akiyo) / -44.37 (foreman) / -49.52 (mobile) / -34.15 (harbour)
1969            // BD-SSIM against Fast, for 2.50x Fast's CPU where Quality costs 16.24x.
1970            fast: ke.subpel
1971                .unwrap_or(cfg.preset == crate::config::Preset::Fast || SeqFastPath::get()),
1972            skip_accel_check: cfg.tune_skip_accel_check,
1973            coded_path_v2: cfg.coded_path_v2,
1974            aq_strength: cfg.aq_strength,
1975            tune_lambda_scale: cfg.tune_lambda_scale,
1976            tune_intra_penalty: cfg.tune_intra_penalty,
1977            satd_q: cfg.tune_satd_q,
1978            subpel_force: cfg.tune_subpel || cfg.preset == crate::config::Preset::Balanced,
1979            me_snap: cfg.tune_me_snap,
1980            me_subpel_iter: cfg.tune_me_subpel_iter,
1981            greedy_skip: cfg.tune_greedy_skip,
1982            greedy_min_free: cfg.tune_greedy_skip_min_free.unwrap_or(85),
1983            rd_skip: cfg.tune_rd_skip,
1984            rd_skip_fast_t: cfg.tune_rd_skip_fast_t.unwrap_or(0.0),
1985            // DECOUPLED from the preset by env, because welding it to `cfg.preset` is
1986            // what made the sub-pel veto's acceptance test unpassable (D5i): a knob that
1987            // forces integer-pel could never reproduce `--preset fast`, since Fast also
1988            // moves this threshold 90 -> 60. `RFF_RDSKIP_MINFREE` makes the combination
1989            // expressible so it can be measured instead of inferred.
1990            rd_skip_min_free: ke.rdskip_minfree
1991                .or(cfg.tune_rd_skip_min_free)
1992                .unwrap_or(if cfg.preset == crate::config::Preset::Fast { 60 } else { 90 }),
1993            satd_var_thresh: i64::MAX,
1994            mb_use_satd: false,
1995            nnz_l_cache: [0x80; 25],
1996            nnz_c_cache: [[0x80; 9]; 2],
1997            mb_skip_sad: vec![0; mb_w * mb_h],
1998            mb_was_skip: vec![false; mb_w * mb_h],
1999        }
2000    }
2001
2002    /// openh264 `PredictSadSkip`: the greedy P_Skip threshold = the median of the
2003    /// skip SADs of the *skip* neighbours (left A, top B, top-right C, top-left
2004    /// fallback for C). Non-skip neighbours contribute 0, so with no skip neighbour
2005    /// the threshold is 0 (no greedy skip). This makes the skip self-calibrating —
2006    /// it only spreads where a neighbour already skipped at a comparable SAD.
2007    fn pred_skip_sad(&self, mb_x: usize, mb_y: usize) -> u32 {
2008        let mbw = self.mb_w;
2009        let at = |x: isize, y: isize| -> Option<(bool, u32)> {
2010            if x < 0 || y < 0 || x >= mbw as isize {
2011                return None;
2012            }
2013            let i = y as usize * mbw + x as usize;
2014            Some((self.mb_was_skip[i], self.mb_skip_sad[i]))
2015        };
2016        let a = at(mb_x as isize - 1, mb_y as isize); // left
2017        let b = at(mb_x as isize, mb_y as isize - 1); // top
2018        let c = at(mb_x as isize + 1, mb_y as isize - 1) // top-right
2019            .or_else(|| at(mb_x as isize - 1, mb_y as isize - 1)); // top-left fallback
2020        let sad = |n: Option<(bool, u32)>| n.filter(|&(s, _)| s).map_or(0, |(_, v)| v);
2021        let (sa, sb, sc) = (sad(a), sad(b), sad(c));
2022        // B and C unavailable but A available → A only.
2023        if b.is_none() && c.is_none() && a.is_some() {
2024            return sa;
2025        }
2026        match (
2027            a.is_some_and(|(s, _)| s),
2028            b.is_some_and(|(s, _)| s),
2029            c.is_some_and(|(s, _)| s),
2030        ) {
2031            (true, false, false) => sa,
2032            (false, true, false) => sb,
2033            (false, false, true) => sc,
2034            _ => sb.max(sa.min(sc)).min(sa.max(sc)), // median(sa, sb, sc)
2035        }
2036    }
2037
2038    /// The `mb_qp_delta` for the current macroblock (`qp − cur_qp`) and commits the
2039    /// running QPy — called ONLY where the syntax actually codes a delta (I_16x16
2040    /// always; inter / I_4x4 when `cbp != 0`), so a skip / cbp==0 MB leaves `cur_qp`
2041    /// unchanged and inherits it, exactly as the decoder's `step_qp` does.
2042    fn qp_delta(&mut self) -> i32 {
2043        let d = self.qp as i32 - self.cur_qp as i32;
2044        // Spec §7.4.5: mb_qp_delta shall be in [-26, +25]. Shipped knobs bound
2045        // |d| well inside that (AQ_DQP_MAX + MBTREE_DQP_MAX), but an external
2046        // qpo map could exceed it — an illegal bitstream every strict decoder
2047        // may reject (ours reconstructs it anyway via the §7.4.5 modulo).
2048        debug_assert!((-26..=25).contains(&d), "mb_qp_delta {d} outside [-26,25]");
2049        self.cur_qp = self.qp;
2050        d
2051    }
2052
2053    /// MV-predictor neighbors (left, above, above-right) for the 16×16 partition
2054    /// of macroblock `(mb_x, mb_y)`, read from the per-4×4-block grids.
2055    fn mv_neighbors(&self, mb_x: usize, mb_y: usize) -> [MvNeighbor; 3] {
2056        let w4 = self.mb_w * 4;
2057        let get = |avail: bool, bx: isize, by: isize| {
2058            if avail {
2059                let idx = by as usize * w4 + bx as usize;
2060                MvNeighbor {
2061                    available: true,
2062                    mv: self.mv_y[idx],
2063                    ref_idx: self.ref_idx_y[idx],
2064                }
2065            } else {
2066                MvNeighbor::NONE
2067            }
2068        };
2069        let (bx, by) = (mb_x as isize * 4, mb_y as isize * 4);
2070        let a = get(mb_x > 0, bx - 1, by);
2071        let b = get(mb_y > 0, bx, by - 1);
2072        // C = above-right; if unavailable, fall back to D = above-left.
2073        let c = if mb_y > 0 && mb_x + 1 < self.mb_w {
2074            get(true, bx + 4, by - 1)
2075        } else {
2076            get(mb_x > 0 && mb_y > 0, bx - 1, by - 1)
2077        };
2078        [a, b, c]
2079    }
2080
2081    /// The `P_Skip` motion vector (spec §8.4.1.1). P_Skip always references
2082    /// index 0 (the most recent picture).
2083    fn skip_mv(&self, mb_x: usize, mb_y: usize) -> (i32, i32) {
2084        let [a, b, c] = self.mv_neighbors(mb_x, mb_y);
2085        if !a.available
2086            || !b.available
2087            || (a.ref_idx == 0 && a.mv == (0, 0))
2088            || (b.ref_idx == 0 && b.mv == (0, 0))
2089        {
2090            (0, 0)
2091        } else {
2092            predict_mv(a, b, c, 0)
2093        }
2094    }
2095
2096    /// Records a macroblock's per-4×4-block motion state (`ref` = reference index
2097    /// for inter, ignored for intra where `inter` is false).
2098    fn set_mb_mv(&mut self, mb_x: usize, mb_y: usize, mv: (i32, i32), inter: bool, refi: i32) {
2099        let w4 = self.mb_w * 4;
2100        for dy in 0..4 {
2101            for dx in 0..4 {
2102                let idx = (mb_y * 4 + dy) * w4 + (mb_x * 4 + dx);
2103                self.mv_y[idx] = mv;
2104                self.inter_y[idx] = inter;
2105                self.ref_idx_y[idx] = if inter { refi } else { -1 };
2106            }
2107        }
2108    }
2109
2110    /// Block-level MV-predictor neighbors for a partition whose top-left 4×4
2111    /// block is `(pbx, pby)` and which is `pwb` blocks wide. Availability uses
2112    /// the decoded-block grid, so in-macroblock partitions see earlier ones.
2113    fn mv_neighbors_block(&self, pbx: isize, pby: isize, pwb: isize) -> [MvNeighbor; 3] {
2114        let (w4, h4) = ((self.mb_w * 4) as isize, (self.mb_h * 4) as isize);
2115        let get = |bx: isize, by: isize| -> MvNeighbor {
2116            if bx < 0 || by < 0 || bx >= w4 || by >= h4 || !self.coded_y[(by * w4 + bx) as usize] {
2117                MvNeighbor::NONE
2118            } else {
2119                let idx = (by * w4 + bx) as usize;
2120                MvNeighbor { available: true, mv: self.mv_y[idx], ref_idx: self.ref_idx_y[idx] }
2121            }
2122        };
2123        let a = get(pbx - 1, pby);
2124        let b = get(pbx, pby - 1);
2125        let mut c = get(pbx + pwb, pby - 1);
2126        if !c.available {
2127            c = get(pbx - 1, pby - 1); // D fallback
2128        }
2129        [a, b, c]
2130    }
2131
2132    /// List-aware block MV-predictor neighbors (`list` 0 or 1), for the B-slice
2133    /// per-list `mvd` predictor. Identical geometry to [`Self::mv_neighbors_block`]
2134    /// but reads the List-1 motion grid when `list == 1`, matching the decoder's
2135    /// `mv_neighbors_list`. A neighbor not coded in this list reads `ref_idx = -1`
2136    /// (so `predict_partition_mv` treats it as non-matching, exactly as the decoder).
2137    fn mv_neighbors_block_list(&self, pbx: isize, pby: isize, pwb: isize, list: usize) -> [MvNeighbor; 3] {
2138        let (w4, h4) = ((self.mb_w * 4) as isize, (self.mb_h * 4) as isize);
2139        let (mvg, refg): (&[(i32, i32)], &[i32]) = if list == 0 {
2140            (&self.mv_y, &self.ref_idx_y)
2141        } else {
2142            (&self.mv1_y, &self.ref_idx1_y)
2143        };
2144        let get = |bx: isize, by: isize| -> MvNeighbor {
2145            if bx < 0 || by < 0 || bx >= w4 || by >= h4 || !self.coded_y[(by * w4 + bx) as usize] {
2146                MvNeighbor::NONE
2147            } else {
2148                let idx = (by * w4 + bx) as usize;
2149                MvNeighbor { available: true, mv: mvg[idx], ref_idx: refg[idx] }
2150            }
2151        };
2152        let a = get(pbx - 1, pby);
2153        let b = get(pbx, pby - 1);
2154        let mut c = get(pbx + pwb, pby - 1);
2155        if !c.available {
2156            c = get(pbx - 1, pby - 1); // D fallback
2157        }
2158        [a, b, c]
2159    }
2160
2161    /// SATD cost of a motion-compensated `rw`×`rh` luma region against the source —
2162    /// THE per-candidate ME cost function (Challenge-1 A2 shape: the per-search
2163    /// invariants arrive as parameters instead of being re-derived per candidate).
2164    /// `hp` is the already-resolved plane cache (`None` ⇔ the fast preset, whose
2165    /// SATD path never reads planes), `hr_on` the hoisted `RFF_HPEL_REF` knob,
2166    /// `src_row` the hoisted source slice base. Dispatch order (interior full-pel →
2167    /// in-place plane read → fused avg+SATD → materialize → `mc_luma` fallback) is
2168    /// the historical `mc_satd` order, so the accepted candidate set — and the
2169    /// bitstream — are byte-identical to it.
2170    #[allow(clippy::too_many_arguments)]
2171    #[inline]
2172    fn mc_satd_hp(
2173        &self,
2174        reference: &crate::RefFrame,
2175        hp: Option<&rusty_h264_common::inter::HpelPlanes>,
2176        hr_on: bool,
2177        // `hr_on && RFF_SATD_AVG` (and accel compiled in) — hoisted per search like
2178        // `hr_on`, so the fused-kernel gate costs zero OnceLock loads per candidate.
2179        // Unused (and always false) on non-accel builds.
2180        sa_on: bool,
2181        src_row: &[u8],
2182        lx: usize,
2183        ly: usize,
2184        rw: usize,
2185        rh: usize,
2186        mv: (i32, i32),
2187    ) -> i64 {
2188        #[cfg(not(accel_x86))]
2189        let _ = sa_on;
2190        #[cfg(feature = "profile")]
2191        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(2);
2192        let ch = self.mb_h * 16;
2193        let cw = self.cw;
2194        let (ix0, iy0) = (lx as isize + (mv.0 >> 2) as isize, ly as isize + (mv.1 >> 2) as isize);
2195        let interior_fullpel = mv.0 & 3 == 0
2196            && mv.1 & 3 == 0
2197            && ix0 >= 0
2198            && iy0 >= 0
2199            && ix0 + rw as isize <= cw as isize
2200            && iy0 + rh as isize <= ch as isize;
2201        #[cfg(feature = "profile")]
2202        {
2203            let fullpel = mv.0 & 3 == 0 && mv.1 & 3 == 0;
2204            satdpath::bump(if interior_fullpel { 0 } else if fullpel { 1 } else { 2 });
2205        }
2206        if interior_fullpel {
2207            let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeCost);
2208            let (rx0, ry0) = (ix0 as usize, iy0 as usize);
2209            return satd_px(src_row, cw, &reference.y[ry0 * cw + rx0..], cw, rw, rh);
2210        }
2211        if let Some(hp) = hp {
2212            if hr_on {
2213                if let Some((plane, base, stride)) =
2214                    rusty_h264_common::inter::hpel_ref(hp, lx, ly, rw, rh, mv.0, mv.1)
2215                {
2216                    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeCost);
2217                    return satd_px(src_row, cw, &plane[base..], stride, rw, rh);
2218                }
2219            }
2220            // A3: QUARTER-pel — fuse the two-plane (a+b+1)>>1 average into the
2221            // SATD kernel itself (no 256-byte materialize + reload, no FFI hop).
2222            // `satd_avg` returns the exact `Σ|H·d|` that `satd_px` computes on
2223            // the materialized average, so the cost value — and the bitstream —
2224            // are byte-identical; on non-AVX2 (or a declined size) it returns
2225            // `None` and the old materialize path below runs unchanged.
2226            #[cfg(accel_x86)]
2227            if sa_on {
2228                if let Some((pa, ba, pb, bb, stride)) =
2229                    rusty_h264_common::inter::hpel_qpel_refs(hp, lx, ly, rw, rh, mv.0, mv.1)
2230                {
2231                    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeCost);
2232                    if let Some(v) = rusty_h264_accel::satd_avg(
2233                        src_row, cw, &pa[ba..], &pb[bb..], stride, rw, rh,
2234                    ) {
2235                        return v as i64;
2236                    }
2237                }
2238            }
2239            let mut pred = [0u8; 256];
2240            if rusty_h264_common::inter::hpel_block(hp, lx, ly, rw, rh, mv.0, mv.1, &mut pred) {
2241                return satd_px(src_row, cw, &pred, rw, rw, rh);
2242            }
2243            mc_luma(&reference.y, cw, ch, lx, ly, rw, rh, mv.0, mv.1, &mut pred);
2244            return satd_px(src_row, cw, &pred, rw, rw, rh);
2245        }
2246        let mut pred = [0u8; 256];
2247        mc_luma(&reference.y, cw, ch, lx, ly, rw, rh, mv.0, mv.1, &mut pred);
2248        satd_px(src_row, cw, &pred, rw, rw, rh)
2249    }
2250
2251    /// Track-B B2.1: the SAD twin of `mc_satd_hp` — the SAME dispatch ladder
2252    /// (interior full-pel → in-place plane read → fused avg → materialize →
2253    /// `mc_luma`), with SAD (`psadbw`-class) distortion. `mc_sad` (the fast
2254    /// preset's function) had NONE of the SATD path's accumulated wins, so the
2255    /// first B2 cut measured 61% MORE `mc_luma` fallbacks; this is the parity fix.
2256    /// Every arm reads the same samples the materializing path would, so the SAD
2257    /// value — and therefore the B2-on bitstream — is unchanged by this function.
2258    #[allow(clippy::too_many_arguments)]
2259    #[inline]
2260    fn mc_sad_hp(
2261        &self,
2262        reference: &crate::RefFrame,
2263        hp: Option<&rusty_h264_common::inter::HpelPlanes>,
2264        hr_on: bool,
2265        src_row: &[u8],
2266        lx: usize,
2267        ly: usize,
2268        rw: usize,
2269        rh: usize,
2270        mv: (i32, i32),
2271        _asrc: Option<&[u8; 256]>,
2272    ) -> i64 {
2273        #[cfg(feature = "profile")]
2274        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(2);
2275        let ch = self.mb_h * 16;
2276        let cw = self.cw;
2277        let (ix0, iy0) = (lx as isize + (mv.0 >> 2) as isize, ly as isize + (mv.1 >> 2) as isize);
2278        let interior_fullpel = mv.0 & 3 == 0
2279            && mv.1 & 3 == 0
2280            && ix0 >= 0
2281            && iy0 >= 0
2282            && ix0 + rw as isize <= cw as isize
2283            && iy0 + rh as isize <= ch as isize;
2284        if interior_fullpel {
2285            let (rx0, ry0) = (ix0 as usize, iy0 as usize);
2286            #[cfg(accel)]
2287            if rw == 16 && rh == 16 {
2288                if let Some(src) = _asrc {
2289                    return rusty_h264_accel::sad_16x16(src, 16, &reference.y[ry0 * cw + rx0..], cw)
2290                        as i64;
2291                }
2292            }
2293            return sad_strided(src_row, cw, &reference.y[ry0 * cw + rx0..], cw, rw, rh);
2294        }
2295        if let Some(hp) = hp {
2296            if hr_on {
2297                // Single-plane phases (h/v/c half-pel AND edge full-pel via the
2298                // padded `f` plane — the E-3 move, which `mc_sad` never had).
2299                if let Some((plane, base, stride)) =
2300                    rusty_h264_common::inter::hpel_ref(hp, lx, ly, rw, rh, mv.0, mv.1)
2301                {
2302                    return sad_strided(src_row, cw, &plane[base..], stride, rw, rh);
2303                }
2304                // Quarter-pel: fused (a+b+1)>>1 + SAD, no materialize.
2305                if let Some((pa, ba, pb, bb, stride)) =
2306                    rusty_h264_common::inter::hpel_qpel_refs(hp, lx, ly, rw, rh, mv.0, mv.1)
2307                {
2308                    return sad_avg_strided(src_row, cw, &pa[ba..], &pb[bb..], stride, rw, rh);
2309                }
2310            }
2311            let mut pred = [0u8; 256];
2312            if rusty_h264_common::inter::hpel_block(hp, lx, ly, rw, rh, mv.0, mv.1, &mut pred) {
2313                return sad_strided(src_row, cw, &pred, rw, rw, rh);
2314            }
2315            mc_luma(&reference.y, cw, ch, lx, ly, rw, rh, mv.0, mv.1, &mut pred);
2316            return sad_strided(src_row, cw, &pred, rw, rw, rh);
2317        }
2318        let mut pred = [0u8; 256];
2319        mc_luma(&reference.y, cw, ch, lx, ly, rw, rh, mv.0, mv.1, &mut pred);
2320        sad_strided(src_row, cw, &pred, rw, rw, rh)
2321    }
2322
2323    /// SAD (sum of absolute differences) of a motion-compensated `rw`×`rh` luma
2324    /// region against the source — the **fast** preset's motion-search cost.
2325    ///
2326    /// SAD is far cheaper than SATD (no Hadamard transform), and the inner loop is
2327    /// written as `Σ a.abs_diff(b)` over `u8` slices, the exact pattern LLVM
2328    /// auto-vectorizes to the `psadbw` SAD instruction — the same instruction
2329    /// x264's hand-written assembly uses, but reached without any `unsafe`. (x264's
2330    /// fast presets use SAD for the full-pel search for precisely this reason.)
2331    #[allow(clippy::too_many_arguments)]
2332    fn mc_sad(
2333        &self,
2334        reference: &crate::RefFrame,
2335        sy: &[u8],
2336        lx: usize,
2337        ly: usize,
2338        rw: usize,
2339        rh: usize,
2340        mv: (i32, i32),
2341        // 16-aligned source MB (built once per search) for the asm SAD; `None`
2342        // (and unused) on the scalar build.
2343        _asrc: Option<&[u8; 256]>,
2344    ) -> i64 {
2345        // Descent E depth-6: tag WHO is calling mc_luma. The search's edge fallback and
2346        // reconstruction land in the same `inter-mc` bucket; pricing a recon-side lever
2347        // against the merged total is pricing the wrong population.
2348        #[cfg(feature = "profile")]
2349        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(2);
2350        let ch = self.mb_h * 16;
2351        let cw = self.cw;
2352        let (ix0, iy0) = (lx as isize + (mv.0 >> 2) as isize, ly as isize + (mv.1 >> 2) as isize);
2353        let interior_fullpel = mv.0 & 3 == 0
2354            && mv.1 & 3 == 0
2355            && ix0 >= 0
2356            && iy0 >= 0
2357            && ix0 + rw as isize <= cw as isize
2358            && iy0 + rh as isize <= ch as isize;
2359        // Full-pel interior 16×16: openh264's `psadbw` SAD of the aligned source vs
2360        // the (movdqu) reference block. SAD is exact, so this is byte-identical to the
2361        // scalar path — a pure ME speedup (~2.4× the kernel).
2362        #[cfg(accel)]
2363        if interior_fullpel && rw == 16 && rh == 16 {
2364            if let Some(src) = _asrc {
2365                let (rx0, ry0) = (ix0 as usize, iy0 as usize);
2366                return rusty_h264_accel::sad_16x16(src, 16, &reference.y[ry0 * cw + rx0..], cw)
2367                    as i64;
2368            }
2369        }
2370        let mut sad = 0u32;
2371        if interior_fullpel {
2372            // Direct from the reference (a copy at full-pel) — no interpolation.
2373            let (rx0, ry0) = (ix0 as usize, iy0 as usize);
2374            let refy = &reference.y;
2375            for dy in 0..rh {
2376                let s = &sy[(ly + dy) * cw + lx..][..rw];
2377                let r = &refy[(ry0 + dy) * cw + rx0..][..rw];
2378                sad += s.iter().zip(r).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
2379            }
2380        } else {
2381            let mut pred = [0u8; 256];
2382            // Same plane-cache read (and same preset gate) as `mc_satd`.
2383            let from_planes = !self.fast
2384                && rusty_h264_common::inter::hpel_block(
2385                    reference.hpel(cw, ch),
2386                    lx,
2387                    ly,
2388                    rw,
2389                    rh,
2390                    mv.0,
2391                    mv.1,
2392                    &mut pred,
2393                );
2394            if !from_planes {
2395                mc_luma(&reference.y, cw, ch, lx, ly, rw, rh, mv.0, mv.1, &mut pred);
2396            }
2397            for dy in 0..rh {
2398                let s = &sy[(ly + dy) * cw + lx..][..rw];
2399                let p = &pred[dy * rw..][..rw];
2400                sad += s.iter().zip(p).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
2401            }
2402        }
2403        sad as i64
2404    }
2405
2406    /// `bi_dist` for an arbitrary rect — the B 16×8 / 8×16 partition search needs
2407    /// the bi-blend distortion of a half, not of the whole macroblock. Same blend
2408    /// and same SAD/SATD choice as the 16×16 form.
2409    #[allow(clippy::too_many_arguments)]
2410    fn bi_dist_rect(
2411        &self,
2412        l0: &crate::RefFrame,
2413        l1: &crate::RefFrame,
2414        sy: &[u8],
2415        lx: usize,
2416        ly: usize,
2417        rw: usize,
2418        rh: usize,
2419        mv0: (i32, i32),
2420        mv1: (i32, i32),
2421    ) -> i64 {
2422        let ch = self.mb_h * 16;
2423        let (mut a, mut b) = ([0u8; 256], [0u8; 256]);
2424        mc_luma(&l0.y, self.cw, ch, lx, ly, rw, rh, mv0.0, mv0.1, &mut a);
2425        mc_luma(&l1.y, self.cw, ch, lx, ly, rw, rh, mv1.0, mv1.1, &mut b);
2426        let n = rw * rh;
2427        let mut avg = [0u8; 256];
2428        for i in 0..n {
2429            avg[i] = bi_blend(a[i] as i32, b[i] as i32, self.bi_w);
2430        }
2431        if self.fast && !self.mb_use_satd {
2432            let mut sad = 0u32;
2433            for dy in 0..rh {
2434                let s = &sy[(ly + dy) * self.cw + lx..][..rw];
2435                let p = &avg[dy * rw..][..rw];
2436                sad += s.iter().zip(p).map(|(&x, &y)| x.abs_diff(y) as u32).sum::<u32>();
2437            }
2438            sad as i64
2439        } else {
2440            satd_px(&sy[ly * self.cw + lx..], self.cw, &avg, rw, rw, rh)
2441        }
2442    }
2443
2444    /// Luma distortion of a `B_Bi` 16×16 prediction: motion-compensate `l0`/`l1`,
2445    /// average `(p+q+1)>>1` (the decoder's `b_mc` blend at `weighted_bipred_idc=0`),
2446    /// and score vs the source with the SAME metric the per-list searches used —
2447    /// SAD on the fast path, SATD when this MB is SATD-routed — so `J_bi` compares
2448    /// directly against `J0`/`J1`.
2449    fn bi_dist(
2450        &self,
2451        l0: &crate::RefFrame,
2452        l1: &crate::RefFrame,
2453        sy: &[u8],
2454        lx: usize,
2455        ly: usize,
2456        mv0: (i32, i32),
2457        mv1: (i32, i32),
2458    ) -> i64 {
2459        // Descent E/F: identify this mc_luma population by call site.
2460        #[cfg(feature = "profile")]
2461        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(4);
2462        let ch = self.mb_h * 16;
2463        let (mut a, mut b) = ([0u8; 256], [0u8; 256]);
2464        mc_luma(&l0.y, self.cw, ch, lx, ly, 16, 16, mv0.0, mv0.1, &mut a);
2465        mc_luma(&l1.y, self.cw, ch, lx, ly, 16, 16, mv1.0, mv1.1, &mut b);
2466        let mut avg = [0u8; 256];
2467        for i in 0..256 {
2468            avg[i] = bi_blend(a[i] as i32, b[i] as i32, self.bi_w);
2469        }
2470        if self.fast && !self.mb_use_satd {
2471            let mut sad = 0u32;
2472            for dy in 0..16 {
2473                let s = &sy[(ly + dy) * self.cw + lx..][..16];
2474                let p = &avg[dy * 16..][..16];
2475                sad += s.iter().zip(p).map(|(&x, &y)| x.abs_diff(y) as u32).sum::<u32>();
2476            }
2477            sad as i64
2478        } else {
2479            satd_px(&sy[ly * self.cw + lx..], self.cw, &avg, 16, 16, 16)
2480        }
2481    }
2482
2483    /// Distortion of a pre-formed 16×16 luma prediction vs the source (SAD on the
2484    /// fast path, SATD when SATD-routed) — the mode-decision cost for `B_Direct`,
2485    /// on the same scale as the per-list search J so they compare directly.
2486    fn pred_dist(&self, sy: &[u8], lx: usize, ly: usize, pred: &[u8; 256]) -> i64 {
2487        if self.fast && !self.mb_use_satd {
2488            let mut sad = 0u32;
2489            for dy in 0..16 {
2490                let s = &sy[(ly + dy) * self.cw + lx..][..16];
2491                let p = &pred[dy * 16..][..16];
2492                sad += s.iter().zip(p).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
2493            }
2494            sad as i64
2495        } else {
2496            satd_px(&sy[ly * self.cw + lx..], self.cw, pred, 16, 16, 16)
2497        }
2498    }
2499
2500    /// `colZeroFlag` for absolute 4×4 block `(bx, by)` (spec §8.4.1.2.2): true when
2501    /// the co-located picture `RefPicList1[0]` (`l1`) is short-term (always, here —
2502    /// we use no long-term refs) and its co-located block uses List-0 reference 0
2503    /// with a near-zero (|·| ≤ 1) motion vector. Must match the decoder's `col_zero`.
2504    fn col_zero(&self, l1: &crate::RefFrame, bx: usize, by: usize) -> bool {
2505        if l1.w4 == 0 {
2506            return false;
2507        }
2508        let idx = by * l1.w4 + bx;
2509        if idx >= l1.ref_idx.len() {
2510            return false;
2511        }
2512        // b-pyramid: the co-located picture can be a REFERENCE B, whose blocks
2513        // may be L1-only — `predFlagL0Col == 0` reads List 1 instead (spec
2514        // §8.4.1.2.2). This is the SAME defect the decoder root-caused on real
2515        // x264 pyramid streams; the two derivations must mirror or the
2516        // encoder's spatial-direct picks drift from what the decoder computes.
2517        // P/I co-located pictures have empty `ref_idx1` and never take this arm.
2518        if l1.ref_idx[idx] < 0 {
2519            if let (Some(&r1), Some(&m1)) = (l1.ref_idx1.get(idx), l1.mv1.get(idx)) {
2520                return r1 == 0 && m1.0.abs() <= 1 && m1.1.abs() <= 1;
2521            }
2522            return false;
2523        }
2524        l1.ref_idx[idx] == 0 && l1.mv[idx].0.abs() <= 1 && l1.mv[idx].1.abs() <= 1
2525    }
2526
2527    /// Bi-predictive MC of one small region into `pred_y`/`c_pred` at MB-relative
2528    /// offset `(dx, dy)` — the per-4×4 primitive the spatial-direct derivation uses.
2529    /// Mirrors the decoder's `b_mc` (average `(p+q+1)>>1` for bi, copy for uni).
2530    #[allow(clippy::too_many_arguments)]
2531    fn b_mc_block(
2532        &self,
2533        l0: &crate::RefFrame,
2534        l1: &crate::RefFrame,
2535        mb_x: usize,
2536        mb_y: usize,
2537        dx: usize,
2538        dy: usize,
2539        refi0: i32,
2540        m0: (i32, i32),
2541        refi1: i32,
2542        m1: (i32, i32),
2543        pred_y: &mut [u8; 256],
2544        c_pred: &mut [[u8; 64]; 2],
2545    ) {
2546        // Descent E/F: identify this mc_luma population by call site.
2547        #[cfg(feature = "profile")]
2548        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(4);
2549        let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
2550        let (px, py) = (mb_x * 16 + dx, mb_y * 16 + dy);
2551        let (mut a, mut b) = ([0u8; 16], [0u8; 16]);
2552        // 4-wide luma exists ONLY here: P partitions bottom out at 8×8, so B-frame
2553        // spatial-direct is the encoder's only 4×4 MC. With B-frames on it is ~8% of
2554        // all MC calls and HALF of all sub-pel ones — and `luma_h`/`luma_v` dispatch
2555        // to asm only at width 16/8, so 4-wide otherwise runs the scalar 6-tap.
2556        // Serving it from the cached half-pel planes (bit-identical, and they are
2557        // already built for this reference by the motion search) is strictly better
2558        // than adding a 4-wide asm kernel.
2559        let mc4 = |r: &crate::RefFrame, mv: (i32, i32), out: &mut [u8; 16]| {
2560            if !self.fast
2561                && bdirect_planes_enabled()
2562                && rusty_h264_common::inter::hpel_block(
2563                    r.hpel(self.cw, ch), px, py, 4, 4, mv.0, mv.1, out,
2564                )
2565            {
2566                return;
2567            }
2568            mc_luma(&r.y, self.cw, ch, px, py, 4, 4, mv.0, mv.1, out);
2569        };
2570        if refi0 >= 0 {
2571            mc4(l0, m0, &mut a);
2572        }
2573        if refi1 >= 0 {
2574            mc4(l1, m1, &mut b);
2575        }
2576        for yy in 0..4 {
2577            for xx in 0..4 {
2578                let i = yy * 4 + xx;
2579                let v = match (refi0 >= 0, refi1 >= 0) {
2580                    (true, true) => bi_blend(a[i] as i32, b[i] as i32, self.bi_w),
2581                    (true, false) => a[i],
2582                    _ => b[i],
2583                };
2584                pred_y[(dy + yy) * 16 + (dx + xx)] = v;
2585            }
2586        }
2587        // Chroma: the co-located 2×2 block at half resolution.
2588        let (cpx, cpy) = (mb_x * 8 + dx / 2, mb_y * 8 + dy / 2);
2589        for c in 0..2 {
2590            let (r0, r1) = if c == 0 { (&l0.u, &l1.u) } else { (&l0.v, &l1.v) };
2591            let (mut ca, mut cb) = ([0u8; 4], [0u8; 4]);
2592            if refi0 >= 0 {
2593                mc_chroma(r0, self.ccw, cch, cpx, cpy, 2, 2, m0.0, m0.1, &mut ca);
2594            }
2595            if refi1 >= 0 {
2596                mc_chroma(r1, self.ccw, cch, cpx, cpy, 2, 2, m1.0, m1.1, &mut cb);
2597            }
2598            for yy in 0..2 {
2599                for xx in 0..2 {
2600                    let i = yy * 2 + xx;
2601                    let v = match (refi0 >= 0, refi1 >= 0) {
2602                        (true, true) => bi_blend(ca[i] as i32, cb[i] as i32, self.bi_w),
2603                        (true, false) => ca[i],
2604                        _ => cb[i],
2605                    };
2606                    c_pred[c][(dy / 2 + yy) * 8 + (dx / 2 + xx)] = v;
2607                }
2608            }
2609        }
2610    }
2611
2612    /// Spatial-direct (`direct_spatial_mv_pred_flag == 1`) prediction for a 16×16 B
2613    /// macroblock — the shared basis of `B_Skip` and `B_Direct_16x16`. Returns the
2614    /// prediction and the per-4×4 `(refIdxL0, mvL0, refIdxL1, mvL1)` motion the
2615    /// decoder's `decode_b_direct` derives (so the caller commits identical motion).
2616    fn b_direct(
2617        &self,
2618        l0: &crate::RefFrame,
2619        l1: &crate::RefFrame,
2620        mb_x: usize,
2621        mb_y: usize,
2622    ) -> ([u8; 256], [[u8; 64]; 2], [(i32, (i32, i32), i32, (i32, i32)); 16]) {
2623        let (nbx, nby) = ((mb_x * 4) as isize, (mb_y * 4) as isize);
2624        let n0 = self.mv_neighbors_block_list(nbx, nby, 4, 0);
2625        let n1 = self.mv_neighbors_block_list(nbx, nby, 4, 1);
2626        let min_pos = |a: i32, b: i32| if a < 0 { b } else if b < 0 { a } else { a.min(b) };
2627        let rid = |n: &[MvNeighbor; 3]| min_pos(min_pos(n[0].ref_idx, n[1].ref_idx), n[2].ref_idx);
2628        let (mut refi0, mut refi1) = (rid(&n0), rid(&n1));
2629        let direct_zero = refi0 < 0 && refi1 < 0;
2630        if direct_zero {
2631            refi0 = 0;
2632            refi1 = 0;
2633        }
2634        let mv0 = if refi0 >= 0 && !direct_zero { predict_mv(n0[0], n0[1], n0[2], refi0) } else { (0, 0) };
2635        let mv1 = if refi1 >= 0 && !direct_zero { predict_mv(n1[0], n1[1], n1[2], refi1) } else { (0, 0) };
2636        let mut pred_y = [0u8; 256];
2637        let mut c_pred = [[0u8; 64]; 2];
2638        let mut motion = [(0i32, (0i32, 0i32), 0i32, (0i32, 0i32)); 16];
2639        for sby in 0..4 {
2640            for sbx in 0..4 {
2641                // direct_8x8_inference_flag = 1 (SPS): every 4×4 in an 8×8 takes
2642                // the 8×8's OUTER-CORNER co-located block — (0,0)(3,0)(0,3)(3,3),
2643                // the decoder's `col_block` mapping, spec 8.4.1.2.1.
2644                let (czx, czy) = ((sbx / 2) * 3, (sby / 2) * 3);
2645                let cz = !direct_zero && self.col_zero(l1, mb_x * 4 + czx, mb_y * 4 + czy);
2646                let m0 = if refi0 == 0 && cz { (0, 0) } else { mv0 };
2647                let m1 = if refi1 == 0 && cz { (0, 0) } else { mv1 };
2648                motion[sby * 4 + sbx] = (refi0, m0, refi1, m1);
2649                self.b_mc_block(l0, l1, mb_x, mb_y, sbx * 4, sby * 4, refi0, m0, refi1, m1, &mut pred_y, &mut c_pred);
2650            }
2651        }
2652        (pred_y, c_pred, motion)
2653    }
2654
2655    /// Commits a spatial-direct MB's per-4×4 motion into the List-0/List-1 grids so
2656    /// later MBs' neighbor predictors see it (mirrors the decoder's `b_set_motion`).
2657    fn commit_direct_motion(&mut self, mb_x: usize, mb_y: usize, motion: &[(i32, (i32, i32), i32, (i32, i32)); 16]) {
2658        let w4 = self.mb_w * 4;
2659        for sby in 0..4 {
2660            for sbx in 0..4 {
2661                let (refi0, m0, refi1, m1) = motion[sby * 4 + sbx];
2662                let idx = (mb_y * 4 + sby) * w4 + (mb_x * 4 + sbx);
2663                self.inter_y[idx] = true;
2664                self.coded_y[idx] = true;
2665                self.mv_y[idx] = m0;
2666                self.ref_idx_y[idx] = refi0;
2667                self.mv1_y[idx] = m1;
2668                self.ref_idx1_y[idx] = refi1;
2669            }
2670        }
2671    }
2672
2673    /// Rate-aware motion search for a luma region: full-pel diamond + half/
2674    /// quarter-pel refinement minimizing `J = SATD + λ·bits(mvd)`, where the
2675    /// motion cost is measured against `predictors[0]` (the MV predictor the
2676    /// `mvd` will actually be coded against). The search is seeded from every
2677    /// entry in `predictors` plus `(0,0)`. Returns the best MV and its `J`.
2678    ///
2679    /// The rate term is only a *search heuristic* — whatever MV it picks is still
2680    /// coded as a correct `mvd`, so this never affects decodability.
2681    #[allow(clippy::too_many_arguments)]
2682    /// ME ORACLE PROBE (`RFF_ME_ORACLE=1`): does our search actually FIND the best
2683    /// motion vector available to it? Accumulates our chosen cost against an
2684    /// exhaustive +-24 full-pel search refined by the identical sub-pel pass, so a
2685    /// gap is attributable to the SEARCH, not to the cost function or precision.
2686    /// [n, sum(our cost), sum(oracle cost), blocks where oracle won, cost() evals]
2687    fn motion_search(
2688        &self,
2689        reference: &crate::RefFrame,
2690        sy: &[u8],
2691        lx: usize,
2692        ly: usize,
2693        rw: usize,
2694        rh: usize,
2695        predictors: &[(i32, i32)],
2696        lambda_me: f64,
2697        // Some(mv) => skip the full-pel search entirely and refine THIS vector. The
2698        // starting COST is recomputed here rather than passed in, so the baseline the
2699        // refinement must beat is priced by the same closure as every candidate.
2700        start: Option<(i32, i32)>,
2701    ) -> ((i32, i32), i64) {
2702        // Bit length of `se(d)` (Exp-Golomb), i.e. what an `mvd` component costs.
2703        // Branchless closed form of the old `while n > 1 { n >>= 1; len += 2 }` loop:
2704        // that loop yields `len = 1 + 2·floor(log2(codenum+1))`, and for x ≥ 1
2705        // `floor(log2(x)) == 31 - x.leading_zeros()`. Removes a data-dependent branch
2706        // from the innermost ME cost — bit-identical (verified over the d range).
2707        let mvk = mv_cost_kind(self.mv_smooth);
2708        // Law 5: resolve the cost TABLE once per search. `get_or_init` on an
2709        // initialized OnceLock is still an acquire load + branch, and `mvbits`
2710        // is the innermost ME cost — it ran per CANDIDATE per COMPONENT. The
2711        // empty slice for the step model costs nothing and initializes nothing.
2712        let mvtab: &[u16] = match mvk {
2713            1 => MV_COST_TAB.get_or_init(build_mv_cost),
2714            2 => MV_TRUE_BIASED.get_or_init(build_true_biased),
2715            _ => &[],
2716        };
2717        let mvbits = |d: i32| -> u32 {
2718            // H-23: the ME rate model. `RFF_MVCOST=1` swaps the Exp-Golomb STEP
2719            // function for x264's smooth curve `2·log2(|d|+1) + 0.718 + (d!=0)`.
2720            // The step function is FLAT inside a power-of-two bracket — it prices
2721            // d=4 and d=7 identically, so the search takes the far end of a
2722            // bracket for free, inflating |mvd| (and with it the sign+prefix bits
2723            // the accountant found are ~14% of the payload). λ cannot fix this:
2724            // scaling a flat region leaves it flat. Table is in WHOLE bits to keep
2725            // the caller's integer arithmetic; ×4 internally then rounded, so the
2726            // curve's ordering survives quantization.
2727            match mvk {
2728                1 | 2 => {
2729                    let a = d.unsigned_abs().min(4095) as usize;
2730                    mvtab[a] as u32
2731                }
2732                _ => {
2733                    let codenum = if d > 0 { (2 * d - 1) as u32 } else { (-2 * d) as u32 };
2734                    1 + 2 * (31 - (codenum + 1).leading_zeros())
2735                }
2736            }
2737        };
2738        let center = predictors[0];
2739        let probe = me_oracle_on();
2740        // Track-B B2: the full-pel phase (seeds/snap/diamond) prices candidates in
2741        // the SAD domain; the winner is repriced in SATD before rescue/sub-pel.
2742        // Refine-only searches have no full-pel phase, so B2 does not apply there.
2743        // `self.sadfp` is force-mode at construction or the per-frame `b2_mgain`
2744        // dispatcher's routing (mode 1).
2745        let sadfp = !self.fast && start.is_none() && self.sadfp;
2746        // Build the 16-aligned source MB ONCE per search for the asm SAD path (fast
2747        // preset — and B2's SAD full-pel phase — full 16×16). Amortized over every
2748        // candidate's SAD; the reference block stays unaligned (movdqu). Scalar
2749        // build does no copy.
2750        #[cfg(accel)]
2751        let asrc_buf = if (self.fast || sadfp) && rw == 16 && rh == 16 {
2752            let mut a = AlignedMb([0u8; 256]);
2753            for dy in 0..16 {
2754                a.0[dy * 16..dy * 16 + 16].copy_from_slice(&sy[(ly + dy) * self.cw + lx..][..16]);
2755            }
2756            Some(a)
2757        } else {
2758            None
2759        };
2760        #[cfg(accel)]
2761        let asrc: Option<&[u8; 256]> = asrc_buf.as_ref().map(|a| &a.0);
2762        #[cfg(not(accel))]
2763        let asrc: Option<&[u8; 256]> = None;
2764        // Challenge-1 A2: hoist the SATD path's per-search invariants OUT of the
2765        // per-candidate closure. `mc_satd` re-derived, for EVERY candidate: the
2766        // plane-cache OnceLock (an acquire load + branch, twice on the quarter-pel
2767        // arm), the `RFF_HPEL_REF` OnceLock, and the source-row slice base (a bounds
2768        // check). All are constant across the ~20-50 evaluations of one search.
2769        // `mc_satd_hp` is the same dispatch with those values passed in — the same
2770        // arms in the same order, so the accepted candidate set is byte-identical.
2771        let use_sad = self.fast && !self.mb_use_satd;
2772        let cw = self.cw;
2773        // Every non-fast search sub-pel-refines at the end, so the planes are built
2774        // for any reference a search touches — hoisting the get_or_init here does not
2775        // build planes a lazy path would have avoided.
2776        let hp: Option<&rusty_h264_common::inter::HpelPlanes> =
2777            if !self.fast { Some(reference.hpel(cw, self.mb_h * 16)) } else { None };
2778        let hr_on = hpel_ref_enabled();
2779        // A3 gate, hoisted with the rest (`RFF_HPEL_REF=0` restores the FULL pre-C/A3
2780        // copy path, so the fused kernel rides the same master anchor).
2781        let sa_on = cfg!(accel_x86) && hr_on && satd_avg_enabled();
2782        let src_row = &sy[ly * cw + lx..];
2783        // H-14 R3: the MeCtx fast evaluator — ONE geometry validation per search,
2784        // then per-eval integer bounds + direct kernel (collects the measured
2785        // ~23 ns/eval dispatch chain). Values are exactly the safe path's, so a
2786        // candidate served here cannot change the bitstream; out-of-window
2787        // candidates fall back to `mc_satd_hp` (equal values there too).
2788        #[cfg(accel_x86)]
2789        let mectx = if !use_sad && mectx_enabled() {
2790            hp.and_then(|p| {
2791                rusty_h264_accel::MeCtx::new(
2792                    src_row, cw, &p.f, &p.h, &p.v, &p.c, p.stride, p.pad, p.pw, p.ph,
2793                    lx, ly, rw, rh,
2794                )
2795            })
2796        } else {
2797            None
2798        };
2799        let cost = |mv: (i32, i32)| -> i64 {
2800            let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
2801            // The smooth table carries 4× resolution; fold that into λ so the
2802            // rate/distortion balance is unchanged and only the SHAPE differs.
2803            let lam_r = if mvk != 0 { lambda_me * 0.25 } else { lambda_me };
2804            // Fast preset: SAD (psadbw — asm kernel on `--features asm`, else auto-vec)
2805            // — far cheaper than SATD, the single biggest reason x264 fast out-runs us.
2806            let dist = if use_sad {
2807                self.mc_sad(reference, sy, lx, ly, rw, rh, mv, asrc)
2808            } else {
2809                #[cfg(accel_x86)]
2810                {
2811                    match mectx.as_ref().and_then(|c| c.eval(mv.0, mv.1)) {
2812                        Some(d) => d as i64,
2813                        None => {
2814                            self.mc_satd_hp(reference, hp, hr_on, sa_on, src_row, lx, ly, rw, rh, mv)
2815                        }
2816                    }
2817                }
2818                #[cfg(not(accel_x86))]
2819                {
2820                    self.mc_satd_hp(reference, hp, hr_on, sa_on, src_row, lx, ly, rw, rh, mv)
2821                }
2822            };
2823            dist + (lam_r * rate as f64) as i64
2824        };
2825        // B2's full-pel-phase cost: SAD distortion, λ scaled to the SAD domain
2826        // (`RFF_ME_SADL`, hoisted). Falls through to `cost` (SATD) whenever B2 is
2827        // off, so every pre-B2 path is untouched.
2828        let lam_fp = lambda_me * if sadfp { me_sadfp_lambda() } else { 1.0 };
2829        let cost_fp = |mv: (i32, i32)| -> i64 {
2830            if !sadfp {
2831                return cost(mv);
2832            }
2833            let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
2834            self.mc_sad_hp(reference, hp, hr_on, src_row, lx, ly, rw, rh, mv, asrc)
2835                + (lam_fp * rate as f64) as i64
2836        };
2837        // Seed from (0,0) and each predictor; keep the cheapest.
2838        let refine_only = start.is_some();
2839        let (mut best, mut best_c) = match start {
2840            Some(mv) => (mv, cost(mv)),
2841            None => {
2842                let mut b = (0, 0);
2843                let mut bc = cost_fp(b);
2844                for &p in predictors {
2845                    let pc = cost_fp(p);
2846                    if pc < bc {
2847                        bc = pc;
2848                        b = p;
2849                    }
2850                }
2851                (b, bc)
2852            }
2853        };
2854        // SNAP THE DIAMOND CENTRE TO INTEGER-PEL. The diamond below steps by whole
2855        // pels, so a fractional centre makes EVERY candidate fractional and forces
2856        // all of them through `mc_luma`'s 6-tap filter — measured at 84-90% of all
2857        // SATD evaluations. Snapping puts the whole full-pel phase on the direct
2858        // (no-interpolation) SATD path. The pre-snap seed is kept and re-compared
2859        // after refinement, so this can only change WHERE we search, never make the
2860        // returned vector worse than the seed we started from.
2861        let (seed_mv, mut seed_c) = (best, best_c);
2862        if !refine_only && self.me_snap && (best.0 & 3 != 0 || best.1 & 3 != 0) {
2863            let snapped = ((best.0 + 2).div_euclid(4) * 4, (best.1 + 2).div_euclid(4) * 4);
2864            best_c = cost_fp(snapped);
2865            best = snapped;
2866        }
2867        // Coarse-to-fine full-pel search: a 4-point diamond walked at each step
2868        // size from 16 px down to 1 px (steps in quarter-pel units: 64,32,…,4).
2869        // The larger initial steps reach fast motion the predictor missed; the
2870        // diamond stays orthogonal (no diagonals) — diagonal probes were found to
2871        // chase equally-good far matches on ambiguous motion, wrecking MV-field
2872        // coherence and the neighbor predictors.
2873        // The fast preset trusts the neighbour MV predictor and refines locally
2874        // (one coarse reach + fine), like x264's `me=dia`; quality sweeps the full
2875        // coarse-to-fine range. Each step's diamond still walks until no
2876        // improvement, so even fast reaches far motion — just in smaller hops.
2877        // Descent A: the coarse rungs are ~76-80% of full-pel evals at a 0.05-1.0% hit
2878        // rate (near-equal eval counts per rung = the walk almost never walks, so each
2879        // rung is a flat ~4-eval toll). RFF_DIA_LADDER selects which rungs to pay for.
2880        let mut ladder = [0i32; 5];
2881        let mut nladder = 0usize;
2882        let steps: &[i32] = if self.fast {
2883            &[16, 4]
2884        } else {
2885            // Shape-aware: sub-8x8 partitions inherit a converged parent MV.
2886            let m = if rw < 8 || rh < 8 { dia_sub_mask() } else { dia_mask() };
2887            for (i, r) in DIA_RUNGS.iter().enumerate() {
2888                if m & (1 << i) != 0 {
2889                    ladder[nladder] = *r;
2890                    nladder += 1;
2891                }
2892            }
2893            &ladder[..nladder]
2894        };
2895        let _gd = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeDiamond);
2896        // FC: batch a fixed-centre diamond pass through the x4 kernels when every
2897        // candidate is an interior full-pel 16×16 read — one source band covers all
2898        // four candidates. Applies to BOTH cost domains (`sad_16x16_x4` on
2899        // SAD-routed frames, `satd_16x16_x4` otherwise); the fast preset keeps its
2900        // own untouched path. Argmin-of-4 replaces the first-improver cascade —
2901        // measured BD-POSITIVE on the SAD domain (bus −1.71→−2.61) and gated on the
2902        // corpus for the SATD domain the same way. `RFF_ME_FC=0` restores cascade.
2903        #[cfg_attr(not(accel_x86), allow(unused_variables))] // consumed by accel_x86-only blocks
2904        let fc = !self.fast && cfg!(accel_x86) && me_fc_enabled()
2905            && matches!((rw, rh), (16, 16) | (16, 8) | (8, 16) | (8, 8));
2906        #[cfg_attr(not(accel_x86), allow(unused_variables))] // consumed by accel_x86-only blocks
2907        let ch_px = self.mb_h as isize * 16;
2908        for (_si, &step) in steps.iter().enumerate() {
2909            if refine_only {
2910                break;
2911            }
2912            loop {
2913                #[cfg(accel_x86)]
2914                if fc && best.0 & 3 == 0 && best.1 & 3 == 0 {
2915                    // All four candidates full-pel; interior iff the ±step box is.
2916                    let s = (step >> 2) as isize;
2917                    let (bx, by) = (lx as isize + (best.0 >> 2) as isize, ly as isize + (best.1 >> 2) as isize);
2918                    if bx - s >= 0 && by - s >= 0 && bx + s + rw as isize <= cw as isize && by + s + rh as isize <= ch_px {
2919                        let offs = [
2920                            (by * cw as isize + bx + s) as usize,
2921                            (by * cw as isize + bx - s) as usize,
2922                            ((by + s) * cw as isize + bx) as usize,
2923                            ((by - s) * cw as isize + bx) as usize,
2924                        ];
2925                        // 16-wide shapes go through the batch kernel; 8-wide ones
2926                        // measured SLOWER batched than the per-candidate Wels asm
2927                        // (H-8 speed gate), so they evaluate individually inside the
2928                        // SAME argmin — identical values, identical comparisons,
2929                        // identical bitstream.
2930                        let batch = if rw != 16 {
2931                            None
2932                        } else if sadfp {
2933                            rusty_h264_accel::sad_x4(src_row, cw, &reference.y, offs, cw, rw, rh)
2934                        } else {
2935                            rusty_h264_accel::satd_x4(src_row, cw, &reference.y, offs, cw, rw, rh)
2936                        };
2937                        {
2938                            let ring = [(step, 0), (-step, 0), (0, step), (0, -step)];
2939                            let (mut bi, mut bc) = (usize::MAX, best_c);
2940                            for (i, &(dx, dy)) in ring.iter().enumerate() {
2941                                let mv = (best.0 + dx, best.1 + dy);
2942                                let cc = match batch {
2943                                    Some(sads) => {
2944                                        let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
2945                                        sads[i] as i64 + (lam_fp * rate as f64) as i64
2946                                    }
2947                                    None => cost_fp(mv),
2948                                };
2949                                #[cfg(feature = "profile")]
2950                                diastats::ev(_si);
2951                                if cc < bc {
2952                                    bc = cc;
2953                                    bi = i;
2954                                }
2955                            }
2956                            if bi == usize::MAX {
2957                                break;
2958                            }
2959                            best_c = bc;
2960                            best = (best.0 + ring[bi].0, best.1 + ring[bi].1);
2961                            #[cfg(feature = "profile")]
2962                            diastats::imp(_si);
2963                            continue;
2964                        }
2965                    }
2966                }
2967                let mut improved = false;
2968                for &(dx, dy) in &[(step, 0), (-step, 0), (0, step), (0, -step)] {
2969                    let c = (best.0 + dx, best.1 + dy);
2970                    let cc = cost_fp(c);
2971                    #[cfg(feature = "profile")]
2972                    diastats::ev(_si);
2973                    if cc < best_c {
2974                        best_c = cc;
2975                        best = c;
2976                        improved = true;
2977                        #[cfg(feature = "profile")]
2978                        diastats::imp(_si);
2979                    }
2980                }
2981                if !improved {
2982                    break;
2983                }
2984            }
2985        }
2986        // DIAMOND-STALLED RESCUE (content-adaptive: fires on the FAILURE, not a proxy).
2987        // The gradient-descent diamond stalls at a plateau on FLAT cost surfaces and
2988        // never reaches the far-but-better MV that exists within ±16 (measured: ~+22%
2989        // BD-rate vs x264's simple dia on smooth content). The precise stall signal is
2990        // the CONJUNCTION: a FLAT source block (low variance) whose diamond match STILL
2991        // has a high residual — because on a flat surface the RIGHT MV predicts near-
2992        // perfectly, so a high residual there means the diamond missed it (a stall).
2993        // (Residual alone fires on busy blocks where a high residual is inherent — that
2994        // was 3.3× slower on mand for nothing; variance alone fires on flat-but-well-
2995        // predicted blocks. The AND targets exactly the stalls.) Then a FINE ±16 step-2
2996        // grid reaches the true minimum. Fires on a fraction of blocks → affordable.
2997        // Quality preset only.
2998        drop(_gd);
2999        // B2: the full-pel phase priced in the SAD domain — reprice the winner AND
3000        // the pre-snap seed into the SATD domain the rescue + sub-pel phases (and the
3001        // final seed-vs-refined comparison) trade in. Two SATD evaluations per
3002        // search, against the ~20-50 candidate evaluations the SAD domain cheapened.
3003        if sadfp {
3004            best_c = cost(best);
3005            seed_c = cost(seed_mv);
3006        }
3007        let _gr = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeRescue);
3008        // H-14 R1 brick 1: `me_fast` defaults TRUE, which makes `flat`'s value
3009        // IRRELEVANT to the gate below on every default search — yet the full
3010        // rw×rh sum+sum-of-squares walk (256 pixel loads + muls) ran EAGERLY per
3011        // search. Lazy-evaluate it: same boolean outcome in every case (me_fast
3012        // short-circuits first), the dead variance pass simply never runs.
3013        let flat = |sself: &Self| {
3014            !refine_only && {
3015                let (mut s, mut ss) = (0u64, 0u64);
3016                for dy in 0..rh {
3017                    for dx in 0..rw {
3018                        let v = sy[(ly + dy) * sself.cw + lx + dx] as u64;
3019                        s += v;
3020                        ss += v * v;
3021                    }
3022                }
3023                // `n = rw * rh` is 256/128/64/32/16 for every H.264 partition --
3024                // always a power of two -- but the compiler cannot prove that of a
3025                // runtime value, so both of these were real `div` instructions.
3026                // A shift is EXACT here; the assert is what keeps it exact, because
3027                // a shift on a non-power-of-2 is silently wrong.
3028                let n = (rw * rh) as u64;
3029                debug_assert!(n.is_power_of_two(), "partition area must be a power of two");
3030                let sh = n.trailing_zeros();
3031                ((ss - ((s * s) >> sh)) >> sh) < sself.me_wide_var
3032            }
3033        };
3034        // The online payoff gate may have disabled the rescue for the rest of this
3035        // frame (irreducible-residual content — rotation/fractal — where the fine grid
3036        // fixes almost nothing; measured 2.25× on rot for a ~0% BD gain). A gated-off
3037        // frame runs exactly the diamond → identical to me_wide-off → never worse.
3038        // FAST-MOTION extension: the flat gate targets smooth-surface stalls, but the
3039        // diamond ALSO stalls on FAST motion (bus/football: an exhaustive ±24 search
3040        // recovers 6-15% BD) — those blocks are high-VARIANCE (detail) so `flat` misses
3041        // them. `me_fast` also fires on any high-residual block; the online payoff gate
3042        // then keeps it only where a wider search actually pays off (fast motion), and
3043        // disables it on irreducible-residual detail — the same self-tuning as flat.
3044        if self.me_wide && !self.fast && (self.me_fast || flat(self)) && !self.resc_off.get() {
3045            // H-14 R1 brick 2: `best` was priced by the SAME `dist + (λ·rate) as
3046            // i64` formula on every path that can reach here (cost, cost_fp after
3047            // the B2 reprice, the FC batch with lam_fp == λ off SAD frames), so
3048            // its distortion is recoverable EXACTLY by subtraction — the extra
3049            // full SATD kernel call per search was pure recompute (the
3050            // codec-eliminate-redundancy "return the already-computed value").
3051            let rate_b = mvbits(best.0 - center.0) + mvbits(best.1 - center.1);
3052            let dist = best_c - (lambda_me * rate_b as f64) as i64;
3053            if dist / (rw * rh).max(1) as i64 > self.me_rescue {
3054                // FINE ±16 step-2 grid + ±1 refine — recover the true minimum the
3055                // diamond missed. Fires only on flat-block stalls, so it is affordable.
3056                // SNAP THE GRID CENTRE TO INTEGER-PEL: the diamond seed can be sub-pel
3057                // (sub-pel neighbour predictors), and since every grid point shares
3058                // cx&3, a sub-pel centre forces the WHOLE ±16 grid through mc_luma
3059                // interpolation — measured 89% of zoom's rescue cost. The rescue only
3060                // needs the right REGION (a far MV the diamond missed); the sub-pel
3061                // refine that follows recovers the fraction. Integer centre → the grid
3062                // hits the fast full-pel SATD path (no interpolation).
3063                let pre_c = best_c;
3064                let (cx, cy) = ((best.0 + 2).div_euclid(4) * 4, (best.1 + 2).div_euclid(4) * 4);
3065                let mut gb = best;
3066                // BATCHED FULL-PEL GRID (accel): now that the grid centre is integer-pel
3067                // (all points interior full-pel), hoist the interior/bounds check out of
3068                // the loop and call the AVX2 SATD directly — skipping mc_satd's per-point
3069                // interior test + satd_px dispatch. BYTE-IDENTICAL to the cost() path
3070                // (same 2·satd_16x16 + rate), so it is default-on (RFF_ME_BATCH=0 to A/B
3071                // it off). ~+7% zoom / +4% tsrc on top of the snap; the SATD kernel itself
3072                // is already AVX2 and its transform can't amortise across the grid, so
3073                // this per-call-overhead trim is the ceiling for an "asm grid kernel".
3074                let cw = self.cw;
3075                let r = self.me_range;
3076                let batched = rw == 16 && rh == 16 && cfg!(accel) && {
3077                    let (icdx, icdy) = (cx >> 2, cy >> 2);
3078                    lx as i32 + icdx >= r
3079                        && lx as i32 + icdx + r + 16 <= cw as i32
3080                        && ly as i32 + icdy >= r
3081                        && ly as i32 + icdy + r + 16 <= (self.mb_h * 16) as i32
3082                        && me_batch_enabled()
3083                };
3084                #[cfg(accel)]
3085                if batched {
3086                    let (icdx, icdy) = ((cx >> 2), (cy >> 2));
3087                    let src = &sy[ly * cw + lx..];
3088                    let mut dy = -r;
3089                    while dy <= r {
3090                        let rby = (ly as i32 + icdy + dy) as usize;
3091                        let mut dx = -r;
3092                        while dx <= r {
3093                            let rbx = (lx as i32 + icdx + dx) as usize;
3094                            let satd =
3095                                2 * rusty_h264_accel::satd_16x16(src, cw, &reference.y[rby * cw + rbx..], cw) as i64;
3096                            let mv = (cx + dx * 4, cy + dy * 4);
3097                            let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
3098                            let cc = satd + (lambda_me * rate as f64) as i64;
3099                            if cc < best_c {
3100                                best_c = cc;
3101                                gb = mv;
3102                            }
3103                            dx += 2;
3104                        }
3105                        dy += 2;
3106                    }
3107                }
3108                if !batched {
3109                    let mut dy = -r;
3110                    while dy <= r {
3111                        let mut dx = -r;
3112                        while dx <= r {
3113                            let cc = cost((cx + dx * 4, cy + dy * 4));
3114                            if cc < best_c {
3115                                best_c = cc;
3116                                gb = (cx + dx * 4, cy + dy * 4);
3117                            }
3118                            dx += 2;
3119                        }
3120                        dy += 2;
3121                    }
3122                }
3123                best = gb;
3124                for dy in -1..=1 {
3125                    for dx in -1..=1 {
3126                        let c = (best.0 + dx * 4, best.1 + dy * 4);
3127                        let cc = cost(c);
3128                        if cc < best_c {
3129                            best_c = cc;
3130                            best = c;
3131                        }
3132                    }
3133                }
3134                // LEARNING PHASE: for the first `me_learn` stalls of the frame, tally
3135                // whether the grid actually paid off (≥6.25% cost cut). Once the window
3136                // fills, if too few paid off the residual is irreducible on this content
3137                // → disable the rescue for the rest of the frame. The window's own MVs
3138                // are committed, but they're a small spatially-clustered set (not
3139                // improvement-selected), so on net-neutral content (rot) they can't
3140                // regress — only frame-level on/off avoids the per-block B-direct
3141                // selection effect.
3142                let n = self.resc_n.get();
3143                if n < self.me_learn {
3144                    self.resc_n.set(n + 1);
3145                    if best_c * 16 <= pre_c * 15 {
3146                        self.resc_big.set(self.resc_big.get() + 1);
3147                    }
3148                    if n + 1 == self.me_learn
3149                        && self.resc_big.get() * 100 < self.me_learn * self.me_payoff_pct
3150                    {
3151                        self.resc_off.set(true);
3152                    }
3153                }
3154            }
3155        }
3156        drop(_gr);
3157        let _gs = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MeSubpel);
3158        // Sub-pel refinement uses the 6-tap/bilinear interpolation — the expensive
3159        // per-pixel `mc_luma` path that profiling pinned at ~55% of the entire
3160        // encode. The fast preset skips it (integer-pel only, like x264's fastest
3161        // presets `subme=0`): ~3× faster, trading a little quality on sub-pixel
3162        // motion. The quality preset does the full half-pel + quarter-pel rings.
3163        if probe {
3164            // Exhaustive +-24 full-pel around the same centre, then the SAME sub-pel
3165            // pass, so only the full-pel search strategy differs.
3166            let mut ob = center;
3167            let mut oc = i64::MAX;
3168            for gy in -24i32..=24 {
3169                for gx in -24i32..=24 {
3170                    let c = (center.0 + gx * 4, center.1 + gy * 4);
3171                    let cc = cost(c);
3172                    if cc < oc {
3173                        oc = cc;
3174                        ob = c;
3175                    }
3176                }
3177            }
3178            let fullpel_best = ob;
3179            for &st in &[2i32, 1] {
3180                for &(dx, dy) in &[(st, 0), (-st, 0), (0, st), (0, -st)] {
3181                    let c = (ob.0 + dx, ob.1 + dy);
3182                    let cc = cost(c);
3183                    if cc < oc {
3184                        oc = cc;
3185                        ob = c;
3186                    }
3187                }
3188            }
3189            // EXHAUSTIVE sub-pel: every quarter-pel offset in +-3 around the full-pel
3190            // winner. Our own pass is a single 4-point probe at half then quarter, so
3191            // this is what separates a sub-pel deficiency from a full-pel one.
3192            let mut oc_sp = oc;
3193            for dy in -3i32..=3 {
3194                for dx in -3i32..=3 {
3195                    let c = (fullpel_best.0 + dx, fullpel_best.1 + dy);
3196                    let cc = cost(c);
3197                    if cc < oc_sp {
3198                        oc_sp = cc;
3199                    }
3200                }
3201            }
3202            // our own sub-pel pass has not run yet; replicate it for a fair compare
3203            let (mut mb_, mut mc_) = (best, best_c);
3204            for &st in &[2i32, 1] {
3205                for &(dx, dy) in &[(st, 0), (-st, 0), (0, st), (0, -st)] {
3206                    let c = (mb_.0 + dx, mb_.1 + dy);
3207                    let cc = cost(c);
3208                    if cc < mc_ {
3209                        mc_ = cc;
3210                        mb_ = c;
3211                    }
3212                }
3213            }
3214            use std::sync::atomic::Ordering::Relaxed;
3215            ME_PROBE[0].fetch_add(1, Relaxed);
3216            ME_PROBE[1].fetch_add(mc_.max(0) as u64, Relaxed);
3217            ME_PROBE[2].fetch_add(oc.max(0) as u64, Relaxed);
3218            ME_PROBE[3].fetch_add((mc_ > oc) as u64, Relaxed);
3219            ME_PROBE[5].fetch_add(oc_sp.max(0) as u64, Relaxed);
3220            ME_PROBE[6].fetch_add((mc_ > oc_sp) as u64, Relaxed);
3221        }
3222        let subpel: &[i32] = if (self.fast && !self.subpel_force) || (self.sp_defer.get() && !refine_only) {
3223            &[]
3224        } else {
3225            &[2, 1]
3226        };
3227        // U1 harvest: the null arm is the full-pel winner we would keep on a skip.
3228        let (hv_pre, mut hv_evals) = (best_c, 0u32);
3229        // `to_best` = eval index of the LAST improvement; `ring1` = the cost after the
3230        // first 8-point half-pel ring. Together they answer "how many of these 29
3231        // evaluations actually matter", which is the ceiling for any cheaper pattern.
3232        let (mut hv_to_best, mut hv_ring1) = (0u32, i64::MIN);
3233        // SHAPE-DISPATCHED SUB-PEL PATTERN (best_part campaign). Same reasoning as
3234        // the sub-partition diamond ladder: a sub-8x8 partition inherits a parent
3235        // MV that has ALREADY been full-pel searched and sub-pel refined, so the
3236        // expensive walk-to-convergence 8-point pattern is confirming an answer it
3237        // was handed. This module's own harvest sized that: ~29 evaluations per
3238        // refinement, last improvement at ~14-15 (half the work confirms), and the
3239        // first ring alone carries 64-72% of the gain. Sub-partitions take pattern
3240        // pattern 2 (8-point ring, SINGLE pass) unless a caller pinned one.
3241        // Swept all four on BD-rate vs no-splits (fine ladder active):
3242        //
3243        //   pat            foreman SSIM   bus SSIM
3244        //   0 8pt+iterate     -2.21         -5.49
3245        //   1 4pt+iterate     -2.06         -5.49
3246        //   2 8pt+single      -2.13         -5.64   <- best on bus, ~full on foreman
3247        //   3 4pt+single      -2.03         -5.44
3248        //
3249        // The RING is what carries the gain; the ITERATION is confirmation. Pattern
3250        // 2 drops ~29 evals to ~8 and BEATS the full walk on bus — dropping the
3251        // ring as well (1, 3) is where quality actually goes. `RFF_SUBPEL_SUB`
3252        // overrides (0-3); `=0` restores the full pattern for sub-partitions.
3253        let sub_shape = rw < 8 || rh < 8;
3254        let mut pat = subpel_pattern_override().unwrap_or_else(|| {
3255            if sub_shape {
3256                static P: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
3257                *P.get_or_init(|| {
3258                    std::env::var("RFF_SUBPEL_SUB").ok().and_then(|v| v.parse().ok()).unwrap_or(2)
3259                })
3260            } else if self.sp_single_pass {
3261                2
3262            } else {
3263                0
3264            }
3265        });
3266        let (sp_learn, sp_t) = sp_dispatch_cfg();
3267        // Only dispatch when the caller has not pinned a pattern (pat 0 = default).
3268        let sp_dispatching = sp_learn > 0 && pat == 0 && !subpel.is_empty();
3269        if sp_dispatching && self.sp_learn_n.get() >= sp_learn && self.sp_1pass.get() {
3270            pat = 2;
3271        }
3272        // Descent D-2 MEMO. The ring walks around a MOVING centre, so iteration N+1's
3273        // ring necessarily re-contains the previous centre and several previous ring
3274        // points: 27-44% of sub-pel evaluations re-price an MV this refinement already
3275        // priced. `cost()` is PURE in `mv` (rate from mv-centre; distortion from the
3276        // fixed reference/source/block captures), so memoizing is EXACT -- identical
3277        // costs, identical comparisons, identical chosen MV, byte-identical output.
3278        // A miss simply recomputes, so the table's hit rate is a SPEED property only.
3279        //
3280        // 64-entry direct-mapped on the low bits of the MV, tagged with the full MV so
3281        // a collision is a miss rather than a wrong answer. Stack-resident (1 KiB) and
3282        // re-initialized per refinement: measured cheaper than a thread-local + RefCell
3283        // borrow on every evaluation, since ~60% of lookups miss.
3284        const SP_MEMO_N: usize = 64;
3285        #[inline(always)]
3286        fn sp_slot(mv: (i32, i32)) -> usize {
3287            ((mv.0 & 7) as usize) | (((mv.1 & 7) as usize) << 3)
3288        }
3289        let mut memo_mv = [(i32::MIN, i32::MIN); SP_MEMO_N];
3290        let mut memo_c = [0i64; SP_MEMO_N];
3291        if !subpel.is_empty() {
3292            let s0 = sp_slot(best);
3293            memo_mv[s0] = best;
3294            memo_c[s0] = best_c;
3295        }
3296        // Descent D-2 census: the ring walks around a MOVING centre, so iteration N+1's ring
3297        // necessarily re-contains the previous centre and several previous ring points.
3298        // Count how many sub-pel evaluations price an MV this refinement ALREADY priced
3299        // -- redundant recompute is byte-identically removable, unlike dropping work.
3300        #[cfg(feature = "profile")]
3301        let mut seen: Vec<(i32, i32)> = Vec::with_capacity(64);
3302        #[cfg(feature = "profile")]
3303        {
3304            seen.push(best);
3305        }
3306        // Track-B B3: the sub-pel iteration BUDGET. The ring walks until no
3307        // improvement; Descent D's census says iteration 1 carries 55% of evals at
3308        // an 11-13% hit rate, iteration 2 another 35-40% at 1.5-2.5%, and the tail
3309        // past that almost never pays — but under B2's SAD-chosen starts the tail
3310        // GROWS (+27% ns/search), eating the SAD savings. A cap bounds the walk the
3311        // way x264's fixed subme budget does. 0 (default) = unlimited =
3312        // byte-identical; bitstream-changing otherwise → BD-gated, opt-in.
3313        let sp_cap = sp_maxit();
3314        // ③: batched fixed-centre half-pel ring (see `sp_fc_enabled`).
3315        #[cfg_attr(not(accel_x86), allow(unused_variables))] // consumed by accel_x86-only blocks
3316        let sp_fc = sp_fc_enabled() && !self.fast && cfg!(accel_x86)
3317            && matches!((rw, rh), (16, 16) | (16, 8) | (8, 16) | (8, 8));
3318        for &step in subpel {
3319            // Snapping starts this refine from an integer centre instead of the
3320            // seed's own fractional lattice, so a single 8-point pass can leave
3321            // precision behind. Walk it until it stops improving to compensate —
3322            // the snap is what pays for the extra probes.
3323            let ring8 = [
3324                (step, 0), (-step, 0), (0, step), (0, -step),
3325                (step, step), (-step, -step), (step, -step), (-step, step),
3326            ];
3327            let ring4 = [(step, 0), (-step, 0), (0, step), (0, -step)];
3328            let ring: &[(i32, i32)] = if pat & 1 != 0 { &ring4 } else { &ring8 };
3329            let mut _iter = 0u32;
3330            loop {
3331                // ③: from an INTEGER centre at step 2, all 8 ring candidates are
3332                // single-plane reads (h/h/v/v axes, c/c/c/c diagonals) — batch them
3333                // as two x4 kernel calls and take the argmin (first-wins in ring
3334                // order). Any decline (edge, half-pel centre, ring4 pattern) falls
3335                // through to the cascading walk for this pass.
3336                // ③b: the QUARTER step — every ±1 offset makes a component odd, so
3337                // all 8 candidates are two-plane average pairs regardless of the
3338                // centre's phase; two `satd_avg_x4` calls cover the ring.
3339                #[cfg(accel_x86)]
3340                if sp_fc && step == 1 && pat & 1 == 0 {
3341                    _iter += 1;
3342                    let hp8 = hp.expect("sp_fc implies non-fast, which resolves hp");
3343                    let ring8 = [
3344                        (1, 0), (-1, 0), (0, 1), (0, -1),
3345                        (1, 1), (-1, -1), (1, -1), (-1, 1),
3346                    ];
3347                    let mut prs: [Option<(&[u8], usize, &[u8], usize, usize)>; 8] = [None; 8];
3348                    let mut all = true;
3349                    for (i, &(dx, dy)) in ring8.iter().enumerate() {
3350                        prs[i] = rusty_h264_common::inter::hpel_qpel_refs(
3351                            hp8, lx, ly, rw, rh, best.0 + dx, best.1 + dy,
3352                        );
3353                        all &= prs[i].is_some();
3354                    }
3355                    if all {
3356                        let stride = prs[0].unwrap().4;
3357                        // Batch kernel for 16-wide only (8-wide measured slower
3358                        // batched than the per-candidate fused path — H-8 gate);
3359                        // either way the SAME argmin over the SAME values.
3360                        let pack = |a: usize, b: usize, c2: usize, d: usize| {
3361                            if rw != 16 {
3362                                return None;
3363                            }
3364                            let g = |i: usize| {
3365                                let (pa, oa, pb, ob, _) = prs[i].unwrap();
3366                                (pa, oa, pb, ob)
3367                            };
3368                            rusty_h264_accel::satd_avg_x4(
3369                                src_row, cw, [g(a), g(b), g(c2), g(d)], stride, rw, rh,
3370                            )
3371                        };
3372                        {
3373                            let (ax, di) = (pack(0, 1, 2, 3), pack(4, 5, 6, 7));
3374                            let (mut bi, mut bc) = (usize::MAX, best_c);
3375                            for i in 0..8 {
3376                                let (dx, dy) = ring8[i];
3377                                let mv = (best.0 + dx, best.1 + dy);
3378                                let cc = match (i < 4, &ax, &di) {
3379                                    (true, Some(ax), _) => {
3380                                        let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
3381                                        ax[i] as i64 + (lambda_me * rate as f64) as i64
3382                                    }
3383                                    (false, _, Some(di)) => {
3384                                        let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
3385                                        di[i - 4] as i64 + (lambda_me * rate as f64) as i64
3386                                    }
3387                                    _ => cost(mv),
3388                                };
3389                                hv_evals += 1;
3390                                if cc < bc {
3391                                    bc = cc;
3392                                    bi = i;
3393                                }
3394                            }
3395                            if hv_ring1 == i64::MIN {
3396                                hv_ring1 = if bi == usize::MAX { best_c } else { bc };
3397                            }
3398                            if bi == usize::MAX
3399                                || !self.me_subpel_iter
3400                                || pat & 2 != 0
3401                                || (sp_cap != 0 && _iter >= sp_cap)
3402                            {
3403                                if bi != usize::MAX {
3404                                    best_c = bc;
3405                                    best = (best.0 + ring8[bi].0, best.1 + ring8[bi].1);
3406                                    hv_to_best = hv_evals;
3407                                }
3408                                break;
3409                            }
3410                            best_c = bc;
3411                            best = (best.0 + ring8[bi].0, best.1 + ring8[bi].1);
3412                            hv_to_best = hv_evals;
3413                            continue;
3414                        }
3415                    }
3416                    _iter -= 1;
3417                }
3418                #[cfg(accel_x86)]
3419                if sp_fc && step == 2 && best.0 & 3 == 0 && best.1 & 3 == 0 && pat & 1 == 0 {
3420                    _iter += 1;
3421                    let hp8 = hp.expect("sp_fc implies non-fast, which resolves hp");
3422                    let ring8 = [
3423                        (step, 0), (-step, 0), (0, step), (0, -step),
3424                        (step, step), (-step, -step), (step, -step), (-step, step),
3425                    ];
3426                    let mut refs8: [Option<(&[u8], usize, usize)>; 8] = [None; 8];
3427                    let mut all = true;
3428                    for (i, &(dx, dy)) in ring8.iter().enumerate() {
3429                        refs8[i] = rusty_h264_common::inter::hpel_ref(
3430                            hp8, lx, ly, rw, rh, best.0 + dx, best.1 + dy,
3431                        );
3432                        all &= refs8[i].is_some();
3433                    }
3434                    if all {
3435                        let stride = refs8[0].unwrap().2;
3436                        // 16-wide batches; 8-wide evaluates per candidate (H-8 gate)
3437                        // — identical values, identical argmin, identical bitstream.
3438                        let pack = |a: usize, b: usize, c2: usize, d: usize| {
3439                            if rw != 16 {
3440                                return None;
3441                            }
3442                            let g = |i: usize| {
3443                                let (p, o, _) = refs8[i].unwrap();
3444                                (p, o)
3445                            };
3446                            rusty_h264_accel::satd_x4p(
3447                                src_row, cw, [g(a), g(b), g(c2), g(d)], stride, rw, rh,
3448                            )
3449                        };
3450                        {
3451                            let (ax, di) = (pack(0, 1, 2, 3), pack(4, 5, 6, 7));
3452                            let (mut bi, mut bc) = (usize::MAX, best_c);
3453                            for i in 0..8 {
3454                                let (dx, dy) = ring8[i];
3455                                let mv = (best.0 + dx, best.1 + dy);
3456                                let cc = match (i < 4, &ax, &di) {
3457                                    (true, Some(ax), _) => {
3458                                        let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
3459                                        ax[i] as i64 + (lambda_me * rate as f64) as i64
3460                                    }
3461                                    (false, _, Some(di)) => {
3462                                        let rate = mvbits(mv.0 - center.0) + mvbits(mv.1 - center.1);
3463                                        di[i - 4] as i64 + (lambda_me * rate as f64) as i64
3464                                    }
3465                                    _ => cost(mv),
3466                                };
3467                                hv_evals += 1;
3468                                if cc < bc {
3469                                    bc = cc;
3470                                    bi = i;
3471                                }
3472                            }
3473                            if hv_ring1 == i64::MIN {
3474                                hv_ring1 = if bi == usize::MAX { best_c } else { bc };
3475                            }
3476                            if bi == usize::MAX
3477                                || !self.me_subpel_iter
3478                                || pat & 2 != 0
3479                                || (sp_cap != 0 && _iter >= sp_cap)
3480                            {
3481                                if bi != usize::MAX {
3482                                    best_c = bc;
3483                                    best = (best.0 + ring8[bi].0, best.1 + ring8[bi].1);
3484                                    hv_to_best = hv_evals;
3485                                }
3486                                break;
3487                            }
3488                            best_c = bc;
3489                            best = (best.0 + ring8[bi].0, best.1 + ring8[bi].1);
3490                            hv_to_best = hv_evals;
3491                            continue;
3492                        }
3493                    }
3494                    _iter -= 1; // declined — the cascade pass below re-counts it
3495                }
3496                let mut improved = false;
3497                _iter += 1;
3498                for (_pi, &(dx, dy)) in ring.iter().enumerate() {
3499                    let c = (best.0 + dx, best.1 + dy);
3500                    let slot = sp_slot(c);
3501                    let cc = if memo_mv[slot] == c {
3502                        memo_c[slot]
3503                    } else {
3504                        let v = cost(c);
3505                        memo_mv[slot] = c;
3506                        memo_c[slot] = v;
3507                        v
3508                    };
3509                    hv_evals += 1;
3510                    // Descent D: which ring POSITION and which ITERATION actually pay?
3511                    // Same census that showed the diamond's coarse rungs were noise,
3512                    // aimed at the stage that is now 41% of encode.
3513                    #[cfg(feature = "profile")]
3514                    {
3515                        spstats::ev(if step == 2 { 0 } else { 1 }, _pi, _iter);
3516                        if seen.contains(&c) {
3517                            spstats::redundant();
3518                        } else {
3519                            seen.push(c);
3520                        }
3521                    }
3522                    if cc < best_c {
3523                        best_c = cc;
3524                        best = c;
3525                        improved = true;
3526                        hv_to_best = hv_evals;
3527                        #[cfg(feature = "profile")]
3528                        spstats::imp(if step == 2 { 0 } else { 1 }, _pi, _iter);
3529                    }
3530                }
3531                if hv_ring1 == i64::MIN {
3532                    hv_ring1 = best_c;
3533                }
3534                if !improved
3535                    || !self.me_subpel_iter
3536                    || pat & 2 != 0
3537                    || (sp_cap != 0 && _iter >= sp_cap)
3538                {
3539                    break;
3540                }
3541            }
3542        }
3543        if sp_dispatching {
3544            let n = self.sp_learn_n.get();
3545            if n < sp_learn {
3546                self.sp_learn_n.set(n + 1);
3547                if hv_ring1 != i64::MIN {
3548                    self.sp_ring1.set(self.sp_ring1.get() + (hv_pre - hv_ring1).max(0));
3549                    self.sp_total.set(self.sp_total.get() + (hv_pre - best_c).max(0));
3550                }
3551                if n + 1 == sp_learn {
3552                    let tot = self.sp_total.get();
3553                    // Concentrated in ring 1 -> the later rings are affordable to drop.
3554                    self.sp_1pass.set(tot > 0 && self.sp_ring1.get() * 100 >= tot * sp_t);
3555                }
3556            }
3557        }
3558        if !subpel.is_empty() && subpel_harvest::enabled() {
3559            subpel_harvest::record(hv_pre, best_c, lambda_me, rw, rh, hv_evals, hv_to_best, hv_ring1);
3560        }
3561        // The snap moved the search off the seed; if the seed was better after all,
3562        // keep it. This is what makes the snap safe by construction.
3563        if self.me_snap && seed_c < best_c {
3564            best = seed_mv;
3565            best_c = seed_c;
3566        }
3567        (best, best_c)
3568    }
3569
3570    /// Encodes macroblock `(mb_x, mb_y)` as an inter macroblock of the given
3571    /// `mode` (0 = P_L0_16x16, 1 = P_16x8, 2 = P_8x16) with one motion vector
3572    /// per partition: motion-compensate each partition, code the macroblock
3573    /// residual, and reconstruct.
3574    #[allow(clippy::too_many_arguments)]
3575    /// Dispatch to the current coded path (`_v1`) or the isolated fused path
3576    /// (`_v2`), selected by the hidden `coded_path_v2` A/B knob. Both must produce
3577    /// byte-identical bitstreams (gated by the `coded_path_ab` test); the split
3578    /// exists so the two run side-by-side in one binary for honest timing.
3579    #[allow(clippy::too_many_arguments)]
3580    fn encode_inter_mb(
3581        &mut self,
3582        w: &mut BitWriter,
3583        refs: &[crate::RefFrame],
3584        sy: &[u8],
3585        su: &[u8],
3586        sv: &[u8],
3587        mb_x: usize,
3588        mb_y: usize,
3589        mode: u8,
3590        parts: &[(i32, (i32, i32))],
3591    ) {
3592        // RDOQ fork at the DISPATCH: `_v2` is the accel-only coefficient-fused
3593        // path and HARD-quantizes — it has no trellis support in either its
3594        // luma or chroma quant. Under a non-zero `rdoq_strength` (B slices
3595        // ship `cabac_rdoq_b = 32` by default; P dispatches on grain/screen)
3596        // it must yield to `_v1`, or accel and scalar builds emit DIFFERENT
3597        // inter bitstreams. Found as the SECOND divergent site while gating
3598        // the first (the `_v1` accel chroma arm) — the twins lesson: the
3599        // divergence class is "accel quant without an rdoq fork", and it had
3600        // two members.
3601        if self.coded_path_v2 && self.rdoq_strength <= 0.0 {
3602            self.encode_inter_mb_v2(w, refs, sy, su, sv, mb_x, mb_y, mode, parts);
3603        } else {
3604            self.encode_inter_mb_v1(w, refs, sy, su, sv, mb_x, mb_y, mode, parts);
3605        }
3606    }
3607
3608    /// Isolated, coefficient-fused inter coding path (A/B twin of `_v1`). The
3609    /// quantized luma levels stay in the hot 16-byte-aligned i16 DCT buffer for the
3610    /// whole MB; the i32 form is materialized on demand only for *coded* blocks
3611    /// (CAVLC scan + recon dequant), so uncoded quads never pay the conversion and
3612    /// there is no 256-word i32 `q_blocks` round-trip. Byte-identical to `_v1`
3613    /// (gated by `coded_path_ab`). Accel-only optimization; the scalar build reuses
3614    /// `_v1` unchanged.
3615    #[allow(clippy::too_many_arguments)]
3616    fn encode_inter_mb_v2(
3617        &mut self,
3618        w: &mut BitWriter,
3619        refs: &[crate::RefFrame],
3620        sy: &[u8],
3621        su: &[u8],
3622        sv: &[u8],
3623        mb_x: usize,
3624        mb_y: usize,
3625        mode: u8,
3626        parts: &[(i32, (i32, i32))],
3627    ) {
3628        // Descent E/F: identify this mc_luma population by call site.
3629        #[cfg(feature = "profile")]
3630        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(1);
3631        #[cfg(not(accel))]
3632        {
3633            self.encode_inter_mb_v1(w, refs, sy, su, sv, mb_x, mb_y, mode, parts);
3634        }
3635        #[cfg(accel)]
3636        {
3637            let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncInterCode);
3638            let (qp, qpc) = (self.qp, self.qpc);
3639            let w4 = self.mb_w * 4;
3640            let (_ch, cch) = (self.mb_h * 16, self.mb_h * 8);
3641
3642            // ---- per-partition motion compensation + MV prediction (== v1) ----
3643            let mut pred_y = [0u8; 256];
3644            let mut c_pred = [[0u8; 64]; 2];
3645            let mut mvds = [(0i32, 0i32); 4];
3646            let mut n_mvd = 0;
3647            let _g_mc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
3648            for (part, &(rx, ry, rw, rh)) in inter_partitions(mode).iter().enumerate() {
3649                let (refi, mv) = parts[part];
3650                let reference = &refs[refi as usize];
3651                let (pbx, pby) = ((mb_x * 4 + rx / 4) as isize, (mb_y * 4 + ry / 4) as isize);
3652                let [a, b, c] = self.mv_neighbors_block(pbx, pby, (rw / 4) as isize);
3653                let pmv = predict_partition_mv(mode, part, a, b, c, refi);
3654                mvds[n_mvd] = (mv.0 - pmv.0, mv.1 - pmv.1);
3655                n_mvd += 1;
3656                for by in ry / 4..ry / 4 + rh / 4 {
3657                    let d = (mb_y * 4 + by) * w4 + mb_x * 4 + rx / 4;
3658                    let n4 = rw / 4;
3659                    self.mv_y[d..d + n4].fill(mv);
3660                    self.inter_y[d..d + n4].fill(true);
3661                    self.ref_idx_y[d..d + n4].fill(refi);
3662                    self.coded_y[d..d + n4].fill(true);
3663                }
3664                if rw == 16 && rh == 16 {
3665                    self.mc_luma_cached(reference, mb_x * 16, mb_y * 16, 16, 16, mv.0, mv.1, &mut pred_y);
3666                    self.wp_luma(refi, &mut pred_y, 0, 0, 16, 16);
3667                } else {
3668                    let mut tmp = [0u8; 256];
3669                    self.mc_luma_cached(reference, mb_x * 16 + rx, mb_y * 16 + ry, rw, rh, mv.0, mv.1, &mut tmp);
3670                    // H-17: the per-pixel re-stride was the runtime-width copy trap
3671                    // (a bounds-checked store per pixel); const-width row copies are
3672                    // byte-identical and lower to inline moves.
3673                    if rw == 8 {
3674                        for dy in 0..rh {
3675                            pred_y[(ry + dy) * 16 + rx..][..8].copy_from_slice(&tmp[dy * 8..][..8]);
3676                        }
3677                    } else {
3678                        for dy in 0..rh {
3679                            pred_y[(ry + dy) * 16 + rx..][..16].copy_from_slice(&tmp[dy * 16..][..16]);
3680                        }
3681                    }
3682                    self.wp_luma(refi, &mut pred_y, rx, ry, rw, rh);
3683                }
3684                let (crx, cry, crw, crh) = (rx / 2, ry / 2, rw / 2, rh / 2);
3685                for cc in 0..2 {
3686                    let rc = if cc == 0 { &reference.u } else { &reference.v };
3687                    if crw == 8 && crh == 8 {
3688                        mc_chroma(rc, self.ccw, cch, mb_x * 8, mb_y * 8, 8, 8, mv.0, mv.1, &mut c_pred[cc]);
3689                    } else {
3690                        let mut tc = [0u8; 64];
3691                        mc_chroma(rc, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv.0, mv.1, &mut tc);
3692                        // H-17: same const-width row-copy fix as luma.
3693                        if crw == 4 {
3694                            for dy in 0..crh {
3695                                c_pred[cc][(cry + dy) * 8 + crx..][..4].copy_from_slice(&tc[dy * 4..][..4]);
3696                            }
3697                        } else {
3698                            for dy in 0..crh {
3699                                c_pred[cc][(cry + dy) * 8 + crx..][..8].copy_from_slice(&tc[dy * 8..][..8]);
3700                            }
3701                        }
3702                    }
3703                }
3704            }
3705
3706            // ---- luma residual + quantization: keep levels in the i16 buffer ----
3707            let mut dctw = AlignedDct([0i16; 256]);
3708            let dct = &mut dctw.0;
3709            let mut cbp_luma = 0u32;
3710            drop(_g_mc);
3711            let _g_tq = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncTq);
3712            let base = mb_y * 16 * self.cw + mb_x * 16;
3713            for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
3714                rusty_h264_accel::dct_four_t4(
3715                    &mut dct[qi * 64..qi * 64 + 64],
3716                    &sy[base + qy * self.cw + qx..],
3717                    self.cw,
3718                    &pred_y[qy * 16 + qx..],
3719                    16,
3720                );
3721            }
3722            let ff = rusty_h264_common::transform::quant_dz_ff(qp, 6);
3723            let mf = &rusty_h264_common::transform::QUANT_MF_OH[qp as usize];
3724            for qi in 0..4 {
3725                rusty_h264_accel::quant_four_4x4(&mut dct[qi * 64..qi * 64 + 64], &ff, mf);
3726            }
3727            // cbp per quad straight from the i16 levels (no i32 q_blocks copy).
3728            for blk in 0..16 {
3729                if dct[blk * 16..blk * 16 + 16].iter().any(|&v| v != 0) {
3730                    cbp_luma |= 1 << (blk / 4);
3731                }
3732            }
3733
3734            // ---- chroma residual (identical to v1: c_q stays i32) ----
3735            let mut c_dc_levels = [[0i32; 4]; 2];
3736            let mut c_recon_dc = [[0i32; 4]; 2];
3737            let mut c_q = [[[0i32; 16]; 4]; 2];
3738            let (mut any_ac, mut any_dc) = (false, false);
3739            for c in 0..2 {
3740                let src = if c == 0 { su } else { sv };
3741                let dc2x2 = {
3742                    #[repr(align(16))]
3743                    struct A([i16; 64]);
3744                    let mut cdct = A([0i16; 64]);
3745                    rusty_h264_accel::dct_four_t4(
3746                        &mut cdct.0,
3747                        &src[(mb_y * 8) * self.ccw + mb_x * 8..],
3748                        self.ccw,
3749                        &c_pred[c],
3750                        8,
3751                    );
3752                    let dc = [cdct.0[0] as i32, cdct.0[16] as i32, cdct.0[32] as i32, cdct.0[48] as i32];
3753                    let ffc = rusty_h264_common::transform::quant_dz_ff(qpc, 6);
3754                    let mfc = &rusty_h264_common::transform::QUANT_MF_OH[qpc as usize];
3755                    rusty_h264_accel::quant_four_4x4(&mut cdct.0, &ffc, mfc);
3756                    for i in 0..4 {
3757                        let q = &mut c_q[c][i];
3758                        q[0] = 0;
3759                        for j in 1..16 {
3760                            let v = cdct.0[i * 16 + j] as i32;
3761                            q[j] = v;
3762                            if v != 0 {
3763                                any_ac = true;
3764                            }
3765                        }
3766                    }
3767                    dc
3768                };
3769                let dl = forward_quant_chroma_dc(&dc2x2, qpc, false);
3770                if dl.iter().any(|&v| v != 0) {
3771                    any_dc = true;
3772                }
3773                c_recon_dc[c] = inverse_quant_chroma_dc(&dl, qpc);
3774                c_dc_levels[c] = dl;
3775            }
3776            let cbp_chroma: u32 = if any_ac { 2 } else if any_dc { 1 } else { 0 };
3777            let cbp = cbp_luma | (cbp_chroma << 4);
3778
3779            // ---- emit syntax (== v1) ----
3780            drop(_g_tq);
3781            let _g_syn = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
3782            w.write_ue(mode as u32);
3783            // P_8x8 (mb_type 3): sub_mb_type per 8×8 (spec 7.3.5.2) — v1 parity;
3784            // omitting these desynced every v2 P_8x8 macroblock.
3785            if mode == 3 {
3786                for _ in 0..4 {
3787                    w.write_ue(0);
3788                }
3789            }
3790            let num_refs = refs.len();
3791            if num_refs > 1 {
3792                for &(refi, _) in parts {
3793                    write_ref_idx(w, refi, num_refs);
3794                }
3795            }
3796            for &(mvdx, mvdy) in &mvds[..n_mvd] {
3797                w.write_se(mvdx);
3798                w.write_se(mvdy);
3799            }
3800            write_cbp_inter(w, cbp);
3801            // transform_size_8x8_flag (v1 parity): v2 codes 4×4-transform residual
3802            // only, but the flag must be PRESENT whenever the stream enables the
3803            // 8×8 transform — the decoder reads it unconditionally for
3804            // cbp_luma != 0. Every shape v2 emits allows it (P_8x8 subs are all
3805            // P_L0_8x8), so presence == (cbp_luma > 0 && transform_8x8).
3806            if cbp_luma > 0 && self.transform_8x8 {
3807                w.write_bit(false);
3808            }
3809            if cbp != 0 {
3810                w.write_se(self.qp_delta()); // mb_qp_delta (AQ per-MB QPy)
3811            }
3812            self.nnz_cache_load(mb_x, mb_y);
3813            drop(_g_syn);
3814
3815            // ---- CAVLC: scan straight from the i16 levels for coded blocks ----
3816            let _g_scan = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Scatter);
3817            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
3818                let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
3819                let total = if cbp_luma & (1 << (blk / 4)) != 0 {
3820                    let nc = self.nc_pred(lbx, lby);
3821                    let scan16 = scan_4x4_dcac_i16(&dct[blk * 16..blk * 16 + 16]);
3822                    encode_residual_block(w, &scan16, 16, nc) as u8
3823                } else {
3824                    0
3825                };
3826                self.nnz_cache_set(lbx, lby, total);
3827                self.nnz_y[by * w4 + bx] = total;
3828            }
3829            if cbp_chroma != 0 {
3830                for c in 0..2 {
3831                    encode_residual_block(w, &c_dc_levels[c], 4, -1);
3832                }
3833            }
3834            if cbp_chroma == 2 {
3835                self.chroma_cache_load(mb_x, mb_y);
3836                let w2 = self.mb_w * 2;
3837                for c in 0..2 {
3838                    for &(bx, by) in &CHROMA_4X4_SCAN_XY {
3839                        let nc = self.chroma_nc_pred(c, bx, by);
3840                        let ac = scan_4x4_ac(&c_q[c][by * 2 + bx]);
3841                        let total = encode_residual_block(w, &ac, 15, nc) as u8;
3842                        self.chroma_nnz_cache_set(c, bx, by, total);
3843                        self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total;
3844                    }
3845                }
3846            }
3847            drop(_g_scan);
3848
3849            // ---- reconstruction: dequantize luma straight from the i16 levels ----
3850            let _g_rec = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::SkipRecon);
3851            #[repr(align(16))]
3852            struct Align16([i16; 64]);
3853            let mut dct_in = Align16([0i16; 64]);
3854            for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
3855                let rec_off = base + qy * self.cw + qx;
3856                if cbp_luma & (1 << qi) == 0 {
3857                    for r in 0..8 {
3858                        let (dsti, srci) = (rec_off + r * self.cw, (qy + r) * 16 + qx);
3859                        self.rec_y[dsti..dsti + 8].copy_from_slice(&pred_y[srci..srci + 8]);
3860                    }
3861                    continue;
3862                }
3863                for k in 0..4 {
3864                    let blk = qi * 4 + k;
3865                    let mut lvl = [0i32; 16];
3866                    for i in 0..16 {
3867                        lvl[i] = dct[blk * 16 + i] as i32;
3868                    }
3869                    let deq = dequantize(&lvl, qp);
3870                    for i in 0..16 {
3871                        dct_in.0[k * 16 + i] = deq[i] as i16;
3872                    }
3873                }
3874                rusty_h264_accel::idct_four_t4_rec(
3875                    &mut self.rec_y[rec_off..],
3876                    self.cw,
3877                    &pred_y[qy * 16 + qx..],
3878                    16,
3879                    &dct_in.0,
3880                );
3881            }
3882            // chroma recon (identical to v1)
3883            for c in 0..2 {
3884                let base_c = (mb_y * 8) * self.ccw + mb_x * 8;
3885                let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
3886                if cbp_chroma == 0 {
3887                    for r in 0..8 {
3888                        let dsti = base_c + r * self.ccw;
3889                        plane[dsti..dsti + 8].copy_from_slice(&c_pred[c][r * 8..r * 8 + 8]);
3890                    }
3891                } else {
3892                    #[repr(align(16))]
3893                    struct A([i16; 64]);
3894                    let mut d = A([0i16; 64]);
3895                    for i in 0..4 {
3896                        let deq = dequantize(&c_q[c][i], qpc);
3897                        for j in 0..16 {
3898                            d.0[i * 16 + j] = deq[j] as i16;
3899                        }
3900                        d.0[i * 16] = c_recon_dc[c][i] as i16;
3901                    }
3902                    rusty_h264_accel::idct_four_t4_rec(&mut plane[base_c..], self.ccw, &c_pred[c], 8, &d.0);
3903                }
3904            }
3905            for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
3906                self.modes_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 2;
3907            }
3908        }
3909    }
3910
3911    #[allow(clippy::too_many_arguments)]
3912    fn encode_inter_mb_v1(
3913        &mut self,
3914        w: &mut BitWriter,
3915        refs: &[crate::RefFrame],
3916        sy: &[u8],
3917        su: &[u8],
3918        sv: &[u8],
3919        mb_x: usize,
3920        mb_y: usize,
3921        mode: u8,
3922        parts: &[(i32, (i32, i32))],
3923    ) {
3924        self.encode_inter_mb_v1_b(w, refs, sy, su, sv, mb_x, mb_y, mode, parts, None);
3925    }
3926
3927    /// As [`Self::encode_inter_mb_v1`], but `b_mode` selects B-slice framing: the
3928    /// macroblock is coded as `B_L0_16x16` (`mb_type == 1`) instead of the P-slice
3929    /// `mb_type == mode`. Everything else — the single List-0 partition, the median
3930    /// `mvd_l0` predictor, the residual, and the reconstruction — is byte-identical
3931    /// to `P_L0_16x16`, so the caller passes `mode == 0`, `refs == &[L0_anchor]`
3932    /// (length 1 ⇒ no `ref_idx` coded), and `parts == &[(0, mv)]`.
3933    /// Decide + reconstruct one inter macroblock (motion compensation, residual,
3934    /// quantize, reconstruct, commit motion grids) — everything except entropy
3935    /// coding. Returns an [`InterPlan`] coded by either backend, so CAVLC and CABAC
3936    /// share this whole path bit-for-bit (the P/B analogue of [`plan_mb`]).
3937    #[allow(clippy::too_many_arguments)]
3938    fn plan_inter_mb(
3939        &mut self,
3940        refs: &[crate::RefFrame],
3941        sy: &[u8],
3942        su: &[u8],
3943        sv: &[u8],
3944        mb_x: usize,
3945        mb_y: usize,
3946        mode: u8,
3947        parts: &[(i32, (i32, i32))],
3948        bspec: Option<BInter>,
3949        sub_types: [u8; 4],
3950    ) -> InterPlan {
3951        crate::signals::census::work(crate::signals::census::W_MB_PLAN);
3952        // Descent E/F: identify this mc_luma population by call site.
3953        #[cfg(feature = "profile")]
3954        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(1);
3955        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncInterCode);
3956        let (qp, qpc) = (self.qp, self.qpc);
3957        let w4 = self.mb_w * 4;
3958        let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
3959
3960        // ---- per-partition motion compensation + MV prediction ----
3961        let mut pred_y = [0u8; 256];
3962        let mut c_pred = [[0u8; 64]; 2];
3963        let mut mvds = [(0i32, 0i32); 16]; // ≤16 sub-partitions; no per-MB Vec alloc
3964        let mut plan_refs = [0i32; 4]; // per-partition ref_idx_l0 (0 for B / 1-ref)
3965        let mut n_mvd = 0;
3966        let _g_mc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
3967        // The SPLIT test must come FIRST. `mvmode > 0` means a 16x8/8x16 partition
3968        // beat every 16x16 mode INCLUDING direct, and when it beat direct the caller
3969        // leaves `dir` at 0 -- so a `dir == 0` test placed ahead of this one claims
3970        // the macroblock, reconstructs B_Direct, and emits nothing into `mvds`, while
3971        // `emit_mb_cabac_b` still writes the split mb_type. The decoder then reads a
3972        // B_Bi_16x8 with two zero mvds where the encoder reconstructed direct motion.
3973        // Measured: 34 macroblocks per 6 frames, -2.4 dB luma, and INVISIBLE to the
3974        // conformance matrix -- both decoders agree with each other, they just
3975        // disagree with the encoder.
3976        if let Some(b) = bspec.filter(|b| b.mvmode > 0) {
3977            // ---- B 16x8 / 8x16: two partitions, each L0 / L1 / Bi ----
3978            // Prediction and commit run PARTITION-major (partition 1 predicts off
3979            // partition 0's committed motion, exactly as the decoder's recon does);
3980            // the mvds are then serialised LIST-major for the emit, which is the
3981            // spec 7.3.5.1 order the decoder parses.
3982            let (rects, _) = b_part_layout(b.mvmode);
3983            let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
3984            let mut pm: [[(i32, i32); 2]; 2] = [[(0, 0); 2]; 2]; // [part][list] mvd
3985            for (part, &(rx, ry, rw, rh)) in rects.iter().enumerate() {
3986                let (pred, mv0, mv1) = b.parts2[part];
3987                let (u0, u1) = (pred == 1 || pred == 3, pred == 2 || pred == 3);
3988                let (pbx, pby) = ((mb_x * 4 + rx / 4) as isize, (mb_y * 4 + ry / 4) as isize);
3989                if u0 {
3990                    let [a, c0, c1] = self.mv_neighbors_block_list(pbx, pby, (rw / 4) as isize, 0);
3991                    let p = predict_partition_mv(b.mvmode, part, a, c0, c1, 0);
3992                    pm[part][0] = (mv0.0 - p.0, mv0.1 - p.1);
3993                }
3994                if u1 {
3995                    let [a, c0, c1] = self.mv_neighbors_block_list(pbx, pby, (rw / 4) as isize, 1);
3996                    let p = predict_partition_mv(b.mvmode, part, a, c0, c1, 0);
3997                    pm[part][1] = (mv1.0 - p.0, mv1.1 - p.1);
3998                }
3999                // Motion compensation for this rect.
4000                let (lx, ly) = (mb_x * 16 + rx, mb_y * 16 + ry);
4001                let (cx, cy) = (mb_x * 8 + rx / 2, mb_y * 8 + ry / 2);
4002                let (cw2, ch2) = (rw / 2, rh / 2);
4003                let mut ay = [0u8; 256];
4004                let mut by_ = [0u8; 256];
4005                let mut ac = [[0u8; 64]; 2];
4006                let mut bc = [[0u8; 64]; 2];
4007                if u0 {
4008                    mc_luma(&refs[0].y, self.cw, ch, lx, ly, rw, rh, mv0.0, mv0.1, &mut ay);
4009                    mc_chroma(&refs[0].u, self.ccw, cch, cx, cy, cw2, ch2, mv0.0, mv0.1, &mut ac[0]);
4010                    mc_chroma(&refs[0].v, self.ccw, cch, cx, cy, cw2, ch2, mv0.0, mv0.1, &mut ac[1]);
4011                }
4012                if u1 {
4013                    mc_luma(&b.l1.y, self.cw, ch, lx, ly, rw, rh, mv1.0, mv1.1, &mut by_);
4014                    mc_chroma(&b.l1.u, self.ccw, cch, cx, cy, cw2, ch2, mv1.0, mv1.1, &mut bc[0]);
4015                    mc_chroma(&b.l1.v, self.ccw, cch, cx, cy, cw2, ch2, mv1.0, mv1.1, &mut bc[1]);
4016                }
4017                for r in 0..rh {
4018                    for c in 0..rw {
4019                        let d = (ry + r) * 16 + rx + c;
4020                        let sidx = r * rw + c;
4021                        pred_y[d] = match (u0, u1) {
4022                            (true, true) => bi_blend(ay[sidx] as i32, by_[sidx] as i32, self.bi_w),
4023                            (true, false) => ay[sidx],
4024                            _ => by_[sidx],
4025                        };
4026                    }
4027                }
4028                for cc in 0..2 {
4029                    for r in 0..ch2 {
4030                        for c in 0..cw2 {
4031                            let d = (ry / 2 + r) * 8 + rx / 2 + c;
4032                            let sidx = r * cw2 + c;
4033                            c_pred[cc][d] = match (u0, u1) {
4034                                (true, true) => bi_blend(ac[cc][sidx] as i32, bc[cc][sidx] as i32, self.bi_w),
4035                                (true, false) => ac[cc][sidx],
4036                                _ => bc[cc][sidx],
4037                            };
4038                        }
4039                    }
4040                }
4041                // Commit this partition before the next one predicts.
4042                let (cmv0, cr0) = (if u0 { mv0 } else { (0, 0) }, if u0 { 0 } else { -1 });
4043                let (cmv1, cr1) = (if u1 { mv1 } else { (0, 0) }, if u1 { 0 } else { -1 });
4044                for by2 in ry / 4..(ry + rh) / 4 {
4045                    let d = (mb_y * 4 + by2) * w4 + mb_x * 4 + rx / 4;
4046                    let n4 = rw / 4;
4047                    self.inter_y[d..d + n4].fill(true);
4048                    self.coded_y[d..d + n4].fill(true);
4049                    self.mv_y[d..d + n4].fill(cmv0);
4050                    self.ref_idx_y[d..d + n4].fill(cr0);
4051                    self.mv1_y[d..d + n4].fill(cmv1);
4052                    self.ref_idx1_y[d..d + n4].fill(cr1);
4053                }
4054            }
4055            // Serialise LIST-major: all L0 mvds, then all L1.
4056            for list in 0..2 {
4057                for part in 0..2 {
4058                    let pred = b.parts2[part].0;
4059                    let used = if list == 0 { pred == 1 || pred == 3 } else { pred == 2 || pred == 3 };
4060                    if used {
4061                        mvds[n_mvd] = pm[part][list];
4062                        n_mvd += 1;
4063                    }
4064                }
4065            }
4066        } else if let Some(b) = bspec.filter(|b| b.dir == 0) {
4067            // ---- B_Direct_16x16 (mb_type 0): spatial-direct prediction, no mvd ----
4068            let (dp, dc, motion) = self.b_direct(&refs[0], b.l1, mb_x, mb_y);
4069            pred_y = dp;
4070            c_pred = dc;
4071            self.commit_direct_motion(mb_x, mb_y, &motion);
4072        } else if let Some(b) = bspec {
4073            // ---- B 16×16 prediction: List-0 / List-1 / Bi ----
4074            let use0 = b.dir == 1 || b.dir == 3;
4075            let use1 = b.dir == 2 || b.dir == 3;
4076            let (lx, ly) = (mb_x * 16, mb_y * 16);
4077            let (cx, cy) = (mb_x * 8, mb_y * 8);
4078            let (pbx, pby) = ((mb_x * 4) as isize, (mb_y * 4) as isize);
4079            // Per-list `mvd` against the median predictor over that list's neighbors.
4080            if use0 {
4081                let [a, c0, c1] = self.mv_neighbors_block_list(pbx, pby, 4, 0);
4082                let p = predict_partition_mv(0, 0, a, c0, c1, 0);
4083                mvds[n_mvd] = (b.mv0.0 - p.0, b.mv0.1 - p.1);
4084                n_mvd += 1;
4085            }
4086            if use1 {
4087                let [a, c0, c1] = self.mv_neighbors_block_list(pbx, pby, 4, 1);
4088                let p = predict_partition_mv(0, 0, a, c0, c1, 0);
4089                mvds[n_mvd] = (b.mv1.0 - p.0, b.mv1.1 - p.1);
4090                n_mvd += 1;
4091            }
4092            // Motion compensation. L0/L1 write straight into pred; Bi averages
4093            // (p+q+1)>>1 — the decoder's `b_mc` blend with weighted_bipred_idc=0.
4094            let mut a_y = [0u8; 256];
4095            let mut b_y = [0u8; 256];
4096            let mut a_c = [[0u8; 64]; 2];
4097            let mut b_c = [[0u8; 64]; 2];
4098            if use0 {
4099                mc_luma(&refs[0].y, self.cw, ch, lx, ly, 16, 16, b.mv0.0, b.mv0.1, &mut a_y);
4100                mc_chroma(&refs[0].u, self.ccw, cch, cx, cy, 8, 8, b.mv0.0, b.mv0.1, &mut a_c[0]);
4101                mc_chroma(&refs[0].v, self.ccw, cch, cx, cy, 8, 8, b.mv0.0, b.mv0.1, &mut a_c[1]);
4102            }
4103            if use1 {
4104                mc_luma(&b.l1.y, self.cw, ch, lx, ly, 16, 16, b.mv1.0, b.mv1.1, &mut b_y);
4105                mc_chroma(&b.l1.u, self.ccw, cch, cx, cy, 8, 8, b.mv1.0, b.mv1.1, &mut b_c[0]);
4106                mc_chroma(&b.l1.v, self.ccw, cch, cx, cy, 8, 8, b.mv1.0, b.mv1.1, &mut b_c[1]);
4107            }
4108            match (use0, use1) {
4109                (true, true) => {
4110                    for i in 0..256 {
4111                        pred_y[i] = bi_blend(a_y[i] as i32, b_y[i] as i32, self.bi_w);
4112                    }
4113                    for c in 0..2 {
4114                        for i in 0..64 {
4115                            c_pred[c][i] = bi_blend(a_c[c][i] as i32, b_c[c][i] as i32, self.bi_w);
4116                        }
4117                    }
4118                }
4119                (true, false) => {
4120                    pred_y = a_y;
4121                    c_pred = a_c;
4122                }
4123                _ => {
4124                    pred_y = b_y;
4125                    c_pred = b_c;
4126                }
4127            }
4128            // Commit per-list motion so later MBs' per-list predictors see it.
4129            // Row fills (E1, 11.16): every value is CONSTANT across the MB.
4130            let (cmv0, cr0) = (if use0 { b.mv0 } else { (0, 0) }, if use0 { 0 } else { -1 });
4131            let (cmv1, cr1) = (if use1 { b.mv1 } else { (0, 0) }, if use1 { 0 } else { -1 });
4132            for by in 0..4 {
4133                let d = (mb_y * 4 + by) * w4 + mb_x * 4;
4134                self.inter_y[d..d + 4].fill(true);
4135                self.coded_y[d..d + 4].fill(true);
4136                self.mv_y[d..d + 4].fill(cmv0);
4137                self.ref_idx_y[d..d + 4].fill(cr0);
4138                self.mv1_y[d..d + 4].fill(cmv1);
4139                self.ref_idx1_y[d..d + 4].fill(cr1);
4140            }
4141        } else if mode == 3 && sub_types != [0u8; 4] {
4142            // ---- P_8x8 with sub-partitions (Great Gate P3.3) ------------------
4143            // Mirrors the decoder's `decode_p8x8` EXACTLY: per sub-partition in
4144            // decode order, median-predict from the COMMITTED grid (plain
4145            // `predict_mv` -- the 16x8/8x16 directional rules do not apply to
4146            // sub-partitions), derive the mvd, commit, then motion-compensate.
4147            // `parts` is FLAT in decode order; `ref_idx` is per 8x8 (spec: its
4148            // sub-partitions share it).
4149            let mut k = 0usize;
4150            for p8 in 0..4usize {
4151                let (b8x, b8y) = ((p8 % 2) * 8, (p8 / 2) * 8);
4152                plan_refs[p8] = parts[k].0;
4153                for &(srx, sry, srw, srh) in sub_mb_partitions_p(sub_types[p8]) {
4154                    let (refi, mv) = parts[k];
4155                    debug_assert_eq!(refi, plan_refs[p8], "ref_idx_l0 is per 8x8");
4156                    k += 1;
4157                    let (px, py) = (b8x + srx, b8y + sry);
4158                    let (pbx, pby) =
4159                        ((mb_x * 4 + px / 4) as isize, (mb_y * 4 + py / 4) as isize);
4160                    let [a, b, c] = self.mv_neighbors_block(pbx, pby, (srw / 4) as isize);
4161                    let pmv = predict_mv(a, b, c, refi);
4162                    mvds[n_mvd] = (mv.0 - pmv.0, mv.1 - pmv.1);
4163                    n_mvd += 1;
4164                    // Commit BEFORE the next sub-partition predicts (chaining --
4165                    // exactly the decoder's order).
4166                    for by in py / 4..(py + srh) / 4 {
4167                        for bx in px / 4..(px + srw) / 4 {
4168                            let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
4169                            self.mv_y[idx] = mv;
4170                            self.inter_y[idx] = true;
4171                            self.ref_idx_y[idx] = refi;
4172                            self.coded_y[idx] = true;
4173                        }
4174                    }
4175                    // Luma + chroma MC into the sub-region (parametric kernels --
4176                    // 4-wide takes the scalar fall-through; the 4-wide kernel
4177                    // brick is the recorded default-on precondition).
4178                    let reference = &refs[refi as usize];
4179                    let mut tmp = [0u8; 256];
4180                    mc_luma(&reference.y, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, srw, srh, mv.0, mv.1, &mut tmp);
4181                    for dy in 0..srh {
4182                        pred_y[(py + dy) * 16 + px..][..srw].copy_from_slice(&tmp[dy * srw..][..srw]);
4183                    }
4184                    self.wp_luma(refi, &mut pred_y, px, py, srw, srh);
4185                    let (crx, cry, crw, crh) = (px / 2, py / 2, srw / 2, srh / 2);
4186                    for cc in 0..2 {
4187                        let rc = if cc == 0 { &reference.u } else { &reference.v };
4188                        let mut tc = [0u8; 64];
4189                        mc_chroma(rc, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv.0, mv.1, &mut tc);
4190                        for dy in 0..crh {
4191                            c_pred[cc][(cry + dy) * 8 + crx..][..crw].copy_from_slice(&tc[dy * crw..][..crw]);
4192                        }
4193                    }
4194                }
4195            }
4196        } else {
4197        for (part, &(rx, ry, rw, rh)) in inter_partitions(mode).iter().enumerate() {
4198            let (refi, mv) = parts[part];
4199            plan_refs[part] = refi; // per-partition ref_idx_l0 → carried to the CABAC emit
4200            let reference = &refs[refi as usize];
4201            let (pbx, pby) = ((mb_x * 4 + rx / 4) as isize, (mb_y * 4 + ry / 4) as isize);
4202            let [a, b, c] = self.mv_neighbors_block(pbx, pby, (rw / 4) as isize);
4203            let pmv = predict_partition_mv(mode, part, a, b, c, refi);
4204            mvds[n_mvd] = (mv.0 - pmv.0, mv.1 - pmv.1);
4205            n_mvd += 1;
4206            // Commit this partition's motion so later partitions can predict from it.
4207            for by in ry / 4..ry / 4 + rh / 4 {
4208                for bx in rx / 4..rx / 4 + rw / 4 {
4209                    let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
4210                    self.mv_y[idx] = mv;
4211                    self.inter_y[idx] = true;
4212                    self.ref_idx_y[idx] = refi;
4213                    self.coded_y[idx] = true;
4214                }
4215            }
4216            // Luma MC into the partition's sub-region. A full-MB (16×16) partition is
4217            // the whole `pred_y`, so MC straight into it — no scratch + repack copy.
4218            if rw == 16 && rh == 16 {
4219                self.mc_luma_cached(reference, mb_x * 16, mb_y * 16, 16, 16, mv.0, mv.1, &mut pred_y);
4220            } else {
4221                let mut tmp = [0u8; 256];
4222                self.mc_luma_cached(reference, mb_x * 16 + rx, mb_y * 16 + ry, rw, rh, mv.0, mv.1, &mut tmp);
4223                // H-17: const-width row copies (see the v2 twin).
4224                if rw == 8 {
4225                    for dy in 0..rh {
4226                        pred_y[(ry + dy) * 16 + rx..][..8].copy_from_slice(&tmp[dy * 8..][..8]);
4227                    }
4228                } else {
4229                    for dy in 0..rh {
4230                        pred_y[(ry + dy) * 16 + rx..][..16].copy_from_slice(&tmp[dy * 16..][..16]);
4231                    }
4232                }
4233            }
4234            self.wp_luma(refi, &mut pred_y, rx, ry, rw, rh);
4235            // Chroma MC (half-resolution region); 8×8 = the whole plane prediction.
4236            let (crx, cry, crw, crh) = (rx / 2, ry / 2, rw / 2, rh / 2);
4237            for cc in 0..2 {
4238                let rc = if cc == 0 { &reference.u } else { &reference.v };
4239                if crw == 8 && crh == 8 {
4240                    mc_chroma(rc, self.ccw, cch, mb_x * 8, mb_y * 8, 8, 8, mv.0, mv.1, &mut c_pred[cc]);
4241                } else {
4242                    let mut tc = [0u8; 64];
4243                    mc_chroma(rc, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv.0, mv.1, &mut tc);
4244                    // H-17: const-width row copies (see the v2 twin).
4245                    if crw == 4 {
4246                        for dy in 0..crh {
4247                            c_pred[cc][(cry + dy) * 8 + crx..][..4].copy_from_slice(&tc[dy * 4..][..4]);
4248                        }
4249                    } else {
4250                        for dy in 0..crh {
4251                            c_pred[cc][(cry + dy) * 8 + crx..][..8].copy_from_slice(&tc[dy * 8..][..8]);
4252                        }
4253                    }
4254                }
4255            }
4256        }
4257        } // end P per-partition formation (else of the B branch)
4258
4259        // ---- luma residual + quantization ----
4260        let mut q_blocks = [[0i32; 16]; 16]; // raster, levels
4261        let mut cbp_luma = 0u32;
4262        // Inter 8x8-transform candidate (High profile, scalar path). Filled by the
4263        // per-MB 4x4-vs-8x8 RD below; false/zero means the 4x4 residual is used.
4264        #[allow(unused_mut)]
4265        let mut t8x8 = false;
4266        #[allow(unused_mut)]
4267        let mut q8 = [[0i32; 64]; 4];
4268        drop(_g_mc);
4269        let _g_tq = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncTq);
4270        #[cfg(accel)]
4271        {
4272            // openh264 `WelsDctFourT4_sse2` (fused residual+DCT) → i16, then
4273            // `WelsQuantFour4x4_sse2` in place — the whole DCT→quant chain stays in i16,
4274            // no i32 round-trip. Quant is openh264's structure carrying OUR deadzone
4275            // (`quant_dz_ff` + `QUANT_MF_OH`), so levels are bit-identical to `quantize`.
4276            let mut dctw = AlignedDct([0i16; 256]);
4277            let dct = &mut dctw.0;
4278            let base = mb_y * 16 * self.cw + mb_x * 16;
4279            for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
4280                rusty_h264_accel::dct_four_t4(
4281                    &mut dct[qi * 64..qi * 64 + 64],
4282                    &sy[base + qy * self.cw + qx..],
4283                    self.cw,
4284                    &pred_y[qy * 16 + qx..],
4285                    16,
4286                );
4287            }
4288            if self.rdoq_strength > 0.0 {
4289                // Trellis for inter (Great Gate P2 — mirrors the I16 site): scalar
4290                // RDOQ from the asm DCT output instead of the asm hard quantizer.
4291                // Inter codes DC in the 4×4 (first=0) and uses the /6 deadzone —
4292                // exactly the scalar arm's `rdoq(&coeffs, qp, 6, strength, 0)`.
4293                for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4294                    let coeffs: [i32; 16] = std::array::from_fn(|i| dct[blk * 16 + i] as i32);
4295                    let q = rdoq(&coeffs, qp, 6, self.rdoq_strength, 0);
4296                    if q.iter().any(|&v| v != 0) {
4297                        cbp_luma |= 1 << (blk / 4);
4298                    }
4299                    q_blocks[lby * 4 + lbx] = q;
4300                }
4301            } else {
4302            let ff = rusty_h264_common::transform::quant_dz_ff(qp, 6);
4303            let mf = &rusty_h264_common::transform::QUANT_MF_OH[qp as usize];
4304            for qi in 0..4 {
4305                rusty_h264_accel::quant_four_4x4(&mut dct[qi * 64..qi * 64 + 64], &ff, mf);
4306            }
4307            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4308                let mut nz = false;
4309                for i in 0..16 {
4310                    let v = dct[blk * 16 + i] as i32;
4311                    q_blocks[lby * 4 + lbx][i] = v;
4312                    nz |= v != 0;
4313                }
4314                if nz {
4315                    cbp_luma |= 1 << (blk / 4);
4316                }
4317            }
4318            } // end hard-quantize arm (rdoq_strength == 0)
4319        }
4320        #[cfg(not(accel))]
4321        {
4322            // Scalar/`wide`: gather all 16 residual blocks, batched forward-DCT, quantize.
4323            let mut res_blocks = [[0i32; 16]; 16]; // raster
4324            for lby in 0..4 {
4325                for lbx in 0..4 {
4326                    let b = &mut res_blocks[lby * 4 + lbx];
4327                    for dy in 0..4 {
4328                        let row = &sy[(mb_y * 16 + lby * 4 + dy) * self.cw + mb_x * 16 + lbx * 4..][..4];
4329                        for dx in 0..4 {
4330                            b[dy * 4 + dx] = row[dx] as i32
4331                                - pred_y[(lby * 4 + dy) * 16 + (lbx * 4 + dx)] as i32;
4332                        }
4333                    }
4334                }
4335            }
4336            let mut coeffs = [[0i32; 16]; 16];
4337            forward_dct_blocks(&res_blocks, &mut coeffs);
4338            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4339                let q = rdoq(&coeffs[lby * 4 + lbx], qp, 6, self.rdoq_strength, 0);
4340                if q.iter().any(|&v| v != 0) {
4341                    cbp_luma |= 1 << (blk / 4);
4342                }
4343                q_blocks[lby * 4 + lbx] = q;
4344            }
4345        }
4346
4347        // Per-MB transform-size RD (runs in scalar AND accel builds — q_blocks +
4348        // cbp_luma are filled by whichever quant path ran; the 8x8 candidate + its
4349        // recon are pure Rust). One 8x8 DCT per 8x8 block vs four 4x4s.
4350        // Content-adaptive by construction — the winner is chosen per MB.
4351        //
4352        // `sub_types == [0;4]` IS the spec's `noSubMbPartSizeLessThan8x8Flag`
4353        // (7.3.5): transform_size_8x8_flag is FORBIDDEN when any sub-partition is
4354        // smaller than 8x8. The comment this replaces asserted "every inter
4355        // partition here is >= 8x8", which was true when it was written and stopped
4356        // being true when sub-8x8 shipped -- `sub_types` is a parameter of this very
4357        // function. A stale invariant in a comment is not a guard.
4358        {
4359            // `allow_t8` is the spec's condition for transform_size_8x8_flag being
4360            // PERMITTED at all, evaluated here rather than at emit time: if the plan
4361            // picked 8x8 for a macroblock that may not signal it, the flag would be
4362            // suppressed while our reconstruction still used the 8x8 transform --
4363            // encoder/decoder drift, which our own conformance gate cannot see.
4364            //   * `sub_types == [0;4]` is noSubMbPartSizeLessThan8x8Flag.
4365            //   * B_Direct_16x16 is permitted since direct_8x8_inference_flag = 1
4366            //     in our SPS (its direct partitions count as 8×8).
4367            let allow_t8 = sub_types == [0u8; 4];
4368            if self.t8_pick && self.inter8x8 != 0 && allow_t8 {
4369                let lambda =
4370                    0.85 * self.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
4371                let mut ssd4 = 0i64;
4372                let mut rate4 = 0f64;
4373                for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4374                    let mut predb = [0i32; 16];
4375                    for dy in 0..4 {
4376                        for dx in 0..4 {
4377                            predb[dy * 4 + dx] =
4378                                pred_y[(lby * 4 + dy) * 16 + (lbx * 4 + dx)] as i32;
4379                        }
4380                    }
4381                    let deq = dequantize(&q_blocks[lby * 4 + lbx], qp);
4382                    let s = reconstruct_4x4(&deq, &predb);
4383                    for dy in 0..4 {
4384                        for dx in 0..4 {
4385                            let sx = mb_x * 16 + lbx * 4 + dx;
4386                            let syy = mb_y * 16 + lby * 4 + dy;
4387                            let d = s[dy * 4 + dx] as i64 - sy[syy * self.cw + sx] as i64;
4388                            ssd4 += d * d;
4389                        }
4390                    }
4391                    for &l in &q_blocks[lby * 4 + lbx] {
4392                        if l != 0 {
4393                            rate4 += rdoq_rate((l as i64).abs());
4394                        }
4395                    }
4396                }
4397                let (q8c, cbp8, rate8, _rec8, ssd8) =
4398                    plan_inter8_luma(sy, self.cw, mb_x, mb_y, &pred_y, qp);
4399                // Both candidates priced with the SAME level-aware rate (Σ rdoq_rate);
4400                // `inter8_pen` is an optional extra bias (default 0) on the 8x8 flag.
4401                let j4 = ssd4 as f64 + lambda * (rate4 + 16.0);
4402                let j8 = ssd8 as f64 + lambda * (rate8 + 16.0 + self.inter8_pen as f64);
4403                if cbp8 > 0 && j8 < j4 {
4404                    t8x8 = true;
4405                    cbp_luma = cbp8;
4406                    q8 = q8c;
4407                }
4408            }
4409        }
4410
4411        // ---- chroma residual (prediction already built per partition) ----
4412        let mut c_dc_levels = [[0i32; 4]; 2];
4413        let mut c_recon_dc = [[0i32; 4]; 2];
4414        let mut c_q = [[[0i32; 16]; 4]; 2];
4415        let (mut any_ac, mut any_dc) = (false, false);
4416        for c in 0..2 {
4417            let src = if c == 0 { su } else { sv };
4418            // Fast path: one dct_four_t4 covers the whole 8x8 chroma region (all 4
4419            // blocks, residual+DCT fused straight from the planes); block b's pre-quant
4420            // DC is dct[b*16] (quad z-scan == 2x2 raster); quant_four_4x4 with our
4421            // FF/MF is bit-identical to scalar `quantize`. Same pairing the P_Skip
4422            // free-check proved byte-identical over the corpus.
4423            #[cfg(accel)]
4424            let (mut dc2x2, applied) = if self.rdoq_strength > 0.0 {
4425                // RDOQ fork — the SAME fork every other accel quant site
4426                // carries (inter luma, I16 AC, intra chroma AC). The fused
4427                // dct+quant kernel HARD-quantizes, so under a non-zero trellis
4428                // strength it must yield to the scalar twin below. Without
4429                // this, accel and scalar builds emitted DIFFERENT bitstreams
4430                // for inter chroma AC the day `cabac_rdoq_b` shipped
4431                // default-on — the one path where the accel/scalar
4432                // byte-identity invariant silently did not hold.
4433                ([0i32; 4], false)
4434            } else {
4435                #[repr(align(16))]
4436                struct A([i16; 64]);
4437                let mut dct = A([0i16; 64]);
4438                rusty_h264_accel::dct_four_t4(
4439                    &mut dct.0,
4440                    &src[(mb_y * 8) * self.ccw + mb_x * 8..],
4441                    self.ccw,
4442                    &c_pred[c],
4443                    8,
4444                );
4445                let dc = [
4446                    dct.0[0] as i32,
4447                    dct.0[16] as i32,
4448                    dct.0[32] as i32,
4449                    dct.0[48] as i32,
4450                ];
4451                let ffc = rusty_h264_common::transform::quant_dz_ff(qpc, 6);
4452                let mfc = &rusty_h264_common::transform::QUANT_MF_OH[qpc as usize];
4453                rusty_h264_accel::quant_four_4x4(&mut dct.0, &ffc, mfc);
4454                for i in 0..4 {
4455                    let q = &mut c_q[c][i];
4456                    q[0] = 0;
4457                    for j in 1..16 {
4458                        let v = dct.0[i * 16 + j] as i32;
4459                        q[j] = v;
4460                        if v != 0 {
4461                            any_ac = true;
4462                        }
4463                    }
4464                }
4465                (dc, true)
4466            };
4467            #[cfg(not(accel))]
4468            let (mut dc2x2, applied) = ([0i32; 4], false);
4469            if !applied {
4470                // Scalar/`wide` twin: gather, batch forward DCT, quantize per block.
4471                let mut res_blocks = [[0i32; 16]; 4];
4472                for by in 0..2 {
4473                    for bx in 0..2 {
4474                        let b = &mut res_blocks[by * 2 + bx];
4475                        for dy in 0..4 {
4476                            let row = &src[(mb_y * 8 + by * 4 + dy) * self.ccw + mb_x * 8 + bx * 4..][..4];
4477                            for dx in 0..4 {
4478                                b[dy * 4 + dx] = row[dx] as i32
4479                                    - c_pred[c][(by * 4 + dy) * 8 + (bx * 4 + dx)] as i32;
4480                            }
4481                        }
4482                    }
4483                }
4484                let mut coeffs = [[0i32; 16]; 4];
4485                forward_dct_blocks(&res_blocks, &mut coeffs);
4486                for i in 0..4 {
4487                    dc2x2[i] = coeffs[i][0];
4488                    let mut q = rdoq(&coeffs[i], qpc, 6, self.rdoq_strength, 1);
4489                    q[0] = 0;
4490                    if q[1..].iter().any(|&v| v != 0) {
4491                        any_ac = true;
4492                    }
4493                    c_q[c][i] = q;
4494                }
4495            }
4496            let dl = forward_quant_chroma_dc(&dc2x2, qpc, false);
4497            if dl.iter().any(|&v| v != 0) {
4498                any_dc = true;
4499            }
4500            c_recon_dc[c] = inverse_quant_chroma_dc(&dl, qpc);
4501            c_dc_levels[c] = dl;
4502        }
4503        let cbp_chroma: u32 = if any_ac { 2 } else if any_dc { 1 } else { 0 };
4504        let cbp = cbp_luma | (cbp_chroma << 4);
4505
4506        drop(_g_tq);
4507        let _g_rec = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::SkipRecon);
4508        // ---- reconstruction (luma) ----
4509        #[cfg(accel)]
4510        if t8x8 {
4511            // 8x8-transform recon is pure Rust (no asm 8x8 kernels yet); inverse of
4512            // the decoder's t8x8 inter path. Same code as the scalar branch below.
4513            let weight = [16i32; 64];
4514            for b8 in 0..4usize {
4515                let (b8x, b8y) = (b8 % 2, b8 / 2);
4516                let res_r = inverse_quant_8x8(&q8[b8], qp, &weight);
4517                let predb: [i32; 64] = std::array::from_fn(|i| {
4518                    pred_y[(b8y * 8 + i / 8) * 16 + (b8x * 8 + i % 8)] as i32
4519                });
4520                let recon = add_residual_8x8(&res_r, &predb);
4521                for dy in 0..8 {
4522                    let d = (mb_y * 16 + b8y * 8 + dy) * self.cw + mb_x * 16 + b8x * 8;
4523                    self.rec_y[d..d + 8].copy_from_slice(&recon[dy * 8..dy * 8 + 8]);
4524                }
4525            }
4526        } else {
4527            // Dequantize all 16 blocks into the 4-quadrant int16 layout (16-byte
4528            // aligned — the kernel uses movdqa coeff loads), then inverse-DCT + add
4529            // prediction + clip per quadrant via openh264. The inverse butterfly +
4530            // (x+32)>>6 is bit-identical to reconstruct_4x4 (verified in accel).
4531            // An 8x8 quad whose cbp bit is clear has ZERO residual: reconstruction
4532            // IS the prediction (the decoder's own uncoded-region fast path) — a row
4533            // copy replaces dequant + convert + idct for that quad. Byte-identical:
4534            // idct of an all-zero block adds (0+32)>>6 = 0 to pred, clip is identity.
4535            #[repr(align(16))]
4536            struct Align16([i16; 64]);
4537            let mut dct_in = Align16([0i16; 64]);
4538            let base = mb_y * 16 * self.cw + mb_x * 16;
4539            for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
4540                let rec_off = base + qy * self.cw + qx;
4541                if cbp_luma & (1 << qi) == 0 {
4542                    for r in 0..8 {
4543                        let (dsti, srci) = (rec_off + r * self.cw, (qy + r) * 16 + qx);
4544                        self.rec_y[dsti..dsti + 8].copy_from_slice(&pred_y[srci..srci + 8]);
4545                    }
4546                    continue;
4547                }
4548                for k in 0..4 {
4549                    let blk = qi * 4 + k;
4550                    let (lbx, lby) = LUMA_4X4_SCAN_XY[blk];
4551                    let deq = dequantize(&q_blocks[lby * 4 + lbx], qp);
4552                    for i in 0..16 {
4553                        dct_in.0[k * 16 + i] = deq[i] as i16;
4554                    }
4555                }
4556                rusty_h264_accel::idct_four_t4_rec(
4557                    &mut self.rec_y[rec_off..],
4558                    self.cw,
4559                    &pred_y[qy * 16 + qx..],
4560                    16,
4561                    &dct_in.0,
4562                );
4563            }
4564        }
4565        #[cfg(not(accel))]
4566        if t8x8 {
4567            // 8x8-transform reconstruction (inverse of the decoder's t8x8 inter path).
4568            let weight = [16i32; 64];
4569            for b8 in 0..4usize {
4570                let (b8x, b8y) = (b8 % 2, b8 / 2);
4571                let res_r = inverse_quant_8x8(&q8[b8], qp, &weight);
4572                let predb: [i32; 64] = std::array::from_fn(|i| {
4573                    pred_y[(b8y * 8 + i / 8) * 16 + (b8x * 8 + i % 8)] as i32
4574                });
4575                let recon = add_residual_8x8(&res_r, &predb);
4576                for dy in 0..8 {
4577                    let d = (mb_y * 16 + b8y * 8 + dy) * self.cw + mb_x * 16 + b8x * 8;
4578                    self.rec_y[d..d + 8].copy_from_slice(&recon[dy * 8..dy * 8 + 8]);
4579                }
4580            }
4581        } else {
4582            for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4583                let deq = dequantize(&q_blocks[lby * 4 + lbx], qp);
4584                // Fused recon straight from the u8 prediction (E1 r2; same
4585                // transplant as plan_i4x4's) — no i32 predb, no temp, no store.
4586                reconstruct_4x4_into(
4587                    &deq,
4588                    &pred_y,
4589                    (lby * 4) * 16 + lbx * 4,
4590                    16,
4591                    &mut self.rec_y,
4592                    (mb_y * 16 + lby * 4) * self.cw + mb_x * 16 + lbx * 4,
4593                    self.cw,
4594                );
4595            }
4596        }
4597        for c in 0..2 {
4598            // Fast path: dequantize into the quad i16 layout (raster == the kernel's
4599            // z-order for a 2x2) with the Hadamard DC injected, then ONE
4600            // idct+add-pred+clip kernel writes the 8x8 straight into the plane —
4601            // bit-identical to the scalar tail below (verified kernel pairing).
4602            #[cfg(accel)]
4603            {
4604                let base = (mb_y * 8) * self.ccw + mb_x * 8;
4605                let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
4606                if cbp_chroma == 0 {
4607                    // No chroma residual at all: recon = prediction (row copies).
4608                    for r in 0..8 {
4609                        let dsti = base + r * self.ccw;
4610                        plane[dsti..dsti + 8].copy_from_slice(&c_pred[c][r * 8..r * 8 + 8]);
4611                    }
4612                } else {
4613                    #[repr(align(16))]
4614                    struct A([i16; 64]);
4615                    let mut d = A([0i16; 64]);
4616                    for i in 0..4 {
4617                        let deq = dequantize(&c_q[c][i], qpc);
4618                        for j in 0..16 {
4619                            d.0[i * 16 + j] = deq[j] as i16;
4620                        }
4621                        d.0[i * 16] = c_recon_dc[c][i] as i16;
4622                    }
4623                    rusty_h264_accel::idct_four_t4_rec(&mut plane[base..], self.ccw, &c_pred[c], 8, &d.0);
4624                }
4625            }
4626            #[cfg(not(accel))]
4627            {
4628                // Dequantize the 4 blocks (raster, DC overridden by the 2×2-Hadamard
4629                // recon), then batch the inverse DCT and share the add+clip tail.
4630                let mut deq_blocks = [[0i32; 16]; 4];
4631                for i in 0..4 {
4632                    deq_blocks[i] = dequantize(&c_q[c][i], qpc);
4633                    deq_blocks[i][0] = c_recon_dc[c][i];
4634                }
4635                let mut res = [[0i32; 16]; 4];
4636                inverse_dct_blocks(&deq_blocks, &mut res);
4637                let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
4638                for by in 0..2 {
4639                    for bx in 0..2 {
4640                        let mut predb = [0i32; 16];
4641                        for dy in 0..4 {
4642                            for dx in 0..4 {
4643                                predb[dy * 4 + dx] = c_pred[c][(by * 4 + dy) * 8 + (bx * 4 + dx)] as i32;
4644                            }
4645                        }
4646                        let s = add_residual_4x4(&res[by * 2 + bx], &predb);
4647                        store(plane, self.ccw, mb_x * 8 + bx * 4, mb_y * 8 + by * 4, &s);
4648                    }
4649                }
4650            }
4651        }
4652        // MV grid + coded flags were set per partition; mark modes as DC.
4653        for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4654            self.modes_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 2;
4655        }
4656        InterPlan { mvds, plan_refs, n_mvd, cbp, q_blocks, c_dc_levels, c_q, t8x8, q8, sub_types }
4657    }
4658
4659    /// Code one planned inter macroblock as CAVLC (the original `encode_inter_mb_v1_b`
4660    /// tail). `plan_inter_mb` already committed the reconstruction + motion grids.
4661    #[allow(clippy::too_many_arguments)]
4662    fn encode_inter_mb_v1_b(
4663        &mut self,
4664        w: &mut BitWriter,
4665        refs: &[crate::RefFrame],
4666        sy: &[u8],
4667        su: &[u8],
4668        sv: &[u8],
4669        mb_x: usize,
4670        mb_y: usize,
4671        mode: u8,
4672        parts: &[(i32, (i32, i32))],
4673        bspec: Option<BInter>,
4674    ) {
4675        let plan = self.plan_inter_mb(refs, sy, su, sv, mb_x, mb_y, mode, parts, bspec, [0u8; 4]);
4676        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncEmit);
4677        self.emit_inter_cavlc(w, refs.len(), mb_x, mb_y, mode, parts, bspec, &plan);
4678    }
4679
4680    /// CAVLC entropy coding for a planned inter macroblock.
4681    #[allow(clippy::too_many_arguments)]
4682    fn emit_inter_cavlc(
4683        &mut self,
4684        w: &mut BitWriter,
4685        num_refs: usize,
4686        mb_x: usize,
4687        mb_y: usize,
4688        mode: u8,
4689        parts: &[(i32, (i32, i32))],
4690        bspec: Option<BInter>,
4691        plan: &InterPlan,
4692    ) {
4693        let w4 = self.mb_w * 4;
4694        let (cbp, cbp_luma, cbp_chroma) = (plan.cbp, plan.cbp & 15, plan.cbp >> 4);
4695        // Same rule as the CABAC path (and as `plan_inter_mb`'s `allow_t8`):
4696        // with direct_8x8_inference_flag = 1 every shape we emit (incl.
4697        // B_Direct_16x16) may carry transform_size_8x8_flag.
4698        let allow8 = true;
4699        let _ = &bspec; // shape still consumed below for mb_type
4700        // mb_pred order (spec 7.3.5.1): mb_type, then all ref_idx_l0, then all mvd_l0.
4701        // B-slice mb_type = the B direction 1/2/3; P-slice uses `mode`. ref_idx coded
4702        // only when >1 reference is active.
4703        w.write_ue(bspec.map_or(mode as u32, |b| b.dir as u32)); // inter mb_type
4704        // P_8x8 (mb_type 3): sub_mb_type per 8×8 (spec 7.3.5.2, before ref_idx/mvd).
4705        // 0 = P_L0_8x8 (one MV) — the only shape emitted for now.
4706        if mode == 3 {
4707            for _ in 0..4 {
4708                w.write_ue(0);
4709            }
4710        }
4711        if num_refs > 1 {
4712            for &(refi, _) in parts {
4713                write_ref_idx(w, refi, num_refs);
4714            }
4715        }
4716        for &(mvdx, mvdy) in &plan.mvds[..plan.n_mvd] {
4717            w.write_se(mvdx);
4718            w.write_se(mvdy);
4719        }
4720        write_cbp_inter(w, cbp);
4721        // transform_size_8x8_flag: after cbp, before mb_qp_delta, present only when
4722        // luma has coefficients, the 8x8 transform is enabled, and the macroblock is
4723        // ALLOWED to signal it. Omitting `allow8` wrote the flag on B_Direct_16x16
4724        // macroblocks, which is exactly why CAVLC B + 8x8 produced an invalid slice
4725        // ("mb_type N in B slice too large") -- the defect the old blanket refusal
4726        // in `lib.rs` was masking rather than the missing feature it claimed.
4727        if cbp_luma > 0 && self.transform_8x8 && allow8 {
4728            w.write_bit(plan.t8x8);
4729        }
4730        if cbp != 0 {
4731            w.write_se(self.qp_delta()); // mb_qp_delta (AQ per-MB QPy)
4732        }
4733        self.nnz_cache_load(mb_x, mb_y);
4734        if plan.t8x8 {
4735            // 8x8 residual: four interleaved 4x4 CAVLC sub-blocks per 8x8 block
4736            // (coeff k of sub s -> 8x8 scan position 4k+s), the inverse of the
4737            // decoder's t8x8 inter luma read. nnz set per 4x4 sub-block.
4738            for b8 in 0..4usize {
4739                let (b8x, b8y) = (b8 % 2, b8 / 2);
4740                let scan8 = scan_8x8_fwd(&plan.q8[b8]);
4741                for sub in 0..4usize {
4742                    let (cx, cy) = (b8x * 2 + sub % 2, b8y * 2 + sub / 2);
4743                    let (bx, by) = (mb_x * 4 + cx, mb_y * 4 + cy);
4744                    let total = if cbp_luma & (1 << b8) != 0 {
4745                        let nc = self.nc_pred(cx, cy);
4746                        let blk: [i32; 16] = std::array::from_fn(|k| scan8[4 * k + sub]);
4747                        encode_residual_block(w, &blk, 16, nc) as u8
4748                    } else {
4749                        0
4750                    };
4751                    self.nnz_cache_set(cx, cy, total);
4752                    self.nnz_y[by * w4 + bx] = total;
4753                }
4754            }
4755        } else {
4756            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4757                let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
4758                let total = if cbp_luma & (1 << (blk / 4)) != 0 {
4759                    let nc = self.nc_pred(lbx, lby);
4760                    let scan16 = scan_4x4_dcac(&plan.q_blocks[lby * 4 + lbx]);
4761                    encode_residual_block(w, &scan16, 16, nc) as u8
4762                } else {
4763                    0
4764                };
4765                self.nnz_cache_set(lbx, lby, total);
4766                self.nnz_y[by * w4 + bx] = total;
4767            }
4768        }
4769        if cbp_chroma != 0 {
4770            for c in 0..2 {
4771                encode_residual_block(w, &plan.c_dc_levels[c], 4, -1);
4772            }
4773        }
4774        if cbp_chroma == 2 {
4775            self.chroma_cache_load(mb_x, mb_y);
4776            let w2 = self.mb_w * 2;
4777            for c in 0..2 {
4778                for &(bx, by) in &CHROMA_4X4_SCAN_XY {
4779                    let nc = self.chroma_nc_pred(c, bx, by);
4780                    let ac = scan_4x4_ac(&plan.c_q[c][by * 2 + bx]);
4781                    let total = encode_residual_block(w, &ac, 15, nc) as u8;
4782                    self.chroma_nnz_cache_set(c, bx, by, total);
4783                    self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total;
4784                }
4785            }
4786        }
4787    }
4788
4789    /// Descent F: reconstruction / skip-check MC through the cached half-pel planes
4790    /// instead of the per-pixel 6-tap. `hpel_block` is proven bit-identical to `mc_luma`
4791    /// (`hpel_block_matches_mc_luma_exactly`) and the `f` plane is the padded,
4792    /// edge-replicated reference, so both paths are BYTE-IDENTICAL; anything outside the
4793    /// padded plane still falls back to `mc_luma`.
4794    ///
4795    /// Census that motivated it: with the search's edge fallback fixed, `mc_luma` is
4796    /// 3.8-5.2% of encode and splits recon ~56-67% / skip-check ~24-35%, the latter at a
4797    /// content-independent one call per macroblock.
4798    #[inline]
4799    fn mc_luma_cached(
4800        &self,
4801        reference: &crate::RefFrame,
4802        x0: usize,
4803        y0: usize,
4804        bw: usize,
4805        bh: usize,
4806        mvx: i32,
4807        mvy: i32,
4808        out: &mut [u8],
4809    ) {
4810        let ch = self.mb_h * 16;
4811        let cw = self.cw;
4812        if !self.fast {
4813            let p = reference.hpel(cw, ch);
4814            if rusty_h264_common::inter::hpel_block(p, x0, y0, bw, bh, mvx, mvy, out) {
4815                return;
4816            }
4817            if let Some((plane, base, stride)) =
4818                rusty_h264_common::inter::hpel_ref(p, x0, y0, bw, bh, mvx, mvy)
4819            {
4820                for r in 0..bh {
4821                    out[r * bw..r * bw + bw].copy_from_slice(&plane[base + r * stride..][..bw]);
4822                }
4823                return;
4824            }
4825        }
4826        mc_luma(&reference.y, cw, ch, x0, y0, bw, bh, mvx, mvy, out);
4827    }
4828
4829    /// Motion-compensates the `P_Skip` prediction (luma + both chroma) from
4830    /// reference 0 at the skip MV.
4831    /// Luma half of the P_Skip prediction. Split out so the fast path can test the
4832    /// luma residual first and only motion-compensate chroma when luma is free —
4833    /// for the majority of (non-free) macroblocks the chroma MC is never needed.
4834    /// Applies this slice's explicit LUMA weight for reference `r` to a region
4835    /// of a 16-stride prediction buffer — the encoder-side twin of the
4836    /// decoder's `weight_partition` luma arm, same integer form (denom 6:
4837    /// `((p·w + 32) >> 6) + o`, clamped). Identity/off skips in O(1).
4838    #[inline]
4839    fn wp_luma(&self, r: i32, buf: &mut [u8; 256], x0: usize, y0: usize, rw: usize, rh: usize) {
4840        let Some(&(lw, lo)) = self.wp.get(r.max(0) as usize) else { return };
4841        if lw == 64 && lo == 0 {
4842            return;
4843        }
4844        for dy in 0..rh {
4845            for p in buf[(y0 + dy) * 16 + x0..][..rw].iter_mut() {
4846                *p = (((*p as i32 * lw + 32) >> 6) + lo).clamp(0, 255) as u8;
4847            }
4848        }
4849    }
4850
4851    fn skip_predict_luma(
4852        &self,
4853        refs: &[crate::RefFrame],
4854        mb_x: usize,
4855        mb_y: usize,
4856        mv: (i32, i32),
4857    ) -> [u8; 256] {
4858        // Descent E/F: identify this mc_luma population by call site.
4859        #[cfg(feature = "profile")]
4860        let _site = rusty_h264_common::inter::mcstats::SiteTag::new(3);
4861        let reference = &refs[0]; // P_Skip always references index 0
4862        let mut pred_y = [0u8; 256];
4863        self.mc_luma_cached(reference, mb_x * 16, mb_y * 16, 16, 16, mv.0, mv.1, &mut pred_y);
4864        // P_Skip references index 0 — weighted like any other P prediction
4865        // (the decoder weights its P_Skip recon too).
4866        self.wp_luma(0, &mut pred_y, 0, 0, 16, 16);
4867        pred_y
4868    }
4869
4870    /// Chroma half of the P_Skip prediction (see [`Self::skip_predict_luma`]).
4871    fn skip_predict_chroma(
4872        &self,
4873        refs: &[crate::RefFrame],
4874        mb_x: usize,
4875        mb_y: usize,
4876        mv: (i32, i32),
4877    ) -> [[u8; 64]; 2] {
4878        let reference = &refs[0];
4879        let cch = self.mb_h * 8;
4880        let mut pred_c = [[0u8; 64]; 2];
4881        for c in 0..2 {
4882            let rc = if c == 0 { &reference.u } else { &reference.v };
4883            mc_chroma(rc, self.ccw, cch, mb_x * 8, mb_y * 8, 8, 8, mv.0, mv.1, &mut pred_c[c]);
4884        }
4885        pred_c
4886    }
4887
4888    /// Whether the luma half of the P_Skip prediction has an all-zero quantized
4889    /// residual. Tested first and independently so the caller can defer the chroma
4890    /// MC + test for the common case where luma already disqualifies the skip (a
4891    /// "free", exact P_Skip costs no bits and is strictly beneficial).
4892    fn skip_luma_is_free(&self, sy: &[u8], mb_x: usize, mb_y: usize, pred_y: &[u8; 256]) -> bool {
4893        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncFree);
4894        let qp = self.qp;
4895        // Fast path (deployment): the SAME asm kernels the coding path uses —
4896        // `dct_four_t4` computes the 4x4 DCTs of (src - pred) for an 8x8 quad
4897        // STRAIGHT FROM THE PLANES (no scalar gather), `quant_four_4x4` quantizes
4898        // with the identical FF/MF math as scalar `quantize` (bit-identical), and
4899        // "free" = all 64 levels zero, which is order-independent. Per-quad early
4900        // exit. The knob interleaves this against the scalar twin for A/B.
4901        #[cfg(accel)]
4902        if self.skip_accel_check {
4903            #[repr(align(16))]
4904            struct Align16([i16; 64]);
4905            let mut dct = Align16([0i16; 64]);
4906            let ff = rusty_h264_common::transform::quant_dz_ff(qp, 6);
4907            let mf = &rusty_h264_common::transform::QUANT_MF_OH[qp as usize];
4908            for &(qx, qy) in &[(0usize, 0usize), (8, 0), (0, 8), (8, 8)] {
4909                rusty_h264_accel::dct_four_t4(
4910                    &mut dct.0,
4911                    &sy[(mb_y * 16 + qy) * self.cw + mb_x * 16 + qx..],
4912                    self.cw,
4913                    &pred_y[qy * 16 + qx..],
4914                    16,
4915                );
4916                rusty_h264_accel::quant_four_4x4(&mut dct.0, &ff, mf);
4917                if dct.0.iter().any(|&v| v != 0) {
4918                    return false;
4919                }
4920            }
4921            return true;
4922        }
4923        // Exact quantize-to-zero bounds (mirrors `quantize`: level != 0 iff
4924        // (|c| + ff[p])·mf_oh[p] >= 2^16). With |C_ij| <= 4·SAD (max |H| entry = 2)
4925        // and C_DC = Σres, most blocks are decided by one SAD/sum pass — the full
4926        // scalar DCT+quant proof only runs for the rare undecided middle band.
4927        // BIT-EXACT: both shortcuts are sufficient conditions of the exact check.
4928        let ff = rusty_h264_common::transform::quant_dz_ff(qp, 6);
4929        // NINE integer divides per skip test became a table lookup.
4930        // `(65536 + mf - 1) / mf` is `ceil(65536 / mf)`, a pure function of
4931        // `mf = QUANT_MF_OH[qp][p]` -- 52 x 8 values, so the table is EXACT.
4932        // `t_dc` also re-divided the `p == 0` case the loop had just computed.
4933        let ceil8 = &rusty_h264_common::transform::CEIL_65536_MF[qp as usize];
4934        let mut t_min = i32::MAX;
4935        for p in 0..8 {
4936            t_min = t_min.min(ceil8[p] as i32 - ff[p] as i32);
4937        }
4938        let t_dc = ceil8[0] as i32 - ff[0] as i32;
4939        // Whole-MB gate: SAD(any 4x4) <= SAD(MB), so 4*SAD_MB < T_min proves all 16
4940        // blocks quantize to zero from ONE (psadbw) SAD. On skip-heavy content most
4941        // free MBs are exact/near-exact copies (SAD_MB ~ 0) - they skip the whole
4942        // per-block walk. Not-free MBs pay one extra SAD (~2% of their check).
4943        for by in 0..4 {
4944            for bx in 0..4 {
4945                let mut res = [0i32; 16];
4946                let (mut sad, mut dc) = (0i32, 0i32);
4947                for dy in 0..4 {
4948                    let row = &sy[(mb_y * 16 + by * 4 + dy) * self.cw + mb_x * 16 + bx * 4..][..4];
4949                    for dx in 0..4 {
4950                        let d = row[dx] as i32
4951                            - pred_y[(by * 4 + dy) * 16 + (bx * 4 + dx)] as i32;
4952                        res[dy * 4 + dx] = d;
4953                        sad += d.abs();
4954                        dc += d;
4955                    }
4956                }
4957                if 4 * sad < t_min {
4958                    continue; // every |C| <= 4·SAD < T_min → all levels zero
4959                }
4960                if dc.abs() >= t_dc {
4961                    return false; // DC level provably nonzero
4962                }
4963                if quantize(&forward_core(&res), qp, 6).iter().any(|&v| v != 0) {
4964                    return false;
4965                }
4966            }
4967        }
4968        true
4969    }
4970
4971    /// Chroma half of [`Self::skip_is_free`].
4972    fn skip_chroma_is_free(
4973        &self,
4974        su: &[u8],
4975        sv: &[u8],
4976        mb_x: usize,
4977        mb_y: usize,
4978        pred_c: &[[u8; 64]; 2],
4979    ) -> bool {
4980        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncFree);
4981        let qpc = self.qpc;
4982        // Fast path: one dct_four_t4 covers the whole 8x8 chroma plane region (all 4
4983        // blocks, residual+DCT fused, no scalar gather). Block order is the quad's
4984        // z-scan == raster for 2x2, so block b's DC (pre-quant) sits at dct[b*16] —
4985        // exactly the dc2x2 the Hadamard check needs. quant_four_4x4 with our FF/MF
4986        // is bit-identical to scalar `quantize`; AC-free = positions 1..16 all zero.
4987        #[cfg(accel)]
4988        if self.skip_accel_check {
4989            #[repr(align(16))]
4990            struct Align16C([i16; 64]);
4991            let mut dct = Align16C([0i16; 64]);
4992            let ff = rusty_h264_common::transform::quant_dz_ff(qpc, 6);
4993            let mf = &rusty_h264_common::transform::QUANT_MF_OH[qpc as usize];
4994            for c in 0..2 {
4995                let src = if c == 0 { su } else { sv };
4996                rusty_h264_accel::dct_four_t4(
4997                    &mut dct.0,
4998                    &src[(mb_y * 8) * self.ccw + mb_x * 8..],
4999                    self.ccw,
5000                    &pred_c[c],
5001                    8,
5002                );
5003                let dc2x2 = [
5004                    dct.0[0] as i32,
5005                    dct.0[16] as i32,
5006                    dct.0[32] as i32,
5007                    dct.0[48] as i32,
5008                ];
5009                rusty_h264_accel::quant_four_4x4(&mut dct.0, &ff, mf);
5010                for b in 0..4 {
5011                    if dct.0[b * 16 + 1..b * 16 + 16].iter().any(|&v| v != 0) {
5012                        return false;
5013                    }
5014                }
5015                if forward_quant_chroma_dc(&dc2x2, qpc, false).iter().any(|&v| v != 0) {
5016                    return false;
5017                }
5018            }
5019            return true;
5020        }
5021        for c in 0..2 {
5022            let src = if c == 0 { su } else { sv };
5023            let mut dc2x2 = [0i32; 4];
5024            for &(bx, by) in &CHROMA_4X4_SCAN_XY {
5025                let mut res = [0i32; 16];
5026                // Row slices (11.15): the LUMA twin got this shape in the
5027                // transcendentals round (23 bc -> 2); the chroma twin was missed.
5028                for dy in 0..4 {
5029                    let row = &src[(mb_y * 8 + by * 4 + dy) * self.ccw + mb_x * 8 + bx * 4..][..4];
5030                    for dx in 0..4 {
5031                        res[dy * 4 + dx] = row[dx] as i32
5032                            - pred_c[c][(by * 4 + dy) * 8 + (bx * 4 + dx)] as i32;
5033                    }
5034                }
5035                let coeffs = forward_core(&res);
5036                dc2x2[by * 2 + bx] = coeffs[0];
5037                if quantize(&coeffs, qpc, 6)[1..].iter().any(|&v| v != 0) {
5038                    return false;
5039                }
5040            }
5041            if forward_quant_chroma_dc(&dc2x2, qpc, false).iter().any(|&v| v != 0) {
5042                return false;
5043            }
5044        }
5045        true
5046    }
5047
5048    /// SSD between the source and a macroblock prediction (luma + chroma).
5049    #[allow(clippy::too_many_arguments)]
5050    fn pred_ssd(
5051        &self,
5052        sy: &[u8],
5053        su: &[u8],
5054        sv: &[u8],
5055        mb_x: usize,
5056        mb_y: usize,
5057        pred_y: &[u8; 256],
5058        pred_c: &[[u8; 64]; 2],
5059    ) -> i64 {
5060        let mut ssd = 0i64;
5061        for dy in 0..16 {
5062            let i = (mb_y * 16 + dy) * self.cw + mb_x * 16;
5063            for (a, b) in sy[i..i + 16].iter().zip(&pred_y[dy * 16..dy * 16 + 16]) {
5064                let d = *a as i64 - *b as i64;
5065                ssd += d * d;
5066            }
5067        }
5068        for c in 0..2 {
5069            let src = if c == 0 { su } else { sv };
5070            for dy in 0..8 {
5071                let i = (mb_y * 8 + dy) * self.ccw + mb_x * 8;
5072                for (a, b) in src[i..i + 8].iter().zip(&pred_c[c][dy * 8..dy * 8 + 8]) {
5073                    let d = *a as i64 - *b as i64;
5074                    ssd += d * d;
5075                }
5076            }
5077        }
5078        ssd
5079    }
5080
5081    /// SSD between the *reconstructed* macroblock and the source.
5082    fn mb_ssd(&self, sy: &[u8], su: &[u8], sv: &[u8], mb_x: usize, mb_y: usize) -> i64 {
5083        let mut ssd = 0i64;
5084        // TWO bounds checks per pixel (source and recon) became two per ROW.
5085        for dy in 0..16 {
5086            let i = (mb_y * 16 + dy) * self.cw + mb_x * 16;
5087            for (a, b) in sy[i..i + 16].iter().zip(&self.rec_y[i..i + 16]) {
5088                let d = *a as i64 - *b as i64;
5089                ssd += d * d;
5090            }
5091        }
5092        // CHROMA WEIGHT. Chroma SSD is summed at 1:1 with luma here, but every
5093        // metric this decision is graded on is LUMA (`ssim_y`, Y-PSNR), and a
5094        // 4:2:0 macroblock carries half as many chroma samples as luma, so an
5095        // equal-weight sum lets chroma steer a decision the grader cannot see.
5096        // Worst on the most chroma-rich content in the corpus. Default 1.0 =
5097        // byte-identical; the sweep lives in the gate ledger.
5098        let cw_ = chroma_ssd_weight();
5099        if cw_ != 0.0 {
5100            let mut cssd = 0i64;
5101            for c in 0..2 {
5102                let (src, rec) = if c == 0 { (su, &self.rec_u) } else { (sv, &self.rec_v) };
5103                for dy in 0..8 {
5104                    let i = (mb_y * 8 + dy) * self.ccw + mb_x * 8;
5105                    for (a, b) in src[i..i + 8].iter().zip(&rec[i..i + 8]) {
5106                        let d = *a as i64 - *b as i64;
5107                        cssd += d * d;
5108                    }
5109                }
5110            }
5111            ssd += if cw_ == 1.0 { cssd } else { (cssd as f64 * cw_) as i64 };
5112        }
5113        ssd
5114    }
5115
5116    /// Reconstructs a `P_Skip` macroblock (reconstruction *is* the prediction —
5117    /// no residual coded) and records its motion state.
5118    /// Writes a macroblock's prediction into the recon planes verbatim, with NO
5119    /// motion-state side effects (the B path commits motion via
5120    /// `commit_direct_motion`). B_Skip used to skip this entirely — legal while
5121    /// B recon had no reader, but intra-in-B predicts from these planes, and a
5122    /// stale neighbour is encoder-recon drift the two-decoder gate cannot see
5123    /// (it shows up as a quality drop at unchanged bytes).
5124    fn commit_pred_pixels(&mut self, mb_x: usize, mb_y: usize, pred_y: &[u8; 256], pred_c: &[[u8; 64]; 2]) {
5125        let base = mb_y * 16 * self.cw + mb_x * 16;
5126        for r in 0..16 {
5127            let d = base + r * self.cw;
5128            self.rec_y[d..d + 16].copy_from_slice(&pred_y[r * 16..r * 16 + 16]);
5129        }
5130        let cbase = mb_y * 8 * self.ccw + mb_x * 8;
5131        for c in 0..2 {
5132            let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
5133            for r in 0..8 {
5134                let d = cbase + r * self.ccw;
5135                plane[d..d + 8].copy_from_slice(&pred_c[c][r * 8..r * 8 + 8]);
5136            }
5137        }
5138    }
5139
5140    fn commit_skip(
5141        &mut self,
5142        mb_x: usize,
5143        mb_y: usize,
5144        mv: (i32, i32),
5145        pred_y: &[u8; 256],
5146        pred_c: &[[u8; 64]; 2],
5147    ) {
5148        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MvGrid);
5149        // Skip recon = the prediction verbatim: straight row copies (byte-identical
5150        // to the old per-4x4 gather + store scatter, ~5x fewer ops).
5151        let base = mb_y * 16 * self.cw + mb_x * 16;
5152        for r in 0..16 {
5153            let d = base + r * self.cw;
5154            self.rec_y[d..d + 16].copy_from_slice(&pred_y[r * 16..r * 16 + 16]);
5155        }
5156        let cbase = mb_y * 8 * self.ccw + mb_x * 8;
5157        for c in 0..2 {
5158            let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
5159            for r in 0..8 {
5160                let d = cbase + r * self.ccw;
5161                plane[d..d + 8].copy_from_slice(&pred_c[c][r * 8..r * 8 + 8]);
5162            }
5163        }
5164        self.set_mb_mv(mb_x, mb_y, mv, true, 0);
5165        let w4 = self.mb_w * 4;
5166        for row in 0..4 {
5167            let st = (mb_y * 4 + row) * w4 + mb_x * 4;
5168            self.modes_y[st..st + 4].fill(2);
5169            self.coded_y[st..st + 4].fill(true);
5170        }
5171    }
5172
5173    /// Trial-encodes an inter macroblock to measure its rate-distortion cost
5174    /// `(SSD, bits)` without committing: snapshot the macroblock's grid + recon
5175    /// region, run the real `encode_inter_mb` into a scratch writer, read the
5176    /// bit count and reconstruction SSD, then restore. Neighbor CAVLC context is
5177    /// read (not mutated), so the bit count is accurate.
5178    #[allow(clippy::too_many_arguments)]
5179    fn trial_inter(
5180        &mut self,
5181        refs: &[crate::RefFrame],
5182        sy: &[u8],
5183        su: &[u8],
5184        sv: &[u8],
5185        mb_x: usize,
5186        mb_y: usize,
5187        mode: u8,
5188        parts: &[(i32, (i32, i32))],
5189    ) -> (i64, usize) {
5190        let snap = self.save_mb(mb_x, mb_y);
5191        let mut scratch = BitWriter::new();
5192        self.encode_inter_mb(&mut scratch, refs, sy, su, sv, mb_x, mb_y, mode, parts);
5193        let bits = scratch.bit_len();
5194        let ssd = self.mb_ssd(sy, su, sv, mb_x, mb_y);
5195        self.load_mb(mb_x, mb_y, &snap);
5196        (ssd, bits)
5197    }
5198
5199    /// Trial-encodes the macroblock as **intra** (`encode_mb` runs its own
5200    /// I_16x16-vs-I_4x4 decision), measuring `(SSD, bits)` without committing —
5201    /// the intra candidate for the RD mode decision.
5202    /// Trial-encodes THIS macroblock as coded (`plan_mb` picks intra vs the
5203    /// already-chosen inter) and returns `(recon SSD, real bits)`, restoring
5204    /// every grid it touched. The RD currency for a mode decision — see
5205    /// `intra_rd_on`.
5206    fn trial_intra(
5207        &mut self,
5208        sy: &[u8],
5209        su: &[u8],
5210        sv: &[u8],
5211        mb_x: usize,
5212        mb_y: usize,
5213        is_p: bool,
5214    ) -> (i64, usize) {
5215        let mut snap = enc_scratch::take_snap_b();
5216        self.save_mb_into(mb_x, mb_y, &mut snap);
5217        // E2 r2: a fresh BitWriter (heap Vec) was built PER RD TRIAL; recycle
5218        // this thread's — `clear()` keeps the grown allocation.
5219        let mut scratch = enc_scratch::take_bits();
5220        scratch.clear();
5221        encode_mb(self, &mut scratch, mb_x, mb_y, sy, su, sv, is_p);
5222        let bits = scratch.bit_len();
5223        enc_scratch::put_bits(scratch);
5224        let ssd = self.mb_ssd(sy, su, sv, mb_x, mb_y);
5225        self.load_mb(mb_x, mb_y, &snap);
5226        enc_scratch::put_snap_b(snap);
5227        (ssd, bits)
5228    }
5229
5230    /// Best `(ref_idx, mv, cost)` for one partition by `SATD + λ·bits`, searched
5231    /// across every reference (`cost` is that SATD-domain rate-distortion cost).
5232    /// `extra` seeds the search with already-found MVs (e.g. the 16×16 result when
5233    /// refining a sub-partition).
5234    #[allow(clippy::too_many_arguments)]
5235    #[inline]
5236    fn best_part(
5237        &self,
5238        refs: &[crate::RefFrame],
5239        sy: &[u8],
5240        nb: &[MvNeighbor; 3],
5241        num_refs: usize,
5242        rx: usize,
5243        ry: usize,
5244        rw: usize,
5245        rh: usize,
5246        extra: &[(i32, i32)],
5247        lme: f64,
5248    ) -> (i32, (i32, i32), i64) {
5249        crate::signals::census::work(crate::signals::census::W_BEST_PART);
5250        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMe);
5251        let [a, b, c] = *nb;
5252        let (mut br, mut bmv, mut bc) = (0i32, (0, 0), i64::MAX);
5253        for r in 0..num_refs {
5254            // EXACT ref_bits prune (multiref campaign): reference `r`'s total
5255            // cost is `motion_cost + λ·ref_bits(r)` with `motion_cost >= 0`
5256            // (SATD plus a nonnegative mvd rate), so it is bounded below by
5257            // the λ·ref_bits term alone. Once the incumbent `bc` is at or
5258            // under that bound, reference `r` cannot win the strict `<` — and
5259            // `ref_bits` is NONDECREASING in `r` (Exp-Golomb length; pinned by
5260            // `ref_bits_is_monotone`), so neither can any later reference:
5261            // `break`, byte-identically. Fires exactly where multi-ref costs
5262            // the most for the least — near-perfect ref-0 matches on cheap
5263            // partitions at high λ.
5264            let rb = (lme * ref_bits(r, num_refs) as f64) as i64;
5265            if rb >= bc {
5266                break;
5267            }
5268            crate::signals::census::work(crate::signals::census::W_REF_SEARCH);
5269            // STACK seeds. This was `vec![..]` + `extend_from_slice` — a heap
5270            // allocation on EVERY search, and the sub-8x8 split arm took the call
5271            // count from 50k to 208k per clip, so it is ~208k allocations whose
5272            // payload is at most three MVs. `extra` is [] / [mv16] / [mv16, mv]
5273            // at every call site; the assert pins that rather than trusting it.
5274            debug_assert!(extra.len() <= 3, "seed budget");
5275            let mut sbuf = [(0i32, 0i32); 4];
5276            sbuf[0] = predict_mv(a, b, c, r as i32);
5277            let n = 1 + extra.len().min(3);
5278            sbuf[1..n].copy_from_slice(&extra[..n - 1]);
5279            let seeds = &sbuf[..n];
5280            let (mv, cost) = self.motion_search(&refs[r], sy, rx, ry, rw, rh, &seeds, lme, None);
5281            let cost = cost + rb;
5282            if cost < bc {
5283                bc = cost;
5284                br = r as i32;
5285                bmv = mv;
5286            }
5287        }
5288        (br, bmv, bc)
5289    }
5290
5291    /// Sub-pel-refines ONE already-chosen partition, reusing `motion_search`'s cost
5292    /// closure via its `start` hook so the rate term and predictor centre are exactly
5293    /// the ones the full search used. Companion to `best_part` under `sp_defer`.
5294    #[allow(clippy::too_many_arguments)]
5295    fn refine_part(
5296        &self,
5297        refs: &[crate::RefFrame],
5298        sy: &[u8],
5299        nb: &[MvNeighbor; 3],
5300        num_refs: usize,
5301        rx: usize,
5302        ry: usize,
5303        rw: usize,
5304        rh: usize,
5305        lme: f64,
5306        r: i32,
5307        mv: (i32, i32),
5308    ) -> ((i32, i32), i64) {
5309        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMe);
5310        let [a, b, c] = *nb;
5311        let rb = (lme * ref_bits(r as usize, num_refs) as f64) as i64;
5312        let seeds = [predict_mv(a, b, c, r)];
5313        let (m, cc) = self.motion_search(&refs[r as usize], sy, rx, ry, rw, rh, &seeds, lme, Some(mv));
5314        (m, cc + rb)
5315    }
5316
5317    /// Cheapest `I_16x16` prediction's SAD over the four whole-block modes, using
5318    /// the already-reconstructed top/left neighbours — the intra candidate's cost
5319    /// in the fast (SAD) mode decision, without the full `I_4x4` search.
5320    fn best_i16_sad(&self, sy: &[u8], mb_x: usize, mb_y: usize) -> i64 {
5321        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncIntraCost);
5322        let (lx, ly) = (mb_x * 16, mb_y * 16);
5323        let (avail_top, avail_left) = (mb_y > 0, mb_x > 0);
5324        let mut top = [0u8; 16];
5325        let mut left = [0u8; 16];
5326        if avail_top {
5327            let r = (ly - 1) * self.cw + lx;
5328            top.copy_from_slice(&self.rec_y[r..r + 16]);
5329        }
5330        if avail_left {
5331            // E2 r2 EXPERIMENT: a bounded column slice — `i * cw` is provably
5332            // inside `15*cw + 1` for i < 16, so LLVM can retire the per-element
5333            // checks the strided gather carried. (Kept only if the bc count
5334            // dropped; see 11.12a.)
5335            let col = &self.rec_y[ly * self.cw + lx - 1..(ly + 15) * self.cw + lx];
5336            for i in 0..16 {
5337                left[i] = col[i * self.cw];
5338            }
5339        }
5340        let corner = if avail_top && avail_left {
5341            self.rec_y[(ly - 1) * self.cw + lx - 1]
5342        } else {
5343            0
5344        };
5345        let mut best = i64::MAX;
5346        for mode in [I16Mode::Dc, I16Mode::Vertical, I16Mode::Horizontal, I16Mode::Plane] {
5347            if !mode.available(avail_top, avail_left) {
5348                continue;
5349            }
5350            let pred = i16_pred(self, mode, avail_top, avail_left, &top, &left, corner, lx, ly);
5351            best = best.min(sad_16x16(sy, self.cw, lx, ly, &pred));
5352        }
5353        best
5354    }
5355
5356    /// SATD sibling of [`Self::best_i16_sad`] — the intra candidate's cost in the
5357    /// quality preset's SATD mode decision (openh264's `WelsMdI16x16`).
5358    fn best_i16_satd(&self, sy: &[u8], mb_x: usize, mb_y: usize) -> i64 {
5359        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncIntraCost);
5360        let (lx, ly) = (mb_x * 16, mb_y * 16);
5361        let (avail_top, avail_left) = (mb_y > 0, mb_x > 0);
5362        let mut top = [0u8; 16];
5363        let mut left = [0u8; 16];
5364        if avail_top {
5365            let r = (ly - 1) * self.cw + lx;
5366            top.copy_from_slice(&self.rec_y[r..r + 16]);
5367        }
5368        if avail_left {
5369            // E2 r2 EXPERIMENT: a bounded column slice — `i * cw` is provably
5370            // inside `15*cw + 1` for i < 16, so LLVM can retire the per-element
5371            // checks the strided gather carried. (Kept only if the bc count
5372            // dropped; see 11.12a.)
5373            let col = &self.rec_y[ly * self.cw + lx - 1..(ly + 15) * self.cw + lx];
5374            for i in 0..16 {
5375                left[i] = col[i * self.cw];
5376            }
5377        }
5378        let corner = if avail_top && avail_left {
5379            self.rec_y[(ly - 1) * self.cw + lx - 1]
5380        } else {
5381            0
5382        };
5383        let mut best = i64::MAX;
5384        for mode in [I16Mode::Dc, I16Mode::Vertical, I16Mode::Horizontal, I16Mode::Plane] {
5385            if !mode.available(avail_top, avail_left) {
5386                continue;
5387            }
5388            let pred = i16_pred(self, mode, avail_top, avail_left, &top, &left, corner, lx, ly);
5389            best = best.min(satd_16x16(sy, self.cw, lx, ly, &pred));
5390        }
5391        best
5392    }
5393
5394    /// Snapshots the per-block grids and reconstruction for one macroblock, so a
5395    /// trial encode can be rolled back.
5396    fn save_mb(&self, mb_x: usize, mb_y: usize) -> MbState {
5397        let mut d = MbState::default();
5398        self.save_mb_into(mb_x, mb_y, &mut d);
5399        d
5400    }
5401
5402    /// [`save_mb`](Self::save_mb) into an existing buffer, reusing its allocations.
5403    /// The per-macroblock region is a fixed size, so after the first call every
5404    /// `Vec` already has the capacity it needs and refilling is a pure copy.
5405    fn save_mb_into(&self, mb_x: usize, mb_y: usize, d: &mut MbState) {
5406        let w4 = self.mb_w * 4;
5407        let w2 = self.mb_w * 2;
5408        // REFUTED, do not retry: the `load_mb` row-slice shape does NOT mirror onto
5409        // this function. Rewriting these as `$o.clear()` + `extend_from_slice` per
5410        // row does retire all 15 bounds checks, but `Vec::extend_from_slice` carries
5411        // a capacity check and a `memcpy` call of its own, and the function grew
5412        // 1030 -> 1771 instructions (+72%) to buy them. A write into a
5413        // pre-sized destination (`load_mb`) and an append into a growable one are
5414        // not the same shape; only the former is a clean win.
5415        macro_rules! reg4 {
5416            ($v:expr, $o:expr) => {{
5417                $o.clear();
5418                for dy in 0..4 {
5419                    for dx in 0..4 {
5420                        $o.push($v[(mb_y * 4 + dy) * w4 + mb_x * 4 + dx]);
5421                    }
5422                }
5423            }};
5424        }
5425        macro_rules! regn {
5426            ($v:expr, $o:expr, $n:expr, $ox:expr, $oy:expr, $stride:expr) => {{
5427                $o.clear();
5428                for dy in 0..$n {
5429                    for dx in 0..$n {
5430                        $o.push($v[($oy + dy) * $stride + $ox + dx]);
5431                    }
5432                }
5433            }};
5434        }
5435        regn!(self.rec_y, d.rec_y, 16, mb_x * 16, mb_y * 16, self.cw);
5436        regn!(self.rec_u, d.rec_u, 8, mb_x * 8, mb_y * 8, self.ccw);
5437        regn!(self.rec_v, d.rec_v, 8, mb_x * 8, mb_y * 8, self.ccw);
5438        reg4!(self.nnz_y, d.nnz_y);
5439        regn!(self.nnz_c[0], d.nnz_c[0], 2, mb_x * 2, mb_y * 2, w2);
5440        regn!(self.nnz_c[1], d.nnz_c[1], 2, mb_x * 2, mb_y * 2, w2);
5441        reg4!(self.mv_y, d.mv_y);
5442        reg4!(self.inter_y, d.inter_y);
5443        reg4!(self.ref_idx_y, d.ref_idx_y);
5444        reg4!(self.coded_y, d.coded_y);
5445        reg4!(self.modes_y, d.modes_y);
5446        d.cur_qp = self.cur_qp;
5447    }
5448
5449    /// Restores a macroblock's grids + reconstruction from a [`save_mb`] snapshot.
5450    fn load_mb(&mut self, mb_x: usize, mb_y: usize, s: &MbState) {
5451        let w4 = self.mb_w * 4;
5452        let w2 = self.mb_w * 2;
5453        // One bounds check PER ROW instead of per element. `$n` is a literal at
5454        // every call site, so both slices have a compile-time extent and LLVM
5455        // folds the length equality `copy_from_slice` would otherwise check --
5456        // this is the shape that WORKS, as distinct from the runtime-extent row
5457        // slice the decoder campaign measured and REFUTED.
5458        macro_rules! put4 {
5459            ($v:expr, $src:expr) => {
5460                for dy in 0..4 {
5461                    let d = (mb_y * 4 + dy) * w4 + mb_x * 4;
5462                    $v[d..d + 4].copy_from_slice(&$src[dy * 4..dy * 4 + 4]);
5463                }
5464            };
5465        }
5466        macro_rules! putn {
5467            ($v:expr, $src:expr, $n:expr, $ox:expr, $oy:expr, $stride:expr) => {
5468                for dy in 0..$n {
5469                    let d = ($oy + dy) * $stride + $ox;
5470                    $v[d..d + $n].copy_from_slice(&$src[dy * $n..dy * $n + $n]);
5471                }
5472            };
5473        }
5474        putn!(self.rec_y, s.rec_y, 16, mb_x * 16, mb_y * 16, self.cw);
5475        putn!(self.rec_u, s.rec_u, 8, mb_x * 8, mb_y * 8, self.ccw);
5476        putn!(self.rec_v, s.rec_v, 8, mb_x * 8, mb_y * 8, self.ccw);
5477        put4!(self.nnz_y, s.nnz_y);
5478        putn!(self.nnz_c[0], s.nnz_c[0], 2, mb_x * 2, mb_y * 2, w2);
5479        putn!(self.nnz_c[1], s.nnz_c[1], 2, mb_x * 2, mb_y * 2, w2);
5480        put4!(self.mv_y, s.mv_y);
5481        put4!(self.inter_y, s.inter_y);
5482        put4!(self.ref_idx_y, s.ref_idx_y);
5483        put4!(self.coded_y, s.coded_y);
5484        put4!(self.modes_y, s.modes_y);
5485        self.cur_qp = s.cur_qp;
5486    }
5487
5488    /// Loads the per-MB luma nnz prediction cache (openh264 `scan8` style): the top
5489    /// row from the macroblock above and the left column from the macroblock to the
5490    /// left (both already in `nnz_y`), with `0x80` at the picture edges. After this,
5491    /// neighbour nnz reads are branchless cache indexing — no bounds-checked `Option`.
5492    fn nnz_cache_load(&mut self, mb_x: usize, mb_y: usize) {
5493        let w4 = self.mb_w * 4;
5494        for lbx in 0..4 {
5495            self.nnz_l_cache[1 + lbx] = if mb_y == 0 {
5496                0x80
5497            } else {
5498                self.nnz_y[(mb_y * 4 - 1) * w4 + (mb_x * 4 + lbx)]
5499            };
5500        }
5501        for lby in 0..4 {
5502            self.nnz_l_cache[(lby + 1) * 5] = if mb_x == 0 {
5503                0x80
5504            } else {
5505                self.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 - 1)]
5506            };
5507        }
5508    }
5509
5510    /// Branchless nnz prediction (`nC`) for luma block `(lbx,lby)` from the cache —
5511    /// the `0x80` sentinel + `& 0x7f` mask collapse the four availability cases
5512    /// (matches the scalar nnz predict). Call after the block's left/top are cached.
5513    #[inline]
5514    fn nc_pred(&self, lbx: usize, lby: usize) -> i32 {
5515        let left = self.nnz_l_cache[(lby + 1) * 5 + lbx] as i32; // (lbx-1)+1
5516        let top = self.nnz_l_cache[lby * 5 + (lbx + 1)] as i32; // (lby-1)+1
5517        let r = left + top;
5518        if r < 0x80 {
5519            (r + 1) >> 1
5520        } else {
5521            r & 0x7f
5522        }
5523    }
5524
5525    /// Records a luma block's nnz into the per-MB cache (for later neighbour reads).
5526    #[inline]
5527    fn nnz_cache_set(&mut self, lbx: usize, lby: usize, total: u8) {
5528        self.nnz_l_cache[(lby + 1) * 5 + (lbx + 1)] = total;
5529    }
5530
5531    /// Loads the per-MB chroma nnz prediction cache (both planes) from the chroma
5532    /// blocks above/left, `0x80` at the picture edges — the chroma analogue of
5533    /// [`Self::nnz_cache_load`] (2×2 blocks → padded 3×3 grid).
5534    fn chroma_cache_load(&mut self, mb_x: usize, mb_y: usize) {
5535        let w2 = self.mb_w * 2;
5536        for c in 0..2 {
5537            for bx in 0..2 {
5538                self.nnz_c_cache[c][1 + bx] = if mb_y == 0 {
5539                    0x80
5540                } else {
5541                    self.nnz_c[c][(mb_y * 2 - 1) * w2 + (mb_x * 2 + bx)]
5542                };
5543            }
5544            for by in 0..2 {
5545                self.nnz_c_cache[c][(by + 1) * 3] = if mb_x == 0 {
5546                    0x80
5547                } else {
5548                    self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 - 1)]
5549                };
5550            }
5551        }
5552    }
5553
5554    /// Branchless chroma nnz prediction (`nC`) for plane `c`, block `(bx,by)`.
5555    #[inline]
5556    fn chroma_nc_pred(&self, c: usize, bx: usize, by: usize) -> i32 {
5557        let left = self.nnz_c_cache[c][(by + 1) * 3 + bx] as i32;
5558        let top = self.nnz_c_cache[c][by * 3 + (bx + 1)] as i32;
5559        let r = left + top;
5560        if r < 0x80 {
5561            (r + 1) >> 1
5562        } else {
5563            r & 0x7f
5564        }
5565    }
5566
5567    /// Records a chroma block's nnz into the per-MB cache.
5568    #[inline]
5569    fn chroma_nnz_cache_set(&mut self, c: usize, bx: usize, by: usize, total: u8) {
5570        self.nnz_c_cache[c][(by + 1) * 3 + (bx + 1)] = total;
5571    }
5572}
5573
5574/// Encodes a slice's macroblocks then RBSP trailing bits, returning the
5575/// **deblocked** reconstruction to serve as the next frame's reference.
5576///
5577/// `is_p` selects P-slice framing (`mb_skip_run` prefix + intra `mb_type` +5
5578/// offset). In phase 4a every macroblock is still coded intra; motion-compensated
5579/// macroblocks arrive in 4b (using `reference`).
5580/// Boundary strengths for one macroblock, derived from the encoder's own grids
5581/// the moment it finishes coding.
5582///
5583/// `ref_idx_y` holds raw indices (-1 for intra) rather than the deblocker's
5584/// `NO_REF` sentinel; safe because reference identity is only compared between
5585/// two INTER blocks, which always carry a valid index.
5586// NOT inlined: this sits at three exits of the hottest loop in the encoder, and
5587// inlining it there costs more in I-cache and register pressure on the
5588// surrounding code than the call saves (measured: the loop grew ~2x the
5589// derivation's own cost).
5590#[inline(never)]
5591fn derive_mb_bs_from(
5592    fe: &FrameEncoder,
5593    mb_x: usize,
5594    mb_y: usize,
5595    kind: rusty_h264_common::deblock::MbKind,
5596) -> rusty_h264_common::deblock::MbBs {
5597    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncBs);
5598    let view = rusty_h264_common::deblock::BlockInfo {
5599        inter: &fe.inter_y,
5600        nnz: &fe.nnz_y,
5601        mv: &fe.mv_y,
5602        ref_id: &fe.ref_idx_y,
5603        mv1: &[],
5604        ref_id1: &[],
5605        w4: fe.mb_w * 4,
5606        t8x8: &[],
5607        poc0: &[],
5608        poc1: &[],
5609        bs: &[], kind: &[],
5610    };
5611    rusty_h264_common::deblock::derive_mb_kind(&view, mb_x, mb_y, kind)
5612}
5613
5614pub(crate) fn encode_slice_data(
5615    w: &mut BitWriter,
5616    cfg: &EncoderConfig,
5617    frame: &YuvFrame,
5618    qp: u8,
5619    is_p: bool,
5620    refs: &[crate::RefFrame],
5621    qpo: &[i32],
5622    aq_probe: Option<&YuvFrame>,
5623    wp: &[(i32, i32)],
5624) -> crate::RefFrame {
5625    let _g_prep = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncPrep);
5626    let mut fe = FrameEncoder::new(cfg);
5627    fe.wp = wp.to_vec();
5628    let precomp = rusty_h264_common::deblock::precomputed_bs_enabled();
5629    let mut bs_grid =
5630        vec![rusty_h264_common::deblock::MbBs::UNSET; if precomp { fe.mb_w * fe.mb_h } else { 0 }];
5631    fe.qp = qp;
5632    fe.qpc = chroma_qp(qp);
5633    fe.cur_qp = qp;
5634    if cfg.cabac_dz_div > 0 {
5635        fe.idz = cfg.cabac_dz_div; // CABAC-specific dead-zone override
5636    } // QPY_PREV starts at the slice QP so the first mb_qp_delta is 0
5637    let (sy, su, sv) = coded_source(cfg, frame);
5638    // Great Gate P1: ONE lazy signal vector per frame; every gate below reads
5639    // through it, so no probe runs twice and unused signals cost nothing.
5640    // On an IDR (no refs) the previous SOURCE frame stands in as the temporal
5641    // reference — the AQ grain veto needs it (docs/gate-ledger.md aq-grain-veto);
5642    // every ME gate below still keys on `refs`, not on the signal vector.
5643    let probe_y: Option<Vec<u8>> =
5644        if refs.is_empty() { aq_probe.map(|f| coded_source(cfg, f).0.into_owned()) } else { None };
5645    let sig = FrameSignals::new(
5646        &sy,
5647        fe.cw,
5648        fe.mb_w,
5649        fe.mb_h,
5650        refs.first().map(|r| &r.y[..]).or(probe_y.as_deref()),
5651    );
5652    apply_screen_t8_veto(&mut fe, &sig);
5653    let lambda = 0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
5654    let num_refs = refs.len();
5655    // me_wide CONTENT GATE: on a pure PAN the global-MC residual ≈ 0, so the diamond's
5656    // seed (median = pan MV) is already right and the wide rescue only over-fits
5657    // (spurious MVs that hurt the B-frames' spatial-direct — the panc regression).
5658    // Gate it off there; non-uniform content (real stalls) reads well above 0.
5659    if is_p && fe.me_wide && !refs.is_empty() && sig.gmc_residual() < fe.me_wide_coh {
5660        fe.me_wide = false;
5661    }
5662    // me_wide HEAD-ROOM GATE (the dispatcher the truth table asked for). The rescue
5663    // only pays where a wide search actually beats a predictor-local one; measure
5664    // that directly per frame and route the frame. `RFF_ME_HR` sets the threshold
5665    // (percent); 0 disables the gate and restores the always-on behaviour.
5666    // Skip the probe entirely when the gate is disabled: it must not tax the
5667    // default path (`RFF_ME_HR=0`), which stays byte-identical to pre-gate output.
5668    if fe.me_wide && !refs.is_empty() && (me_wide_hr_thresh() > 0.0 || me_wide_hr_dbg()) {
5669        let hr = sig.headroom();
5670        if me_wide_hr_dbg() {
5671            eprintln!("ME_HR qp{qp} headroom={hr:.2}");
5672        }
5673        if me_wide_hr_thresh() > 0.0 && hr < me_wide_hr_thresh() {
5674            fe.me_wide = false;
5675        }
5676    }
5677    // Track-B B2 DISPATCH (WHYS H-2): SAD full-pel wins where a plain full-pel
5678    // translational search actually improves on zero motion (`b2_mgain`) and loses
5679    // on flash/fine-detail content. Probe per frame, route the frame — per-frame,
5680    // not cross-frame, so it stays deterministic under GOP-parallel encode.
5681    if me_sadfp_mode() == 1 && !fe.fast && !refs.is_empty() {
5682        let (mg, dc) = sig.mgain_dc();
5683        if me_sadt_dbg() {
5684            eprintln!("B2_MG qp{qp} mgain={mg:.3} dcfrac={dc:.3}");
5685        }
5686        fe.sadfp = mg >= me_sadt() && dc <= me_sad_dcmax();
5687        // H-24: the mv-cost SHAPE rides the same probe (its BD sign-flip tracks
5688        // motion for the same physical reason B2's does).
5689        if mv_smooth_mode() == 1 {
5690            // dcfrac veto mirrors B2's: crew-class FLASH frames satisfy the mgain
5691            // test but SAD/mvd statistics mislead there (H-13/H-26).
5692            fe.mv_smooth = mg >= mv_smooth_t() && dc <= me_sad_dcmax();
5693        }
5694        // H-13: near-static frames skip the split searches entirely.
5695        let smg = split_mg();
5696        if smg > 0.0 {
5697            fe.do_splits = mg >= smg;
5698        }
5699    }
5700    // Content-adaptive cost-function dispatch (codec-content-adaptive-dispatch): the
5701    // fast preset prices modes by cheap SAD, which is rate-blind on detailed MBs;
5702    // route the top `satd_q` fraction of highest-VARIANCE MBs to the rate-faithful
5703    // SATD cost. A per-frame PERCENTILE threshold makes the routed fraction — hence
5704    // the speed/quality split — content-invariant (same q → same fraction on any
5705    // clip). `satd_q == 0` leaves the threshold at MAX (pure SAD, byte-identical).
5706    if is_p && fe.satd_q > 0.0 {
5707        fe.satd_var_thresh = sig.var_percentile_thresh(fe.satd_q);
5708    }
5709    // Adaptive Quantization: per-MB target QPy from content (finer on flat MBs,
5710    // coarser on busy ones). `mb_qpy` records each MB's ACTUAL QPy (a skip / cbp==0
5711    // MB inherits `cur_qp`), for the deblock filter. `strength 0` → uniform → the
5712    // mb_qp_delta stays 0, byte-identical.
5713    let mut aq_qp = aq_qp_map(&sig, qp, fe.aq_strength);
5714    apply_mbtree_qpo(&mut aq_qp, qpo); // mb-tree temporal AQ (empty = byte-identical)
5715    signals::harvest(
5716        &sig,
5717        if is_p { 'P' } else { 'I' },
5718        qp,
5719        &signals::GateDecisions {
5720            me_wide: fe.me_wide,
5721            sadfp: fe.sadfp,
5722            mv_smooth: fe.mv_smooth,
5723            do_splits: fe.do_splits,
5724            lme_scale: 1.0,
5725            satd_thresh: fe.satd_var_thresh,
5726        },
5727    );
5728    let mut mb_qpy = enc_scratch::take_qpy();
5729    mb_qpy.clear();
5730    mb_qpy.resize(fe.mb_w * fe.mb_h, qp);
5731    let mut skip_run = 0u32;
5732    // ---- adaptive RD-skip gate -------------------------------------------
5733    // RD P_Skip is a large win on temporally redundant content and a large LOSS
5734    // on detailed content (SSIM: akiyo -13.1%, FourPeople -5.6% vs in_to_tree
5735    // +34.0%, stockholm +95.7%). The separating signal is the content's own
5736    // FREE-skip rate — how much of it is already exactly redundant — and the gap
5737    // is wide (winners >=58.7%, losers <=6.4%). Measure it ONLINE over the first
5738    // slice of the frame and enable RD skip for the remainder only if it clears
5739    // the bar. Within-frame, so it stays deterministic under GOP-parallel encode.
5740    if is_p && mv_cmp_on() {
5741        MVCMP_FRAME.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
5742    }
5743    // Reused across every RD-skip candidate — see `MbState`.
5744    let mut rdskip_snap = MbState::default();
5745    let mut rdskip_free = 0usize;
5746    let mut rdskip_seen = 0usize;
5747    let mut rdskip_on = false;
5748    let mut greedy_on = fe.greedy_min_free == 0; // 0 = ungated (historic behaviour)
5749    let rdskip_learn = (fe.mb_w * fe.mb_h / 8).max(64);
5750    let rdskip_min_free = fe.rd_skip_min_free as usize;
5751
5752    drop(_g_prep);
5753    let _g_loop = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMbLoop);
5754    for mb_y in 0..fe.mb_h {
5755        for mb_x in 0..fe.mb_w {
5756            let mb_idx = mb_y * fe.mb_w + mb_x;
5757            let mb_qp = aq_qp[mb_idx];
5758            fe.qp = mb_qp;
5759            fe.qpc = chroma_qp(mb_qp);
5760            // P_Skip: motion-compensate from the most-recent reference; accept if free.
5761            // Chosen inter coding: (mb_type, per-partition (ref_idx, mv)).
5762            let mut inter: Option<InterChoice> = None;
5763            // Bits of an inter macroblock already encoded by the skip decision
5764            // below. When present the emit path splices them instead of encoding
5765            // the same macroblock a second time.
5766            let mut coded: Option<BitWriter> = None;
5767            if is_p {
5768                if num_refs > 0 {
5769                    // P_Skip prediction (reference 0). A free skip (zero residual) is
5770                    // taken immediately; the quality preset also takes a greedy P_Skip
5771                    // when its SAD is below the neighbour-predicted bound (below).
5772                    let _g_skip = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncSkip);
5773                    let _g_smc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Neighbors);
5774                    rdskip_seen += 1;
5775                    if rdskip_seen >= rdskip_learn {
5776                        rdskip_on = rdskip_free * 100 >= rdskip_seen * rdskip_min_free;
5777                        greedy_on = fe.greedy_min_free == 0
5778                            || rdskip_free * 100 >= rdskip_seen * fe.greedy_min_free as usize;
5779                    }
5780                    let mv_skip = fe.skip_mv(mb_x, mb_y);
5781                    let skip_y = fe.skip_predict_luma(refs, mb_x, mb_y, mv_skip);
5782                    drop(_g_smc);
5783                    let luma_free = fe.skip_luma_is_free(&sy, mb_x, mb_y, &skip_y);
5784                    // Chroma MC only when it can matter: luma already free (so the
5785                    // skip might be taken) or the quality path needs it below.
5786                    let skip_c = if luma_free || !fe.fast {
5787                        fe.skip_predict_chroma(refs, mb_x, mb_y, mv_skip)
5788                    } else {
5789                        [[0u8; 64]; 2]
5790                    };
5791                    let is_free =
5792                        luma_free && fe.skip_chroma_is_free(&su, &sv, mb_x, mb_y, &skip_c);
5793                    // Skip-prediction luma SAD (the quality preset's predicted-SAD apparatus).
5794                    let skip_sad = if fe.fast {
5795                        0
5796                    } else {
5797                        let (lx, ly) = (mb_x * 16, mb_y * 16);
5798                        let mut s = 0u32;
5799                        for dy in 0..16 {
5800                            let src = &sy[(ly + dy) * fe.cw + lx..][..16];
5801                            let p = &skip_y[dy * 16..][..16];
5802                            s += src.iter().zip(p).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
5803                        }
5804                        s
5805                    };
5806                    if is_free {
5807                        fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, &skip_c);
5808                        if !fe.fast {
5809                            fe.mb_was_skip[mb_idx] = true;
5810                            fe.mb_skip_sad[mb_idx] = skip_sad;
5811                        }
5812                        mb_qpy[mb_idx] = fe.cur_qp; // skip inherits QPy
5813                        rdskip_free += 1;
5814                        if precomp {
5815                            bs_grid[mb_idx] = derive_mb_bs_from(&fe, mb_x, mb_y, rusty_h264_common::deblock::MbKind::Skip);
5816                        }
5817                        skip_run += 1;
5818                        continue;
5819                    }
5820                    drop(_g_skip);
5821                    let (lx, ly) = (mb_x * 16, mb_y * 16);
5822                    let nb = {
5823                        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMvPred);
5824                        fe.mv_neighbors_block(mb_x as isize * 4, mb_y as isize * 4, 4)
5825                    };
5826                    let lme = lambda.sqrt();
5827
5828                    if fe.fast {
5829                        // Fast preset: pick the cheapest *prediction* by SATD (no
5830                        // trial-encoding), then always code its residual — P_16x16 vs
5831                        // I_16x16 only, no sub-partitions. Crucially it does NOT make a
5832                        // SATD skip-vs-code decision: P_Skip is taken only for a truly
5833                        // free (zero-residual) macroblock, handled above. Pricing skip
5834                        // by SATD would drop residual the QP wants coded and tank PSNR;
5835                        // like x264's fast presets, fast trades *efficiency* (more bits)
5836                        // for speed, not quality. The faster ME is what makes it fast.
5837                        // Adaptive dispatch: high-variance MBs price by SATD (both
5838                        // inter — via `mb_use_satd` in `best_part` — and intra), the
5839                        // rest by cheap SAD. Set the per-MB flag before best_part.
5840                        // Dedup (E15 W9): memoized twin, already built when satd_q > 0.
5841                        fe.mb_use_satd = fe.satd_q > 0.0
5842                            && sig.mb_vars()[mb_y * fe.mb_w + mb_x] >= fe.satd_var_thresh;
5843                        let (r16, mv16, cost_inter) =
5844                            fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 16, &[], lme);
5845                        let cost_intra = if fe.mb_use_satd {
5846                            fe.best_i16_satd(&sy, mb_x, mb_y)
5847                        } else {
5848                            fe.best_i16_sad(&sy, mb_x, mb_y)
5849                        } + (lme * fe.tune_intra_penalty) as i64;
5850                        inter = if cost_intra < cost_inter {
5851                            None // intra wins → encode_mb below
5852                        } else {
5853                            Some((0, vec![(r16, mv16)]))
5854                        };
5855                    } else {
5856                        // Quality preset: openh264's mode-decision model — SATD + λ·mvbits
5857                        // cost ESTIMATE (no per-candidate trial-encode); modes are ranked
5858                        // by that cost and only the winner is encoded (once) below. This
5859                        // removes ~the 93%-of-quality re-encode cost.
5860
5861                        // Greedy P_Skip (openh264 `PredictSadSkip`): take the skip when its
5862                        // luma SAD is below the neighbour-predicted skip SAD. The threshold
5863                        // is what skip neighbours achieved, so the skip propagates from the
5864                        // free skips and self-limits — no fixed bound, no inter-chain drift.
5865                        if fe.greedy_skip && greedy_on && skip_sad < fe.pred_skip_sad(mb_x, mb_y) {
5866                            fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, &skip_c);
5867                            fe.mb_was_skip[mb_idx] = true;
5868                            fe.mb_skip_sad[mb_idx] = skip_sad;
5869                            mb_qpy[mb_idx] = fe.cur_qp; // skip inherits QPy
5870                            if precomp {
5871                                bs_grid[mb_idx] = derive_mb_bs_from(&fe, mb_x, mb_y, rusty_h264_common::deblock::MbKind::Skip);
5872                            }
5873                            skip_run += 1;
5874                            continue;
5875                        }
5876
5877                        // 16×16 baseline (SATD + λ·bits, with sub-pel refinement).
5878                        let (r16, mv16, c16) =
5879                            fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 16, &[], lme);
5880                        let mut best_c = c16;
5881                        let mut pick: Option<InterChoice> = Some((0, vec![(r16, mv16)]));
5882
5883                        // Sub-partitions, ranked by SATD, gated on a heavy 16×16 (a likely
5884                        // motion boundary — the 4 sub-pel searches are the expensive part).
5885                        const QSTEP16: [i64; 6] = [10, 11, 13, 14, 16, 18];
5886                        let qstep16 = QSTEP16[(fe.qp % 6) as usize] << (fe.qp / 6);
5887                        let split_gate = ((30 * (qstep16 + 160)) >> 3) * 2;
5888                        let split_t = split_t();
5889                        if fe.do_splits && c16 > split_gate && (split_t <= 0.0 || (c16 as f64) >= split_t * lme) {
5890                            let (rt, mvt, ct) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 8, &[mv16], lme);
5891                            let (rb, mvb, cb) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly + 8, 16, 8, &[mv16], lme);
5892                            let (rl, mvl, cl) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 8, 16, &[mv16], lme);
5893                            let (rr, mvr, cr) = fe.best_part(refs, &sy, &nb, num_refs, lx + 8, ly, 8, 16, &[mv16], lme);
5894                            if ct + cb < best_c {
5895                                best_c = ct + cb;
5896                                pick = Some((1u8, vec![(rt, mvt), (rb, mvb)]));
5897                            }
5898                            if cl + cr < best_c {
5899                                best_c = cl + cr;
5900                                pick = Some((2u8, vec![(rl, mvl), (rr, mvr)]));
5901                            }
5902
5903                            // P_8x8: four independent 8×8 sub-partitions (finer motion
5904                            // granularity — the win on complex/boundary motion). Each 8×8
5905                            // seeded by the 16×16 MV; the exact chained MVD is computed in
5906                            // plan_inter_mb. Same heavy-16×16 gate as the 2-way splits.
5907                            if fe.sub8x8 {
5908                                let mut c8 = (lme * 4.0) as i64; // ~4 sub_mb_type bits
5909                                let mut p8 = Vec::with_capacity(4);
5910                                for &(qx, qy) in &[(0usize, 0usize), (8, 0), (0, 8), (8, 8)] {
5911                                    let (r, mv, c) = fe.best_part(
5912                                        refs, &sy, &nb, num_refs, lx + qx, ly + qy, 8, 8, &[mv16], lme,
5913                                    );
5914                                    c8 += c;
5915                                    p8.push((r, mv));
5916                                }
5917                                if c8 < best_c {
5918                                    best_c = c8;
5919                                    pick = Some((3u8, p8));
5920                                }
5921                            }
5922                        }
5923
5924                        // U5-struct: everything above searched FULL-PEL only when
5925                        // `sp_defer` is set. Now that a shape has won, refine just its
5926                        // sub-blocks — the losing shapes' refinements were the waste
5927                        // (measured 3.4–6.4× more refinement than necessary).
5928                        if fe.sp_defer.get() {
5929                            if let Some((mode, parts)) = pick.as_mut() {
5930                                let regions: &[(usize, usize, usize, usize)] = match mode {
5931                                    1 => &[(0, 0, 16, 8), (0, 8, 16, 8)],
5932                                    2 => &[(0, 0, 8, 16), (8, 0, 8, 16)],
5933                                    3 => &[(0, 0, 8, 8), (8, 0, 8, 8), (0, 8, 8, 8), (8, 8, 8, 8)],
5934                                    _ => &[(0, 0, 16, 16)],
5935                                };
5936                                let mut tot = if *mode == 3 { (lme * 4.0) as i64 } else { 0 };
5937                                for (i, &(qx, qy, pw, ph)) in regions.iter().enumerate() {
5938                                    let (r, mv) = parts[i];
5939                                    let (m2, c2) = fe.refine_part(
5940                                        refs, &sy, &nb, num_refs, lx + qx, ly + qy, pw, ph, lme, r, mv,
5941                                    );
5942                                    parts[i] = (r, m2);
5943                                    tot += c2;
5944                                }
5945                                best_c = tot;
5946                            }
5947                        }
5948                        if split_harvest::enabled() {
5949                            let won = match pick.as_ref().map(|p| p.0) {
5950                                Some(0) | None => 0u8,
5951                                Some(m) => m,
5952                            };
5953                            split_harvest::record(c16, best_c, lme, split_gate, won);
5954                        }
5955                        // Intra is ALWAYS a candidate (textured / occluded content):
5956                        // I_16x16 SATD + λ·mode bits.
5957                        let c_intra = fe.best_i16_satd(&sy, mb_x, mb_y)
5958                            + (lme * fe.tune_intra_penalty) as i64;
5959                        inter = if c_intra < best_c { None } else { pick };
5960                        fe.mb_was_skip[mb_idx] = false;
5961                        fe.mb_skip_sad[mb_idx] = skip_sad;
5962                    }
5963
5964                    // ---- RD P_Skip ----------------------------------------
5965                    // The default criterion skips only when the residual quantizes
5966                    // to EXACTLY zero. That matches x264 at both extremes (akiyo
5967                    // 72.5% vs 73.6%, mobile 1.0% vs 1.4%) but falls 17-23 points
5968                    // short in the middle (foreman 6.4% vs 23.6%), because x264
5969                    // also skips macroblocks whose residual is small-but-nonzero.
5970                    // Decide it properly: trial-encode the chosen mode for real
5971                    // bits + reconstruction SSD, and compare J = SSD + lambda*R
5972                    // against the skip. Raw-SAD versions of this comparison fail
5973                    // badly (coding REPAIRS the residual, skipping keeps it), so
5974                    // the distortion term has to come from the reconstruction.
5975                    if fe.rd_skip && rdskip_on && inter.is_some() {
5976                        let skip_cp = fe.skip_predict_chroma(refs, mb_x, mb_y, mv_skip);
5977                        // A P_Skip carries no residual, so its RECONSTRUCTION *is*
5978                        // its prediction — the skip SSD needs no state mutation at
5979                        // all. The commit / mb_ssd / restore round trip this
5980                        // replaces cost a full macroblock save+restore on every
5981                        // candidate, including the ones that go on to code.
5982                        let ssd_s = fe.pred_ssd(&sy, &su, &sv, mb_x, mb_y, &skip_y, &skip_cp);
5983                        debug_assert_eq!(ssd_s, {
5984                            let snap = fe.save_mb(mb_x, mb_y);
5985                            fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, &skip_cp);
5986                            let v = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y);
5987                            fe.load_mb(mb_x, mb_y, &snap);
5988                            v
5989                        }, "skip prediction SSD must equal the committed-skip reconstruction SSD");
5990                        // A skip inside a run costs ~1 bit of mb_skip_run.
5991                        let j_skip = ssd_s as f64 + lambda;
5992                        // Search-skip gate: when the null arm is this cheap it
5993                        // almost always wins, so take it without pricing the coded
5994                        // arm at all. This is where the decision's remaining cost
5995                        // lives — the coded arm is encoded and then discarded on
5996                        // 55-80% of candidates.
5997                        let take_skip = if fe.rd_skip_fast_t > 0.0
5998                            && (ssd_s as f64) <= lambda * fe.rd_skip_fast_t
5999                        {
6000                            true
6001                        } else {
6002                        // Otherwise encode ONCE, into scratch, and KEEP the state.
6003                        // If the skip loses, those are the real bits and they splice
6004                        // straight into the slice. The previous shape trial-encoded,
6005                        // threw the result away, and then encoded again — paying
6006                        // twice on the path that actually codes.
6007                            fe.save_mb_into(mb_x, mb_y, &mut rdskip_snap);
6008                            // E11 dig (11.17): pooled — was a fresh Vec per coded-arm trial.
6009                            let mut scratch = enc_scratch::take_bits();
6010                            scratch.clear();
6011                            {
6012                                let (m, p) = inter.as_ref().unwrap();
6013                                fe.encode_inter_mb(
6014                                    &mut scratch, refs, &sy, &su, &sv, mb_x, mb_y, *m, p,
6015                                );
6016                            }
6017                            let bits_c = scratch.bit_len();
6018                            let ssd_c = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y);
6019                            let won = j_skip <= ssd_c as f64 + lambda * bits_c as f64;
6020                            if won {
6021                                fe.load_mb(mb_x, mb_y, &rdskip_snap); // undo it; take the skip
6022                                enc_scratch::put_bits(scratch); // recycle the unused coded arm
6023                                true
6024                            } else {
6025                                coded = Some(scratch); // keep it — no second encode
6026                                false
6027                            }
6028                        };
6029                        if take_skip {
6030                            fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, &skip_cp);
6031                            if !fe.fast {
6032                                fe.mb_was_skip[mb_idx] = true;
6033                                fe.mb_skip_sad[mb_idx] = skip_sad;
6034                            }
6035                            mb_qpy[mb_idx] = fe.cur_qp;
6036                            if precomp {
6037                                bs_grid[mb_idx] = derive_mb_bs_from(
6038                                    &fe, mb_x, mb_y,
6039                                    rusty_h264_common::deblock::MbKind::Skip,
6040                                );
6041                            }
6042                            skip_run += 1;
6043                            continue;
6044                        }
6045                    }
6046                }
6047                w.write_ue(skip_run); // run of skipped macroblocks before this one
6048                skip_run = 0;
6049            }
6050            if mv_force_on() && is_p && inter.is_some() {
6051                let fi = MVCMP_FRAME.load(std::sync::atomic::Ordering::Relaxed);
6052                let ext = EXT_MV.lock().unwrap();
6053                if let Some(field) = ext.get(fi) {
6054                    let w4 = fe.mb_w * 4;
6055                    let b0 = (mb_y * 4) * w4 + mb_x * 4;
6056                    // uniform 16x16 only: a sub-partitioned macroblock has no single
6057                    // vector to transplant, so leave those to our own decision
6058                    let uniform = (0..4).all(|r| {
6059                        (0..4).all(|c| field.get(b0 + r * w4 + c) == field.get(b0))
6060                    });
6061                    if uniform {
6062                        if let Some(&emv) = field.get(b0) {
6063                            inter = Some((0, vec![(0, emv)]));
6064                            MVCMP[6].fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6065                        }
6066                    }
6067                }
6068            }
6069            if mv_cmp_on() && is_p {
6070                if let Some((mode, parts)) = inter.as_ref() {
6071                    let fi = MVCMP_FRAME.load(std::sync::atomic::Ordering::Relaxed);
6072                    let ext = EXT_MV.lock().unwrap();
6073                    if let Some(field) = ext.get(fi) {
6074                        let bidx = (mb_y * 4) * (fe.mb_w * 4) + mb_x * 4;
6075                        if let Some(&emv) = field.get(bidx) {
6076                            let (mode, parts) = (*mode, parts.clone());
6077                            drop(ext);
6078                            // Both priced through the SAME pipeline: MC, transform,
6079                            // quantize, CAVLC. Real bits, real reconstruction SSD.
6080                            let (so, bo) =
6081                                fe.trial_inter(refs, &sy, &su, &sv, mb_x, mb_y, mode, &parts);
6082                            let (se, be) = fe.trial_inter(
6083                                refs, &sy, &su, &sv, mb_x, mb_y, 0, &[(0, emv)],
6084                            );
6085                            let jo = so as f64 + lambda * bo as f64;
6086                            let je = se as f64 + lambda * be as f64;
6087                            use std::sync::atomic::Ordering::Relaxed;
6088                            MVCMP[0].fetch_add(1, Relaxed);
6089                            MVCMP[1].fetch_add(bo as u64, Relaxed);
6090                            MVCMP[2].fetch_add(be as u64, Relaxed);
6091                            MVCMP[3].fetch_add(so.max(0) as u64, Relaxed);
6092                            MVCMP[4].fetch_add(se.max(0) as u64, Relaxed);
6093                            MVCMP[5].fetch_add((je < jo) as u64, Relaxed);
6094                            MVCMP[6].fetch_add((parts[0].1 != emv) as u64, Relaxed);
6095                        }
6096                    }
6097                }
6098            }
6099            // Capture the kind before `inter` is consumed: the deblocking
6100            // strengths of an intra macroblock are pure constants.
6101            let mb_kind = match &inter {
6102                // A single partition covers the whole macroblock with one
6103                // (ref, mv), which collapses the internal derivation to nnz.
6104                Some((_, parts)) if parts.len() == 1 => {
6105                    rusty_h264_common::deblock::MbKind::InterUniform
6106                }
6107                Some(_) => rusty_h264_common::deblock::MbKind::Inter,
6108                None => rusty_h264_common::deblock::MbKind::Intra,
6109            };
6110            match inter {
6111                Some((mode, parts)) => match coded {
6112                    // Encoded already, during the skip decision — splice the bits in
6113                    // rather than encoding this macroblock for a second time.
6114                    Some(sc) => {
6115                        w.append(&sc);
6116                        enc_scratch::put_bits(sc);
6117                    }
6118                    None => {
6119                        fe.encode_inter_mb(w, refs, &sy, &su, &sv, mb_x, mb_y, mode, &parts)
6120                    }
6121                },
6122                None => encode_mb(&mut fe, w, mb_x, mb_y, &sy, &su, &sv, is_p),
6123            }
6124            mb_qpy[mb_idx] = fe.cur_qp; // ACTUAL QPy (updated iff an mb_qp_delta was coded)
6125            if precomp {
6126                bs_grid[mb_idx] = derive_mb_bs_from(&fe, mb_x, mb_y, mb_kind);
6127            }
6128        }
6129    }
6130    debug_assert!(
6131        !precomp || bs_grid.iter().all(|b| *b != rusty_h264_common::deblock::MbBs::UNSET),
6132        "a macroblock loop exit failed to store its boundary strengths"
6133    );
6134    if is_p && skip_run > 0 {
6135        w.write_ue(skip_run); // trailing skipped macroblocks
6136    }
6137    w.rbsp_trailing_bits();
6138
6139    // Deblock the reconstruction; the result is the inter reference. Baseline: the
6140    // intra mask is `!inter_y` (passed directly, no alloc); no B (List-1 empty); no
6141    // 8×8 transform (t8x8 empty). ref_id is each block's List-0 ref index.
6142    drop(_g_loop);
6143    let _g_fin = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncFinal);
6144    // No NO_REF-mapping collect: it ran over every 4x4 block every frame (~1.9 MB
6145    // of allocation + map at 1080p) to produce a grid that is only ever read for
6146    // INTER-vs-INTER comparisons, where the encoder's raw indices are already
6147    // equivalent. Intra blocks short-circuit before reference identity is touched.
6148    let info = rusty_h264_common::deblock::BlockInfo {
6149        inter: &fe.inter_y,
6150        nnz: &fe.nnz_y,
6151        mv: &fe.mv_y,
6152        ref_id: &fe.ref_idx_y,
6153        mv1: &[],
6154        ref_id1: &[],
6155        w4: fe.mb_w * 4,
6156        t8x8: &[],
6157        bs: &bs_grid,
6158        poc0: &[],
6159        poc1: &[],
6160        kind: &[],
6161    };
6162    // Per-MB actual QPy (AQ varies it; `mb_qp_delta`-driven). With `aq_strength 0`
6163    // this is uniform, reproducing the old scalar-QP filtering exactly.
6164    drop(_g_fin);
6165    rusty_h264_common::deblock::filter_frame(
6166        &mut fe.rec_y,
6167        &mut fe.rec_u,
6168        &mut fe.rec_v,
6169        fe.mb_w,
6170        fe.mb_h,
6171        &mb_qpy,
6172        0, // chroma_qp_index_offset — the encoder emits 0
6173        0, // slice_alpha_c0_offset — the encoder always signals zero offsets
6174        0, // slice_beta_offset
6175        &info,
6176    );
6177    enc_scratch::put_qpy(mb_qpy);
6178    let w4 = fe.mb_w * 4;
6179    crate::RefFrame {
6180        y: fe.rec_y,
6181        u: fe.rec_u,
6182        v: fe.rec_v,
6183        poc: 0,       // set by the caller (it knows the display order)
6184        frame_num: 0, // set by the caller
6185        // List-0 motion field, for a later B-frame's spatial-direct colZeroFlag.
6186        mv: fe.mv_y,
6187        ref_idx: fe.ref_idx_y,
6188        mv1: Vec::new(),
6189        ref_idx1: Vec::new(),
6190        w4,
6191        // Filtered lazily on first sub-pel search use (see `RefFrame::hpel`).
6192        hpel: std::sync::OnceLock::new(),
6193    }
6194}
6195
6196/// Codes a B-slice's macroblock layer. B-frames are **non-reference**, so the
6197/// reconstruction is computed (the CAVLC nnz predictor needs it) but discarded.
6198///
6199/// This brick: every MB is coded `B_L0_16x16` (`mb_type == 1`) — a real
6200/// motion-compensated prediction from `l0` (the nearest PAST anchor, List-0 index
6201/// 0) plus a coded residual. Because every MB is List-0-only with `ref_idx`
6202/// inferred 0, the per-4×4 List-0 motion field and its median `mvd` predictor are
6203/// byte-identical to the P-slice `P_L0_16x16` path — so this reuses
6204/// [`FrameEncoder::encode_inter_mb_v1_b`] verbatim, differing from P only in the
6205/// `mb_type` value. `l1` (nearest future anchor) is unused until `B_Bi` lands.
6206#[allow(clippy::too_many_arguments)]
6207#[allow(clippy::too_many_arguments)]
6208pub(crate) fn encode_slice_data_b(
6209    w: &mut BitWriter,
6210    cfg: &EncoderConfig,
6211    frame: &YuvFrame,
6212    qp: u8,
6213    poc: i32,
6214    l0: &crate::RefFrame,
6215    l1: &crate::RefFrame,
6216    _qpo: &[i32],
6217) {
6218    let mut fe = FrameEncoder::new(cfg);
6219    fe.qp = qp;
6220    fe.qpc = chroma_qp(qp);
6221    fe.cur_qp = qp;
6222    if cfg.cabac_dz_div > 0 {
6223        fe.idz = cfg.cabac_dz_div; // CABAC-specific dead-zone override
6224    } // QPY_PREV starts at the slice QP so the first mb_qp_delta is 0
6225    // Implicit bi-prediction weights from the anchor POC distances (matches the
6226    // decoder). Equidistant B (bframes==1) → 32:32 (plain average); unequal → weighted.
6227    fe.bi_w = implicit_bi_weights(poc, l0.poc, l1.poc);
6228    let (sy, su, sv) = coded_source(cfg, frame);
6229    // Great Gate P1: the shared per-frame signal vector (List-0 anchor as ref).
6230    let sig = FrameSignals::new(&sy, fe.cw, fe.mb_w, fe.mb_h, Some(&l0.y[..]));
6231    apply_screen_t8_veto(&mut fe, &sig);
6232    let lambda = 0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
6233    let lme = lambda.sqrt();
6234    let refs = std::slice::from_ref(l0); // List-0 = [nearest past anchor]
6235    // Same content-adaptive SAD→SATD dispatch as the P path (codec-content-adaptive-
6236    // dispatch): the top `satd_q` fraction of highest-variance MBs price by SATD.
6237    if fe.satd_q > 0.0 {
6238        fe.satd_var_thresh = sig.var_percentile_thresh(fe.satd_q);
6239    }
6240    signals::harvest(
6241        &sig,
6242        'b',
6243        qp,
6244        &signals::GateDecisions { satd_thresh: fe.satd_var_thresh, ..Default::default() },
6245    );
6246    let mut skip_run = 0u32; // run of consecutive B_Skip MBs pending a coded MB
6247    for mb_y in 0..fe.mb_h {
6248        for mb_x in 0..fe.mb_w {
6249            let (lx, ly) = (mb_x * 16, mb_y * 16);
6250            let (pbx, pby) = (mb_x as isize * 4, mb_y as isize * 4);
6251            // Dedup (E15 W9): memoized twin, already built when satd_q > 0.
6252            fe.mb_use_satd =
6253                fe.satd_q > 0.0 && sig.mb_vars()[mb_y * fe.mb_w + mb_x] >= fe.satd_var_thresh;
6254            // Per-list median MV predictors — the search-rate center AND the actual
6255            // `mvd` predictor (identical to the decoder's `predict_partition_mv`).
6256            let n0 = fe.mv_neighbors_block_list(pbx, pby, 4, 0);
6257            let n1 = fe.mv_neighbors_block_list(pbx, pby, 4, 1);
6258            let pmv0 = predict_partition_mv(0, 0, n0[0], n0[1], n0[2], 0);
6259            let pmv1 = predict_partition_mv(0, 0, n1[0], n1[1], n1[2], 0);
6260            // Independent List-0 / List-1 motion searches (their J already includes
6261            // the mvd rate against the matching predictor, so J0/J1 compare directly).
6262            // Spatial-direct prediction (basis of B_Skip and B_Direct_16x16).
6263            let (dp, dc, dmotion) = fe.b_direct(l0, l1, mb_x, mb_y);
6264            // B_Skip: take the direct prediction with NO coded residual (~1 bit in
6265            // the mb_skip_run) only when it is truly FREE — its residual quantizes to
6266            // zero at the B QP, so skipping loses nothing. (A looser SATD-threshold
6267            // skip was measured strictly WORSE: on B's derived prediction the SATD
6268            // proxy over-values the skip, dropping residual the quantizer wanted —
6269            // the same proxy-vs-quantization gap seen on sub-pel. So skip only when
6270            // provably free; the rest goes through the L0/L1/Bi/Direct RD decision.)
6271            if fe.skip_luma_is_free(&sy, mb_x, mb_y, &dp)
6272                && fe.skip_chroma_is_free(&su, &sv, mb_x, mb_y, &dc)
6273            {
6274                fe.commit_direct_motion(mb_x, mb_y, &dmotion);
6275                fe.commit_pred_pixels(mb_x, mb_y, &dp, &dc);
6276                skip_run += 1;
6277                continue;
6278            }
6279            let d_direct = fe.pred_dist(&sy, lx, ly, &dp);
6280            let (mv0, j0) = fe.motion_search(l0, &sy, lx, ly, 16, 16, &[pmv0], lme, None);
6281            let (mv1, j1) = fe.motion_search(l1, &sy, lx, ly, 16, 16, &[pmv1], lme, None);
6282            // Bi: average the two winners' predictions; rate = both mvds.
6283            let d_bi = fe.bi_dist(l0, l1, &sy, lx, ly, mv0, mv1);
6284            let r_bi = mvd_bits(mv0.0 - pmv0.0) + mvd_bits(mv0.1 - pmv0.1)
6285                + mvd_bits(mv1.0 - pmv1.0) + mvd_bits(mv1.1 - pmv1.1);
6286            let j_bi = d_bi + (lme * r_bi as f64) as i64;
6287            // B_Direct (mb_type 0): spatial-direct prediction, NO coded MV — so its
6288            // J (d_direct, computed above) carries zero mvd rate and it wins wherever
6289            // the derived motion predicts as well as an explicit vector.
6290            // Pick the cheapest of {0=Direct, 1=L0, 2=L1, 3=Bi}; Direct wins ties.
6291            let (mut dir, mut best) = (0u8, d_direct);
6292            if j0 < best { dir = 1; best = j0; }
6293            if j1 < best { dir = 2; best = j1; }
6294            if j_bi < best { dir = 3; best = j_bi; }
6295            let _ = best; // CAVLC B has no partition search to price against it
6296            w.write_ue(skip_run); // run of B_Skips preceding this coded MB
6297            skip_run = 0;
6298            let bspec = BInter { dir, l1, mv0, mv1, mvmode: 0, parts2: [(0, (0, 0), (0, 0)); 2] };
6299            fe.encode_inter_mb_v1_b(w, refs, &sy, &su, &sv, mb_x, mb_y, 0, &[], Some(bspec));
6300        }
6301    }
6302    if skip_run > 0 {
6303        w.write_ue(skip_run); // trailing B_Skip run
6304    }
6305    w.rbsp_trailing_bits();
6306}
6307
6308/// `se(d)` Exp-Golomb bit length — the `mvd`-component rate for the B mode
6309/// decision. Same closed form as `motion_search`'s private `mvbits` (kept separate
6310/// so the P search's heuristic — and thus P output — is untouched).
6311#[inline(always)]
6312fn mvd_bits(d: i32) -> u32 {
6313    let codenum = if d > 0 { (2 * d - 1) as u32 } else { (-2 * d) as u32 };
6314    1 + 2 * (31 - (codenum + 1).leading_zeros())
6315}
6316
6317/// Reads a 4×4 residual block (source minus a raster prediction block).
6318/// Writes `ref_idx_l0` (spec: `te(v)` when two references are active — a single
6319/// flag — else `ue(v)`). Only called when more than one reference is active.
6320fn write_ref_idx(w: &mut BitWriter, refi: i32, num_refs: usize) {
6321    if num_refs == 2 {
6322        w.write_bit(refi == 0); // te(v): value = !bit
6323    } else {
6324        w.write_ue(refi as u32);
6325    }
6326}
6327
6328/// Approximate bit cost of coding `ref_idx = r` with `num_refs` active, for the
6329/// motion-estimation rate term. Zero with a single reference (no `ref_idx` coded).
6330fn ref_bits(r: usize, num_refs: usize) -> u32 {
6331    if num_refs <= 1 {
6332        0
6333    } else if num_refs == 2 {
6334        1
6335    } else {
6336        let mut n = r as u32 + 1;
6337        let mut len = 1;
6338        while n > 1 {
6339            n >>= 1;
6340            len += 2;
6341        }
6342        len
6343    }
6344}
6345
6346fn residual(src: &[u8], stride: usize, x0: usize, y0: usize, pred: &[i32; 16]) -> [i32; 16] {
6347    let mut r = [0i32; 16];
6348    for dy in 0..4 {
6349        let row = &src[(y0 + dy) * stride + x0..][..4];
6350        for dx in 0..4 {
6351            r[dy * 4 + dx] = row[dx] as i32 - pred[dy * 4 + dx];
6352        }
6353    }
6354    r
6355}
6356
6357/// Writes reconstructed samples back into a plane.
6358fn store(plane: &mut [u8], stride: usize, x0: usize, y0: usize, s: &[u8; 16]) {
6359    for dy in 0..4 {
6360        let d = (y0 + dy) * stride + x0;
6361        plane[d..d + 4].copy_from_slice(&s[dy * 4..dy * 4 + 4]);
6362    }
6363}
6364
6365/// Extracts the 4×4 raster prediction block at `(bx, by)` from a 16×16 (256-sample)
6366/// luma prediction.
6367#[cfg(not(accel))]
6368fn pred_block(pred: &[u8; 256], bx: usize, by: usize) -> [i32; 16] {
6369    let mut p = [0i32; 16];
6370    for dy in 0..4 {
6371        let row = &pred[(by * 4 + dy) * 16 + bx * 4..][..4];
6372        for dx in 0..4 {
6373            p[dy * 4 + dx] = row[dx] as i32;
6374        }
6375    }
6376    p
6377}
6378
6379/// Sum of absolute transformed differences over a 16×16 luma macroblock — the
6380/// mode-decision cost (correlates with coded bits better than plain SAD).
6381/// SATD of a `w`×`h` luma block: `src` (stride `ss`) vs `pred` (stride `ps`).
6382///
6383/// With the `accel` cfg and a supported size this is `2 · rusty_h264_accel::satd_*`
6384/// (the portable SIMD kernels that replaced openh264's asm, same contract), which
6385/// is **byte-identical** to the scalar `Σ|H·d|` Hadamard: the kernel returns
6386/// `(Σ+1)>>1`, and `Σ` is always even (every 4×4 Hadamard coefficient shares the block
6387/// sum's parity, so 16 of them sum even), so `×2` recovers `Σ` exactly — proven over
6388/// 20 k random blocks at 4×4/8×8/16×16 in `tests/satd_asm_compare.rs`. Without accel (or
6389/// for an unsupported size) it falls back to the scalar Hadamard — the original path.
6390#[inline]
6391pub(crate) fn satd_px(src: &[u8], ss: usize, pred: &[u8], ps: usize, w: usize, h: usize) -> i64 {
6392    #[cfg(accel)]
6393    {
6394        let asm = match (w, h) {
6395            (16, 16) => Some(rusty_h264_accel::satd_16x16(src, ss, pred, ps)),
6396            (16, 8) => Some(rusty_h264_accel::satd_16x8(src, ss, pred, ps)),
6397            (8, 16) => Some(rusty_h264_accel::satd_8x16(src, ss, pred, ps)),
6398            (8, 8) => Some(rusty_h264_accel::satd_8x8(src, ss, pred, ps)),
6399            (4, 4) => Some(rusty_h264_accel::satd_4x4(src, ss, pred, ps)),
6400            // CENSUS #8, closed by COMPOSITION rather than new intrinsics. The
6401            // sub-8x8 split arm made 8x4 and 4x8 hot, and openh264 ships no
6402            // kernel for either — but SATD here is DEFINED as the sum of 4x4
6403            // Hadamards (see the scalar arm below), so both are exactly two
6404            // `satd_4x4` calls. Each wrapper returns (Σ+1)>>1 and every 4x4 Σ is
6405            // even, so summing the halves and doubling once is bit-identical to
6406            // the scalar path — verified by hash, not argued.
6407            (8, 4) => Some(
6408                rusty_h264_accel::satd_4x4(src, ss, pred, ps)
6409                    + rusty_h264_accel::satd_4x4(&src[4..], ss, &pred[4..], ps),
6410            ),
6411            (4, 8) => Some(
6412                rusty_h264_accel::satd_4x4(src, ss, pred, ps)
6413                    + rusty_h264_accel::satd_4x4(&src[4 * ss..], ss, &pred[4 * ps..], ps),
6414            ),
6415            _ => None,
6416        };
6417        if let Some(v) = asm {
6418            return 2 * v as i64;
6419        }
6420    }
6421    // Scalar Hadamard (also the no-asm path): Σ over the 4×4 sub-blocks.
6422    let (nbx, nby) = (w / 4, h / 4);
6423    let mut blocks = [[0i32; 16]; 16];
6424    let mut bi = 0;
6425    for by in 0..nby {
6426        for bx in 0..nbx {
6427            let blk = &mut blocks[bi];
6428            for dy in 0..4 {
6429                for dx in 0..4 {
6430                    blk[dy * 4 + dx] =
6431                        src[(by * 4 + dy) * ss + bx * 4 + dx] as i32 - pred[(by * 4 + dy) * ps + bx * 4 + dx] as i32;
6432                }
6433            }
6434            bi += 1;
6435        }
6436    }
6437    satd_4x4_sum(&blocks[..nbx * nby])
6438}
6439
6440/// SAD of a `w`×`h` block: `src` (stride `ss`) vs a strided region `r` (stride `rs`)
6441/// — the openh264 `psadbw` kernels for the shapes that ship them (they take strides,
6442/// so in-place plane reads need NO materialize), scalar `Σ abs_diff` rows otherwise
6443/// (LLVM lowers the idiom to `psadbw` for contiguous rows).
6444#[inline]
6445fn sad_strided(src: &[u8], ss: usize, r: &[u8], rs: usize, w: usize, h: usize) -> i64 {
6446    #[cfg(accel)]
6447    {
6448        match (w, h) {
6449            (16, 16) => return rusty_h264_accel::sad_16x16(src, ss, r, rs) as i64,
6450            (16, 8) => return rusty_h264_accel::sad_16x8(src, ss, r, rs) as i64,
6451            (8, 16) => return rusty_h264_accel::sad_8x16(src, ss, r, rs) as i64,
6452            _ => {}
6453        }
6454    }
6455    let mut sad = 0u32;
6456    for dy in 0..h {
6457        let a = &src[dy * ss..][..w];
6458        let b = &r[dy * rs..][..w];
6459        sad += a.iter().zip(b).map(|(&x, &y)| x.abs_diff(y) as u32).sum::<u32>();
6460    }
6461    sad as i64
6462}
6463
6464/// Fused `SAD(src, (a+b+1)>>1)` — the quarter-pel SAD without materializing the
6465/// average (the B2 sibling of the A3 `satd_avg` kernel, scalar because the avg+SAD
6466/// idiom auto-vectorizes and quarter-phase SAD evals are seed-frequency only).
6467#[inline]
6468fn sad_avg_strided(src: &[u8], ss: usize, a: &[u8], b: &[u8], rs: usize, w: usize, h: usize) -> i64 {
6469    let mut sad = 0u32;
6470    for dy in 0..h {
6471        let s = &src[dy * ss..][..w];
6472        let pa = &a[dy * rs..][..w];
6473        let pb = &b[dy * rs..][..w];
6474        for i in 0..w {
6475            let p = ((pa[i] as u16 + pb[i] as u16 + 1) >> 1) as u8;
6476            sad += s[i].abs_diff(p) as u32;
6477        }
6478    }
6479    sad as i64
6480}
6481
6482fn satd_16x16(src: &[u8], stride: usize, lx: usize, ly: usize, pred: &[u8; 256]) -> i64 {
6483    satd_px(&src[ly * stride + lx..], stride, pred, 16, 16, 16)
6484}
6485
6486/// SAD over a 16×16 luma macroblock against a prediction — the fast preset's
6487/// intra cost, kept in the same (SAD) domain as its inter cost. `Σ a.abs_diff(b)`
6488/// over `u8` slices auto-vectorizes to `psadbw`.
6489fn sad_16x16(src: &[u8], stride: usize, lx: usize, ly: usize, pred: &[u8; 256]) -> i64 {
6490    let mut sad = 0u32;
6491    for dy in 0..16 {
6492        let s = &src[(ly + dy) * stride + lx..][..16];
6493        let p = &pred[dy * 16..][..16];
6494        sad += s.iter().zip(p).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
6495    }
6496    sad as i64
6497}
6498
6499/// SATD over an 8×8 chroma block (four 4×4 sub-blocks) against a prediction.
6500fn satd_8x8(src: &[u8], stride: usize, x0: usize, y0: usize, pred: &[u8; 64]) -> i64 {
6501    satd_px(&src[y0 * stride + x0..], stride, pred, 8, 8, 8)
6502}
6503
6504/// SATD of one 4×4 luma block against a prediction.
6505fn satd_4x4(src: &[u8], stride: usize, px: usize, py: usize, pred: &[u8; 16]) -> i64 {
6506    satd_px(&src[py * stride + px..], stride, pred, 4, 4, 4)
6507}
6508
6509/// Whether an `Intra_4x4` mode is usable given top/left neighbor availability.
6510fn i4_mode_available(mode: u8, top: bool, left: bool) -> bool {
6511    match mode {
6512        0 | 3 | 7 => top,        // vertical, diag-down-left, vertical-left
6513        1 | 8 => left,           // horizontal, horizontal-up
6514        2 => true,               // DC
6515        _ => top && left,        // diag-down-right, vertical-right, horizontal-down
6516    }
6517}
6518
6519/// Result of planning an I_4x4 macroblock (luma). Reconstruction has already
6520/// been written into the frame's `rec_y` and `coded_y` by [`plan_i4x4`].
6521struct I4Plan {
6522    modes: [u8; 16],       // per-block intra4x4 mode, raster [lby*4+lbx]
6523    q: [[i32; 16]; 16],    // per-block quantized coefficients (full, raster)
6524    cbp_luma: u32,         // 4-bit coded-block-pattern (one bit per 8×8 region)
6525    nonzero: i64,          // total non-zero coefficients (rate proxy)
6526}
6527
6528/// A fully-decided intra macroblock: the mode decision, the quantized coefficients,
6529/// and the committed reconstruction. Produced by [`plan_mb`] (which reuses the
6530/// entire mode-decision + transform + reconstruct path), then consumed by an
6531/// entropy backend — `emit_mb_cavlc` or `emit_mb_cabac` — so the two coders share
6532/// every non-entropy decision bit-for-bit (the bringup-encoder reuse guarantee).
6533struct MbPlan {
6534    use_i4: bool,
6535    // I_16x16 (when !use_i4): prediction mode, whether any AC is coded (cbp_luma=15),
6536    // luma DC levels (block order), per-4×4 quantized AC (raster).
6537    i16_mode: I16Mode,
6538    i16_cbp15: bool,
6539    i16_dc_levels: [i32; 16],
6540    i16_q: [[i32; 16]; 16],
6541    // I_4x4 (when use_i4 && i8 is None): the sub-plan, already reconstructed.
6542    i4: Option<I4Plan>,
6543    // I_8x8 (High profile; when use_i4 && i8 is Some): the sub-plan, already
6544    // reconstructed. use_i4 means "I_NxN"; i8 present disambiguates 8x8 from 4x4.
6545    i8: Option<I8Plan>,
6546    // Chroma (shared by both luma types).
6547    chroma_mode: u8,
6548    cbp_chroma: u32,
6549    c_dc_levels: [[i32; 4]; 2],
6550    c_q_blocks: [[[i32; 16]; 4]; 2],
6551}
6552
6553/// A fully-decided inter macroblock: the per-partition motion residuals, coded
6554/// block pattern, and quantized residual, with the reconstruction + motion grids
6555/// already committed. Produced by [`FrameEncoder::plan_inter_mb`] (which reuses the
6556/// whole MC + residual + reconstruct path), then coded by `emit_inter_cavlc` or
6557/// `emit_inter_cabac` — so the two entropy backends share every non-entropy
6558/// decision bit-for-bit (the P/B analogue of [`MbPlan`]).
6559struct InterPlan {
6560    // Per-partition mvd (P: mvd_l0; B: mvd_l0 then mvd_l1). 16 slots: P_8x8 with
6561    // 4x4 sub-partitions carries up to 16 (Great Gate P3.3); every other mode <= 4.
6562    mvds: [(i32, i32); 16],
6563    plan_refs: [i32; 4],   // per-partition ref_idx_l0 (multi-ref P; 0 for B / single-ref)
6564    /// P_8x8 only: `sub_mb_type` per 8x8 quad ([0;4] = all 8x8 = the pre-P3.3
6565    /// shape, byte-identical emission). Ignored by every other mode.
6566    sub_types: [u8; 4],
6567    n_mvd: usize,
6568    cbp: u32,
6569    q_blocks: [[i32; 16]; 16], // luma quantized levels (raster) — used when !t8x8
6570    c_dc_levels: [[i32; 4]; 2],
6571    c_q: [[[i32; 16]; 4]; 2],
6572    t8x8: bool,           // transform_size_8x8_flag (High profile, 8x8 luma residual)
6573    q8: [[i32; 64]; 4],   // per-8x8-block quantized levels (raster) — used when t8x8
6574}
6575
6576/// Gathers the 4×4 luma intra neighbors at pixel `(px, py)` from `rec_y`.
6577fn gather_i4(
6578    fe: &FrameEncoder,
6579    px: usize,
6580    py: usize,
6581    avail_top: bool,
6582    avail_left: bool,
6583    bx: usize,
6584    by: usize,
6585) -> ([u8; 8], [u8; 4], u8) {
6586    let (cw, w4) = (fe.cw, fe.mb_w * 4);
6587    let mut top = [0u8; 8];
6588    let mut left = [0u8; 4];
6589    let mut corner = 0;
6590    if avail_top {
6591        let r = (py - 1) * cw + px;
6592        top[..4].copy_from_slice(&fe.rec_y[r..r + 4]);
6593        let tr_avail = bx + 1 < w4 && fe.coded_y[(by - 1) * w4 + (bx + 1)];
6594        if tr_avail {
6595            top[4..8].copy_from_slice(&fe.rec_y[r + 4..r + 8]);
6596        } else {
6597            let t3 = top[3];
6598            top[4..8].fill(t3);
6599        }
6600    }
6601    if avail_left {
6602        let col = &fe.rec_y[py * cw + px - 1..(py + 3) * cw + px];
6603        for i in 0..4 {
6604            left[i] = col[i * cw];
6605        }
6606    }
6607    if avail_top && avail_left {
6608        corner = fe.rec_y[(py - 1) * cw + px - 1];
6609    }
6610    (top, left, corner)
6611}
6612
6613/// Plans an I_4x4 macroblock: picks a mode per 4×4 block (lowest-SATD available
6614/// mode), quantizes, and reconstructs serially into `rec_y` so each block can
6615/// predict from the previous one.
6616/// Neighbour 4x4 block intra mode for the MPM candidate: in-MB blocks read the
6617/// in-progress local `modes`; blocks in earlier MBs read `fe.modes_y`. (bx, by)
6618/// are the current block's absolute 4x4 grid coords.
6619#[inline]
6620fn modes_at(fe: &FrameEncoder, modes: &[u8; 16], lbx: usize, lby: usize, dx: isize, dy: isize, bx: usize, by: usize) -> u8 {
6621    let (nx, ny) = (lbx as isize + dx, lby as isize + dy);
6622    if (0..4).contains(&nx) && (0..4).contains(&ny) {
6623        modes[ny as usize * 4 + nx as usize]
6624    } else {
6625        let w4 = fe.mb_w * 4;
6626        let gx = (bx as isize + dx) as usize;
6627        let gy = (by as isize + dy) as usize;
6628        fe.modes_y[gy * w4 + gx]
6629    }
6630}
6631
6632fn plan_i4x4(fe: &mut FrameEncoder, sy: &[u8], mb_x: usize, mb_y: usize, qp: u8) -> I4Plan {
6633    let w4 = fe.mb_w * 4;
6634    let mut modes = [2u8; 16];
6635    let mut q = [[0i32; 16]; 16];
6636    let mut cbp_luma = 0u32;
6637    let mut nonzero = 0i64;
6638
6639    for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
6640        let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
6641        let (px, py) = (bx * 4, by * 4);
6642        let avail_top = by > 0;
6643        let avail_left = bx > 0;
6644        let (top, left, corner) = gather_i4(fe, px, py, avail_top, avail_left, bx, by);
6645
6646        // Pick the lowest-SATD available mode. RUSTY_FAST_INTRA prunes the
6647        // candidate set to {MPM, DC, V, H} (x264-ultrafast-style); the H.264
6648        // predicted mode (min of left/top block modes, DC on the edge) keeps the
6649        // 1-bit prev_intra4x4_pred_mode signalling cheap for the common winner.
6650        let mut best_m = 2u8;
6651        let mut best_cost = i64::MAX;
6652        // E2 W16: keep the winner's prediction from the search loop; it was
6653        // re-predicted below after the decision.
6654        let mut best_pred = [0u8; 16];
6655        if fe.fast && fast_intra_enabled() {
6656            let lm = if bx > 0 { modes_at(fe, &modes, lbx, lby, -1, 0, bx, by) } else { 2 };
6657            let tm = if by > 0 { modes_at(fe, &modes, lbx, lby, 0, -1, bx, by) } else { 2 };
6658            let mpm = lm.min(tm);
6659            let mut cands = [mpm, 2u8, 0, 1];
6660            for i in 1..4 {
6661                for j in 0..i {
6662                    if cands[i] == cands[j] {
6663                        cands[i] = 255;
6664                    }
6665                }
6666            }
6667            for &m in cands.iter() {
6668                if m == 255 || !i4_mode_available(m, avail_top, avail_left) {
6669                    continue;
6670                }
6671                let pred = intra4x4_pred(m, avail_top, avail_left, &top, &left, corner);
6672                let cost = satd_4x4(sy, fe.cw, px, py, &pred);
6673                if cost < best_cost {
6674                    best_cost = cost;
6675                    best_m = m;
6676                    best_pred = pred;
6677                }
6678            }
6679        } else {
6680            for m in 0..9u8 {
6681                if !i4_mode_available(m, avail_top, avail_left) {
6682                    continue;
6683                }
6684                let pred = intra4x4_pred(m, avail_top, avail_left, &top, &left, corner);
6685                let cost = satd_4x4(sy, fe.cw, px, py, &pred);
6686                if cost < best_cost {
6687                    best_cost = cost;
6688                    best_m = m;
6689                    best_pred = pred;
6690                }
6691            }
6692        }
6693
6694        // Quantize + reconstruct with the chosen mode (the search's own winner).
6695        let pred = best_pred;
6696        let mut predb = [0i32; 16];
6697        for i in 0..16 {
6698            predb[i] = pred[i] as i32;
6699        }
6700        let res = residual(sy, fe.cw, px, py, &predb);
6701        let qb = rdoq(&forward_core(&res), qp, fe.idz, fe.rdoq_strength, 0); // full 16 incl DC
6702        // E2 W17: the decoder's fused recon (11.6a win 1 executed) — no [u8;16]
6703        // temp, no separate `store` walk; abl/prof parity is inside the callee.
6704        reconstruct_4x4_into(&dequantize(&qb, qp), &pred, 0, 4, &mut fe.rec_y, py * fe.cw + px, fe.cw);
6705        fe.coded_y[by * w4 + bx] = true;
6706
6707        let nz = qb.iter().filter(|&&v| v != 0).count();
6708        if nz > 0 {
6709            cbp_luma |= 1 << ((lby / 2) * 2 + (lbx / 2));
6710        }
6711        nonzero += nz as i64;
6712        modes[lby * 4 + lbx] = best_m;
6713        q[lby * 4 + lbx] = qb;
6714    }
6715    I4Plan {
6716        modes,
6717        q,
6718        cbp_luma,
6719        nonzero,
6720    }
6721}
6722
6723/// A planned I_8x8 macroblock (High profile): one intra8x8 mode + one 8x8 DCT per
6724/// 8x8 block. Reconstructed serially into `rec_y` (each block predicts from the
6725/// previous), and `modes_y` written per block so later blocks' MPM sees earlier.
6726struct I8Plan {
6727    modes: [u8; 4],     // per-8x8-block intra8x8 mode (raster b8 0..3)
6728    q: [[i32; 64]; 4],  // per-8x8-block quantized levels (raster)
6729    cbp_luma: u32,      // 4-bit coded-block-pattern (one bit per 8x8 block)
6730    nonzero: i64,       // rate proxy
6731}
6732
6733/// Forward zig-zag scan of a raster 8x8 block: `scan[i] = raster[ZIGZAG_8X8[i]]`
6734/// (the inverse of the decoder's `un_scan_8x8`).
6735const ZIGZAG_8X8: [usize; 64] = [
6736    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
6737    13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
6738    52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
6739];
6740
6741#[inline]
6742fn scan_8x8_fwd(raster: &[i32; 64]) -> [i32; 64] {
6743    std::array::from_fn(|i| raster[ZIGZAG_8X8[i]])
6744}
6745
6746/// Gather the 8x8 intra reference samples (top[16] incl top-right, left[8], corner)
6747/// from `rec_y` — the encoder counterpart of the decoder's `gather_i8`.
6748fn gather_i8_enc(
6749    fe: &FrameEncoder,
6750    px: usize,
6751    py: usize,
6752    avail_top: bool,
6753    avail_left: bool,
6754    bx: usize,
6755    by: usize,
6756) -> ([u8; 16], [u8; 8], u8, bool) {
6757    let (cw, w4) = (fe.cw, fe.mb_w * 4);
6758    let mut top = [0u8; 16];
6759    let mut left = [0u8; 8];
6760    let mut corner = 0;
6761    if avail_top {
6762        let r = (py - 1) * cw + px;
6763        top[..8].copy_from_slice(&fe.rec_y[r..r + 8]);
6764        let tr_avail = bx + 2 < w4 && fe.coded_y[(by - 1) * w4 + (bx + 2)];
6765        if tr_avail {
6766            top[8..16].copy_from_slice(&fe.rec_y[r + 8..r + 16]);
6767        } else {
6768            let t7 = top[7];
6769            top[8..16].fill(t7);
6770        }
6771    }
6772    if avail_left {
6773        let col = &fe.rec_y[py * cw + px - 1..(py + 7) * cw + px];
6774        for i in 0..8 {
6775            left[i] = col[i * cw];
6776        }
6777    }
6778    let avail_corner = avail_top && avail_left;
6779    if avail_corner {
6780        corner = fe.rec_y[(py - 1) * cw + px - 1];
6781    }
6782    (top, left, corner, avail_corner)
6783}
6784
6785/// Plans an I_8x8 macroblock: per 8x8 block, picks the lowest-SATD intra8x8 mode,
6786/// 8x8-forward-transforms + quantizes, and reconstructs serially into `rec_y`.
6787fn plan_i8x8(fe: &mut FrameEncoder, sy: &[u8], mb_x: usize, mb_y: usize, qp: u8) -> I8Plan {
6788    let w4 = fe.mb_w * 4;
6789    let mut modes = [2u8; 4];
6790    let mut q = [[0i32; 64]; 4];
6791    let mut cbp_luma = 0u32;
6792    let mut nonzero = 0i64;
6793    let weight = [16i32; 64];
6794
6795    for b8 in 0..4usize {
6796        let (b8x, b8y) = (b8 % 2, b8 / 2);
6797        let (px, py) = (mb_x * 16 + b8x * 8, mb_y * 16 + b8y * 8);
6798        let (bx, by) = (mb_x * 4 + b8x * 2, mb_y * 4 + b8y * 2); // top-left 4x4 cell
6799        let avail_top = b8y > 0 || mb_y > 0;
6800        let avail_left = b8x > 0 || mb_x > 0;
6801        let (top, left, corner, avail_corner) =
6802            gather_i8_enc(fe, px, py, avail_top, avail_left, bx, by);
6803
6804        // Mode decision: lowest-SATD available intra8x8 mode (same 9 modes / avail
6805        // rules as intra4x4). The MPM (predict_i4_mode on the top-left 4x4) keeps the
6806        // 1-bit prev-mode signalling cheap; a small penalty biases toward it.
6807        let predicted = predict_i4_mode(fe, bx, by);
6808        let mut best_m = 2u8;
6809        let mut best_cost = i64::MAX;
6810        // E2 W18: keep the winner's prediction; it was re-predicted below.
6811        let mut best_pred = [0u8; 64];
6812        for m in 0..9u8 {
6813            if !i4_mode_available(m, avail_top, avail_left) {
6814                continue;
6815            }
6816            let pred = intra8x8_pred(m, avail_top, avail_left, avail_corner, &top, &left, corner);
6817            let mut cost = satd_8x8(sy, fe.cw, px, py, &pred);
6818            if m != predicted {
6819                cost += 4 * fe.qp as i64; // ~mode-signal penalty (rem vs prev flag)
6820            }
6821            if cost < best_cost {
6822                best_cost = cost;
6823                best_m = m;
6824                best_pred = pred;
6825            }
6826        }
6827        modes[b8] = best_m;
6828
6829        // Forward 8x8 transform + quantize + reconstruct (shared decoder primitives).
6830        let pred = best_pred;
6831        let mut res = [0i32; 64];
6832        // E2 W19: row slices (the proven plan_inter8_luma shape).
6833        for dy in 0..8 {
6834            let row = &sy[(py + dy) * fe.cw + px..][..8];
6835            for dx in 0..8 {
6836                res[dy * 8 + dx] = row[dx] as i32 - pred[dy * 8 + dx] as i32;
6837            }
6838        }
6839        let levels = quantize_8x8(&forward_core_8x8(&res), qp, &weight, fe.idz);
6840        let nz = levels.iter().filter(|&&v| v != 0).count();
6841        if nz > 0 {
6842            cbp_luma |= 1 << b8;
6843        }
6844        nonzero += nz as i64;
6845        q[b8] = levels;
6846
6847        let res_r = inverse_quant_8x8(&levels, qp, &weight);
6848        let predb: [i32; 64] = std::array::from_fn(|i| pred[i] as i32);
6849        let recon = add_residual_8x8(&res_r, &predb);
6850        for dy in 0..8 {
6851            let d = (py + dy) * fe.cw + px;
6852            fe.rec_y[d..d + 8].copy_from_slice(&recon[dy * 8..dy * 8 + 8]);
6853        }
6854        // Publish the mode into all four 4x4 cells + mark coded — so the next 8x8
6855        // block's MPM (and later MBs' neighbours) see it, exactly as the decoder does.
6856        for sry in 0..2 {
6857            let d = (by + sry) * w4 + bx;
6858            fe.modes_y[d..d + 2].fill(best_m);
6859            fe.coded_y[d..d + 2].fill(true);
6860        }
6861    }
6862    I8Plan {
6863        modes,
6864        q,
6865        cbp_luma,
6866        nonzero,
6867    }
6868}
6869
6870/// Inter 8×8-transform luma candidate. Forward-8×8 + quantize + reconstruct each of
6871/// the four 8×8 blocks of the motion-compensated residual `(source − pred_y)`, the
6872/// pure inverse of the decoder's t8x8 inter luma path (`inv_quant8` ∘ `un_scan_8x8`
6873/// ∘ `add_residual_8x8`). Returns the quantized levels, `cbp_luma`, a LEVEL-AWARE rate
6874/// estimate (Σ `rdoq_rate(|level|)` — charges the 8×8's fewer-but-larger coeffs at
6875/// their true bit cost, not a blind count), the 256-sample reconstruction, and its
6876/// SSD vs source. Inter deadzone `dz_div = 6`; scaling list flat (16).
6877#[allow(clippy::too_many_arguments)]
6878fn plan_inter8_luma(
6879    sy: &[u8],
6880    cw: usize,
6881    mb_x: usize,
6882    mb_y: usize,
6883    pred_y: &[u8; 256],
6884    qp: u8,
6885) -> ([[i32; 64]; 4], u32, f64, [u8; 256], i64) {
6886    let weight = [16i32; 64];
6887    let mut q8 = [[0i32; 64]; 4];
6888    let mut cbp = 0u32;
6889    let mut rate = 0f64;
6890    let mut rec = [0u8; 256];
6891    let mut ssd = 0i64;
6892    for b8 in 0..4usize {
6893        let (b8x, b8y) = (b8 % 2, b8 / 2);
6894        let mut res = [0i32; 64];
6895        for dy in 0..8 {
6896            let row = &sy[(mb_y * 16 + b8y * 8 + dy) * cw + mb_x * 16 + b8x * 8..][..8];
6897            for dx in 0..8 {
6898                let p = pred_y[(b8y * 8 + dy) * 16 + (b8x * 8 + dx)] as i32;
6899                res[dy * 8 + dx] = row[dx] as i32 - p;
6900            }
6901        }
6902        let levels = quantize_8x8(&forward_core_8x8(&res), qp, &weight, 6);
6903        let mut nz = false;
6904        for &l in &levels {
6905            if l != 0 {
6906                nz = true;
6907                rate += rdoq_rate((l as i64).abs());
6908            }
6909        }
6910        if nz {
6911            cbp |= 1 << b8;
6912        }
6913        q8[b8] = levels;
6914
6915        let res_r = inverse_quant_8x8(&levels, qp, &weight);
6916        let predb: [i32; 64] =
6917            std::array::from_fn(|i| pred_y[(b8y * 8 + i / 8) * 16 + (b8x * 8 + i % 8)] as i32);
6918        let recon = add_residual_8x8(&res_r, &predb);
6919        for dy in 0..8 {
6920            let row = &sy[(mb_y * 16 + b8y * 8 + dy) * cw + mb_x * 16 + b8x * 8..][..8];
6921            for dx in 0..8 {
6922                let ri = (b8y * 8 + dy) * 16 + (b8x * 8 + dx);
6923                rec[ri] = recon[dy * 8 + dx];
6924                let d = recon[dy * 8 + dx] as i64 - row[dx] as i64;
6925                ssd += d * d;
6926            }
6927        }
6928    }
6929    (q8, cbp, rate, rec, ssd)
6930}
6931
6932/// 16×16 luma intra prediction. For interior MBs (both neighbors available) this
6933/// dispatches to accel's `i16x16_luma_pred` (bit-identical to the spec
6934/// predictor); edge MBs (partial availability → C-only DC variants) use the scalar
6935/// path. The scalar `top`/`left`/`corner` are gathered by the caller regardless.
6936#[inline]
6937fn i16_pred(
6938    fe: &FrameEncoder,
6939    mode: I16Mode,
6940    avail_top: bool,
6941    avail_left: bool,
6942    top: &[u8; 16],
6943    left: &[u8; 16],
6944    corner: u8,
6945    lx: usize,
6946    ly: usize,
6947) -> [u8; 256] {
6948    #[cfg(accel)]
6949    if avail_top && avail_left {
6950        let mode_n = match mode {
6951            I16Mode::Vertical => 0,
6952            I16Mode::Horizontal => 1,
6953            I16Mode::Dc => 2,
6954            I16Mode::Plane => 3,
6955        };
6956        let mut p = AlignedMb([0; 256]);
6957        rusty_h264_accel::i16x16_luma_pred(mode_n, &mut p.0, &fe.rec_y[..], ly * fe.cw + lx, fe.cw);
6958        return p.0;
6959    }
6960    let _ = (fe, lx, ly);
6961    luma16x16_pred(mode, avail_top, avail_left, top, left, corner)
6962}
6963
6964/// 8×8 chroma intra prediction. Interior MBs use accel's `chroma8x8_pred`
6965/// for the V/Plane modes (bit-identical); DC/Horizontal (C-only in openh264) and edge MBs
6966/// use the scalar path.
6967#[inline]
6968#[allow(clippy::too_many_arguments)]
6969fn chroma_pred(
6970    fe: &FrameEncoder,
6971    mode: u8,
6972    avail_top: bool,
6973    avail_left: bool,
6974    c: usize,
6975    top: &[u8; 8],
6976    left: &[u8; 8],
6977    corner: u8,
6978    cx: usize,
6979    cy: usize,
6980) -> [u8; 64] {
6981    #[cfg(accel)]
6982    if avail_top && avail_left && (mode == 2 || mode == 3) {
6983        let plane = if c == 0 { &fe.rec_u } else { &fe.rec_v };
6984        // E2 W20: a 64-byte aligned buffer — the 256-byte AlignedMb zeroed 192
6985        // dead bytes and then paid a second 64-byte copy-out.
6986        #[repr(align(16))]
6987        struct A64([u8; 64]);
6988        let mut p = A64([0; 64]);
6989        rusty_h264_accel::chroma8x8_pred(mode, &mut p.0, &plane[..], cy * fe.ccw + cx, fe.ccw);
6990        return p.0;
6991    }
6992    let _ = (fe, c, cx, cy);
6993    chroma8x8_pred(mode, avail_top, avail_left, top, left, corner)
6994}
6995
6996/// Predicted `Intra_4x4` mode for the block at absolute coords `(bx, by)` —
6997/// `min` of the left/top neighbor modes, or DC if either is unavailable.
6998fn predict_i4_mode(fe: &FrameEncoder, bx: usize, by: usize) -> u8 {
6999    if bx == 0 || by == 0 {
7000        return 2;
7001    }
7002    let w4 = fe.mb_w * 4;
7003    fe.modes_y[by * w4 + (bx - 1)].min(fe.modes_y[(by - 1) * w4 + bx])
7004}
7005
7006#[allow(clippy::too_many_arguments)]
7007/// Zig-zag scan: block (raster 4×4) index at scan position i.
7008const RDOQ_ZZ: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
7009
7010/// Approximate CABAC bit cost of coding one residual coefficient at magnitude
7011/// `level`: significant_coeff_flag (~1) + coeff_abs_level_minus1 bins (gt1 + UEG0)
7012/// + sign (~1); `level == 0` is significant_coeff_flag = 0 (~1). A coarse model —
7013/// the transform-norm/bin-to-bit scaling is absorbed into the calibrated strength.
7014#[inline]
7015fn rdoq_rate(level: i64) -> f64 {
7016    // The closed form (level 0 → 1, 1 → 3, k ≥ 2 → 3 + min(k−1, 13), saturating
7017    // at 16 from level 14 up) tabulated: two branches + a min + an int→f64
7018    // convert become one clamped load. Same 16 values, BIT-IDENTICAL.
7019    const LUT: [f64; 16] = [
7020        1.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 16.0,
7021    ];
7022    LUT[(level.min(15)) as usize]
7023}
7024
7025/// `65536 / QUANT_MF_OH[qp][k]` for every (qp, k) — [`rdoq`]'s dequant steps.
7026/// The reciprocals are pure functions of two const tables, so they are computed
7027/// ONCE per process instead of eight `divsd` per trellis call (once per 4×4
7028/// residual block). IEEE division is deterministic: same operands, same bits.
7029fn rdoq_qstep(qp: u8) -> &'static [f64; 8] {
7030    static T: std::sync::OnceLock<[[f64; 8]; 52]> = std::sync::OnceLock::new();
7031    &T.get_or_init(|| {
7032        std::array::from_fn(|q| {
7033            std::array::from_fn(|k| 65536.0 / rusty_h264_common::transform::QUANT_MF_OH[q][k] as f64)
7034        })
7035    })[qp as usize]
7036}
7037
7038/// Rate-distortion optimized quantization (CABAC trellis, RDOQ) for one 4×4 residual
7039/// block. Refines the hard-decision levels toward min over {|q|, |q|-1} of
7040/// `SSD_coef + λ·R_cabac` per coefficient (coefficient-domain distortion
7041/// `(|coeff| - level·deq_step)²`; `λ = strength·2^((qp-12)/3)`). `strength == 0`
7042/// returns the hard quantization unchanged (the CAVLC path). `first` = 1 skips the
7043/// DC (AC-only categories: I_16x16 AC, chroma AC), else 0.
7044fn rdoq(coeffs: &[i32; 16], qp: u8, dz_div: i64, strength: f64, first: usize) -> [i32; 16] {
7045    let mut q = quantize(coeffs, qp, dz_div);
7046    if strength <= 0.0 {
7047        return q;
7048    }
7049    let lambda = strength * crate::fastmath::lambda_qp(qp);
7050    // Distortion is measured in the QUANTIZER-INPUT (forward-transform) domain, where
7051    // level L reconstructs to L·qstep, qstep = 2^16 / MF (the inverse of the forward
7052    // quant scale). The transform norm (forward↔pixel) folds into `strength`.
7053    const POS: [usize; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7];
7054    // Eight reciprocals per call became a process-lifetime table ([`rdoq_qstep`]):
7055    // the hoist-to-call-scope round left 8 `divsd` per trellis invocation; both
7056    // inputs are const tables, so the divides now happen once per process.
7057    let qstep = rdoq_qstep(qp);
7058    let dist = |p: usize, level: i64| -> f64 {
7059        let e = coeffs[p].unsigned_abs() as f64 - level as f64 * qstep[POS[p]];
7060        e * e
7061    };
7062    // Pass 1: per-coefficient level lowering (|q| → |q|-1) minimizing D + λ·R.
7063    for i in first..16 {
7064        let p = RDOQ_ZZ[i];
7065        let m = q[p].unsigned_abs() as i64;
7066        if m == 0 {
7067            continue;
7068        }
7069        let j_keep = dist(p, m) + lambda * rdoq_rate(m);
7070        let j_down = dist(p, m - 1) + lambda * rdoq_rate(m - 1);
7071        if j_down < j_keep {
7072            let nl = (m - 1) as i32;
7073            q[p] = if q[p] < 0 { -nl } else { nl };
7074        }
7075    }
7076    // Pass 2: last-significant-position trimming. Zeroing the trailing significant
7077    // coefficient frees its own bits AND the last_significant flag + every sig=0 flag
7078    // between it and the previous significant coefficient (positions past the new last
7079    // aren't coded at all) — the dominant RDOQ gain on sparse (inter) residuals.
7080    loop {
7081        let Some(li) = (first..16).rev().find(|&i| q[RDOQ_ZZ[i]] != 0) else {
7082            break;
7083        };
7084        let p = RDOQ_ZZ[li];
7085        let m = q[p].unsigned_abs() as i64;
7086        let prev = (first..li).rev().find(|&i| q[RDOQ_ZZ[i]] != 0);
7087        let base = prev.map_or(first, |j| j + 1);
7088        let bits = rdoq_rate(m) + 1.0 + (li - base) as f64; // coeff + last-flag + freed sig=0
7089        let d_add = dist(p, 0) - dist(p, m);
7090        if d_add < lambda * bits {
7091            q[p] = 0;
7092        } else {
7093            break;
7094        }
7095    }
7096    q
7097}
7098
7099/// Decide one intra macroblock (I_16x16 vs I_4x4, prediction modes, chroma),
7100/// forward-transform + quantize, and commit the reconstruction + neighbour mode
7101/// state — everything except entropy coding. The returned [`MbPlan`] is coded by
7102/// either entropy backend, so CAVLC and CABAC share this whole path bit-for-bit.
7103fn plan_mb(
7104    fe: &mut FrameEncoder,
7105    mb_x: usize,
7106    mb_y: usize,
7107    sy: &[u8],
7108    su: &[u8],
7109    sv: &[u8],
7110) -> MbPlan {
7111    let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncIntraCode);
7112    let qp = fe.qp;
7113    let qpc = fe.qpc;
7114    // Lagrangian λ for rate-distortion decisions (standard H.264 form).
7115    let lambda = 0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
7116
7117    // ---------------- luma ----------------
7118    let (lx, ly) = (mb_x * 16, mb_y * 16);
7119    let avail_top = mb_y > 0;
7120    let avail_left = mb_x > 0;
7121    let mut top = [0u8; 16];
7122    let mut left = [0u8; 16];
7123    if avail_top {
7124        let r = (ly - 1) * fe.cw + lx;
7125        top.copy_from_slice(&fe.rec_y[r..r + 16]);
7126    }
7127    if avail_left {
7128        let col = &fe.rec_y[ly * fe.cw + lx - 1..(ly + 15) * fe.cw + lx];
7129        for i in 0..16 {
7130            left[i] = col[i * fe.cw];
7131        }
7132    }
7133    let corner = if avail_top && avail_left {
7134        fe.rec_y[(ly - 1) * fe.cw + lx - 1]
7135    } else {
7136        0
7137    };
7138
7139    let w4 = fe.mb_w * 4;
7140
7141    // ============ I_16x16 plan (reconstruct into a local buffer) ============
7142    let mut i16_mode = I16Mode::Dc;
7143    let mut best_pred = i16_pred(fe, I16Mode::Dc, avail_top, avail_left, &top, &left, corner, lx, ly);
7144    let mut best_cost = satd_16x16(sy, fe.cw, lx, ly, &best_pred);
7145    for mode in [I16Mode::Vertical, I16Mode::Horizontal, I16Mode::Plane] {
7146        if !mode.available(avail_top, avail_left) {
7147            continue;
7148        }
7149        let pred = i16_pred(fe, mode, avail_top, avail_left, &top, &left, corner, lx, ly);
7150        let cost = satd_16x16(sy, fe.cw, lx, ly, &pred);
7151        if cost < best_cost {
7152            best_cost = cost;
7153            i16_mode = mode;
7154            best_pred = pred;
7155        }
7156    }
7157    // I_16x16 blocks are independent (one fixed whole-MB prediction), so batch the
7158    // forward DCT (`forward_dct_blocks` → SIMD), bit-identical to `forward_core`.
7159    let mut dc4x4 = [0i32; 16];
7160    let mut i16_q = [[0i32; 16]; 16];
7161    // Fast path: forward DCT of (src - pred) straight from the planes per 8x8 quad,
7162    // quantize with the identical FF/MF math (deadzone = fe.idz), recon via the
7163    // bit-identical idct+add+clip kernel — the same pairing encode_inter_mb and the
7164    // P_Skip free-check already use, byte-identical to the scalar twin below.
7165    #[cfg(accel)]
7166    let (i16_dc_levels, _i16_recon_dc, recon16) = {
7167        #[repr(align(16))]
7168        struct A([i16; 256]);
7169        let mut dct = A([0i16; 256]);
7170        let base = ly * fe.cw + lx;
7171        for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
7172            rusty_h264_accel::dct_four_t4(
7173                &mut dct.0[qi * 64..qi * 64 + 64],
7174                &sy[base + qy * fe.cw + qx..],
7175                fe.cw,
7176                &best_pred[qy * 16 + qx..],
7177                16,
7178            );
7179        }
7180        for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
7181            dc4x4[lby * 4 + lbx] = dct.0[blk * 16] as i32;
7182        }
7183        if fe.rdoq_strength > 0.0 {
7184            // Trellis (all-intra only): scalar RDOQ from the asm DCT output instead of
7185            // the asm hard quantizer. dct.0 keeps the raw DCT here; the recon loop below
7186            // overwrites it with the dequantized RDOQ levels.
7187            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
7188                let coeffs: [i32; 16] = std::array::from_fn(|i| dct.0[blk * 16 + i] as i32);
7189                let mut q = rdoq(&coeffs, qp, fe.idz, fe.rdoq_strength, 1);
7190                q[0] = 0;
7191                i16_q[lby * 4 + lbx] = q;
7192            }
7193        } else {
7194            let ff = rusty_h264_common::transform::quant_dz_ff(qp, fe.idz);
7195            let mf = &rusty_h264_common::transform::QUANT_MF_OH[qp as usize];
7196            for qi in 0..4 {
7197                rusty_h264_accel::quant_four_4x4(&mut dct.0[qi * 64..qi * 64 + 64], &ff, mf);
7198            }
7199            for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
7200                let q = &mut i16_q[lby * 4 + lbx];
7201                q[0] = 0;
7202                for i in 1..16 {
7203                    q[i] = dct.0[blk * 16 + i] as i32;
7204                }
7205            }
7206        }
7207        let i16_dc_levels = forward_quant_luma_dc(&dc4x4, qp, true);
7208        let i16_recon_dc = inverse_quant_luma_dc(&i16_dc_levels, qp);
7209        // Recon: dequantize (DC injected from the Hadamard) back into quad layout,
7210        // then idct+add-pred+clip into the trial buffer.
7211        let mut recon16 = [0u8; 256];
7212        for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
7213            let mut deq = dequantize(&i16_q[lby * 4 + lbx], qp);
7214            deq[0] = i16_recon_dc[lby * 4 + lbx];
7215            for i in 0..16 {
7216                dct.0[blk * 16 + i] = deq[i] as i16;
7217            }
7218        }
7219        for (qi, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
7220            rusty_h264_accel::idct_four_t4_rec(
7221                &mut recon16[qy * 16 + qx..],
7222                16,
7223                &best_pred[qy * 16 + qx..],
7224                16,
7225                &dct.0[qi * 64..qi * 64 + 64],
7226            );
7227        }
7228        (i16_dc_levels, i16_recon_dc, recon16)
7229    };
7230    #[cfg(not(accel))]
7231    let (i16_dc_levels, _i16_recon_dc, recon16) = {
7232        let mut res_blocks = [[0i32; 16]; 16];
7233        for by in 0..4 {
7234            for bx in 0..4 {
7235                let predb = pred_block(&best_pred, bx, by);
7236                res_blocks[by * 4 + bx] = residual(sy, fe.cw, lx + bx * 4, ly + by * 4, &predb);
7237            }
7238        }
7239        let mut coeffs = [[0i32; 16]; 16];
7240        forward_dct_blocks(&res_blocks, &mut coeffs);
7241        for i in 0..16 {
7242            dc4x4[i] = coeffs[i][0];
7243            let mut q = rdoq(&coeffs[i], qp, fe.idz, fe.rdoq_strength, 1);
7244            q[0] = 0;
7245            i16_q[i] = q;
7246        }
7247        let i16_dc_levels = forward_quant_luma_dc(&dc4x4, qp, true);
7248        let i16_recon_dc = inverse_quant_luma_dc(&i16_dc_levels, qp);
7249        let mut recon16 = [0u8; 256];
7250        let mut deq_blocks = [[0i32; 16]; 16];
7251        for i in 0..16 {
7252            deq_blocks[i] = dequantize(&i16_q[i], qp);
7253            deq_blocks[i][0] = i16_recon_dc[i];
7254        }
7255        let mut idct = [[0i32; 16]; 16];
7256        inverse_dct_blocks(&deq_blocks, &mut idct);
7257        for by in 0..4 {
7258            for bx in 0..4 {
7259                let s = add_residual_4x4(&idct[by * 4 + bx], &pred_block(&best_pred, bx, by));
7260                for dy in 0..4 {
7261                    for dx in 0..4 {
7262                        recon16[(by * 4 + dy) * 16 + (bx * 4 + dx)] = s[dy * 4 + dx];
7263                    }
7264                }
7265            }
7266        }
7267        (i16_dc_levels, i16_recon_dc, recon16)
7268    };
7269    let i16_cbp15 = i16_q.iter().any(|b| b[1..].iter().any(|&c| c != 0));
7270    let i16_dc_nz = i16_dc_levels.iter().filter(|&&v| v != 0).count() as i64;
7271    let i16_ac_nz: i64 = i16_q
7272        .iter()
7273        .map(|b| b[1..].iter().filter(|&&v| v != 0).count() as i64)
7274        .sum();
7275    // I_16x16 AC is all-or-nothing: any AC ⇒ all 16 blocks pay a coeff_token.
7276    let i16_rate = i16_dc_nz + i16_ac_nz + if i16_cbp15 { 16 } else { 0 };
7277    // Reconstruction distortion (SSD) for the rate-distortion decision.
7278    let mut ssd16 = 0i64;
7279    for dy in 0..16 {
7280        let sr = (ly + dy) * fe.cw + lx;
7281        for (r, sv2) in recon16[dy * 16..dy * 16 + 16].iter().zip(&sy[sr..sr + 16]) {
7282            let d = *r as i64 - *sv2 as i64;
7283            ssd16 += d * d;
7284        }
7285    }
7286
7287    // ============ chroma (shared by both luma types; commit immediately) ============
7288    let (cx, cy) = (mb_x * 8, mb_y * 8);
7289    // Gather both components' neighbors, then pick a chroma mode by combined SATD.
7290    let mut ntop = [[0u8; 8]; 2];
7291    let mut nleft = [[0u8; 8]; 2];
7292    let mut ncorner = [0u8; 2];
7293    for c in 0..2 {
7294        let rec_c = if c == 0 { &fe.rec_u } else { &fe.rec_v };
7295        if avail_top {
7296            let r = (cy - 1) * fe.ccw + cx;
7297            ntop[c].copy_from_slice(&rec_c[r..r + 8]);
7298        }
7299        if avail_left {
7300            let col = &rec_c[cy * fe.ccw + cx - 1..(cy + 7) * fe.ccw + cx];
7301            for i in 0..8 {
7302                nleft[c][i] = col[i * fe.ccw];
7303            }
7304        }
7305        if avail_top && avail_left {
7306            ncorner[c] = rec_c[(cy - 1) * fe.ccw + cx - 1];
7307        }
7308    }
7309    let mut chroma_mode = 0u8;
7310    let mut best_c_cost = i64::MAX;
7311    // E2 W11 (inline-execution.md 11.12): the WINNING mode's two prediction
7312    // planes were re-predicted after the search; keep them from the loop.
7313    let mut best_pred8 = [[0u8; 64]; 2];
7314    for m in 0..4u8 {
7315        if !chroma_mode_available(m, avail_top, avail_left) {
7316            continue;
7317        }
7318        let mut cost = 0i64;
7319        let mut cur = [[0u8; 64]; 2];
7320        for c in 0..2 {
7321            let src = if c == 0 { su } else { sv };
7322            cur[c] = chroma_pred(fe, m, avail_top, avail_left, c, &ntop[c], &nleft[c], ncorner[c], cx, cy);
7323            cost += satd_8x8(src, fe.ccw, cx, cy, &cur[c]);
7324        }
7325        if cost < best_c_cost {
7326            best_c_cost = cost;
7327            chroma_mode = m;
7328            best_pred8 = cur;
7329        }
7330    }
7331
7332    let mut c_dc_levels = [[0i32; 4]; 2];
7333    let mut c_q_blocks = [[[0i32; 16]; 4]; 2];
7334    let mut any_chroma_ac = false;
7335    let mut any_chroma_dc = false;
7336    for c in 0..2 {
7337        let src = if c == 0 { su } else { sv };
7338        let pred8 = best_pred8[c]; // the search's winner, not a re-prediction
7339        #[cfg_attr(accel, allow(unused_variables))] // non-accel scalar path only
7340        let pblk = |bx: usize, by: usize| -> [i32; 16] {
7341            let mut predb = [0i32; 16];
7342            for dy in 0..4 {
7343                for dx in 0..4 {
7344                    predb[dy * 4 + dx] = pred8[(by * 4 + dy) * 8 + (bx * 4 + dx)] as i32;
7345                }
7346            }
7347            predb
7348        };
7349        // Fast path: forward DCT of (src - pred8) straight from the planes, quantize
7350        // with identical FF/MF (idz deadzone), recon via one idct+add+clip kernel —
7351        // bit-identical to the scalar twin below (proven kernel pairings).
7352        let mut dc2x2 = [0i32; 4];
7353        let mut qbs = [[0i32; 16]; 4];
7354        #[cfg(accel)]
7355        let recon_dc = {
7356            #[repr(align(16))]
7357            struct A([i16; 64]);
7358            let mut d = A([0i16; 64]);
7359            rusty_h264_accel::dct_four_t4(&mut d.0, &src[cy * fe.ccw + cx..], fe.ccw, &pred8, 8);
7360            for i in 0..4 {
7361                dc2x2[i] = d.0[i * 16] as i32;
7362            }
7363            if fe.rdoq_strength > 0.0 {
7364                // Trellis (all-intra only): scalar RDOQ from the asm chroma DCT.
7365                for i in 0..4 {
7366                    let coeffs: [i32; 16] = std::array::from_fn(|j| d.0[i * 16 + j] as i32);
7367                    let mut q = rdoq(&coeffs, qpc, fe.idz, fe.rdoq_strength, 1);
7368                    q[0] = 0;
7369                    if q[1..].iter().any(|&v| v != 0) {
7370                        any_chroma_ac = true;
7371                    }
7372                    qbs[i] = q;
7373                }
7374            } else {
7375                let ff = rusty_h264_common::transform::quant_dz_ff(qpc, fe.idz);
7376                let mf = &rusty_h264_common::transform::QUANT_MF_OH[qpc as usize];
7377                rusty_h264_accel::quant_four_4x4(&mut d.0, &ff, mf);
7378                for i in 0..4 {
7379                    let q = &mut qbs[i];
7380                    q[0] = 0;
7381                    for j in 1..16 {
7382                        let v = d.0[i * 16 + j] as i32;
7383                        q[j] = v;
7384                        if v != 0 {
7385                            any_chroma_ac = true;
7386                        }
7387                    }
7388                }
7389            }
7390            let dl = forward_quant_chroma_dc(&dc2x2, qpc, true);
7391            if dl.iter().any(|&v| v != 0) {
7392                any_chroma_dc = true;
7393            }
7394            let recon_dc = inverse_quant_chroma_dc(&dl, qpc);
7395            for i in 0..4 {
7396                let deq = dequantize(&qbs[i], qpc);
7397                for j in 0..16 {
7398                    d.0[i * 16 + j] = deq[j] as i16;
7399                }
7400                d.0[i * 16] = recon_dc[i] as i16;
7401            }
7402            let plane = if c == 0 { &mut fe.rec_u } else { &mut fe.rec_v };
7403            rusty_h264_accel::idct_four_t4_rec(&mut plane[cy * fe.ccw + cx..], fe.ccw, &pred8, 8, &d.0);
7404            c_dc_levels[c] = dl;
7405            recon_dc
7406        };
7407        #[cfg(not(accel))]
7408        let recon_dc = {
7409            let mut res_blocks = [[0i32; 16]; 4];
7410            for by in 0..2 {
7411                for bx in 0..2 {
7412                    res_blocks[by * 2 + bx] =
7413                        residual(src, fe.ccw, cx + bx * 4, cy + by * 4, &pblk(bx, by));
7414                }
7415            }
7416            let mut coeffs = [[0i32; 16]; 4];
7417            forward_dct_blocks(&res_blocks, &mut coeffs);
7418            for i in 0..4 {
7419                dc2x2[i] = coeffs[i][0];
7420                let mut q = rdoq(&coeffs[i], qpc, fe.idz, fe.rdoq_strength, 1);
7421                q[0] = 0;
7422                qbs[i] = q;
7423                if q[1..].iter().any(|&v| v != 0) {
7424                    any_chroma_ac = true;
7425                }
7426            }
7427            let dl = forward_quant_chroma_dc(&dc2x2, qpc, true);
7428            if dl.iter().any(|&v| v != 0) {
7429                any_chroma_dc = true;
7430            }
7431            let recon_dc = inverse_quant_chroma_dc(&dl, qpc);
7432            let mut deq_blocks = [[0i32; 16]; 4];
7433            for i in 0..4 {
7434                deq_blocks[i] = dequantize(&qbs[i], qpc);
7435                deq_blocks[i][0] = recon_dc[i];
7436            }
7437            let mut idct = [[0i32; 16]; 4];
7438            inverse_dct_blocks(&deq_blocks, &mut idct);
7439            let plane = if c == 0 { &mut fe.rec_u } else { &mut fe.rec_v };
7440            for by in 0..2 {
7441                for bx in 0..2 {
7442                    let s = add_residual_4x4(&idct[by * 2 + bx], &pblk(bx, by));
7443                    store(plane, fe.ccw, cx + bx * 4, cy + by * 4, &s);
7444                }
7445            }
7446            c_dc_levels[c] = dl;
7447            recon_dc
7448        };
7449        let _ = recon_dc;
7450        c_q_blocks[c] = qbs;
7451    }
7452    let cbp_chroma: u32 = if any_chroma_ac {
7453        2
7454    } else if any_chroma_dc {
7455        1
7456    } else {
7457        0
7458    };
7459
7460    // ============ I_NxN plan + RD: I_16x16 vs I_4x4 vs (High profile) I_8x8 ============
7461    // I_4x4 and I_8x8 both reconstruct serially into rec_y, but each block predicts
7462    // only from NEIGHBOURS + earlier blocks it fills itself — never the stale MB
7463    // content — so running I_8x8 after I_4x4 needs no restore. J = SSD + λ·R picks the
7464    // per-MB transform (the content-adaptive win: 8x8 on smooth, 4x4 on detail).
7465    let base = ly * fe.cw + lx;
7466    let i4 = if i16_rate > 2 {
7467        Some(plan_i4x4(fe, sy, mb_x, mb_y, qp))
7468    } else {
7469        None
7470    };
7471    let (j4, i4_recon) = match &i4 {
7472        Some(p) => {
7473            let mut ssd = 0i64;
7474            let mut rec = [0u8; 256];
7475            for dy in 0..16 {
7476                let sr = base + dy * fe.cw;
7477                let row = &fe.rec_y[sr..sr + 16];
7478                rec[dy * 16..dy * 16 + 16].copy_from_slice(row);
7479                for (a, b) in row.iter().zip(&sy[sr..sr + 16]) {
7480                    let d = *a as i64 - *b as i64;
7481                    ssd += d * d;
7482                }
7483            }
7484            (ssd as f64 + lambda * (p.nonzero + 16) as f64, Some(rec))
7485        }
7486        None => (f64::INFINITY, None),
7487    };
7488    // STRUCTURAL gate (candidate): offer the I_8x8 candidate at all only when the
7489    // macroblock's slice type says it is worth offering. See `i8_in_p_on`.
7490    let i8 = if fe.t8_pick && (!fe.intra_in_p || i8_in_p_on()) {
7491        Some(plan_i8x8(fe, sy, mb_x, mb_y, qp))
7492    } else {
7493        None
7494    };
7495    let j8 = match &i8 {
7496        Some(p) => {
7497            let mut ssd = 0i64;
7498            for dy in 0..16 {
7499                let sr = base + dy * fe.cw;
7500                for (a, b) in fe.rec_y[sr..sr + 16].iter().zip(&sy[sr..sr + 16]) {
7501                    let d = *a as i64 - *b as i64;
7502                    ssd += d * d;
7503                }
7504            }
7505            ssd as f64 + lambda * (p.nonzero + 16) as f64
7506        }
7507        None => f64::INFINITY,
7508    };
7509    let j16 = ssd16 as f64 + lambda * i16_rate as f64;
7510
7511    // ============ commit the RD winner's reconstruction + neighbour modes ============
7512    // The 8x8 candidate must clear its rivals BY A MARGIN (default 0 = any win, the
7513    // pre-margin behaviour). `i8_margin` is in lambda units so it is QP-invariant.
7514    let m8 = fe.i8_margin * lambda;
7515    let (use_i4, i4, i8) = if i8.is_some() && j8 + m8 <= j4 && j8 + m8 <= j16 {
7516        // I_8x8: plan_i8x8 already committed rec_y AND modes_y (per 8x8 block).
7517        (true, None, i8)
7518    } else if i4.is_some() && j4 < j16 {
7519        // I_4x4: restore its reconstruction (I_8x8 may have overwritten rec_y), publish modes.
7520        let rec = i4_recon.unwrap();
7521        for dy in 0..16 {
7522            let d = base + dy * fe.cw;
7523            fe.rec_y[d..d + 16].copy_from_slice(&rec[dy * 16..dy * 16 + 16]);
7524        }
7525        let modes = i4.as_ref().unwrap().modes;
7526        for lby in 0..4 {
7527            let d = (mb_y * 4 + lby) * w4 + mb_x * 4;
7528            fe.modes_y[d..d + 4].copy_from_slice(&modes[lby * 4..lby * 4 + 4]);
7529        }
7530        (true, i4, None)
7531    } else {
7532        // I_16x16: commit its reconstruction, mark modes DC.
7533        for dy in 0..16 {
7534            let d = (ly + dy) * fe.cw + lx;
7535            fe.rec_y[d..d + 16].copy_from_slice(&recon16[dy * 16..dy * 16 + 16]);
7536        }
7537        for lby in 0..4 {
7538            let d = (mb_y * 4 + lby) * w4 + mb_x * 4;
7539            fe.modes_y[d..d + 4].fill(2);
7540        }
7541        (false, None, None)
7542    };
7543    // Mark all luma blocks coded for the next macroblock's top-right availability.
7544    for lby in 0..4 {
7545        let d = (mb_y * 4 + lby) * w4 + mb_x * 4;
7546        fe.coded_y[d..d + 4].fill(true);
7547    }
7548
7549    MbPlan {
7550        use_i4,
7551        i16_mode,
7552        i16_cbp15,
7553        i16_dc_levels,
7554        i16_q,
7555        i4,
7556        i8,
7557        chroma_mode,
7558        cbp_chroma,
7559        c_dc_levels,
7560        c_q_blocks,
7561    }
7562}
7563
7564/// Emit one planned intra macroblock as CAVLC (the original `encode_mb` tail). Reads
7565/// only the decided values from `plan`; `plan_mb` already committed recon + modes.
7566fn encode_mb(
7567    fe: &mut FrameEncoder,
7568    w: &mut BitWriter,
7569    mb_x: usize,
7570    mb_y: usize,
7571    sy: &[u8],
7572    su: &[u8],
7573    sv: &[u8],
7574    is_p: bool,
7575) {
7576    fe.intra_in_p = is_p;
7577    let plan = plan_mb(fe, mb_x, mb_y, sy, su, sv);
7578    // In a P-slice, intra macroblock types are offset by 5 (0..4 are inter).
7579    let mb_type_offset = if is_p { 5 } else { 0 };
7580    let w4 = fe.mb_w * 4;
7581    let cbp_chroma = plan.cbp_chroma;
7582
7583    // ============ emit luma ============
7584    if let Some(i8) = plan.i8.as_ref().filter(|_| plan.use_i4) {
7585        // ---- I_8x8 (High profile): mb_type = I_NxN, transform_size_8x8_flag = 1, then
7586        // one intra8x8 mode per 8x8 block, cbp, mb_qp_delta, and the 8x8 residual as
7587        // four interleaved 4x4 CAVLC sub-blocks (coeff k of sub s -> 8x8 scan 4k+s). ----
7588        let cbp = i8.cbp_luma | (cbp_chroma << 4);
7589        w.write_ue(mb_type_offset); // mb_type = I_NxN
7590        w.write_bit(true); // transform_size_8x8_flag = 1
7591        for b8 in 0..4usize {
7592            let (bx, by) = (mb_x * 4 + (b8 % 2) * 2, mb_y * 4 + (b8 / 2) * 2);
7593            let predicted = predict_i4_mode(fe, bx, by);
7594            let actual = i8.modes[b8];
7595            if actual == predicted {
7596                w.write_bit(true);
7597            } else {
7598                w.write_bit(false);
7599                let rem = if actual < predicted { actual } else { actual - 1 };
7600                w.write_bits(rem as u32, 3);
7601            }
7602        }
7603        w.write_ue(plan.chroma_mode as u32); // intra_chroma_pred_mode
7604        write_cbp_intra(w, cbp);
7605        if cbp != 0 {
7606            w.write_se(fe.qp_delta());
7607        }
7608        fe.nnz_cache_load(mb_x, mb_y);
7609        for b8 in 0..4usize {
7610            let (b8x, b8y) = (b8 % 2, b8 / 2);
7611            let scan8 = scan_8x8_fwd(&i8.q[b8]);
7612            for sub in 0..4usize {
7613                let (cx, cy) = (b8x * 2 + sub % 2, b8y * 2 + sub / 2);
7614                let (bx, by) = (mb_x * 4 + cx, mb_y * 4 + cy);
7615                let total = if i8.cbp_luma & (1 << b8) != 0 {
7616                    let nc = fe.nc_pred(cx, cy);
7617                    let blk: [i32; 16] = std::array::from_fn(|k| scan8[4 * k + sub]);
7618                    encode_residual_block(w, &blk, 16, nc) as u8
7619                } else {
7620                    0
7621                };
7622                fe.nnz_cache_set(cx, cy, total);
7623                fe.nnz_y[by * w4 + bx] = total;
7624            }
7625        }
7626    } else if plan.use_i4 {
7627        let i4 = plan.i4.as_ref().unwrap();
7628        let cbp = i4.cbp_luma | (cbp_chroma << 4);
7629        w.write_ue(mb_type_offset); // mb_type = I_4x4 (+5 in P-slices)
7630        if fe.transform_8x8 {
7631            w.write_bit(false); // transform_size_8x8_flag = 0 (this I_NxN is 4x4)
7632        }
7633        for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
7634            let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
7635            let predicted = predict_i4_mode(fe, bx, by);
7636            let actual = i4.modes[lby * 4 + lbx];
7637            if actual == predicted {
7638                w.write_bit(true);
7639            } else {
7640                w.write_bit(false);
7641                let rem = if actual < predicted { actual } else { actual - 1 };
7642                w.write_bits(rem as u32, 3);
7643            }
7644        }
7645        w.write_ue(plan.chroma_mode as u32); // intra_chroma_pred_mode
7646        write_cbp_intra(w, cbp);
7647        if cbp != 0 {
7648            w.write_se(fe.qp_delta()); // mb_qp_delta (AQ per-MB QPy)
7649        }
7650        fe.nnz_cache_load(mb_x, mb_y);
7651        for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
7652            let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
7653            let total = if i4.cbp_luma & (1 << (blk / 4)) != 0 {
7654                let nc = fe.nc_pred(lbx, lby);
7655                let scan16 = scan_4x4_dcac(&i4.q[lby * 4 + lbx]);
7656                encode_residual_block(w, &scan16, 16, nc) as u8
7657            } else {
7658                0
7659            };
7660            fe.nnz_cache_set(lbx, lby, total);
7661            fe.nnz_y[by * w4 + bx] = total;
7662        }
7663    } else {
7664        let mb_type = 1 + plan.i16_mode as u32 + 4 * cbp_chroma + if plan.i16_cbp15 { 12 } else { 0 };
7665        w.write_ue(mb_type + mb_type_offset);
7666        w.write_ue(plan.chroma_mode as u32); // intra_chroma_pred_mode
7667        w.write_se(fe.qp_delta()); // mb_qp_delta (I_16x16 always codes it; AQ per-MB QPy)
7668        fe.nnz_cache_load(mb_x, mb_y);
7669        let nc_dc = fe.nc_pred(0, 0);
7670        let dc_scan = scan_4x4_dcac(&plan.i16_dc_levels);
7671        encode_residual_block(w, &dc_scan, 16, nc_dc);
7672        for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
7673            fe.nnz_cache_set(lbx, lby, 0);
7674            fe.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 0;
7675        }
7676        if plan.i16_cbp15 {
7677            for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
7678                let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
7679                let nc = fe.nc_pred(lbx, lby);
7680                let ac = scan_4x4_ac(&plan.i16_q[lby * 4 + lbx]);
7681                let total = encode_residual_block(w, &ac, 15, nc) as u8;
7682                fe.nnz_cache_set(lbx, lby, total);
7683                fe.nnz_y[by * w4 + bx] = total;
7684            }
7685        }
7686    }
7687
7688    // ============ emit chroma residual (shared) ============
7689    if cbp_chroma != 0 {
7690        for c in 0..2 {
7691            encode_residual_block(w, &plan.c_dc_levels[c], 4, -1);
7692        }
7693    }
7694    if cbp_chroma == 2 {
7695        fe.chroma_cache_load(mb_x, mb_y);
7696        let w2 = fe.mb_w * 2;
7697        for c in 0..2 {
7698            for &(bx, by) in &CHROMA_4X4_SCAN_XY {
7699                let nc = fe.chroma_nc_pred(c, bx, by);
7700                let ac = scan_4x4_ac(&plan.c_q_blocks[c][by * 2 + bx]);
7701                let total = encode_residual_block(w, &ac, 15, nc) as u8;
7702                fe.chroma_nnz_cache_set(c, bx, by, total);
7703                fe.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total;
7704            }
7705        }
7706    }
7707}
7708
7709// ============================================================================
7710// CABAC I-slice entropy coding — the exact forward inverse of the decoder's
7711// `decode_slice_data_cabac` I-slice path (rusty_h264-decoder mb16.rs). Every
7712// binarization + context-selection here mirrors a `parse_*_cabac` there; the
7713// neighbour state (nzc cache, cbf_dc, cat, cmode, mb_cbp, last_delta_qp) is
7714// reconstructed identically so the contexts evolve bit-for-bit. Reuses `plan_mb`
7715// for the entire mode-decision/transform/recon (shared with CAVLC).
7716// ============================================================================
7717
7718// Res-property tables: the ONE copy shared with the decoder via `cabac_tables`
7719// (they were byte-copies here; a single divergent entry desyncs the coders).
7720use rusty_h264_common::cabac_tables::{
7721    CACHE30 as CB_CACHE30, G_SCAN4 as CB_G_SCAN4, NZC_CACHE as CB_NZC_CACHE,
7722    RES_CBF as CB_RES_CBF, RES_MAP as CB_RES_MAP, RES_MAXC2 as CB_RES_MAXC2,
7723    RES_MAXPOS as CB_RES_MAXPOS, RES_ONE as CB_RES_ONE,
7724};
7725const CB_RP_I16_DC: usize = 1;
7726const CB_RP_I16_AC: usize = 2;
7727const CB_RP_LUMA_4X4: usize = 3;
7728const CB_RP_CHROMA_DC: usize = 7;
7729const CB_RP_CHROMA_AC: usize = 9;
7730/// Luma 8x8 (ctxBlockCat 5). Mirrors the decoder's `RP_LUMA_8X8`.
7731const CB_RP_LUMA_8X8: usize = 6;
7732
7733/// Inverse of `cabac_unary(ctx, off)`: bin0 at `ctx`; for value >= 1, `value-1` ones
7734/// then a terminating 0, all at `ctx+off`.
7735fn cb_unary(cab: &mut CabacEncoder, ctx: usize, off: usize, value: u32) {
7736    if value == 0 {
7737        cab.encode_decision(ctx, 0);
7738        return;
7739    }
7740    cab.encode_decision(ctx, 1);
7741    for _ in 0..value - 1 {
7742        cab.encode_decision(ctx + off, 1);
7743    }
7744    cab.encode_decision(ctx + off, 0);
7745}
7746
7747/// Exp-Golomb order-`k` in bypass — inverse of `cabac_exp_bypass(k)`.
7748fn cb_exp_bypass(cab: &mut CabacEncoder, mut k: i32, mut n: u32) {
7749    while n >= (1 << k) {
7750        cab.encode_bypass(1);
7751        n -= 1 << k;
7752        k += 1;
7753    }
7754    cab.encode_bypass(0);
7755    // The suffix tail is exactly `encode_bypass_bits` (MSB-first, k bits) — the
7756    // API CABAC-4 reserved and then reimplemented inline here (H9). Same call
7757    // sequence, byte-identical.
7758    cab.encode_bypass_bits(n, k as u32);
7759}
7760
7761/// UEG0 coeff-level suffix — inverse of `cabac_ueg_level(ctx)` (TU prefix <=13 at
7762/// `ctx`, then an EG0 bypass suffix).
7763fn cb_ueg_level(cab: &mut CabacEncoder, ctx: usize, value: u32) {
7764    if value == 0 {
7765        cab.encode_decision(ctx, 0);
7766        return;
7767    }
7768    let ones = value.min(13);
7769    for _ in 0..ones {
7770        cab.encode_decision(ctx, 1);
7771    }
7772    if value < 13 {
7773        cab.encode_decision(ctx, 0);
7774    } else {
7775        cb_exp_bypass(cab, 0, value - 13);
7776    }
7777}
7778
7779/// `mb_qp_delta` — inverse of `parse_mb_qp_delta_cabac` (ctxIdxOffset 60).
7780pub fn cb_mb_qp_delta(cab: &mut CabacEncoder, last_delta_qp: &mut i32, delta: i32) {
7781    const O: usize = 60;
7782    let ctx_inc = (*last_delta_qp != 0) as usize;
7783    if delta == 0 {
7784        cab.encode_decision(O + ctx_inc, 0);
7785    } else {
7786        cab.encode_decision(O + ctx_inc, 1);
7787        // code = 2|d| - (d>0); the decode's cabac_unary sees code-1.
7788        let code = 2 * delta.unsigned_abs() - (delta > 0) as u32;
7789        cb_unary(cab, O + 2, 1, code - 1);
7790    }
7791    *last_delta_qp = delta;
7792}
7793
7794/// `intra_chroma_pred_mode` (TU cMax=3) — inverse of `parse_intra_chroma_pred_mode_cabac`.
7795fn cb_chroma_pred_mode(cab: &mut CabacEncoder, ctx_inc: usize, mode: u8) {
7796    const C: usize = 64;
7797    if mode == 0 {
7798        cab.encode_decision(C + ctx_inc, 0);
7799        return;
7800    }
7801    cab.encode_decision(C + ctx_inc, 1);
7802    if mode == 1 {
7803        cab.encode_decision(C + 3, 0);
7804    } else if mode == 2 {
7805        cab.encode_decision(C + 3, 1);
7806        cab.encode_decision(C + 3, 0);
7807    } else {
7808        cab.encode_decision(C + 3, 1);
7809        cab.encode_decision(C + 3, 1);
7810    }
7811}
7812
7813/// I-slice `mb_type` — inverse of `parse_mb_type_i_cabac` (ctxIdxOffset 3).
7814fn cb_mb_type_i(
7815    cab: &mut CabacEncoder,
7816    ctx_inc: usize,
7817    use_i4: bool,
7818    i16_mode: u32,
7819    cbp_chroma: u32,
7820    cbp_luma15: bool,
7821) {
7822    const O: usize = 3;
7823    if use_i4 {
7824        cab.encode_decision(O + ctx_inc, 0); // I_NxN
7825        return;
7826    }
7827    cab.encode_decision(O + ctx_inc, 1);
7828    cab.encode_terminate(false); // not I_PCM
7829    cab.encode_decision(O + 3, cbp_luma15 as u32);
7830    if cbp_chroma != 0 {
7831        cab.encode_decision(O + 4, 1);
7832        cab.encode_decision(O + 5, (cbp_chroma == 2) as u32);
7833    } else {
7834        cab.encode_decision(O + 4, 0);
7835    }
7836    cab.encode_decision(O + 6, (i16_mode >> 1) & 1);
7837    cab.encode_decision(O + 7, i16_mode & 1);
7838}
7839
7840/// One `Intra_4x4` pred-mode — inverse of `parse_intra4x4_pred_mode_cabac` (ctx 68).
7841fn cb_intra4x4_pred_mode(cab: &mut CabacEncoder, predicted: u8, actual: u8) {
7842    const IPR: usize = 68;
7843    if actual == predicted {
7844        cab.encode_decision(IPR, 1);
7845    } else {
7846        cab.encode_decision(IPR, 0);
7847        let rem = if actual < predicted { actual } else { actual - 1 } as u32;
7848        cab.encode_decision(IPR + 1, rem & 1);
7849        cab.encode_decision(IPR + 1, (rem >> 1) & 1);
7850        cab.encode_decision(IPR + 1, (rem >> 2) & 1);
7851    }
7852}
7853
7854/// `coded_block_pattern` — inverse of `parse_cbp_cabac` (ctxIdxOffset 73).
7855pub fn cb_cbp(cab: &mut CabacEncoder, top: Option<u8>, left: Option<u8>, cbp: u32) {
7856    const CBP: usize = 73;
7857    let t = |m: u32| top.map_or(0u32, |c| ((c as u32 & m) == 0) as u32);
7858    let l = |m: u32| left.map_or(0u32, |c| ((c as u32 & m) == 0) as u32);
7859    let nb = |x: u32| (x == 0) as u32;
7860    let b0 = cbp & 1;
7861    let b1 = (cbp >> 1) & 1;
7862    let b2 = (cbp >> 2) & 1;
7863    let b3 = (cbp >> 3) & 1;
7864    cab.encode_decision(CBP + (l(1 << 1) + (t(1 << 2) << 1)) as usize, b0);
7865    cab.encode_decision(CBP + (nb(b0) + (t(1 << 3) << 1)) as usize, b1);
7866    cab.encode_decision(CBP + (l(1 << 3) + (nb(b0) << 1)) as usize, b2);
7867    cab.encode_decision(CBP + (nb(b2) + (nb(b1) << 1)) as usize, b3);
7868    let cbp_chroma = cbp >> 4;
7869    let ct = top.map_or(0u32, |c| ((c >> 4) != 0) as u32);
7870    let cl = left.map_or(0u32, |c| ((c >> 4) != 0) as u32);
7871    cab.encode_decision(CBP + 4 + (cl + (ct << 1)) as usize, (cbp_chroma != 0) as u32);
7872    if cbp_chroma != 0 {
7873        let ct2 = top.map_or(0u32, |c| ((c >> 4) == 2) as u32);
7874        let cl2 = left.map_or(0u32, |c| ((c >> 4) == 2) as u32);
7875        cab.encode_decision(CBP + 8 + (cl2 + (ct2 << 1)) as usize, (cbp_chroma == 2) as u32);
7876    }
7877}
7878
7879/// One residual block — inverse of `parse_residual_cabac`. `coeffs` is scan-order
7880/// (len >= maxPos+1). Returns totalCoeffNum (for the nzc cache + deblock nnz).
7881#[allow(clippy::too_many_arguments)]
7882fn cb_residual(
7883    cab: &mut CabacEncoder,
7884    nzc: &mut [u8; 48],
7885    cbf_dc: &mut u16,
7886    iz: usize,
7887    rp: usize,
7888    is_intra: bool,
7889    ndc: (Option<u16>, Option<u16>),
7890    coeffs: &[i32],
7891) -> u32 {
7892    // ctxBlockCat 5 is the ONLY category with no coded_block_flag: presence is inferred
7893    // from CodedBlockPatternLuma, so emitting one here would desync the decoder. Same
7894    // asymmetry the decoder's reader documents.
7895    let is8 = rp == CB_RP_LUMA_8X8;
7896    let is_dc = rp == CB_RP_I16_DC || rp == CB_RP_CHROMA_DC || rp == CB_RP_CHROMA_DC + 1;
7897    let (mut na, mut nb) = (is_intra as u8, is_intra as u8);
7898    let scan = CB_NZC_CACHE[iz.min(23)];
7899    if is_dc {
7900        if let Some(t) = ndc.0 {
7901            nb = ((t >> rp) & 1) as u8;
7902        }
7903        if let Some(l) = ndc.1 {
7904            na = ((l >> rp) & 1) as u8;
7905        }
7906    } else {
7907        if nzc[scan - 8] != 0xff {
7908            nb = (nzc[scan - 8] != 0) as u8;
7909        }
7910        if nzc[scan - 1] != 0xff {
7911            na = (nzc[scan - 1] != 0) as u8;
7912        }
7913    }
7914    let maxpos = CB_RES_MAXPOS[rp] as usize;
7915    let coeff_num = coeffs[..=maxpos].iter().filter(|&&c| c != 0).count() as u32;
7916    let cbf = coeff_num != 0;
7917    if !is8 {
7918        cab.encode_decision(85 + CB_RES_CBF[rp] + (na + (nb << 1)) as usize, cbf as u32);
7919        if !cbf {
7920            if !is_dc {
7921                nzc[scan] = 0;
7922            }
7923            return 0;
7924        }
7925    } else if !cbf {
7926        // Caller must not invoke cat 5 for an all-zero block: with no cbf to carry the
7927        // "empty" signal, the decoder would read a significance map that was never
7928        // written. CBP is what suppresses it, upstream.
7929        debug_assert!(false, "cat 5 called with an all-zero block; CBP should have gated it");
7930        nzc[scan] = 0;
7931        return 0;
7932    }
7933    if is_dc {
7934        *cbf_dc |= 1 << rp;
7935    }
7936    // significance map. For the 4x4 categories ctxIdxInc IS the scan position; cat 5
7937    // folds 63 positions onto 15 (sig) / 9 (last) contexts via the Table 9-43 maps,
7938    // at absolute bases rather than `105/166 + off`.
7939    let map = 105 + CB_RES_MAP[rp];
7940    let last = 166 + CB_RES_MAP[rp];
7941    let lastnz = (0..=maxpos).rev().find(|&i| coeffs[i] != 0).unwrap();
7942    for i in 0..maxpos {
7943        let s = coeffs[i] != 0;
7944        let (sig_ctx, last_ctx) = if is8 {
7945            (
7946                rusty_h264_common::cabac_tables::CAT5_SIG_BASE + rusty_h264_common::cabac_tables::SIG8X8[i] as usize,
7947                rusty_h264_common::cabac_tables::CAT5_LAST_BASE + rusty_h264_common::cabac_tables::LAST8X8[i] as usize,
7948            )
7949        } else {
7950            (map + i, last + i)
7951        };
7952        cab.encode_decision(sig_ctx, s as u32);
7953        if s {
7954            let is_last = i == lastnz;
7955            cab.encode_decision(last_ctx, is_last as u32);
7956            if is_last {
7957                break;
7958            }
7959        }
7960    }
7961    // levels (reverse scan)
7962    let one = 227 + CB_RES_ONE[rp];
7963    let abs = 232 + CB_RES_ONE[rp];
7964    let maxc2 = CB_RES_MAXC2[rp];
7965    let (mut c1, mut c2) = (1i32, 0i32);
7966    for i in (0..=maxpos).rev() {
7967        if coeffs[i] != 0 {
7968            let av = coeffs[i].unsigned_abs();
7969            let gt1 = av > 1;
7970            cab.encode_decision(one + c1 as usize, gt1 as u32);
7971            if gt1 {
7972                cb_ueg_level(cab, abs + c2 as usize, av - 2);
7973                c2 = (c2 + 1).min(maxc2);
7974                c1 = 0;
7975            } else if c1 != 0 {
7976                c1 = (c1 + 1).min(4);
7977            }
7978            cab.encode_bypass((coeffs[i] < 0) as u32);
7979        }
7980    }
7981    if is8 {
7982        // One 8x8 covers four consecutive z-order 4x4 cells. Every later
7983        // coded_block_flag ctxIdxInc reads this cache, so all four must carry the
7984        // count -- writing only `scan` would corrupt the NEXT macroblock's contexts.
7985        // Byte-for-byte the decoder's rule; the two must agree or the stream desyncs.
7986        for k in 0..4 {
7987            nzc[CB_NZC_CACHE[(iz + k).min(23)]] = coeff_num as u8;
7988        }
7989    } else if !is_dc {
7990        nzc[scan] = coeff_num as u8;
7991    }
7992    coeff_num
7993}
7994
7995/// Build the 48-entry padded nzc cache from the top/left neighbour MB exports
7996/// (openh264 `WelsFillCacheNonZeroCount`) — identical to the decoder.
7997fn cb_build_nzc(mb_nzc: &[[u8; 24]], top: Option<usize>, left: Option<usize>) -> [u8; 48] {
7998    let mut nzc = [0xffu8; 48];
7999    if let Some(t) = top {
8000        let tn = mb_nzc[t];
8001        nzc[1..5].copy_from_slice(&tn[12..16]);
8002        (nzc[0], nzc[5], nzc[29]) = (0, 0, 0);
8003        (nzc[6], nzc[7]) = (tn[20], tn[21]);
8004        (nzc[30], nzc[31]) = (tn[22], tn[23]);
8005    }
8006    if let Some(l) = left {
8007        let ln = mb_nzc[l];
8008        (nzc[8], nzc[16], nzc[24], nzc[32]) = (ln[3], ln[7], ln[11], ln[15]);
8009        (nzc[13], nzc[21], nzc[37], nzc[45]) = (ln[17], ln[21], ln[19], ln[23]);
8010    }
8011    nzc
8012}
8013
8014/// Extract the 24-entry per-MB nzc (raster luma + chroma) for future neighbours.
8015fn cb_export_nzc(nzc: &[u8; 48]) -> [u8; 24] {
8016    let mut mn = [0u8; 24];
8017    for k in 0..4 {
8018        mn[k] = nzc[9 + k];
8019        mn[4 + k] = nzc[17 + k];
8020        mn[8 + k] = nzc[25 + k];
8021        mn[12 + k] = nzc[33 + k];
8022    }
8023    (mn[16], mn[17], mn[20], mn[21]) = (nzc[14], nzc[15], nzc[22], nzc[23]);
8024    (mn[18], mn[19], mn[22], mn[23]) = (nzc[38], nzc[39], nzc[46], nzc[47]);
8025    for v in mn.iter_mut() {
8026        if *v == 0xff {
8027            *v = 0;
8028        }
8029    }
8030    mn
8031}
8032
8033/// Per-frame CABAC neighbour state (I-slice): one entry per macroblock, mirroring
8034/// the arrays the decoder's `decode_slice_data_cabac` maintains.
8035struct CabacState {
8036    cat: Vec<u8>,          // 2 = I_16x16, 0 = I_NxN, 100 = inter (mb_type / skip ctxInc)
8037    cmode: Vec<i32>,       // per-MB chroma mode (chroma-pred ctxInc)
8038    mb_cbp: Vec<u8>,       // per-MB cbp byte (cbp ctxInc)
8039    cbf_dc: Vec<u16>,      // per-MB DC coded_block_flag mask (residual DC ctxInc)
8040    mb_nzc: Vec<[u8; 24]>, // per-MB nzc export (residual AC ctxInc)
8041    // Inter (P/B) neighbour state — mirrors the decoder's WelsFillCacheInterCabac.
8042    mb_mvd: Vec<[[i16; 2]; 16]>,  // per-MB per-4x4 List-0 mvd (raster), for the mvd ctxInc cache
8043    mb_ref: Vec<[i8; 16]>,        // per-MB per-4x4 List-0 ref idx (raster); -1 = unavailable
8044    mb_mvd1: Vec<[[i16; 2]; 16]>, // B: per-MB per-4x4 List-1 mvd
8045    mb_ref1: Vec<[i8; 16]>,       // B: per-MB per-4x4 List-1 ref idx
8046    mb_skip: Vec<bool>,           // per-MB mb_skip_flag (skip ctxInc)
8047    mb_direct: Vec<bool>,         // B: per-MB B_Direct/B_Skip (B mb_type ctxInc)
8048    mb_t8x8: Vec<bool>,           // per-MB transform_size_8x8_flag (ctxIdxOffset 399 ctxInc)
8049    last_delta_qp: i32,
8050}
8051
8052impl CabacState {
8053    /// Reset a recycled state to `new(n)`'s exact contents on retained
8054    /// capacity (D13's encoder twin, 11.11).
8055    fn refill(&mut self, n: usize) {
8056        fn rf<T: Clone>(v: &mut Vec<T>, n: usize, val: T) {
8057            v.clear();
8058            v.resize(n, val);
8059        }
8060        rf(&mut self.cat, n, 0);
8061        rf(&mut self.cmode, n, 0);
8062        rf(&mut self.mb_cbp, n, 0);
8063        rf(&mut self.cbf_dc, n, 0);
8064        rf(&mut self.mb_nzc, n, [0u8; 24]);
8065        rf(&mut self.mb_mvd, n, [[0i16; 2]; 16]);
8066        rf(&mut self.mb_ref, n, [-1i8; 16]);
8067        rf(&mut self.mb_mvd1, n, [[0i16; 2]; 16]);
8068        rf(&mut self.mb_ref1, n, [-1i8; 16]);
8069        rf(&mut self.mb_skip, n, false);
8070        rf(&mut self.mb_direct, n, false);
8071        rf(&mut self.mb_t8x8, n, false);
8072        self.last_delta_qp = 0;
8073    }
8074
8075    /// Pooled form of `new(n)`: ~13 vecs (hundreds of KB per slice) recycled
8076    /// from this thread's previous slice.
8077    fn pooled(n: usize) -> Self {
8078        let mut cs = enc_scratch::take_cs().unwrap_or_else(|| CabacState::new(0));
8079        cs.refill(n);
8080        cs
8081    }
8082
8083    fn new(n: usize) -> Self {
8084        CabacState {
8085            cat: vec![0; n],
8086            cmode: vec![0; n],
8087            mb_cbp: vec![0; n],
8088            cbf_dc: vec![0; n],
8089            mb_nzc: vec![[0u8; 24]; n],
8090            mb_mvd: vec![[[0i16; 2]; 16]; n],
8091            mb_ref: vec![[-1i8; 16]; n],
8092            mb_mvd1: vec![[[0i16; 2]; 16]; n],
8093            mb_ref1: vec![[-1i8; 16]; n],
8094            mb_skip: vec![false; n],
8095            mb_direct: vec![false; n],
8096            mb_t8x8: vec![false; n],
8097            last_delta_qp: 0,
8098        }
8099    }
8100}
8101
8102/// Emit one planned intra macroblock as CABAC (I-slice). Mirrors the decoder's
8103/// I-slice MB body exactly: `mb_type`, then per luma-type the intra modes / cbp /
8104/// `mb_qp_delta` / residual in spec order, maintaining `cs` and `fe.nnz_y`.
8105fn emit_mb_cabac_i(
8106    fe: &mut FrameEncoder,
8107    cab: &mut CabacEncoder,
8108    cs: &mut CabacState,
8109    plan: &MbPlan,
8110    mb_x: usize,
8111    mb_y: usize,
8112) {
8113    let mb_w = fe.mb_w;
8114    let addr = mb_y * mb_w + mb_x;
8115    let top = if mb_y > 0 { Some(addr - mb_w) } else { None };
8116    let left = if mb_x > 0 { Some(addr - 1) } else { None };
8117
8118    // ---- mb_type (I-slice prefix; carries I_16x16 pred-mode/cbp) ----
8119    let li = left.map_or(0, |a| (cs.cat[a] >= 2) as usize);
8120    let ti = top.map_or(0, |a| (cs.cat[a] >= 2) as usize);
8121    let acct = crate::bitacct::enabled();
8122    let t0 = if acct { cab.pos() } else { 0 };
8123    if plan.use_i4 {
8124        cb_mb_type_i(cab, li + ti, true, 0, 0, false);
8125    } else {
8126        cb_mb_type_i(cab, li + ti, false, plan.i16_mode as u32, plan.cbp_chroma, plan.i16_cbp15);
8127    }
8128    if acct {
8129        crate::bitacct::add(crate::bitacct::B::MbType, cab.pos() - t0);
8130    }
8131    let t1 = if acct { cab.pos() } else { 0 };
8132    emit_intra_body_cabac(fe, cab, cs, plan, mb_x, mb_y, addr, top, left);
8133    if acct {
8134        crate::bitacct::add(crate::bitacct::B::IntraBody, cab.pos() - t1);
8135    }
8136}
8137
8138/// The intra macroblock body (chroma pred mode, intra modes, cbp, mb_qp_delta,
8139/// residual) shared by I-slice intra and P/B-slice intra — everything AFTER the
8140/// slice-specific `mb_type` prefix (which already carries the I_16x16 pred-mode/cbp).
8141/// Commits a raster-local per-block nnz record into the frame grid as four
8142/// row copies (E28, inline-execution.md 11.16): the emit loops run in SCAN
8143/// order for the CABAC contexts, so they collect locally and commit here —
8144/// one bounds check per row instead of one per block.
8145#[inline]
8146fn nnz_commit_rows(fe: &mut FrameEncoder, mb_x: usize, mb_y: usize, loc: &[u8; 16]) {
8147    let w4 = fe.mb_w * 4;
8148    for lby in 0..4 {
8149        let d = (mb_y * 4 + lby) * w4 + mb_x * 4;
8150        fe.nnz_y[d..d + 4].copy_from_slice(&loc[lby * 4..lby * 4 + 4]);
8151    }
8152}
8153
8154#[allow(clippy::too_many_arguments)]
8155fn emit_intra_body_cabac(
8156    fe: &mut FrameEncoder,
8157    cab: &mut CabacEncoder,
8158    cs: &mut CabacState,
8159    plan: &MbPlan,
8160    mb_x: usize,
8161    mb_y: usize,
8162    addr: usize,
8163    top: Option<usize>,
8164    left: Option<usize>,
8165) {
8166    let cbp_chroma = plan.cbp_chroma;
8167    // chroma-pred-mode ctxInc from neighbour chroma modes (1..=3).
8168    let cci = left.map_or(0, |a| (1..=3).contains(&cs.cmode[a]) as usize)
8169        + top.map_or(0, |a| (1..=3).contains(&cs.cmode[a]) as usize);
8170
8171    let mut nzc;
8172    let mut cbfdc = 0u16;
8173    let ndc = (top.map(|a| cs.cbf_dc[a]), left.map(|a| cs.cbf_dc[a]));
8174
8175    if !plan.use_i4 {
8176        // ---- I_16x16 ----
8177        cb_chroma_pred_mode(cab, cci, plan.chroma_mode);
8178        cs.cmode[addr] = plan.chroma_mode as i32;
8179        cs.cat[addr] = 2;
8180        cs.mb_cbp[addr] = ((cbp_chroma as u8) << 4) | if plan.i16_cbp15 { 15 } else { 0 };
8181        nzc = cb_build_nzc(&cs.mb_nzc, top, left);
8182
8183        let delta = fe.qp_delta();
8184        cb_mb_qp_delta(cab, &mut cs.last_delta_qp, delta);
8185
8186        // luma DC
8187        let dc_scan = scan_4x4_dcac(&plan.i16_dc_levels);
8188        cb_residual(cab, &mut nzc, &mut cbfdc, 0, CB_RP_I16_DC, true, ndc, &dc_scan);
8189        // luma AC
8190        let mut nnz_loc = [0u8; 16];
8191        for (iz, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
8192            let total = if plan.i16_cbp15 {
8193                let ac = scan_4x4_ac(&plan.i16_q[lby * 4 + lbx]);
8194                cb_residual(cab, &mut nzc, &mut cbfdc, iz, CB_RP_I16_AC, true, ndc, &ac)
8195            } else {
8196                nzc[CB_NZC_CACHE[iz]] = 0;
8197                0
8198            };
8199            nnz_loc[lby * 4 + lbx] = total as u8;
8200        }
8201        nnz_commit_rows(fe, mb_x, mb_y, &nnz_loc);
8202        cb_emit_chroma_residual(cab, fe, &mut nzc, &mut cbfdc, ndc, true, plan.cbp_chroma, &plan.c_dc_levels, &plan.c_q_blocks, mb_x, mb_y);
8203    } else if let Some(i8) = plan.i8.as_ref() {
8204        // ---- I_NxN with transform_size_8x8_flag = 1 (I_8x8, High profile) ----
8205        // ORDER IS LOAD-BEARING: for I_NxN the flag precedes the intra pred modes
8206        // (spec 7.3.5), because the modes themselves are per-8x8 when it is set.
8207        // ctxIdx = 399 + condTermFlagA + condTermFlagB, each 1 when that neighbour
8208        // MB carries the flag -- the exact mirror of the decoder's read.
8209        let ta = left.map_or(0, |x| cs.mb_t8x8[x] as usize);
8210        let tb = top.map_or(0, |x| cs.mb_t8x8[x] as usize);
8211        cab.encode_decision(399 + ta + tb, 1);
8212        cs.mb_t8x8[addr] = true;
8213        for b8 in 0..4usize {
8214            let (bx, by) = (mb_x * 4 + (b8 % 2) * 2, mb_y * 4 + (b8 / 2) * 2);
8215            let predicted = predict_i4_mode(fe, bx, by);
8216            cb_intra4x4_pred_mode(cab, predicted, i8.modes[b8]);
8217        }
8218        cb_chroma_pred_mode(cab, cci, plan.chroma_mode);
8219        cs.cmode[addr] = plan.chroma_mode as i32;
8220        cs.cat[addr] = 0;
8221        let cbp = i8.cbp_luma | (cbp_chroma << 4);
8222        cb_cbp(cab, top.map(|a| cs.mb_cbp[a]), left.map(|a| cs.mb_cbp[a]), cbp);
8223        cs.mb_cbp[addr] = cbp as u8;
8224        nzc = cb_build_nzc(&cs.mb_nzc, top, left);
8225
8226        if cbp == 0 {
8227            cs.last_delta_qp = 0;
8228            nnz_commit_rows(fe, mb_x, mb_y, &[0u8; 16]);
8229        } else {
8230            let delta = fe.qp_delta();
8231            cb_mb_qp_delta(cab, &mut cs.last_delta_qp, delta);
8232            let mut nnz_loc = [0u8; 16];
8233            for b8 in 0..4usize {
8234                let (b8x, b8y) = (b8 % 2, b8 / 2);
8235                // Unlike CAVLC -- which has no 8x8 entropy model and must split the
8236                // block into four interleaved 4x4 sub-blocks -- CABAC codes the 8x8
8237                // as ONE 64-coefficient ctxBlockCat-5 block.
8238                let total = if i8.cbp_luma & (1 << b8) != 0 {
8239                    let scan8 = scan_8x8_fwd(&i8.q[b8]);
8240                    cb_residual(cab, &mut nzc, &mut cbfdc, b8 * 4, CB_RP_LUMA_8X8, true, ndc, &scan8)
8241                } else {
8242                    for k in 0..4 {
8243                        nzc[CB_NZC_CACHE[b8 * 4 + k]] = 0;
8244                    }
8245                    0
8246                };
8247                for sy in 0..2 {
8248                    for sx in 0..2 {
8249                        nnz_loc[(b8y * 2 + sy) * 4 + b8x * 2 + sx] = total as u8;
8250                    }
8251                }
8252            }
8253            nnz_commit_rows(fe, mb_x, mb_y, &nnz_loc);
8254            cb_emit_chroma_residual(cab, fe, &mut nzc, &mut cbfdc, ndc, true, plan.cbp_chroma, &plan.c_dc_levels, &plan.c_q_blocks, mb_x, mb_y);
8255        }
8256    } else {
8257        // ---- I_NxN (I_4x4) ----
8258        let i4 = plan.i4.as_ref().unwrap();
8259        if fe.transform_8x8 {
8260            let ta = left.map_or(0, |x| cs.mb_t8x8[x] as usize);
8261            let tb = top.map_or(0, |x| cs.mb_t8x8[x] as usize);
8262            cab.encode_decision(399 + ta + tb, 0);
8263        }
8264        for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
8265            let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
8266            let predicted = predict_i4_mode(fe, bx, by);
8267            cb_intra4x4_pred_mode(cab, predicted, i4.modes[lby * 4 + lbx]);
8268        }
8269        cb_chroma_pred_mode(cab, cci, plan.chroma_mode);
8270        cs.cmode[addr] = plan.chroma_mode as i32;
8271        cs.cat[addr] = 0;
8272        let cbp = i4.cbp_luma | (cbp_chroma << 4);
8273        cb_cbp(cab, top.map(|a| cs.mb_cbp[a]), left.map(|a| cs.mb_cbp[a]), cbp);
8274        cs.mb_cbp[addr] = cbp as u8;
8275        nzc = cb_build_nzc(&cs.mb_nzc, top, left);
8276
8277        if cbp == 0 {
8278            cs.last_delta_qp = 0;
8279            nnz_commit_rows(fe, mb_x, mb_y, &[0u8; 16]);
8280        } else {
8281            let delta = fe.qp_delta();
8282            cb_mb_qp_delta(cab, &mut cs.last_delta_qp, delta);
8283            let mut nnz_loc = [0u8; 16];
8284            for id8 in 0..4usize {
8285                for id4 in 0..4usize {
8286                    let iz = id8 * 4 + id4;
8287                    let (lbx, lby) = LUMA_4X4_SCAN_XY[iz];
8288                    let total = if i4.cbp_luma & (1 << id8) != 0 {
8289                        let sc = scan_4x4_dcac(&i4.q[lby * 4 + lbx]);
8290                        cb_residual(cab, &mut nzc, &mut cbfdc, iz, CB_RP_LUMA_4X4, true, ndc, &sc)
8291                    } else {
8292                        nzc[CB_NZC_CACHE[iz]] = 0;
8293                        0
8294                    };
8295                    nnz_loc[lby * 4 + lbx] = total as u8;
8296                }
8297            }
8298            nnz_commit_rows(fe, mb_x, mb_y, &nnz_loc);
8299            cb_emit_chroma_residual(cab, fe, &mut nzc, &mut cbfdc, ndc, true, plan.cbp_chroma, &plan.c_dc_levels, &plan.c_q_blocks, mb_x, mb_y);
8300        }
8301    }
8302
8303    cs.cbf_dc[addr] = cbfdc;
8304    cs.mb_nzc[addr] = cb_export_nzc(&nzc);
8305}
8306
8307/// Chroma DC + AC residual (shared by intra I_16x16/I_NxN and inter) — matches the
8308/// decoder's chroma residual order. `is_intra` selects the coded_block_flag default
8309/// (nA=nB default to is_intra). Populates the chroma nnz grid for deblock.
8310#[allow(clippy::too_many_arguments)]
8311fn cb_emit_chroma_residual(
8312    cab: &mut CabacEncoder,
8313    fe: &mut FrameEncoder,
8314    nzc: &mut [u8; 48],
8315    cbfdc: &mut u16,
8316    ndc: (Option<u16>, Option<u16>),
8317    is_intra: bool,
8318    cbp_chroma: u32,
8319    c_dc_levels: &[[i32; 4]; 2],
8320    c_q: &[[[i32; 16]; 4]; 2],
8321    mb_x: usize,
8322    mb_y: usize,
8323) {
8324    let w2 = fe.mb_w * 2;
8325    if cbp_chroma >= 1 {
8326        for i in 0..2usize {
8327            cb_residual(cab, nzc, cbfdc, 16 + i * 4, CB_RP_CHROMA_DC + i, is_intra, ndc, &c_dc_levels[i]);
8328        }
8329    }
8330    if cbp_chroma == 2 {
8331        for i in 0..2usize {
8332            for (id4, &(bx, by)) in CHROMA_4X4_SCAN_XY.iter().enumerate() {
8333                let ac = scan_4x4_ac(&c_q[i][by * 2 + bx]);
8334                let total = cb_residual(
8335                    cab, nzc, cbfdc, 16 + i * 4 + id4, CB_RP_CHROMA_AC + i, is_intra, ndc, &ac,
8336                );
8337                fe.nnz_c[i][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total as u8;
8338            }
8339        }
8340    }
8341}
8342
8343/// CABAC all-intra slice-data coder (IDR / I-slice). Mirrors `encode_slice_data`'s
8344/// setup + deblock + `RefFrame` construction, but codes every MB via `plan_mb` +
8345/// `emit_mb_cabac_i` into a CABAC bitstream. `w` already holds the byte-aligned
8346/// slice header; the CABAC bytes are appended after `cabac_alignment_one_bit`.
8347pub(crate) fn encode_slice_data_cabac_intra(
8348    w: &mut BitWriter,
8349    cfg: &EncoderConfig,
8350    frame: &YuvFrame,
8351    qp: u8,
8352    qpo: &[i32],
8353    aq_probe: Option<&YuvFrame>,
8354) -> crate::RefFrame {
8355    let mut fe = FrameEncoder::new(cfg);
8356    fe.qp = qp;
8357    fe.qpc = chroma_qp(qp);
8358    fe.cur_qp = qp;
8359    if cfg.cabac_dz_div > 0 {
8360        fe.idz = cfg.cabac_dz_div; // CABAC-specific dead-zone override
8361    }
8362    let (sy, su, sv) = coded_source(cfg, frame);
8363    // Great Gate P1: the shared per-frame signal vector. Intra has no coding
8364    // reference, but the batch path hands the previous SOURCE frame as the AQ
8365    // grain probe (docs/gate-ledger.md aq-grain-veto) — without it the veto
8366    // fails open and the temporal signals stay cold.
8367    let probe_y: Option<Vec<u8>> = aq_probe.map(|f| coded_source(cfg, f).0.into_owned());
8368    let sig = FrameSignals::new(&sy, fe.cw, fe.mb_w, fe.mb_h, probe_y.as_deref());
8369    apply_screen_t8_veto(&mut fe, &sig);
8370    let mut aq_qp = aq_qp_map(&sig, qp, fe.aq_strength);
8371    apply_mbtree_qpo(&mut aq_qp, qpo); // mb-tree temporal AQ (empty = byte-identical)
8372    signals::harvest(&sig, 'I', qp, &signals::GateDecisions::default());
8373    let mut mb_qpy = enc_scratch::take_qpy();
8374    mb_qpy.clear();
8375    mb_qpy.resize(fe.mb_w * fe.mb_h, qp);
8376
8377    // CABAC trellis (RDOQ): structure-adaptive. ON only for ALL-INTRA streams
8378    // (gop_size<=1), where each IDR is independent so trading a little distortion for
8379    // rate is a clean −0.5..−1.3% BD-rate win. OFF inside a GOP: there the I-frame is
8380    // a REFERENCE, and degrading it costs the dependent P-frames more than the I-frame
8381    // saves (measured ~+0.1% net) — so the safe end is a true no-op (never regresses).
8382    fe.rdoq_strength = if cfg.gop_size <= 1 { cfg.cabac_rdoq } else { 0.0 };
8383    // Contexts init from SliceQPY (the slice qp), init_idc unused for I, is_i = true.
8384    let mut cab = CabacEncoder::new_with_out(qp as i32, 0, true, enc_scratch::take_payload());
8385    let mut cs = CabacState::pooled(fe.mb_w * fe.mb_h);
8386    let total = fe.mb_w * fe.mb_h;
8387    // E15 round 2: slice-constant accountant knob (twin of the P/B hoists).
8388    let acct = crate::bitacct::enabled();
8389
8390    for mb_y in 0..fe.mb_h {
8391        for mb_x in 0..fe.mb_w {
8392            let mb_idx = mb_y * fe.mb_w + mb_x;
8393            let mb_qp = aq_qp[mb_idx];
8394            fe.qp = mb_qp;
8395            fe.qpc = chroma_qp(mb_qp);
8396            let plan = plan_mb(&mut fe, mb_x, mb_y, &sy, &su, &sv);
8397            emit_mb_cabac_i(&mut fe, &mut cab, &mut cs, &plan, mb_x, mb_y);
8398            mb_qpy[mb_idx] = fe.cur_qp;
8399            // end_of_slice_flag (EncodeTerminate): 1 on the last MB, else 0.
8400            cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
8401        }
8402    }
8403    enc_scratch::put_cs(cs);
8404
8405    // Append CABAC slice data after cabac_alignment_one_bit (pad header with 1-bits).
8406    while !w.is_byte_aligned() {
8407        w.write_bit(true);
8408    }
8409    let payload = cab.into_bytes();
8410    w.write_aligned_bytes(&payload);
8411    enc_scratch::put_payload(payload);
8412
8413    // Deblock the reconstruction (all-intra: BS derives from intra-ness) -> reference.
8414    let mut ref_id = enc_scratch::take_refid();
8415    ref_id.clear();
8416    ref_id.extend(fe.ref_idx_y.iter().map(|&r| if r >= 0 { r } else { i32::MIN }));
8417    let info = rusty_h264_common::deblock::BlockInfo {
8418        inter: &fe.inter_y,
8419        nnz: &fe.nnz_y,
8420        mv: &fe.mv_y,
8421        ref_id: &ref_id,
8422        mv1: &[],
8423        ref_id1: &[],
8424        w4: fe.mb_w * 4,
8425        t8x8: &[],
8426        poc0: &[],
8427        poc1: &[],
8428        bs: &[], kind: &[],
8429        };
8430    rusty_h264_common::deblock::filter_frame(
8431        &mut fe.rec_y, &mut fe.rec_u, &mut fe.rec_v, fe.mb_w, fe.mb_h, &mb_qpy, 0, 0, 0, &info,
8432    );
8433    enc_scratch::put_qpy(mb_qpy);
8434    enc_scratch::put_refid(ref_id);
8435    let w4 = fe.mb_w * 4;
8436    crate::RefFrame {
8437        y: fe.rec_y,
8438        u: fe.rec_u,
8439        v: fe.rec_v,
8440        poc: 0,
8441        frame_num: 0,
8442        mv: fe.mv_y,
8443        ref_idx: fe.ref_idx_y,
8444        mv1: Vec::new(),
8445        ref_idx1: Vec::new(),
8446        w4,
8447        // Filtered lazily on first sub-pel search use (see `RefFrame::hpel`).
8448        hpel: std::sync::OnceLock::new(),
8449    }
8450}
8451
8452// ============================================================================
8453// CABAC P-slice entropy coding — the forward inverse of the decoder's
8454// decode_slice_data_cabac P-slice path. mb_skip_flag / mb_type_p / mvd (UEG3) /
8455// inter residual, plus intra-in-P (the shared intra body under a P mb_type prefix).
8456// Scope: 1 reference (no ref_idx), P_16x16/16x8/8x16 (no P_8x8/sub_mb_type) — the
8457// modes the encoder's decision produces.
8458// ============================================================================
8459
8460
8461/// UEG3 mvd suffix — inverse of `decode_ueg_mv(base)` (TU prefix at base+{0,1,2,3,3..},
8462/// cMax 7, then EG3 bypass). `v` is the value decode_ueg_mv returns.
8463fn cb_ueg_mv(cab: &mut CabacEncoder, base: usize, v: u32) {
8464    const P2C: [usize; 8] = [0, 1, 2, 3, 3, 3, 3, 3];
8465    if v == 0 {
8466        cab.encode_decision(base, 0);
8467        return;
8468    }
8469    cab.encode_decision(base, 1);
8470    if v <= 7 {
8471        // (v-1) ones then a terminating 0, at base+P2C[count] for count = 1..
8472        let mut count = 1;
8473        for _ in 0..v - 1 {
8474            cab.encode_decision(base + P2C[count], 1);
8475            count += 1;
8476        }
8477        cab.encode_decision(base + P2C[count], 0);
8478    } else {
8479        // prefix maxes out: 7 ones (count 1..7) then EG3(v-8).
8480        let mut count = 1;
8481        for _ in 0..7 {
8482            cab.encode_decision(base + P2C[count], 1);
8483            count += 1;
8484        }
8485        let acct = crate::bitacct::enabled();
8486        let tb = if acct { cab.pos() } else { 0 };
8487        cb_exp_bypass(cab, 3, v - 8);
8488        if acct {
8489            crate::bitacct::add(crate::bitacct::B::MvdBypass, cab.pos() - tb);
8490        }
8491    }
8492}
8493
8494/// One `mvd` component — inverse of `parse_mvd_cabac(comp, ctx_inc)` (ctxIdxOffset
8495/// 40 for x, 47 for y).
8496fn cb_mvd(cab: &mut CabacEncoder, comp: usize, ctx_inc: usize, d: i32) {
8497    // One accountant-knob read per call (was three; runs per MVD component).
8498    let acct = crate::bitacct::enabled();
8499    let th = if acct { cab.pos() } else { u64::MAX };
8500    let base = 40 + comp * 7;
8501    if d == 0 {
8502        cab.encode_decision(base + ctx_inc, 0);
8503        if th != u64::MAX {
8504            crate::bitacct::add_mvd_sample(0, cab.pos() - th);
8505        }
8506        return;
8507    }
8508    cab.encode_decision(base + ctx_inc, 1);
8509    cb_ueg_mv(cab, base + 3, d.unsigned_abs() - 1); // decode adds 1 back
8510    let ts = if acct { cab.pos() } else { 0 };
8511    cab.encode_bypass((d < 0) as u32);
8512    if acct {
8513        crate::bitacct::add(crate::bitacct::B::MvdSign, cab.pos() - ts);
8514    }
8515    if th != u64::MAX {
8516        crate::bitacct::add_mvd_sample(d.unsigned_abs(), cab.pos() - th);
8517    }
8518}
8519
8520/// `mb_skip_flag` — inverse of `parse_mb_skip_cabac` (ctx 11 P + neighbour-not-skip).
8521fn cb_mb_skip(cab: &mut CabacEncoder, ctx_inc: usize, skip: bool) {
8522    cab.encode_decision(ctx_inc, skip as u32);
8523}
8524
8525/// `ref_idx_l0` (P) — inverse of `parse_ref_idx_cabac`. Unary binarization,
8526/// ctxIdxOffset 54: binIdx 0 → `ctx0` (condTermFlagA + 2·condTermFlagB, condTermFlagN =
8527/// neighbour partition's ref_idx > 0), binIdx 1 → 4, binIdx ≥2 → 5 (spec 9.3.3.1.1.6).
8528pub fn cb_ref_idx(cab: &mut CabacEncoder, ctx0: usize, r: u32) {
8529    const B: usize = 54;
8530    let mut v = r;
8531    let mut bin_idx = 0u32;
8532    loop {
8533        let bin = (v > 0) as u32;
8534        let ctx = match bin_idx {
8535            0 => ctx0,
8536            1 => 4,
8537            _ => 5,
8538        };
8539        cab.encode_decision(B + ctx, bin);
8540        if bin == 0 {
8541            break;
8542        }
8543        v -= 1;
8544        bin_idx += 1;
8545    }
8546}
8547
8548/// P-slice inter `mb_type` (0/1/2 = P_L0_16x16 / P_16x8 / P_8x16) — inverse of the
8549/// inter branch of `parse_mb_type_p_cabac` (ctx base 11).
8550fn cb_mb_type_p_inter(cab: &mut CabacEncoder, mode: u8) {
8551    const S: usize = 11;
8552    cab.encode_decision(S + 3, 0); // inter (prefix bit 0)
8553    match mode {
8554        0 => {
8555            cab.encode_decision(S + 4, 0);
8556            cab.encode_decision(S + 5, 0);
8557        }
8558        3 => {
8559            // P_8x8 (bins "0 0 1")
8560            cab.encode_decision(S + 4, 0);
8561            cab.encode_decision(S + 5, 1);
8562        }
8563        1 => {
8564            cab.encode_decision(S + 4, 1);
8565            cab.encode_decision(S + 6, 1);
8566        }
8567        _ => {
8568            // mode == 2 (P_8x16)
8569            cab.encode_decision(S + 4, 1);
8570            cab.encode_decision(S + 6, 0);
8571        }
8572    }
8573}
8574
8575/// P `sub_mb_type` CABAC — inverse of `parse_sub_mb_type_p_cabac` (ctx base 21).
8576/// Only 0 = P_L0_8x8 (bin "1") is emitted (8×8 sub-partitions only).
8577fn cb_sub_mb_type_p(cab: &mut CabacEncoder, sub_type: u8) {
8578    const S: usize = 21;
8579    // Inverse of `parse_sub_mb_type_p_cabac`: b(S)=1 → 0 (8×8);
8580    // b(S)=0, b(S+1)=0 → 1 (8×4); b(S)=0, b(S+1)=1 → 3−b(S+2) (2 = 4×8, 3 = 4×4).
8581    match sub_type {
8582        0 => cab.encode_decision(S, 1),
8583        1 => {
8584            cab.encode_decision(S, 0);
8585            cab.encode_decision(S + 1, 0);
8586        }
8587        2 => {
8588            cab.encode_decision(S, 0);
8589            cab.encode_decision(S + 1, 1);
8590            cab.encode_decision(S + 2, 1);
8591        }
8592        3 => {
8593            cab.encode_decision(S, 0);
8594            cab.encode_decision(S + 1, 1);
8595            cab.encode_decision(S + 2, 0);
8596        }
8597        _ => unreachable!("invalid P sub_mb_type"),
8598    }
8599}
8600
8601/// P-slice intra `mb_type` prefix — inverse of the intra branch of
8602/// `parse_mb_type_p_cabac` (ctx base 11). Carries the I_16x16 pred-mode/cbp exactly
8603/// like the I-slice mb_type, so the shared intra body re-emits neither.
8604fn cb_mb_type_p_intra(cab: &mut CabacEncoder, plan: &MbPlan) {
8605    const S: usize = 11;
8606    cab.encode_decision(S + 3, 1); // intra (prefix bit 1)
8607    if plan.use_i4 {
8608        cab.encode_decision(S + 6, 0); // I_4x4
8609        return;
8610    }
8611    cab.encode_decision(S + 6, 1); // I_16x16
8612    cab.encode_terminate(false); // not I_PCM
8613    cab.encode_decision(S + 7, plan.i16_cbp15 as u32);
8614    if plan.cbp_chroma != 0 {
8615        cab.encode_decision(S + 8, 1);
8616        cab.encode_decision(S + 8, (plan.cbp_chroma == 2) as u32);
8617    } else {
8618        cab.encode_decision(S + 8, 0);
8619    }
8620    cab.encode_decision(S + 9, (plan.i16_mode as u32 >> 1) & 1);
8621    cab.encode_decision(S + 9, plan.i16_mode as u32 & 1);
8622}
8623
8624/// P-slice partition layout: `(part_idx, z-blocks)` per motion partition (matches
8625/// the decoder's `part!` invocations). part_idx = the partition's top-left z-block
8626/// (its `CACHE30` slot for the mvd ctxInc); z-blocks = every 4x4 it covers.
8627fn p_partition_layout(mode: u8) -> &'static [(usize, &'static [usize])] {
8628    match mode {
8629        1 => &[(0, &[0, 1, 2, 3, 4, 5, 6, 7]), (8, &[8, 9, 10, 11, 12, 13, 14, 15])],
8630        2 => &[(0, &[0, 1, 2, 3, 8, 9, 10, 11]), (4, &[4, 5, 6, 7, 12, 13, 14, 15])],
8631        // P_8x8: four 8×8 quads (z-order 4×4 blocks), part order == inter_partitions(3).
8632        3 => &[(0, &[0, 1, 2, 3]), (4, &[4, 5, 6, 7]), (8, &[8, 9, 10, 11]), (12, &[12, 13, 14, 15])],
8633        _ => &[(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])],
8634    }
8635}
8636
8637/// Sub-partition geometry per `sub_mb_type` (P): pixel rects within an 8×8, in
8638/// decode order. VERBATIM the decoder's `sub_mb_partitions` (spec Table 7-17) —
8639/// the decoder's parse is the contract this encoder inverts (Great Gate P3.3).
8640fn sub_mb_partitions_p(sub_type: u8) -> &'static [(usize, usize, usize, usize)] {
8641    match sub_type {
8642        0 => &[(0, 0, 8, 8)],
8643        1 => &[(0, 0, 8, 4), (0, 4, 8, 4)],
8644        2 => &[(0, 0, 4, 8), (4, 0, 4, 8)],
8645        _ => &[(0, 0, 4, 4), (4, 0, 4, 4), (0, 4, 4, 4), (4, 4, 4, 4)],
8646    }
8647}
8648
8649/// Per-sub-partition `(part_idx, zblocks)` for the mvd cache/context emission —
8650/// the sub-partition refinement of `p_partition_layout(3)`'s quads. `part_idx` =
8651/// the sub-partition's first 4×4 in MB z-order (its top-left), `zblocks` = the
8652/// 4×4s it covers; quad `p8`'s blocks are `4·p8 ..= 4·p8+3` in z-order
8653/// (0=TL, 1=TR, 2=BL, 3=BR within the quad).
8654fn p_sub_partition_layout(p8: usize, sub_type: u8) -> &'static [(usize, &'static [usize])] {
8655    const T: [[&[(usize, &[usize])]; 4]; 4] = [
8656        [
8657            &[(0, &[0, 1, 2, 3])],
8658            &[(0, &[0, 1]), (2, &[2, 3])],
8659            &[(0, &[0, 2]), (1, &[1, 3])],
8660            &[(0, &[0]), (1, &[1]), (2, &[2]), (3, &[3])],
8661        ],
8662        [
8663            &[(4, &[4, 5, 6, 7])],
8664            &[(4, &[4, 5]), (6, &[6, 7])],
8665            &[(4, &[4, 6]), (5, &[5, 7])],
8666            &[(4, &[4]), (5, &[5]), (6, &[6]), (7, &[7])],
8667        ],
8668        [
8669            &[(8, &[8, 9, 10, 11])],
8670            &[(8, &[8, 9]), (10, &[10, 11])],
8671            &[(8, &[8, 10]), (9, &[9, 11])],
8672            &[(8, &[8]), (9, &[9]), (10, &[10]), (11, &[11])],
8673        ],
8674        [
8675            &[(12, &[12, 13, 14, 15])],
8676            &[(12, &[12, 13]), (14, &[14, 15])],
8677            &[(12, &[12, 14]), (13, &[13, 15])],
8678            &[(12, &[12]), (13, &[13]), (14, &[14]), (15, &[15])],
8679        ],
8680    ];
8681    T[p8][sub_type as usize]
8682}
8683
8684/// Emit one motion partition's `mvd` (x,y) and splat it into the 30-entry cache +
8685/// per-MB raster mvd/ref grids — inverse of the decoder's `parse_mvd_partition`.
8686#[allow(clippy::too_many_arguments)]
8687fn cb_emit_mvd_partition(
8688    cab: &mut CabacEncoder,
8689    part_idx: usize,
8690    zblocks: &[usize],
8691    mvdc: &mut [[i16; 2]; 30],
8692    refc: &mut [i8; 30],
8693    mmvd: &mut [[i16; 2]; 16],
8694    mref: &mut [i8; 16],
8695    mvd: (i32, i32),
8696    ref_idx: i8, // the partition's ref_idx_l0 (0 for single-ref) — stored for neighbour context
8697) {
8698    let s = CB_CACHE30[part_idx];
8699    let ctx = |comp: usize| -> usize {
8700        let mut a = 0i32;
8701        if refc[s - 6] >= 0 {
8702            a += mvdc[s - 6][comp].unsigned_abs() as i32;
8703        }
8704        if refc[s - 1] >= 0 {
8705            a += mvdc[s - 1][comp].unsigned_abs() as i32;
8706        }
8707        if a >= 3 {
8708            1 + (a > 32) as usize
8709        } else {
8710            0
8711        }
8712    };
8713    cb_mvd(cab, 0, ctx(0), mvd.0);
8714    cb_mvd(cab, 1, ctx(1), mvd.1);
8715    let (mx, my) = (mvd.0 as i16, mvd.1 as i16);
8716    for &zb in zblocks {
8717        mvdc[CB_CACHE30[zb]] = [mx, my];
8718        refc[CB_CACHE30[zb]] = ref_idx;
8719        mmvd[CB_G_SCAN4[zb]] = [mx, my];
8720        mref[CB_G_SCAN4[zb]] = ref_idx;
8721    }
8722}
8723
8724/// Emit one planned INTER macroblock as CABAC (P-slice, mb_skip_flag already coded
8725/// as 0). `mode`/`parts` + `plan` from `plan_inter_mb`. 1-ref: no ref_idx.
8726fn emit_mb_cabac_p_inter(
8727    fe: &mut FrameEncoder,
8728    cab: &mut CabacEncoder,
8729    cs: &mut CabacState,
8730    mode: u8,
8731    plan: &InterPlan,
8732    mb_x: usize,
8733    mb_y: usize,
8734    num_refs: usize,
8735) {
8736    let mb_w = fe.mb_w;
8737    let addr = mb_y * mb_w + mb_x;
8738    let top = if mb_y > 0 { Some(addr - mb_w) } else { None };
8739    let left = if mb_x > 0 { Some(addr - 1) } else { None };
8740
8741    // Bit accountant (instrument #6): each tap is a `pos()` delta — exact coded
8742    // bits for that element — behind an atomic-bool check when disabled.
8743    let acct = crate::bitacct::enabled();
8744    let mut t0 = if acct { cab.pos() } else { 0 };
8745    cb_mb_type_p_inter(cab, mode);
8746    // P_8x8: four sub_mb_type, spec order before ref_idx/mvd ([0;4] = all 8×8 =
8747    // the pre-P3.3 emission, byte-identical).
8748    if mode == 3 {
8749        for &st in &plan.sub_types {
8750            cb_sub_mb_type_p(cab, st);
8751        }
8752    }
8753    if acct {
8754        crate::bitacct::add(crate::bitacct::B::MbType, cab.pos() - t0);
8755        t0 = cab.pos();
8756    }
8757
8758    // ---- mb_pred (spec 7.3.5.1): all ref_idx_l0 FIRST, then all mvd_l0 ----
8759    let mut mvdc = [[0i16; 2]; 30];
8760    let mut refc = [-1i8; 30];
8761    cb_fill_inter_cache(&cs.mb_ref, &cs.mb_mvd, &mut refc, &mut mvdc, top, left, addr, mb_w);
8762    let mut mmvd = [[0i16; 2]; 16];
8763    let mut mref = [0i8; 16];
8764    let layout = p_partition_layout(mode);
8765    // Phase 1: ref_idx_l0 per partition, only when the slice has >1 active reference.
8766    // Update refc after each so a later partition's ref context sees the earlier one.
8767    if num_refs > 1 {
8768        for (part, &(part_idx, zblocks)) in layout.iter().enumerate() {
8769            let r = plan.plan_refs[part];
8770            let s = CB_CACHE30[part_idx];
8771            let ctx0 = (refc[s - 1] > 0) as usize + 2 * (refc[s - 6] > 0) as usize;
8772            cb_ref_idx(cab, ctx0, r as u32);
8773            for &zb in zblocks {
8774                refc[CB_CACHE30[zb]] = r as i8;
8775            }
8776        }
8777    }
8778    if acct {
8779        crate::bitacct::add(crate::bitacct::B::RefIdx, cab.pos() - t0);
8780        t0 = cab.pos();
8781    }
8782    // Phase 2: mvd per partition (carries the ref into refc/mref for neighbour context).
8783    if mode == 3 && plan.sub_types != [0u8; 4] {
8784        // Sub-partitioned P_8x8: one mvd per sub-partition, decode order, the
8785        // quad ref for context (P3.3 -- layout from `p_sub_partition_layout`).
8786        let mut k = 0usize;
8787        for p8 in 0..4usize {
8788            for &(part_idx, zblocks) in p_sub_partition_layout(p8, plan.sub_types[p8]) {
8789                cb_emit_mvd_partition(
8790                    cab, part_idx, zblocks, &mut mvdc, &mut refc, &mut mmvd, &mut mref,
8791                    plan.mvds[k], plan.plan_refs[p8] as i8,
8792                );
8793                k += 1;
8794            }
8795        }
8796    } else {
8797        for (part, &(part_idx, zblocks)) in layout.iter().enumerate() {
8798            cb_emit_mvd_partition(
8799                cab, part_idx, zblocks, &mut mvdc, &mut refc, &mut mmvd, &mut mref, plan.mvds[part],
8800                plan.plan_refs[part] as i8,
8801            );
8802        }
8803    }
8804    if acct {
8805        crate::bitacct::add(crate::bitacct::B::Mvd, cab.pos() - t0);
8806    }
8807    cs.mb_mvd[addr] = mmvd;
8808    cs.mb_ref[addr] = mref;
8809    cs.cat[addr] = 100;
8810    let allow8 = plan.sub_types == [0u8; 4];
8811    cb_emit_inter_residual(fe, cab, cs, plan, mb_x, mb_y, addr, top, left, allow8);
8812}
8813
8814/// Inter cbp + residual (is_intra = false) — shared by P and B inter MBs. Maintains
8815/// cs.mb_cbp/cbf_dc/mb_nzc/last_delta_qp + fe.nnz_y.
8816#[allow(clippy::too_many_arguments)]
8817fn cb_emit_inter_residual(
8818    fe: &mut FrameEncoder,
8819    cab: &mut CabacEncoder,
8820    cs: &mut CabacState,
8821    plan: &InterPlan,
8822    mb_x: usize,
8823    mb_y: usize,
8824    addr: usize,
8825    top: Option<usize>,
8826    left: Option<usize>,
8827    allow8: bool,
8828) {
8829    let w4 = fe.mb_w * 4;
8830    let cbp = plan.cbp;
8831    let (cbp_luma, cbp_chroma) = (cbp & 15, cbp >> 4);
8832    let acct = crate::bitacct::enabled();
8833    let mut t0 = if acct { cab.pos() } else { 0 };
8834    cb_cbp(cab, top.map(|a| cs.mb_cbp[a]), left.map(|a| cs.mb_cbp[a]), cbp);
8835    if acct {
8836        crate::bitacct::add(crate::bitacct::B::Cbp, cab.pos() - t0);
8837    }
8838    cs.mb_cbp[addr] = cbp as u8;
8839    // transform_size_8x8_flag, INTER position: after cbp, before mb_qp_delta, and
8840    // only when luma carries coefficients (spec 7.3.5). Contrast the I_NxN position,
8841    // which is before the pred modes -- the two are different points in the syntax,
8842    // which is why this needs its own write rather than a shared helper.
8843    // `plan_inter_mb` enforces the noSubMbPartSizeLessThan8x8Flag half of the
8844    // condition by never selecting t8x8 alongside a sub-8x8 split.
8845    // `allow8` is the spec's noSubMbPartSizeLessThan8x8Flag, mirroring the decoder's
8846    // own `allow8`. It gates the flag's PRESENCE, not just its value: omitting it wrote
8847    // one extra bin on every sub-8x8-split P_8x8 with luma coefficients and desynced
8848    // the stream some macroblocks later (ffmpeg reported it as a bogus intra mode).
8849    let t8_present = cbp_luma > 0 && fe.transform_8x8 && allow8;
8850    if t8_present {
8851        let ta = left.map_or(0, |x| cs.mb_t8x8[x] as usize);
8852        let tb = top.map_or(0, |x| cs.mb_t8x8[x] as usize);
8853        cab.encode_decision(399 + ta + tb, plan.t8x8 as u32);
8854    }
8855    // ABSENT means INFERRED ZERO, and the decoder stores that zero as the neighbour
8856    // ctxIdxInc for later macroblocks. Storing `plan.t8x8` here regardless of
8857    // presence would drift our context from the decoder's on any MB where the flag
8858    // was suppressed -- a desync that only shows up MBs later.
8859    cs.mb_t8x8[addr] = t8_present && plan.t8x8;
8860    let mut nzc = cb_build_nzc(&cs.mb_nzc, top, left);
8861    let mut cbfdc = 0u16;
8862    let ndc = (top.map(|a| cs.cbf_dc[a]), left.map(|a| cs.cbf_dc[a]));
8863
8864    if cbp == 0 {
8865        cs.last_delta_qp = 0;
8866        for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
8867            fe.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 0;
8868        }
8869    } else {
8870        let delta = fe.qp_delta();
8871        if acct { t0 = cab.pos(); }
8872        cb_mb_qp_delta(cab, &mut cs.last_delta_qp, delta);
8873        if acct {
8874            crate::bitacct::add(crate::bitacct::B::QpDelta, cab.pos() - t0);
8875            t0 = cab.pos();
8876        }
8877        if plan.t8x8 {
8878            // ctxBlockCat 5: ONE 64-coefficient block per 8x8, no coded_block_flag.
8879            for b8 in 0..4usize {
8880                let (b8x, b8y) = (b8 % 2, b8 / 2);
8881                let total = if cbp_luma & (1 << b8) != 0 {
8882                    let scan8 = scan_8x8_fwd(&plan.q8[b8]);
8883                    cb_residual(cab, &mut nzc, &mut cbfdc, b8 * 4, CB_RP_LUMA_8X8, false, ndc, &scan8)
8884                } else {
8885                    for k in 0..4 {
8886                        nzc[CB_NZC_CACHE[b8 * 4 + k]] = 0;
8887                    }
8888                    0
8889                };
8890                for sy in 0..2 {
8891                    for sx in 0..2 {
8892                        fe.nnz_y[(mb_y * 4 + b8y * 2 + sy) * w4 + (mb_x * 4 + b8x * 2 + sx)] =
8893                            total as u8;
8894                    }
8895                }
8896            }
8897        } else {
8898        for id8 in 0..4usize {
8899            for id4 in 0..4usize {
8900                let iz = id8 * 4 + id4;
8901                let (lbx, lby) = LUMA_4X4_SCAN_XY[iz];
8902                let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
8903                let total = if cbp_luma & (1 << id8) != 0 {
8904                    let sc = scan_4x4_dcac(&plan.q_blocks[lby * 4 + lbx]);
8905                    cb_residual(cab, &mut nzc, &mut cbfdc, iz, CB_RP_LUMA_4X4, false, ndc, &sc)
8906                } else {
8907                    nzc[CB_NZC_CACHE[iz]] = 0;
8908                    0
8909                };
8910                fe.nnz_y[by * w4 + bx] = total as u8;
8911            }
8912        }
8913        }
8914        if acct {
8915            crate::bitacct::add(crate::bitacct::B::ResidLuma, cab.pos() - t0);
8916            t0 = cab.pos();
8917        }
8918        cb_emit_chroma_residual(cab, fe, &mut nzc, &mut cbfdc, ndc, false, cbp_chroma, &plan.c_dc_levels, &plan.c_q, mb_x, mb_y);
8919        if acct {
8920            crate::bitacct::add(crate::bitacct::B::ResidChroma, cab.pos() - t0);
8921        }
8922    }
8923    cs.cbf_dc[addr] = cbfdc;
8924    cs.mb_nzc[addr] = cb_export_nzc(&nzc);
8925}
8926
8927/// Emit one planned INTRA macroblock inside a P-slice: the P mb_type prefix (which
8928/// carries the I_16x16 pred-mode/cbp) then the shared intra body.
8929fn emit_mb_cabac_p_intra(
8930    fe: &mut FrameEncoder,
8931    cab: &mut CabacEncoder,
8932    cs: &mut CabacState,
8933    plan: &MbPlan,
8934    mb_x: usize,
8935    mb_y: usize,
8936) {
8937    let mb_w = fe.mb_w;
8938    let addr = mb_y * mb_w + mb_x;
8939    let top = if mb_y > 0 { Some(addr - mb_w) } else { None };
8940    let left = if mb_x > 0 { Some(addr - 1) } else { None };
8941    let acct = crate::bitacct::enabled();
8942    let t0 = if acct { cab.pos() } else { 0 };
8943    cb_mb_type_p_intra(cab, plan);
8944    emit_intra_body_cabac(fe, cab, cs, plan, mb_x, mb_y, addr, top, left);
8945    if acct {
8946        // Whole intra MB (mb_type + modes + its residual) — intra MBs are ~5% of
8947        // P-frame MBs; splitting them further is a separate tap set.
8948        crate::bitacct::add(crate::bitacct::B::IntraBody, cab.pos() - t0);
8949    }
8950}
8951
8952/// Emit a P_Skip macroblock's `mb_skip_flag = 1` and update neighbour state. The
8953/// motion grid was committed by `commit_skip`; the mvd/ref cache is LEFT at its
8954/// init (-1 ref) — matching the decoder, which does not touch mb_mvd/mb_ref for a
8955/// P_Skip (so a skip neighbour contributes nothing to a later mvd ctxInc).
8956fn emit_p_skip_cabac(cab: &mut CabacEncoder, cs: &mut CabacState, addr: usize, top: Option<usize>, left: Option<usize>) {
8957    let sctx = 11
8958        + left.map_or(0, |a| (!cs.mb_skip[a]) as usize)
8959        + top.map_or(0, |a| (!cs.mb_skip[a]) as usize);
8960    let acct = crate::bitacct::enabled();
8961    let t0 = if acct { cab.pos() } else { 0 };
8962    cb_mb_skip(cab, sctx, true);
8963    if acct {
8964        crate::bitacct::add(crate::bitacct::B::SkipFlag, cab.pos() - t0);
8965    }
8966    cs.mb_skip[addr] = true;
8967    cs.cat[addr] = 100;
8968    cs.last_delta_qp = 0;
8969}
8970
8971/// CABAC P-slice data coder. Mirrors `encode_slice_data`'s decision (P_Skip check +
8972/// fast/quality inter-vs-intra RD) exactly — only the emit differs (per-MB
8973/// mb_skip_flag + CABAC syntax + per-MB end_of_slice terminate).
8974/// Median source macroblock variance for a frame — the TEXTURE dispatch signal for
8975/// the ME lambda scale.
8976///
8977/// Raising the ME rate term biases the search toward cheaper motion vectors, which
8978/// costs texture detail. SSIM is texture-sensitive where PSNR is not, so on maximum-
8979/// texture content a higher lambda improves BD-PSNR while REGRESSING BD-SSIM.
8980/// Measured median MB variance vs BD-SSIM at lme 1.8:
8981///   akiyo 61 (-0.20), foreman 219 (-0.61), city 300 (-0.89), bus 454 (-0.01),
8982///   football 583 (-1.03), **mobile 1554 (+0.45 LOSS)**
8983/// The one loser carries 2.7x the texture of the next clip, so the split is wide.
8984///
8985/// Computed from the SOURCE, so it is available in-slice for BOTH P and B and needs
8986/// no cross-frame state — unlike the B-only direct-win rate, which cannot gate a knob
8987/// that both encoders read and whose carry-forward would be nondeterministic under
8988/// frame-parallel encode. Subsampled 2x2 (16x fewer loads) — a median over ~400
8989/// macroblocks does not need every pixel.
8990// `frame_median_mb_var` lives in `crate::signals` (Great Gate P1) — read through
8991// `FrameSignals::median_var`. NOTE its estimator caveat there: it is deliberately
8992// a DIFFERENT formula from `mb_variance` (the lme clip table was calibrated on it).
8993
8994/// Texture-dispatched ME lambda scale: the calibrated high value on normal content,
8995/// the conservative shipped value on maximum-texture content where it costs SSIM.
8996/// Cached `RFF_LME_Q` env override for [`EncoderConfig::tune_lme_q`] (one binary,
8997/// N sweep arms — and never an `env::var` in a per-frame path).
8998fn lme_q_env() -> Option<f64> {
8999    static E: std::sync::OnceLock<Option<f64>> = std::sync::OnceLock::new();
9000    *E.get_or_init(|| std::env::var("RFF_LME_Q").ok().and_then(|v| v.parse().ok()))
9001}
9002
9003fn me_lambda_scale(cfg: &EncoderConfig, sig: &FrameSignals, per_mb_tex: bool) -> f64 {
9004    let hi = match cfg.tune_lme_hi {
9005        Some(v) if v > 0.0 => v,
9006        _ => return cfg.cabac_lambda_scale,
9007    };
9008    // TWO terms, and each is justified by a DIFFERENT clip it must classify —
9009    // neither alone is sufficient, which is why the texture-only version shipped
9010    // disabled.
9011    //
9012    //   clip      global-MC resid   median var   wants hi lme?
9013    //   akiyo          1.51             61          yes
9014    //   foreman        9.59            219          yes
9015    //   city          12.44            300          yes
9016    //   football      24.83            583          yes
9017    //   TEMPETE       10.52            746          NO  <- caught by TEXTURE (650)
9018    //   MOBILE        19.50           1554          NO  <- caught by TEXTURE
9019    //   BUS           27.47            454          NO  <- caught by MOTION (20)
9020    //
9021    // mobile is maximum texture: a higher ME rate term biases toward cheaper MVs,
9022    // costing texture detail, and SSIM is texture-sensitive where PSNR is not.
9023    // bus is fast GLOBAL motion (a pan): its cost surface is dominated by one
9024    // global vector, so pushing the rate term drags MVs off it. football is
9025    // chaotic LOCAL motion at similar texture and WANTS the high value, so texture
9026    // cannot separate the two — the global-MC residual can, and in the opposite
9027    // direction, which is exactly why the pair works where either alone fails.
9028    // Great Gate P1 (`tune_lme_q`): when the caller applies the texture veto PER MB
9029    // by percentile, skip the frame-median form here so the two never stack — the
9030    // motion veto below stays frame-level in both forms.
9031    if !per_mb_tex && sig.median_var() >= cfg.tune_lme_tex_thresh.unwrap_or(650) {
9032        return cfg.cabac_lambda_scale;
9033    }
9034    if sig.has_ref() {
9035        let mot = cfg.tune_lme_motion_thresh.unwrap_or(26.0);
9036        if sig.gmc_residual() >= mot {
9037            return cfg.cabac_lambda_scale;
9038        }
9039    }
9040    hi
9041}
9042
9043pub(crate) fn encode_slice_data_cabac_p(
9044    w: &mut BitWriter,
9045    cfg: &EncoderConfig,
9046    frame: &YuvFrame,
9047    qp: u8,
9048    refs: &[crate::RefFrame],
9049    qpo: &[i32],
9050    wp: &[(i32, i32)],
9051) -> crate::RefFrame {
9052    let mut fe = FrameEncoder::new(cfg);
9053    fe.wp = wp.to_vec();
9054    fe.qp = qp;
9055    fe.qpc = chroma_qp(qp);
9056    fe.cur_qp = qp;
9057    if cfg.cabac_dz_div > 0 {
9058        fe.idz = cfg.cabac_dz_div; // CABAC-specific dead-zone override
9059    }
9060    // Inter trellis (opt-in, Great Gate P2): P slices are REFERENCES — see
9061    // `cabac_rdoq_p`'s structure-adaptive caveat. 0 = off, byte-identical.
9062    fe.rdoq_strength = 0.0; // set below, once `sig` exists (content-gated)
9063    // RD P_Skip threshold arm (P3 item 2): `RFF_RDSKIP_T` overrides for sweep
9064    // arms and CLI conformance runs, mirroring `RFF_BSKIP_T`. Unset = config.
9065    {
9066        static T: std::sync::OnceLock<Option<f64>> = std::sync::OnceLock::new();
9067        if let Some(t) = *T.get_or_init(|| {
9068            std::env::var("RFF_RDSKIP_T").ok().and_then(|v| v.parse().ok())
9069        }) {
9070            fe.rd_skip = t > 0.0;
9071            fe.rd_skip_fast_t = t;
9072        }
9073    }
9074    let (sy, su, sv) = coded_source(cfg, frame);
9075    // Great Gate P1: ONE lazy signal vector per frame. The lme motion term and
9076    // the me_wide coherence gate below both read `gmc_residual` — memoization
9077    // collapses what used to be TWO full global-MC probes into one.
9078    let sig = FrameSignals::new(&sy, fe.cw, fe.mb_w, fe.mb_h, refs.first().map(|r| &r.y[..]));
9079    apply_screen_t8_veto(&mut fe, &sig);
9080    // CONTENT GATE for P-slice trellis. Flat-on is refuted (loses on 4 of 6 clips at
9081    // strength 32); grain and screen are the two classes where it wins hugely
9082    // (-30.12% / -12.11% BD-SSIM). The discriminator is exactly the reference-structure
9083    // argument in `cabac_rdoq_p`'s doc: a P frame is a reference, so trading its
9084    // distortion for rate propagates -- UNLESS what is being traded away is noise
9085    // (grain) or flat runs (screen), which propagate nothing.
9086    fe.rdoq_strength = if sig.grain_signature() || sig.is_screen() { cfg.cabac_rdoq_p } else { 0.0 };
9087    let lambda = 0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
9088    // Hoisted to SLICE level: the texture median is O(pixels) and the site below
9089    // sits inside the macroblock loop, where recomputing it would be quadratic.
9090    // Great Gate P1 (opt-in, BD-gate pending — great-gate.md §6 P2): `tune_lme_q` /
9091    // `RFF_LME_Q` converts the lme TEXTURE veto from an absolute frame-median test
9092    // (which cannot separate bus 454 from football 583 — they want opposite values)
9093    // to the population-shaped per-MB form: THIS frame's top-q highest-variance MBs
9094    // take the conservative scale individually. None/unset = frame form, byte-identical.
9095    // SHAPE-RD TEXTURE GUARD (Great Gate). shape-rd wins on 12 of 13 clips on
9096    // BOTH metrics and on 13 of 13 on PSNR; the lone loser is mobile (+1.99
9097    // BD-SSIM while WINNING -0.44 PSNR), the natural-corpus texture extreme.
9098    //
9099    // THIS IS A CONSERVATIVE GUARD, NOT A CAUSAL MODEL -- read before touching.
9100    // Four candidate mechanisms were tested and ALL FOUR REFUTED (gate-ledger):
9101    // texture-causes-the-loss is refuted by `maxtex_plaid`, a SYNTHESIZED clip
9102    // at median_var 2583 -- above mobile's 1494 -- which WINS -1.87 unvetoed.
9103    // dcfrac separated only under an unrelated lambda config. AQ accounts for
9104    // at most a fifth (aq=0 still loses +1.64). Chroma-weighting the RD SSD
9105    // moves it MONOTONICALLY THE WRONG WAY (+2.11 at weight 0).
9106    //
9107    // So median_var does not explain the loss; it merely BOUNDS it. Within the
9108    // 24-clip natural truth table exactly one clip exceeds this threshold and
9109    // that clip regresses, so the guard can only ever forgo a win, never create
9110    // a loss. It costs `maxtex_plaid` its -1.87 -- accepted, because synthetic
9111    // single-frequency texture is not content anyone ships. Threshold sits in
9112    // the open natural gap (highest winner foreman_qcif 793 -> mobile 1494).
9113    // Delete this guard the moment a real mechanism is found.
9114    let shape_rd_tex_veto = sig.median_var() > shape_rd_tex_max();
9115    let lme_q = lme_q_env().or(cfg.tune_lme_q).filter(|&q| q > 0.0);
9116    let lme_scale = me_lambda_scale(cfg, &sig, lme_q.is_some());
9117    let lme_mb_thresh: Option<i64> = match lme_q {
9118        Some(q) if lme_scale != cfg.cabac_lambda_scale => Some(sig.var_percentile_thresh(q)),
9119        _ => None,
9120    };
9121    let num_refs = refs.len();
9122    // me_wide content gate (pure-pan → global-MC residual ≈ 0 → off; see encode_slice_data).
9123    if fe.me_wide && !refs.is_empty() {
9124        let coh = sig.gmc_residual();
9125        if std::env::var("RFF_ME_COH_DBG").is_ok() {
9126            eprintln!("ME_COH qp{qp} residual={coh:.2}");
9127        }
9128        if coh < fe.me_wide_coh {
9129            fe.me_wide = false;
9130        }
9131    }
9132    // me_wide HEAD-ROOM GATE (the dispatcher the truth table asked for). The rescue
9133    // only pays where a wide search actually beats a predictor-local one; measure
9134    // that directly per frame and route the frame. `RFF_ME_HR` sets the threshold
9135    // (percent); 0 disables the gate and restores the always-on behaviour.
9136    // Skip the probe entirely when the gate is disabled: it must not tax the
9137    // default path (`RFF_ME_HR=0`), which stays byte-identical to pre-gate output.
9138    if fe.me_wide && !refs.is_empty() && (me_wide_hr_thresh() > 0.0 || me_wide_hr_dbg()) {
9139        let hr = sig.headroom();
9140        if me_wide_hr_dbg() {
9141            eprintln!("ME_HR qp{qp} headroom={hr:.2}");
9142        }
9143        if me_wide_hr_thresh() > 0.0 && hr < me_wide_hr_thresh() {
9144            fe.me_wide = false;
9145        }
9146    }
9147    // Track-B B2 DISPATCH — same probe/route as the CAVLC driver above (the two
9148    // drivers must stay in lockstep; the U5-struct bug came from patching one).
9149    if me_sadfp_mode() == 1 && !fe.fast && !refs.is_empty() {
9150        let (mg, dc) = sig.mgain_dc();
9151        if me_sadt_dbg() {
9152            eprintln!("B2_MG qp{qp} mgain={mg:.3} dcfrac={dc:.3}");
9153        }
9154        fe.sadfp = mg >= me_sadt() && dc <= me_sad_dcmax();
9155        // H-24: the mv-cost SHAPE rides the same probe (its BD sign-flip tracks
9156        // motion for the same physical reason B2's does).
9157        if mv_smooth_mode() == 1 {
9158            // dcfrac veto mirrors B2's: crew-class FLASH frames satisfy the mgain
9159            // test but SAD/mvd statistics mislead there (H-13/H-26).
9160            fe.mv_smooth = mg >= mv_smooth_t() && dc <= me_sad_dcmax();
9161        }
9162        // H-13: near-static frames skip the split searches entirely.
9163        let smg = split_mg();
9164        if smg > 0.0 {
9165            fe.do_splits = mg >= smg;
9166        }
9167    }
9168    if fe.satd_q > 0.0 {
9169        fe.satd_var_thresh = sig.var_percentile_thresh(fe.satd_q);
9170    }
9171    let mut aq_qp = aq_qp_map(&sig, qp, fe.aq_strength);
9172    apply_mbtree_qpo(&mut aq_qp, qpo); // mb-tree temporal AQ (empty = byte-identical)
9173    signals::harvest(
9174        &sig,
9175        'P',
9176        qp,
9177        &signals::GateDecisions {
9178            me_wide: fe.me_wide,
9179            sadfp: fe.sadfp,
9180            mv_smooth: fe.mv_smooth,
9181            do_splits: fe.do_splits,
9182            lme_scale,
9183            satd_thresh: fe.satd_var_thresh,
9184        },
9185    );
9186    let mut mb_qpy = enc_scratch::take_qpy();
9187    mb_qpy.clear();
9188    mb_qpy.resize(fe.mb_w * fe.mb_h, qp);
9189
9190    // Same online free-skip dispatch as the CAVLC path gates the greedy P_Skip on
9191    // (see `encode_slice_data`): measured over the frame so far, within-frame so it
9192    // stays deterministic under GOP-parallel encode.
9193    // Online split-payoff census (see `sub8_pay_cfg`): `seen` = macroblocks that
9194    // ran the split search, `paid` = those whose split survived the RD trial.
9195    let (sub8_minpay, sub8_learn) = sub8_pay_cfg();
9196    let (mut sub8_seen, mut sub8_gain) = (0usize, 0f64);
9197    let mut sub8_paying = true;
9198    let mut greedy_free = 0usize;
9199    let mut greedy_seen = 0usize;
9200    let mut greedy_on = fe.greedy_min_free == 0;
9201    let greedy_learn = (fe.mb_w * fe.mb_h / 8).max(64);
9202    let mut cab =
9203        CabacEncoder::new_with_out(qp as i32, cfg.cabac_init_idc, false, enc_scratch::take_payload()); // P-slice
9204    let mut cs = CabacState::pooled(fe.mb_w * fe.mb_h);
9205    let total = fe.mb_w * fe.mb_h;
9206
9207    // E15 hammer (inline-execution.md 11.8): the asm read showed this driver's
9208    // "1,730 un-vectorised xmm ops" are 24% SEH unwind DIRECTIVES and ~1,200
9209    // scalar f64 moves/compares of RD currency spilled around 461 calls - there
9210    // is no pixel loop to vectorise. The lever is Law 5: every line below was
9211    // re-read per MACROBLOCK (several per CODED macroblock) though each is
9212    // slice-constant. All are cached atomics or pure values - hoisting is
9213    // byte-identical by the same process-constant contract the pre-loop gates
9214    // above already assume.
9215    let lme_base = lambda.sqrt();
9216    let grain = sig.grain_signature();
9217    let split_t_v = split_t();
9218    let shape_rd = shape_rd_on().unwrap_or(cfg.tune_shape_rd);
9219    let want_split_knob = sub8x8_split_on() || cfg.tune_sub8x8_split;
9220    let sub8_gveto = sub8_grain_veto_on();
9221    let sub8_rd = sub8_rd_on() || cfg.tune_sub8_rd;
9222    let use_rd_frame = (intra_rd_on() || cfg.tune_intra_rd) && (!intra_rd_grain_gate() || grain);
9223    let acct = crate::bitacct::enabled();
9224    let greedy_zero = fe.greedy_min_free == 0;
9225    // lme tex veto operands, resolved once (mb_vars is built whenever the
9226    // threshold exists; the map keeps the never-built path allocation-free).
9227    let lme_vars = lme_mb_thresh.map(|t| (sig.mb_vars(), t));
9228    // REFUTED, do not retry (E15 r2): binding `&aq_qp[..total]` removed ZERO
9229    // of the loop's bounds checks (43 -> 43) - the `mb_idx = mb_y*w + mb_x`
9230    // shape defeats the slice-length hint here just as runtime-extent row
9231    // slices did in the decoder campaign.
9232
9233    // ② residue naming: the CABAC driver's MB loop was untapped (the CAVLC twin
9234    // has this scope) — `EncMbLoop − Σ(per-MB stages)` is the per-MB glue.
9235    let _g_loop = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMbLoop);
9236    for mb_y in 0..fe.mb_h {
9237        for mb_x in 0..fe.mb_w {
9238            let mb_idx = mb_y * fe.mb_w + mb_x;
9239            let addr = mb_idx;
9240            let top = if mb_y > 0 { Some(addr - fe.mb_w) } else { None };
9241            let left = if mb_x > 0 { Some(addr - 1) } else { None };
9242            let mb_qp = aq_qp[mb_idx];
9243            fe.qp = mb_qp;
9244            fe.qpc = chroma_qp(mb_qp);
9245            // LAMBDA MUST MATCH THE QP THIS MB IS ACTUALLY QUANTIZED AT. The
9246            // slice `lambda` is built ONCE from the FRAME qp, but AQ (default
9247            // strength 1.0) and mb-tree rewrite `fe.qp` per macroblock on the
9248            // line above. Every RD site below compares SSD_recon against
9249            // lambda*bits, so using the frame lambda misprices rate by
9250            // 2^((qp_frame-qp_mb)/3) -- and AQ moves QP FURTHEST on the
9251            // highest-variance macroblocks, so the error is largest exactly
9252            // where the shape/split decision is hardest. Same family as the
9253            // SATD-vs-recon-SSE wrong-proxy bug that this campaign already
9254            // fixed twice: the currency has to match the decision.
9255            let lam_mb = if cfg.tune_rd_lambda_mb {
9256                0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(fe.qp)
9257            } else {
9258                lambda
9259            };
9260
9261            // ---- P_Skip check (identical logic to encode_slice_data) ----
9262            let mut inter: Option<InterChoice> = None;
9263            // P3.3: sub_mb_type per 8x8 quad when `inter` is mode 3 ([0;4] = all
9264            // 8x8). A companion local rather than an InterChoice field so every
9265            // other constructor site stays untouched.
9266            let mut inter_subs = [0u8; 4];
9267            let mut did_skip = false;
9268            if num_refs > 0 {
9269                let mv_skip = fe.skip_mv(mb_x, mb_y);
9270                let skip_y = fe.skip_predict_luma(refs, mb_x, mb_y, mv_skip);
9271                let luma_free = fe.skip_luma_is_free(&sy, mb_x, mb_y, &skip_y);
9272                // (fast && !luma_free) never READS the chroma prediction — the
9273                // old zero-array arm was a dead 128-byte fill per MB (E15 r2 W18).
9274                let skip_c: Option<[[u8; 64]; 2]> = if luma_free || !fe.fast {
9275                    Some(fe.skip_predict_chroma(refs, mb_x, mb_y, mv_skip))
9276                } else {
9277                    None
9278                };
9279                let is_free = luma_free
9280                    && skip_c.as_ref().is_some_and(|c| fe.skip_chroma_is_free(&su, &sv, mb_x, mb_y, c));
9281                let skip_sad = if fe.fast {
9282                    0
9283                } else {
9284                    let (lx, ly) = (mb_x * 16, mb_y * 16);
9285                    let mut s = 0u32;
9286                    for dy in 0..16 {
9287                        let src = &sy[(ly + dy) * fe.cw + lx..][..16];
9288                        let p = &skip_y[dy * 16..][..16];
9289                        s += src.iter().zip(p).map(|(&a, &b)| a.abs_diff(b) as u32).sum::<u32>();
9290                    }
9291                    s
9292                };
9293                greedy_seen += 1;
9294                if greedy_seen >= greedy_learn {
9295                    greedy_on = greedy_zero
9296                        || greedy_free * 100 >= greedy_seen * fe.greedy_min_free as usize;
9297                }
9298                if is_free {
9299                    // `is_free` implies the Some arm above.
9300                    fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, skip_c.as_ref().unwrap());
9301                    if !fe.fast {
9302                        fe.mb_was_skip[mb_idx] = true;
9303                        fe.mb_skip_sad[mb_idx] = skip_sad;
9304                    }
9305                    greedy_free += 1;
9306                    did_skip = true;
9307                } else {
9308                    signals::census::work(signals::census::W_MB_CODED);
9309                    let (lx, ly) = (mb_x * 16, mb_y * 16);
9310                    let nb = {
9311                        let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncMvPred);
9312                        fe.mv_neighbors_block(mb_x as isize * 4, mb_y as isize * 4, 4)
9313                    };
9314                    // Per-MB tex veto (`tune_lme_q`): top-q variance MBs take the
9315                    // conservative scale; None = the frame-level `lme_scale` exactly.
9316                    let lme = lme_base
9317                        * match lme_vars {
9318                            Some((v, t)) if v[mb_idx] >= t => cfg.cabac_lambda_scale,
9319                            _ => lme_scale,
9320                        };
9321                    if fe.fast {
9322                        // Dedup (E15 W9): `sig.mb_vars()` IS memoized `mb_variance`
9323                        // over the same planes; every path here with `satd_q > 0`
9324                        // already built it via the percentile threshold.
9325                        fe.mb_use_satd = fe.satd_q > 0.0
9326                            && sig.mb_vars()[mb_idx] >= fe.satd_var_thresh;
9327                        let (r16, mv16, cost_inter) =
9328                            fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 16, &[], lme);
9329                        let cost_intra = if fe.mb_use_satd {
9330                            fe.best_i16_satd(&sy, mb_x, mb_y)
9331                        } else {
9332                            fe.best_i16_sad(&sy, mb_x, mb_y)
9333                        } + (lme * fe.tune_intra_penalty) as i64;
9334                        inter = if cost_intra < cost_inter {
9335                            None
9336                        } else {
9337                            Some((0, vec![(r16, mv16)]))
9338                        };
9339                    } else {
9340                        // Quality preset: greedy P_Skip, then 16x16 baseline + sub-partitions + intra.
9341                        if fe.greedy_skip && greedy_on && skip_sad < fe.pred_skip_sad(mb_x, mb_y) {
9342                            // Quality preset: the Some arm always ran above.
9343                            fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, skip_c.as_ref().unwrap());
9344                            fe.mb_was_skip[mb_idx] = true;
9345                            fe.mb_skip_sad[mb_idx] = skip_sad;
9346                            did_skip = true;
9347                        } else {
9348                            let (r16, mv16, c16) =
9349                                fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 16, &[], lme);
9350                            let mut best_c = c16;
9351                            let mut pick: Option<InterChoice> = Some((0, vec![(r16, mv16)]));
9352                            // P3.3: the winning P_8x8 candidate's sub_mb_types
9353                            // ([0;4] unless a split arm won).
9354                            let mut pick_subs = [0u8; 4];
9355                            // Probe #3: every shape the SATD search evaluated, so
9356                            // the RD re-rank can score them all. Cheap to collect
9357                            // (the parts vectors already exist); empty unless the
9358                            // probe is on, so the default path allocates nothing.
9359                            let mut shape_cands: Vec<(u8, Vec<(i32, (i32, i32))>, [u8; 4])> =
9360                                Vec::new();
9361                            // Some(true) = the RD re-rank says INTRA; Some(false) =
9362                            // it says the chosen shape; None = probe off, use SATD.
9363                            let mut shape_rd_intra: Option<bool> = None;
9364                            if shape_rd {
9365                                shape_cands.push((0u8, vec![(r16, mv16)], [0u8; 4]));
9366                            }
9367                            const QSTEP16: [i64; 6] = [10, 11, 13, 14, 16, 18];
9368                            let qstep16 = QSTEP16[(fe.qp % 6) as usize] << (fe.qp / 6);
9369                            let split_gate = ((30 * (qstep16 + 160)) >> 3) * 2;
9370                        if fe.do_splits && c16 > split_gate && (split_t_v <= 0.0 || (c16 as f64) >= split_t_v * lme) {
9371                                let (rt, mvt, ct) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 16, 8, &[mv16], lme);
9372                                let (rb, mvb, cb) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly + 8, 16, 8, &[mv16], lme);
9373                                let (rl, mvl, cl) = fe.best_part(refs, &sy, &nb, num_refs, lx, ly, 8, 16, &[mv16], lme);
9374                                let (rr, mvr, cr) = fe.best_part(refs, &sy, &nb, num_refs, lx + 8, ly, 8, 16, &[mv16], lme);
9375                                if shape_rd {
9376                                    shape_cands.push((1u8, vec![(rt, mvt), (rb, mvb)], [0u8; 4]));
9377                                    shape_cands.push((2u8, vec![(rl, mvl), (rr, mvr)], [0u8; 4]));
9378                                }
9379                                if ct + cb < best_c {
9380                                    best_c = ct + cb;
9381                                    pick = Some((1u8, vec![(rt, mvt), (rb, mvb)]));
9382                                }
9383                                if cl + cr < best_c {
9384                                    best_c = cl + cr;
9385                                    pick = Some((2u8, vec![(rl, mvl), (rr, mvr)]));
9386                                }
9387                                // P_8x8: four 8×8 sub-partitions (see the CAVLC path).
9388                                // P3.3: with RFF_SUB8X8_SPLIT=1 each quad also
9389                                // trials 8x4/4x8/4x4 (single-ref only: ref_idx is
9390                                // per-QUAD syntax, and best_part searches refs per
9391                                // part -- mixed sub-part refs are unrepresentable).
9392                                // Per-quad arm cost = sub-part J sum + REAL
9393                                // sub_mb_type bins (0->1, 1->2, 2/3->3) priced at
9394                                // lme -- the uncharged-syntax lesson. The all-8x8
9395                                // total is arithmetically IDENTICAL to the old
9396                                // `lme*4 + sum(c)` form.
9397                                // GRAIN VETO, third consumer (P3.3 gate). With the
9398                                // decision re-priced in the RD currency the corpus
9399                                // has exactly two remaining losers and both are
9400                                // grain: splitting noise buys prediction error the
9401                                // quantizer discards, and no amount of correct
9402                                // pricing makes fitting noise worthwhile. Frame
9403                                // grain -> no split arm (byte-identical to the
9404                                // all-8x8 P_8x8 the encoder shipped before P3.3).
9405                                let want_split = want_split_knob && num_refs == 1;
9406                                let grain_veto = sub8_gveto && grain;
9407                                if want_split {
9408                                    signals::census::bump(signals::census::SUB8_GRAIN, grain_veto);
9409                                }
9410                                let split_arm = want_split && !grain_veto && sub8_paying;
9411                                if fe.sub8x8 && !split_arm {
9412                                    // Knob OFF: the EXACT legacy pricing, including
9413                                    // its single `(lme*4.0) as i64` truncation --
9414                                    // per-quad `lme as i64` truncates 4x and picks
9415                                    // DIFFERENT candidates (byte-identity bug found
9416                                    // at review, not by the gate).
9417                                    let mut c8 = (lme * 4.0) as i64;
9418                                    let mut p8 = Vec::with_capacity(4);
9419                                    for &(qx, qy) in &[(0usize, 0usize), (8, 0), (0, 8), (8, 8)] {
9420                                        let (r, mv, c) = fe.best_part(
9421                                            refs, &sy, &nb, num_refs, lx + qx, ly + qy, 8, 8, &[mv16], lme,
9422                                        );
9423                                        c8 += c;
9424                                        p8.push((r, mv));
9425                                    }
9426                                    if shape_rd {
9427                                        shape_cands.push((3u8, p8.clone(), [0u8; 4]));
9428                                    }
9429                                    if c8 < best_c {
9430                                        best_c = c8;
9431                                        pick = Some((3u8, p8));
9432                                    }
9433                                } else if fe.sub8x8 {
9434                                    debug_assert!(split_arm);
9435                                    let mut c8 = 0i64;
9436                                    let mut p8: Vec<(i32, (i32, i32))> = Vec::with_capacity(4);
9437                                    let mut subs = [0u8; 4];
9438                                    // The all-8x8 arm, kept whatever the SATD search
9439                                    // picks -- it is the RD probe's other candidate.
9440                                    let mut p8_flat: Vec<(i32, (i32, i32))> = Vec::with_capacity(4);
9441                                    let mut c8_flat = 0i64;
9442                                    let mut hrows: Vec<sub8_harvest::Row> = Vec::new();
9443                                    for (q, &(qx, qy)) in [(0usize, 0usize), (8, 0), (0, 8), (8, 8)].iter().enumerate() {
9444                                        let (r, mv, c) = fe.best_part(
9445                                            refs, &sy, &nb, num_refs, lx + qx, ly + qy, 8, 8, &[mv16], lme,
9446                                        );
9447                                        let j8 = c + lme as i64; // + 1 sub_mb_type bin
9448                                        let mut q_best = j8;
9449                                        let mut q_parts: Vec<(i32, (i32, i32))> = vec![(r, mv)];
9450                                        let mut q_st = 0u8;
9451                                        let mut j_split = i64::MAX; // best split arm, win or lose
9452                                        {
9453                                            for st in 1u8..=3 {
9454                                                let bins = if st == 1 { 2.0 } else { 3.0 };
9455                                                let mut cs = (lme * bins) as i64;
9456                                                let mut ps: Vec<(i32, (i32, i32))> = Vec::with_capacity(4);
9457                                                for &(srx, sry, srw, srh) in sub_mb_partitions_p(st) {
9458                                                    let (rr, mm, cc) = fe.best_part(
9459                                                        refs, &sy, &nb, num_refs,
9460                                                        lx + qx + srx, ly + qy + sry, srw, srh,
9461                                                        &[mv16, mv], lme,
9462                                                    );
9463                                                    cs += cc;
9464                                                    ps.push((rr, mm));
9465                                                }
9466                                                j_split = j_split.min(cs);
9467                                                if cs < q_best {
9468                                                    q_best = cs;
9469                                                    q_parts = ps;
9470                                                    q_st = st;
9471                                                }
9472                                            }
9473                                        }
9474                                        if sub8_harvest::enabled() {
9475                                            hrows.push(sub8_harvest::Row {
9476                                                j8,
9477                                                jsplit: j_split,
9478                                                st: q_st,
9479                                                lme,
9480                                                mbvar: sig.mb_vars()[mb_idx],
9481                                                mvdiv: (mv.0 - mv16.0).abs() + (mv.1 - mv16.1).abs(),
9482                                            });
9483                                        }
9484                                        signals::census::bump(
9485                                            signals::census::SUB8_SPLIT, q_st != 0,
9486                                        );
9487                                        c8 += q_best;
9488                                        c8_flat += j8;
9489                                        subs[q] = q_st;
9490                                        p8.extend(q_parts);
9491                                        p8_flat.push((r, mv));
9492                                    }
9493                                    // RD RE-PRICE (probe): the SATD search has picked
9494                                    // `subs`; ask the CODED macroblock which arm it
9495                                    // actually prefers. Both arms are planned for real
9496                                    // (transform+quantize+reconstruct) and scored
9497                                    // J = SSD_recon + lambda*bits, with the macroblock
9498                                    // state snapshotted and restored around each trial.
9499                                    // RD J the surviving split SAVED over all-8x8,
9500                                    // in lambda units — the census's value unit.
9501                                    let mut split_gain = 0f64;
9502                                    if sub8_rd && subs != [0u8; 4] {
9503                                        let mut snap = enc_scratch::take_snap_a();
9504                                        fe.save_mb_into(mb_x, mb_y, &mut snap);
9505                                        let pa = fe.plan_inter_mb(refs, &sy, &su, &sv, mb_x, mb_y, 3, &p8, None, subs);
9506                                        let ja = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y) as f64
9507                                            + lam_mb * plan_rate_bits(&pa, subs);
9508                                        // E11 (11.16a): the restore BETWEEN trials is
9509                                        // redundant — `plan_inter_mb` fully overwrites
9510                                        // every MbState field it writes (recon + the
9511                                        // four P grids), and the rest (nnz, modes,
9512                                        // cur_qp) move only at EMIT. One final restore
9513                                        // suffices; byte-identity gated with the RD
9514                                        // knobs FORCED ON.
9515                                        let pb = fe.plan_inter_mb(refs, &sy, &su, &sv, mb_x, mb_y, 3, &p8_flat, None, [0u8; 4]);
9516                                        let jb = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y) as f64
9517                                            + lam_mb * plan_rate_bits(&pb, [0u8; 4]);
9518                                        fe.load_mb(mb_x, mb_y, &snap);
9519                                        enc_scratch::put_snap_a(snap);
9520                                        signals::census::bump(
9521                                            signals::census::SUB8_RD_REVERT, jb <= ja,
9522                                        );
9523                                        if sub8_regret::enabled() {
9524                                            // R1 pre-check: keep the MAGNITUDE, which
9525                                            // the `split_gain` path below discards on
9526                                            // the revert branch.
9527                                            sub8_regret::record(
9528                                                ja, jb, lam_mb,
9529                                                subs.iter().filter(|&&x| x != 0).count(),
9530                                            );
9531                                        }
9532                                        if jb <= ja {
9533                                            // The split was a SATD mirage on this MB.
9534                                            subs = [0u8; 4];
9535                                            p8 = std::mem::take(&mut p8_flat);
9536                                            c8 = c8_flat;
9537                                        } else {
9538                                            split_gain = (jb - ja).max(0.0) / lam_mb.max(1e-9);
9539                                        }
9540                                        sub8_harvest::flush(&hrows, subs != [0u8; 4]);
9541                                    } else {
9542                                        sub8_harvest::flush(&hrows, subs != [0u8; 4]);
9543                                    }
9544                                    if sub8_minpay > 0 {
9545                                        sub8_seen += 1;
9546                                        // Value, not a tally: how much RD J this
9547                                        // macroblock's surviving split actually saved
9548                                        // over the all-8x8 arm. Zero when the split
9549                                        // lost — a searched-and-rejected MB is cost
9550                                        // with no payoff, which is what we want the
9551                                        // mean to reflect.
9552                                        sub8_gain += split_gain;
9553                                        if sub8_seen >= sub8_learn {
9554                                            sub8_paying = sub8_gain
9555                                                >= sub8_seen as f64 * sub8_minpay as f64;
9556                                        }
9557                                    }
9558                                    if shape_rd {
9559                                        shape_cands.push((3u8, p8.clone(), subs));
9560                                    }
9561                                    if c8 < best_c {
9562                                        best_c = c8;
9563                                        pick = Some((3u8, p8));
9564                                        pick_subs = subs;
9565                                    }
9566                                }
9567                            }
9568                            // SHAPE RD RE-RANK (probe #3). The SATD search above
9569                            // has produced `pick`; ask the CODED macroblock to
9570                            // re-rank the shapes it actually considered. Each
9571                            // candidate is planned for real and scored
9572                            // J = SSD_recon + lambda*bits, state restored between
9573                            // trials. Candidates are collected as (mode, parts,
9574                            // subs) so the sub-8x8 winner competes on equal terms.
9575                            if shape_rd
9576                                && shape_cands.len() > 1
9577                                && !shape_rd_tex_veto
9578                            {
9579                                let mut snap0 = enc_scratch::take_snap_a();
9580                                fe.save_mb_into(mb_x, mb_y, &mut snap0);
9581                                let mut best_j = f64::INFINITY;
9582                                let mut best_i = 0usize;
9583                                for (i, (m, parts, subs)) in shape_cands.iter().enumerate() {
9584                                    let pl = fe.plan_inter_mb(
9585                                        refs, &sy, &su, &sv, mb_x, mb_y, *m, parts, None, *subs,
9586                                    );
9587                                    let j = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y) as f64
9588                                        + lam_mb * plan_rate_bits(&pl, *subs);
9589                                    if j < best_j {
9590                                        best_j = j;
9591                                        best_i = i;
9592                                    }
9593                                }
9594                                // E11 (11.16a): ONE restore after the loop — each
9595                                // candidate's plan fully overwrites the last (see the
9596                                // sub8-RD note); the intra trial below then starts
9597                                // from the same pre-trial state as before.
9598                                fe.load_mb(mb_x, mb_y, &snap0);
9599                                enc_scratch::put_snap_a(snap0);
9600                                let (m, parts, subs) = shape_cands[best_i].clone();
9601                                signals::census::bump(
9602                                    signals::census::SHAPE_RD_FLIP,
9603                                    pick.as_ref().map(|p| p.0) != Some(m),
9604                                );
9605                                pick = Some((m, parts));
9606                                pick_subs = subs;
9607                                // INTRA COMPETES IN THE SAME CURRENCY. Writing the
9608                                // RD J back into `best_c` and letting the SATD
9609                                // intra test below read it mixes two scales —
9610                                // an SSD+lambda*bits value dwarfs a SATD one, so
9611                                // intra won essentially every macroblock and the
9612                                // probe measured +17..+56% BD. Caught because a
9613                                // better cost function CANNOT lose 50%
9614                                // (codec-measurement §7: an impossible number is
9615                                // the instrument asking for help). One decision,
9616                                // one currency: score intra by RD here and skip
9617                                // the SATD comparison entirely.
9618                                let (ssd_i, bits_i) =
9619                                    fe.trial_intra(&sy, &su, &sv, mb_x, mb_y, true);
9620                                let j_intra = ssd_i as f64 + lam_mb * bits_i as f64;
9621                                shape_rd_intra = Some(j_intra < best_j);
9622                            }
9623                            // U5-struct: refine ONLY the winning shape (see the twin
9624                            // block in the CAVLC driver). This site is the CABAC path —
9625                            // which is now the DEFAULT, so omitting it here left sub-pel
9626                            // deferred but never refined on every default encode.
9627                            if fe.sp_defer.get() {
9628                                if let Some((mode, parts)) = pick.as_mut() {
9629                                    // P3.3: a sub-split winner's regions are its
9630                                    // SUB-partitions. Skipping the refine for them
9631                                    // instead would leave exactly those macroblocks
9632                                    // on INTEGER-pel motion while every other shape
9633                                    // got sub-pel — the same "deferring DELETES the
9634                                    // refinement" failure (+91..+145% BD) the
9635                                    // preset guard above exists to prevent. Inert
9636                                    // today (sp_defer is off unless set explicitly)
9637                                    // but a landmine under that knob.
9638                                    let split_regions: Vec<(usize, usize, usize, usize)> =
9639                                        if *mode == 3 && pick_subs != [0u8; 4] {
9640                                            (0..4)
9641                                                .flat_map(|p8: usize| {
9642                                                    let (bx, by) = ((p8 % 2) * 8, (p8 / 2) * 8);
9643                                                    sub_mb_partitions_p(pick_subs[p8])
9644                                                        .iter()
9645                                                        .map(move |&(sx, sy, sw, sh)| (bx + sx, by + sy, sw, sh))
9646                                                })
9647                                                .collect()
9648                                        } else {
9649                                            Vec::new()
9650                                        };
9651                                    let regions: &[(usize, usize, usize, usize)] = if !split_regions.is_empty() {
9652                                        &split_regions
9653                                    } else {
9654                                        match mode {
9655                                        1 => &[(0, 0, 16, 8), (0, 8, 16, 8)],
9656                                        2 => &[(0, 0, 8, 16), (8, 0, 8, 16)],
9657                                        3 => &[(0, 0, 8, 8), (8, 0, 8, 8), (0, 8, 8, 8), (8, 8, 8, 8)],
9658                                        _ => &[(0, 0, 16, 16)],
9659                                        }
9660                                    };
9661                                    // sub_mb_type bins, charged exactly as the search did.
9662                                    let mut tot = if *mode == 3 {
9663                                        if pick_subs == [0u8; 4] {
9664                                            (lme * 4.0) as i64
9665                                        } else {
9666                                            pick_subs.iter().map(|&st| {
9667                                                if st == 0 { lme as i64 }
9668                                                else { (lme * if st == 1 { 2.0 } else { 3.0 }) as i64 }
9669                                            }).sum()
9670                                        }
9671                                    } else { 0 };
9672                                    for (i, &(qx, qy, pw, ph)) in regions.iter().enumerate() {
9673                                        let (r, mv) = parts[i];
9674                                        let (m2, c2) = fe.refine_part(
9675                                            refs, &sy, &nb, num_refs, lx + qx, ly + qy, pw, ph, lme, r, mv,
9676                                        );
9677                                        parts[i] = (r, m2);
9678                                        tot += c2;
9679                                    }
9680                                    best_c = tot;
9681                                }
9682                            }
9683                            let c_intra = fe.best_i16_satd(&sy, mb_x, mb_y)
9684                                + (lme * fe.tune_intra_penalty) as i64;
9685                            let satd_says_intra = c_intra < best_c;
9686                            // GRAIN-GATED (4th consumer of `grain_signature`).
9687                            // Measured flip rates: grain 18.4%, screen 12.6%,
9688                            // foreman 1.1%, harbour 0.3%, akiyo 0.0% — the SATD
9689                            // proxy is essentially RIGHT on natural content and
9690                            // badly wrong on noise, so paying 1.71x CPU
9691                            // everywhere buys ~0 off grain. Gated: grain wins
9692                            // -4.73 PSNR / -5.22 SSIM, everything else is
9693                            // byte-identical. screen_text is deliberately NOT
9694                            // included: its metrics disagree (+0.53 PSNR /
9695                            // -1.48 SSIM), and a split verdict is not a win.
9696                            let use_rd = use_rd_frame;
9697                            let take_intra = if let Some(rd_says) = shape_rd_intra {
9698                                // The shape re-rank already priced intra against the
9699                                // winning shape in the RD currency — reuse it rather
9700                                // than paying a second trial or mixing scales.
9701                                rd_says
9702                            } else if use_rd {
9703                                // RD arm: plan BOTH candidates for real and compare
9704                                // J = SSD_recon + lambda*bits. `trial_intra` restores
9705                                // the macroblock, so the loser leaves no trace.
9706                                let (ssd_i, bits_i) = fe.trial_intra(&sy, &su, &sv, mb_x, mb_y, true);
9707                                let j_intra = ssd_i as f64 + lambda * bits_i as f64;
9708                                let j_inter = match pick.as_ref() {
9709                                    Some((m, parts)) => {
9710                                        let mut snap = enc_scratch::take_snap_a();
9711                                        fe.save_mb_into(mb_x, mb_y, &mut snap);
9712                                        let pl = fe.plan_inter_mb(
9713                                            refs, &sy, &su, &sv, mb_x, mb_y, *m, parts, None, pick_subs,
9714                                        );
9715                                        let j = fe.mb_ssd(&sy, &su, &sv, mb_x, mb_y) as f64
9716                                            + lambda * plan_rate_bits(&pl, pick_subs);
9717                                        fe.load_mb(mb_x, mb_y, &snap);
9718                                        enc_scratch::put_snap_a(snap);
9719                                        j
9720                                    }
9721                                    None => f64::INFINITY,
9722                                };
9723                                j_intra < j_inter
9724                            } else {
9725                                satd_says_intra
9726                            };
9727                            if use_rd {
9728                                signals::census::bump(
9729                                    signals::census::INTRA_RD_FLIP,
9730                                    take_intra != satd_says_intra,
9731                                );
9732                            }
9733                            inter = if take_intra { None } else { pick };
9734                            if matches!(inter, Some((3, _))) {
9735                                inter_subs = pick_subs; // P3.3: ride with the winner
9736                            }
9737                            fe.mb_was_skip[mb_idx] = false;
9738                            fe.mb_skip_sad[mb_idx] = skip_sad;
9739                        }
9740                    }
9741                }
9742                // ---- RD P_Skip, CABAC port (Great Gate P3 item 2 —
9743                // docs/gate-ledger.md rdskip-preset-gate) ------------------------
9744                // THRESHOLD form only: the CAVLC driver's trial-encode-and-splice
9745                // arm does not transfer to an arithmetic coder, but its fast gate
9746                // (`SSD(skip) ≤ T·λ` — take the null arm without pricing the coded
9747                // one) is exactly the λ-priced-distortion form the RD B_Skip gate
9748                // already proved under CABAC. Distortion is the skip's
9749                // RECONSTRUCTION SSD (a P_Skip's recon IS its prediction), never
9750                // SAD — the wrong-sign-proxy lesson. Gated on the ONLINE free-skip
9751                // census (engage where free skips are COMMON = temporally
9752                // redundant content, the CAVLC fit's separating signal; the same
9753                // `greedy_*` counters already track it here). `tune_rd_skip` off
9754                // (default) = byte-identical; `fast_t ≤ 0` is inert on this path
9755                // (no full-compare arm exists under CABAC — recorded limitation).
9756                if !did_skip
9757                    && fe.rd_skip
9758                    && fe.rd_skip_fast_t > 0.0
9759                    && inter.is_some()
9760                    && greedy_seen >= greedy_learn
9761                    && greedy_free * 100 >= greedy_seen * fe.rd_skip_min_free as usize
9762                {
9763                    // Fast preset only built the chroma prediction on the free
9764                    // path; the RD decision needs the real one.
9765                    let skip_cp = if fe.fast {
9766                        fe.skip_predict_chroma(refs, mb_x, mb_y, mv_skip)
9767                    } else {
9768                        skip_c.unwrap() // quality preset: always Some
9769                    };
9770                    let ssd_s = fe.pred_ssd(&sy, &su, &sv, mb_x, mb_y, &skip_y, &skip_cp);
9771                    if (ssd_s as f64) <= lambda * fe.rd_skip_fast_t {
9772                        fe.commit_skip(mb_x, mb_y, mv_skip, &skip_y, &skip_cp);
9773                        if !fe.fast {
9774                            fe.mb_was_skip[mb_idx] = true;
9775                            fe.mb_skip_sad[mb_idx] = skip_sad;
9776                        }
9777                        did_skip = true;
9778                    }
9779                }
9780            }
9781
9782            // ---- emit ----
9783            if did_skip {
9784                emit_p_skip_cabac(&mut cab, &mut cs, addr, top, left);
9785                mb_qpy[mb_idx] = fe.cur_qp;
9786                cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
9787                continue;
9788            }
9789            // mb_skip_flag = 0
9790            let sctx = 11
9791                + left.map_or(0, |a| (!cs.mb_skip[a]) as usize)
9792                + top.map_or(0, |a| (!cs.mb_skip[a]) as usize);
9793            let tskip = if acct { cab.pos() } else { 0 };
9794            cb_mb_skip(&mut cab, sctx, false);
9795            if acct {
9796                crate::bitacct::add(crate::bitacct::B::SkipFlag, cab.pos() - tskip);
9797            }
9798            cs.mb_skip[addr] = false;
9799            match inter {
9800                Some((mode, parts)) => {
9801                    let plan = fe.plan_inter_mb(refs, &sy, &su, &sv, mb_x, mb_y, mode, &parts, None, inter_subs);
9802                    // ② residue naming: the CABAC entropy EMIT was untapped on the
9803                    // (default) CABAC driver — the whole encoder-side arithmetic
9804                    // coder was landing in `mgmt/other`.
9805                    let _ge = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncEmit);
9806                    emit_mb_cabac_p_inter(&mut fe, &mut cab, &mut cs, mode, &plan, mb_x, mb_y, num_refs);
9807                    signals::census::commit_mb(plan.t8x8);
9808                }
9809                None => {
9810                    fe.intra_in_p = true;
9811                    let plan = plan_mb(&mut fe, mb_x, mb_y, &sy, &su, &sv);
9812                    let _ge = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EncEmit);
9813                    let t8 = plan.i8.is_some() && plan.use_i4;
9814                    emit_mb_cabac_p_intra(&mut fe, &mut cab, &mut cs, &plan, mb_x, mb_y);
9815                    signals::census::commit_mb(t8);
9816                }
9817            }
9818            mb_qpy[mb_idx] = fe.cur_qp;
9819            cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
9820        }
9821    }
9822    enc_scratch::put_cs(cs);
9823
9824    while !w.is_byte_aligned() {
9825        w.write_bit(true);
9826    }
9827    let payload = cab.into_bytes();
9828    w.write_aligned_bytes(&payload);
9829    enc_scratch::put_payload(payload);
9830
9831    // Deblock -> inter reference (same as encode_slice_data).
9832    let mut ref_id = enc_scratch::take_refid();
9833    ref_id.clear();
9834    ref_id.extend(fe.ref_idx_y.iter().map(|&r| if r >= 0 { r } else { i32::MIN }));
9835    let info = rusty_h264_common::deblock::BlockInfo {
9836        inter: &fe.inter_y,
9837        nnz: &fe.nnz_y,
9838        mv: &fe.mv_y,
9839        ref_id: &ref_id,
9840        mv1: &[],
9841        ref_id1: &[],
9842        w4: fe.mb_w * 4,
9843        t8x8: &[],
9844        poc0: &[],
9845        poc1: &[],
9846        bs: &[], kind: &[],
9847        };
9848    rusty_h264_common::deblock::filter_frame(
9849        &mut fe.rec_y, &mut fe.rec_u, &mut fe.rec_v, fe.mb_w, fe.mb_h, &mb_qpy, 0, 0, 0, &info,
9850    );
9851    enc_scratch::put_qpy(mb_qpy);
9852    enc_scratch::put_refid(ref_id);
9853    let w4 = fe.mb_w * 4;
9854    crate::RefFrame {
9855        y: fe.rec_y,
9856        u: fe.rec_u,
9857        v: fe.rec_v,
9858        poc: 0,
9859        frame_num: 0,
9860        mv: fe.mv_y,
9861        ref_idx: fe.ref_idx_y,
9862        mv1: Vec::new(),
9863        ref_idx1: Vec::new(),
9864        w4,
9865        // Filtered lazily on first sub-pel search use (see `RefFrame::hpel`).
9866        hpel: std::sync::OnceLock::new(),
9867    }
9868}
9869
9870// ============================================================================
9871// CABAC B-slice entropy coding — inverse of the decoder's decode_slice_data_cabac
9872// B-slice path. Scope: the modes the encoder's B decision produces — B_Skip,
9873// B_Direct_16x16 (0), B_L0/L1/Bi_16x16 (1/2/3) — no sub_mb_type, no intra-in-B.
9874// The new piece vs P is the dual-list (L0 + L1) mvd/ref neighbour cache.
9875// ============================================================================
9876
9877/// Per-MB slice terminate + bit-accountant tap — the block was a byte-for-byte
9878/// twin at SIX sites across the P and B CABAC drivers (E15 rounds 1-2).
9879#[inline]
9880fn cb_term_acct(cab: &mut CabacEncoder, last: bool, acct: bool) {
9881    let tt = if acct { cab.pos() } else { 0 };
9882    cab.encode_terminate(last);
9883    if acct {
9884        crate::bitacct::add(crate::bitacct::B::Terminate, cab.pos() - tt);
9885    }
9886}
9887
9888/// Fill one list's 30-entry mvd/ref neighbour cache from the per-MB export grids
9889/// (openh264 WelsFillCacheInterCabac). Shared by P (List-0) and B (both lists).
9890fn cb_fill_inter_cache(
9891    mb_ref: &[[i8; 16]],
9892    mb_mvd: &[[[i16; 2]; 16]],
9893    refc: &mut [i8; 30],
9894    mvdc: &mut [[i16; 2]; 30],
9895    top: Option<usize>,
9896    left: Option<usize>,
9897    addr: usize,
9898    mb_w: usize,
9899) {
9900    if let Some(l) = left {
9901        // Row-bind once: the outer runtime index carried a bounds check per
9902        // access (8 in the emitted body); one per array per side suffices.
9903        let (rr, rm) = (&mb_ref[l], &mb_mvd[l]);
9904        for (ci, bi) in [(6usize, 3usize), (12, 7), (18, 11), (24, 15)] {
9905            refc[ci] = rr[bi];
9906            mvdc[ci] = rm[bi];
9907        }
9908    }
9909    if let Some(t) = top {
9910        for (ci, bi) in [(1usize, 12usize), (2, 13), (3, 14), (4, 15)] {
9911            refc[ci] = mb_ref[t][bi];
9912            mvdc[ci] = mb_mvd[t][bi];
9913        }
9914    }
9915    let mb_x = addr % mb_w;
9916    let mb_y = addr / mb_w;
9917    if mb_x > 0 && mb_y > 0 {
9918        let a = addr - mb_w - 1;
9919        (refc[0], mvdc[0]) = (mb_ref[a][15], mb_mvd[a][15]);
9920    }
9921    if mb_y > 0 && mb_x + 1 < mb_w {
9922        let a = addr - mb_w + 1;
9923        (refc[5], mvdc[5]) = (mb_ref[a][12], mb_mvd[a][12]);
9924    }
9925}
9926
9927/// B-slice `mb_type` for the encoder's B modes (0 = B_Direct_16x16, 1 = B_L0_16x16,
9928/// 2 = B_L1_16x16, 3 = B_Bi_16x16) — inverse of `parse_mb_type_b_cabac` (ctx 27).
9929/// B `mb_type` (Table 7-14) for a two-partition macroblock. `p0`/`p1` are 1=L0,
9930/// 2=L1, 3=Bi; `mvmode` 1 = 16x8, 2 = 8x16 (the odd types).
9931pub fn b_part_mb_type(p0: u8, p1: u8, mvmode: u8) -> u32 {
9932    let base = match (p0, p1) {
9933        (1, 1) => 4,
9934        (2, 2) => 6,
9935        (1, 2) => 8,
9936        (2, 1) => 10,
9937        (1, 3) => 12,
9938        (2, 3) => 14,
9939        (3, 1) => 16,
9940        (3, 2) => 18,
9941        _ => 20, // (Bi, Bi)
9942    };
9943    base + if mvmode == 2 { 1 } else { 0 }
9944}
9945
9946/// The two partition rects `(x, y, w, h)` and their z-order block lists for a B
9947/// 16x8 / 8x16 macroblock — the same split the decoder's `b_inter_layout` uses.
9948fn b_part_layout(mvmode: u8) -> ([(usize, usize, usize, usize); 2], [(usize, &'static [usize]); 2]) {
9949    if mvmode == 1 {
9950        ([(0, 0, 16, 8), (0, 8, 16, 8)],
9951         [(0, &[0, 1, 2, 3, 4, 5, 6, 7][..]), (8, &[8, 9, 10, 11, 12, 13, 14, 15][..])])
9952    } else {
9953        ([(0, 0, 8, 16), (8, 0, 8, 16)],
9954         [(0, &[0, 1, 2, 3, 8, 9, 10, 11][..]), (4, &[4, 5, 6, 7, 12, 13, 14, 15][..])])
9955    }
9956}
9957
9958/// B `mb_type` CABAC — the exact inverse of the decoder's `parse_mb_type_b_cabac`
9959/// (ctx base 27). Accepts the FULL spec range 0..=22, not just the four 16x16
9960/// modes, so the B 16x8 / 8x16 / 8x8 partitions become emittable.
9961///
9962/// Binarization, derived from the decoder branch-for-branch:
9963/// ```text
9964///   prefix (non-direct):  B+ctx_inc = 1 ; B+3 = 1
9965///   4-bit m4:             B+4 = bit3 ; B+5 = bit2 ; B+5 = bit1 ; B+5 = bit0
9966///   type 3..10  -> m4 = type - 3        (m4 < 8 -> bit3 = 0)      4 bins
9967///   type 11     -> m4 = 14  (B_Bi_8x16)                           4 bins
9968///   type 22     -> m4 = 15  (B_8x8)                               4 bins
9969///   type 12..21 -> v = type + 4 ; m4 = v >> 1 ; B+5 = v & 1       5 bins
9970/// ```
9971/// The decoder returns `m + 3` for `m < 8`, escapes at 13 (intra) / 14 / 15, and
9972/// otherwise reads a 5th bin and returns `m - 4`; the mapping above reproduces
9973/// every one of those branches. For 0..=3 the value equals the old `dir`, so
9974/// existing call sites are unchanged.
9975pub fn cb_mb_type_b(cab: &mut CabacEncoder, ctx_inc: usize, mb_type: u32) {
9976    const B: usize = 27;
9977    if mb_type == 0 {
9978        cab.encode_decision(B + ctx_inc, 0); // B_Direct_16x16
9979        return;
9980    }
9981    cab.encode_decision(B + ctx_inc, 1);
9982    if mb_type <= 2 {
9983        cab.encode_decision(B + 3, 0);
9984        cab.encode_decision(B + 5, mb_type - 1); // 16x16 L0 / L1
9985        return;
9986    }
9987    cab.encode_decision(B + 3, 1);
9988    let (m4, extra) = if mb_type <= 10 {
9989        (mb_type - 3, None)
9990    } else if mb_type == 11 {
9991        (14, None) // B_Bi_8x16
9992    } else if mb_type == 22 {
9993        (15, None) // B_8x8
9994    } else {
9995        let v = mb_type + 4;
9996        (v >> 1, Some(v & 1))
9997    };
9998    cab.encode_decision(B + 4, (m4 >> 3) & 1);
9999    cab.encode_decision(B + 5, (m4 >> 2) & 1);
10000    cab.encode_decision(B + 5, (m4 >> 1) & 1);
10001    cab.encode_decision(B + 5, m4 & 1);
10002    if let Some(e) = extra {
10003        cab.encode_decision(B + 5, e);
10004    }
10005}
10006
10007const CB_ALL16: [usize; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
10008
10009/// Emit one planned INTER B macroblock (mb_skip_flag already coded 0). `dir` is the
10010/// B direction 0/1/2/3; `plan.mvds` holds mvd_l0 then mvd_l1 (per used list).
10011/// B-slice INTRA `mb_type` — the inverse of the decoder's `parse_mb_type_b`
10012/// `m == 13` escape + `parse_intra_mb_type_cabac(cab, 32)`. Prefix bins walk to
10013/// m4 = 0b1101 = 13, then the intra suffix at ctx base 32 (NOT the I-slice
10014/// layout: bin0 has no ctxInc, cbp/chroma/mode bins share base+1..base+3).
10015fn cb_mb_type_b_intra(cab: &mut CabacEncoder, ctx_inc: usize, plan: &MbPlan) {
10016    const B: usize = 27;
10017    cab.encode_decision(B + ctx_inc, 1); // not B_Direct_16x16
10018    cab.encode_decision(B + 3, 1); // not 16x16 L0/L1
10019    cab.encode_decision(B + 4, 1); // m = 1101 = 13 -> intra escape
10020    cab.encode_decision(B + 5, 1);
10021    cab.encode_decision(B + 5, 0);
10022    cab.encode_decision(B + 5, 1);
10023    const O: usize = 32; // intra suffix ctx base (Table 9-37 suffix)
10024    if plan.use_i4 {
10025        cab.encode_decision(O, 0); // I_NxN
10026        return;
10027    }
10028    cab.encode_decision(O, 1);
10029    cab.encode_terminate(false); // not I_PCM
10030    cab.encode_decision(O + 1, plan.i16_cbp15 as u32);
10031    if plan.cbp_chroma != 0 {
10032        cab.encode_decision(O + 2, 1);
10033        cab.encode_decision(O + 2, (plan.cbp_chroma == 2) as u32);
10034    } else {
10035        cab.encode_decision(O + 2, 0);
10036    }
10037    cab.encode_decision(O + 3, (plan.i16_mode as u32 >> 1) & 1);
10038    cab.encode_decision(O + 3, plan.i16_mode as u32 & 1);
10039}
10040
10041fn emit_mb_cabac_b(
10042    fe: &mut FrameEncoder,
10043    cab: &mut CabacEncoder,
10044    cs: &mut CabacState,
10045    dir: u8,
10046    bsplit: Option<(u8, [(u8, (i32, i32), (i32, i32)); 2])>,
10047    plan: &InterPlan,
10048    mb_x: usize,
10049    mb_y: usize,
10050) {
10051    let mb_w = fe.mb_w;
10052    let addr = mb_y * mb_w + mb_x;
10053    let top = if mb_y > 0 { Some(addr - mb_w) } else { None };
10054    let left = if mb_x > 0 { Some(addr - 1) } else { None };
10055
10056    let bci = left.map_or(0, |a| (!cs.mb_direct[a]) as usize)
10057        + top.map_or(0, |a| (!cs.mb_direct[a]) as usize);
10058    let bmt = match bsplit {
10059        Some((mvmode, parts2)) => b_part_mb_type(parts2[0].0, parts2[1].0, mvmode),
10060        None => dir as u32,
10061    };
10062    cb_mb_type_b(cab, bci, bmt);
10063
10064    // Dual-list mvd/ref caches (L0 = mb_ref/mb_mvd, L1 = mb_ref1/mb_mvd1).
10065    let mut mvdc0 = [[0i16; 2]; 30];
10066    let mut refc0 = [-1i8; 30];
10067    let mut mvdc1 = [[0i16; 2]; 30];
10068    let mut refc1 = [-1i8; 30];
10069    cb_fill_inter_cache(&cs.mb_ref, &cs.mb_mvd, &mut refc0, &mut mvdc0, top, left, addr, mb_w);
10070    cb_fill_inter_cache(&cs.mb_ref1, &cs.mb_mvd1, &mut refc1, &mut mvdc1, top, left, addr, mb_w);
10071    let mut mmvd0 = [[0i16; 2]; 16];
10072    let mut mref0 = [-1i8; 16];
10073    let mut mmvd1 = [[0i16; 2]; 16];
10074    let mut mref1 = [-1i8; 16];
10075    let (use0, use1) = (dir == 1 || dir == 3, dir == 2 || dir == 3);
10076    if let Some((mvmode, parts2)) = bsplit {
10077        // Two partitions: mvds arrive LIST-major from the plan (spec 7.3.5.1), and
10078        // `cb_emit_mvd_partition` needs each partition's z-order block list so a
10079        // later macroblock's mvd ctxInc sees the right neighbours. B here runs a
10080        // single L0 and single L1, so num_ref_idx_active is 1 and NO ref_idx is
10081        // coded — only the mvds.
10082        let (_, zb) = b_part_layout(mvmode);
10083        let mut k = 0;
10084        for list in 0..2 {
10085            for part in 0..2 {
10086                let pred = parts2[part].0;
10087                let used = if list == 0 { pred == 1 || pred == 3 } else { pred == 2 || pred == 3 };
10088                if !used {
10089                    continue;
10090                }
10091                let (pidx, blocks) = zb[part];
10092                if list == 0 {
10093                    cb_emit_mvd_partition(cab, pidx, blocks, &mut mvdc0, &mut refc0, &mut mmvd0, &mut mref0, plan.mvds[k], 0);
10094                } else {
10095                    cb_emit_mvd_partition(cab, pidx, blocks, &mut mvdc1, &mut refc1, &mut mmvd1, &mut mref1, plan.mvds[k], 0);
10096                }
10097                k += 1;
10098            }
10099        }
10100    } else if dir == 0 {
10101        // B_Direct_16x16: no coded motion; ref 0 in both lists (mvd stays 0) so a
10102        // later MB's mvd ctxInc sums |0|.
10103        mref0 = [0i8; 16];
10104        mref1 = [0i8; 16];
10105    } else {
10106        // mvd parse order: list-major (L0 then L1); a single 16x16 partition (idx 0).
10107        let mut k = 0;
10108        if use0 {
10109            cb_emit_mvd_partition(cab, 0, &CB_ALL16, &mut mvdc0, &mut refc0, &mut mmvd0, &mut mref0, plan.mvds[k], 0);
10110            k += 1;
10111        }
10112        if use1 {
10113            cb_emit_mvd_partition(cab, 0, &CB_ALL16, &mut mvdc1, &mut refc1, &mut mmvd1, &mut mref1, plan.mvds[k], 0);
10114        }
10115    }
10116    cs.mb_mvd[addr] = mmvd0;
10117    cs.mb_ref[addr] = mref0;
10118    cs.mb_mvd1[addr] = mmvd1;
10119    cs.mb_ref1[addr] = mref1;
10120    cs.mb_direct[addr] = dir == 0 && bsplit.is_none();
10121    cs.cat[addr] = 100;
10122    // The B rule (R6-5), mirroring the decoder's `allow8` and `plan_inter_mb`'s
10123    // `allow_t8`: direct_8x8_inference_flag = 1 in our SPS, so B_Direct_16x16
10124    // partitions count as 8×8 and every shape we emit may carry the flag
10125    // (`bsplit` only produces 16x8 / 8x16, both >= 8x8; no B_8x8 sub-types).
10126    let allow8 = true;
10127    cb_emit_inter_residual(fe, cab, cs, plan, mb_x, mb_y, addr, top, left, allow8);
10128}
10129
10130/// Emit a B_Skip macroblock's mb_skip_flag = 1 (ctx 24 base) + neighbour state. The
10131/// direct motion was committed by `commit_direct_motion`; ref 0 in both lists, mvd 0
10132/// (matching the decoder's decode_b_skip handling).
10133fn emit_b_skip_cabac(cab: &mut CabacEncoder, cs: &mut CabacState, addr: usize, top: Option<usize>, left: Option<usize>) {
10134    let sctx = 24
10135        + left.map_or(0, |a| (!cs.mb_skip[a]) as usize)
10136        + top.map_or(0, |a| (!cs.mb_skip[a]) as usize);
10137    let acct = crate::bitacct::enabled();
10138    let t0 = if acct { cab.pos() } else { 0 };
10139    cb_mb_skip(cab, sctx, true);
10140    if acct {
10141        crate::bitacct::add(crate::bitacct::B::SkipFlag, cab.pos() - t0);
10142    }
10143    cs.mb_skip[addr] = true;
10144    cs.cat[addr] = 100;
10145    cs.mb_direct[addr] = true;
10146    cs.mb_ref[addr] = [0i8; 16];
10147    cs.mb_ref1[addr] = [0i8; 16];
10148    cs.last_delta_qp = 0;
10149}
10150
10151/// CABAC B-slice data coder. Mirrors `encode_slice_data_b`'s B_Skip-free check +
10152/// L0/L1/Bi/Direct RD decision verbatim; only the emit differs (per-MB
10153/// mb_skip_flag + CABAC + per-MB terminate). B is non-reference → no deblock/return.
10154#[allow(clippy::too_many_arguments)]
10155/// B-slice mode census (env `RFF_BSTATS=1`), so our B_Skip / B_Direct / coded
10156/// split can be compared directly with x264's `mb B ... direct:N% skip:N%` line.
10157/// Counts only; no effect on the bitstream.
10158/// SEQUENCE-SCOPED sub-pel override, set once by `encode_all`.
10159///
10160/// REINSTATED after D5i. It was reverted on the finding that it "did not land", which
10161/// was WRONG: the acceptance test demanded byte-identity with `--preset fast`, and that
10162/// is unreachable because `Preset::Fast` ALSO sets `rd_skip_min_free` to 60 (mb16.rs
10163/// ~1777) which this flag cannot touch. The veto only ever controlled sub-pel, so it
10164/// must be judged against the same preset with sub-pel off -- which is what it does.
10165pub struct SeqFastPath;
10166static SEQ_FAST: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
10167impl SeqFastPath {
10168    pub(crate) fn set(on: bool) -> Self {
10169        SEQ_FAST.store(on, std::sync::atomic::Ordering::Relaxed);
10170        SeqFastPath
10171    }
10172    pub(crate) fn get() -> bool {
10173        SEQ_FAST.load(std::sync::atomic::Ordering::Relaxed)
10174    }
10175}
10176impl Drop for SeqFastPath {
10177    fn drop(&mut self) {
10178        SEQ_FAST.store(false, std::sync::atomic::Ordering::Relaxed);
10179    }
10180}
10181
10182pub mod bstats {
10183    use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
10184    pub static SKIP: AtomicU64 = AtomicU64::new(0);
10185    pub static CODED: AtomicU64 = AtomicU64::new(0);
10186    /// Of the NOT-free macroblocks, how often direct still won the mode decision.
10187    /// B_Skip rides direct-mode motion, so this is the physical quality of the
10188    /// thing the skip is betting on -- the candidate dispatch signal for how hard
10189    /// to push the skip.
10190    pub static DIRWIN: AtomicU64 = AtomicU64::new(0);
10191    /// Of the NOT-free macroblocks, how often a 16×8 / 8×16 partition beat every
10192    /// 16×16 mode. x264 puts 13.5% of its B macroblocks here; this is the column
10193    /// that makes ours comparable.
10194    pub static SPLIT: AtomicU64 = AtomicU64::new(0);
10195    /// Of the NOT-free macroblocks, how often intra beat every inter candidate
10196    /// (the m4 == 13 escape) — scene cuts / occlusion inside a GOP.
10197    pub static INTRA: AtomicU64 = AtomicU64::new(0);
10198    pub fn on() -> bool {
10199        static E: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
10200        *E.get_or_init(|| std::env::var_os("RFF_BSTATS").is_some())
10201    }
10202    pub fn bump(c: &AtomicU64) {
10203        if on() {
10204            c.fetch_add(1, Relaxed);
10205        }
10206    }
10207    /// NOTE: this splits B_Skip from everything-else only. It does NOT separate
10208    /// B_Direct_16x16 (chosen inside the coded path) from genuinely coded modes, so
10209    /// it is comparable to x264's `skip:` column but NOT to its `direct:` column.
10210    pub fn dump() {
10211        let (s, c) = (SKIP.load(Relaxed), CODED.load(Relaxed));
10212        let t = (s + c).max(1) as f64;
10213        eprintln!(
10214            "B-slice census: B_Skip {:.1}%  not-skipped {:.1}%  direct-wins-of-coded {:.1}%  16x8/8x16-of-coded {:.1}%  intra-of-coded {:.1}%   (n={})",
10215            s as f64 * 100.0 / t, c as f64 * 100.0 / t,
10216            DIRWIN.load(Relaxed) as f64 * 100.0 / c.max(1) as f64,
10217            SPLIT.load(Relaxed) as f64 * 100.0 / c.max(1) as f64,
10218            INTRA.load(Relaxed) as f64 * 100.0 / c.max(1) as f64, s + c
10219        );
10220    }
10221}
10222
10223pub(crate) fn encode_slice_data_cabac_b(
10224    w: &mut BitWriter,
10225    cfg: &EncoderConfig,
10226    frame: &YuvFrame,
10227    qp: u8,
10228    poc: i32,
10229    l0: &crate::RefFrame,
10230    l1: &crate::RefFrame,
10231    qpo: &[i32],
10232    // b-pyramid: a REFERENCE B must produce a deblocked reconstruction for
10233    // the DPB, exactly like a P anchor; a leaf B returns `None` and skips the
10234    // filter (the decoder deblocks for display).
10235    is_ref: bool,
10236) -> Option<crate::RefFrame> {
10237    let mut fe = FrameEncoder::new(cfg);
10238    fe.qp = qp;
10239    fe.qpc = chroma_qp(qp);
10240    fe.cur_qp = qp;
10241    // Recycled per-thread scratch (the P/I coders already pool this exact
10242    // buffer); `clear` + `resize` reproduces the fresh `vec![qp; n]` contents.
10243    let mut mb_qpy = enc_scratch::take_qpy();
10244    mb_qpy.clear();
10245    mb_qpy.resize(cfg.mb_width() * cfg.mb_height(), qp);
10246    if cfg.cabac_dz_div > 0 {
10247        fe.idz = cfg.cabac_dz_div; // CABAC-specific dead-zone override
10248    }
10249    // Inter trellis (opt-in, Great Gate P2): B is NON-REFERENCE — the clean
10250    // arm per the structure-adaptive law. 0 = off, byte-identical.
10251    fe.rdoq_strength = cfg.cabac_rdoq_b;
10252    fe.bi_w = implicit_bi_weights(poc, l0.poc, l1.poc);
10253    let (sy, su, sv) = coded_source(cfg, frame);
10254    // Great Gate P1: the shared per-frame signal vector (List-0 anchor as ref).
10255    let sig = FrameSignals::new(&sy, fe.cw, fe.mb_w, fe.mb_h, Some(&l0.y[..]));
10256    apply_screen_t8_veto(&mut fe, &sig);
10257    let lambda = 0.85 * fe.tune_lambda_scale * crate::fastmath::lambda_qp(qp);
10258    // B path keeps the frame-median tex veto even under `tune_lme_q` (its `lme` is
10259    // hoisted, not per-MB) — recorded limitation until the knob clears its BD gate.
10260    let lme_scale = me_lambda_scale(cfg, &sig, false);
10261    let lme = lambda.sqrt() * lme_scale;
10262    let refs = std::slice::from_ref(l0);
10263    if fe.satd_q > 0.0 {
10264        fe.satd_var_thresh = sig.var_percentile_thresh(fe.satd_q);
10265    }
10266    let mut aq_qp = aq_qp_map(&sig, qp, fe.aq_strength);
10267    apply_mbtree_qpo(&mut aq_qp, qpo); // mb-tree temporal AQ (empty = byte-identical)
10268    signals::harvest(
10269        &sig,
10270        'B',
10271        qp,
10272        &signals::GateDecisions {
10273            lme_scale,
10274            satd_thresh: fe.satd_var_thresh,
10275            ..Default::default()
10276        },
10277    );
10278
10279    let mut cab =
10280        CabacEncoder::new_with_out(qp as i32, cfg.cabac_init_idc, false, enc_scratch::take_payload());
10281    let mut cs = CabacState::pooled(fe.mb_w * fe.mb_h);
10282    let total = fe.mb_w * fe.mb_h;
10283    // E15 round 2: slice-constant accountant knob, was re-read up to 10x per MB.
10284    let acct = crate::bitacct::enabled();
10285    // RD B_Skip knobs + the online free-skip census that dispatches it.
10286    let bskip_t = std::env::var("RFF_BSKIP_T").ok().and_then(|v| v.parse::<f64>().ok())
10287        .or(cfg.tune_bskip_rd)
10288        .unwrap_or(0.0);
10289    let bskip_busy_pct = std::env::var("RFF_BSKIP_BUSY").ok().and_then(|v| v.parse::<usize>().ok())
10290        .or(cfg.tune_bskip_busy_pct)
10291        .unwrap_or(60);
10292    let (mut b_seen, mut b_free) = (0usize, 0usize);
10293    // B 16x8/8x16 partition search. Opt-in until the 4-QP per-clip table clears.
10294    let bsplit_env = std::env::var("RFF_BSPLIT").ok().and_then(|v| v.parse::<u32>().ok());
10295    let bsplit_on = bsplit_env.map(|v| v == 1).unwrap_or(cfg.tune_b_split);
10296    let bsplit_probe = bsplit_env.filter(|&v| v >= 2).unwrap_or(0);
10297    // Online DIRECT-WIN rate: of the macroblocks that were not exactly-free, how
10298    // often direct still won the mode decision. B_Skip rides direct-mode motion,
10299    // so this measures the quality of the thing the skip bets on.
10300    let (mut b_coded, mut b_dirwin) = (0usize, 0usize);
10301    let bskip_dirwin_pct = std::env::var("RFF_BSKIP_DIRWIN").ok().and_then(|v| v.parse::<usize>().ok())
10302        .or(cfg.tune_bskip_dirwin_pct)
10303        .unwrap_or(10);
10304
10305    for mb_y in 0..fe.mb_h {
10306        for mb_x in 0..fe.mb_w {
10307            let mb_idx = mb_y * fe.mb_w + mb_x;
10308            let addr = mb_idx;
10309            let top = if mb_y > 0 { Some(addr - fe.mb_w) } else { None };
10310            let left = if mb_x > 0 { Some(addr - 1) } else { None };
10311            let mb_qp = aq_qp[mb_idx];
10312            fe.qp = mb_qp;
10313            fe.qpc = chroma_qp(mb_qp);
10314            let (lx, ly) = (mb_x * 16, mb_y * 16);
10315            let (pbx, pby) = (mb_x as isize * 4, mb_y as isize * 4);
10316            // Dedup (E15 W9): memoized twin, already built when satd_q > 0.
10317            fe.mb_use_satd =
10318                fe.satd_q > 0.0 && sig.mb_vars()[mb_y * fe.mb_w + mb_x] >= fe.satd_var_thresh;
10319            let n0 = fe.mv_neighbors_block_list(pbx, pby, 4, 0);
10320            let n1 = fe.mv_neighbors_block_list(pbx, pby, 4, 1);
10321            let pmv0 = predict_partition_mv(0, 0, n0[0], n0[1], n0[2], 0);
10322            let pmv1 = predict_partition_mv(0, 0, n1[0], n1[1], n1[2], 0);
10323            let (dp, dc, dmotion) = fe.b_direct(l0, l1, mb_x, mb_y);
10324            // B_Skip: free direct prediction → mb_skip_flag = 1.
10325            let free_skip = fe.skip_luma_is_free(&sy, mb_x, mb_y, &dp)
10326                && fe.skip_chroma_is_free(&su, &sv, mb_x, mb_y, &dc);
10327            b_seen += 1;
10328            if free_skip {
10329                b_free += 1;
10330            }
10331            if free_skip {
10332                bstats::bump(&bstats::SKIP);
10333                fe.commit_direct_motion(mb_x, mb_y, &dmotion);
10334                fe.commit_pred_pixels(mb_x, mb_y, &dp, &dc);
10335                emit_b_skip_cabac(&mut cab, &mut cs, addr, top, left);
10336                mb_qpy[mb_idx] = fe.cur_qp;
10337                cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
10338                continue;
10339            }
10340            bstats::bump(&bstats::CODED);
10341            let d_direct = fe.pred_dist(&sy, lx, ly, &dp);
10342            let (mv0, j0) = fe.motion_search(l0, &sy, lx, ly, 16, 16, &[pmv0], lme, None);
10343            let (mv1, j1) = fe.motion_search(l1, &sy, lx, ly, 16, 16, &[pmv1], lme, None);
10344            let d_bi = fe.bi_dist(l0, l1, &sy, lx, ly, mv0, mv1);
10345            let r_bi = mvd_bits(mv0.0 - pmv0.0) + mvd_bits(mv0.1 - pmv0.1)
10346                + mvd_bits(mv1.0 - pmv1.0) + mvd_bits(mv1.1 - pmv1.1);
10347            let j_bi = d_bi + (lme * r_bi as f64) as i64;
10348            let (mut dir, mut best) = (0u8, d_direct);
10349            if j0 < best { dir = 1; best = j0; }
10350            if j1 < best { dir = 2; best = j1; }
10351            if j_bi < best { dir = 3; best = j_bi; }
10352            if dir == 0 { bstats::bump(&bstats::DIRWIN); }
10353            b_coded += 1;
10354            if dir == 0 {
10355                b_dirwin += 1;
10356            }
10357            // ---- RD B_Skip (env RFF_BSKIP_T; unset = byte-identical) ----------
10358            // Our B_Skip previously required the direct residual to quantize to
10359            // EXACTLY zero. Measured against x264 at qp27: that reaches 93.5% of B
10360            // macroblocks on akiyo and 34.5% on foreman -- at or ABOVE x264 -- but
10361            // collapses to 7.8% on mobile where x264 still finds 27.4%. The deficit
10362            // is BUSY-CONTENT-ONLY, a sign flip, so this is a DISPATCH, not a new
10363            // constant: engage only where the free-skip rate is low.
10364            //
10365            // Two terms, both required:
10366            //   * `dir == 0` -- direct actually WON the mode decision. `best` starts
10367            //     at `d_direct` and only falls, so without this the test would fire
10368            //     on macroblocks the search proved are better coded.
10369            //   * distortion under T*lambda -- the residual is not worth its bits.
10370            // Gated on the ONLINE free-skip rate of this frame so far (the same
10371            // signal shape the P path's rd_skip uses, inverted: engage where free
10372            // skips are RARE, which is exactly where we under-skip).
10373            if bskip_t > 0.0
10374                && dir == 0
10375                && b_seen >= 32
10376                && b_free * 100 < b_seen * bskip_busy_pct
10377                // DIRECT-WIN FLOOR. Measured truth table at T=48 (BD-PSNR):
10378                //   football 7.0% direct-win  -> +0.08  LOSS   <- the only loser
10379                //   foreman 14.1%             -> -0.17  win
10380                //   bus     21.4%             -> -0.05  win
10381                //   akiyo   24.7%             -> inert
10382                //   tempete 30.9%             -> -0.16  win
10383                //   mobile  43.1%             -> -0.38  win
10384                // The one regressing clip has by far the lowest direct-win rate, and
10385                // the term is justified by exactly that clip: where direct almost
10386                // never wins the mode decision, its prediction is unreliable and
10387                // skipping on it costs more than the bits it saves.
10388                && b_coded >= 32
10389                && b_dirwin * 100 >= b_coded * bskip_dirwin_pct
10390                && (d_direct as f64) <= bskip_t * lambda
10391            {
10392                bstats::bump(&bstats::SKIP);
10393                fe.commit_direct_motion(mb_x, mb_y, &dmotion);
10394                fe.commit_pred_pixels(mb_x, mb_y, &dp, &dc);
10395                emit_b_skip_cabac(&mut cab, &mut cs, addr, top, left);
10396                mb_qpy[mb_idx] = fe.cur_qp;
10397                cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
10398                continue;
10399            }
10400            // mb_skip_flag = 0, then the coded B MB.
10401            let sctx = 24
10402                + left.map_or(0, |a| (!cs.mb_skip[a]) as usize)
10403                + top.map_or(0, |a| (!cs.mb_skip[a]) as usize);
10404            let tskip = if acct { cab.pos() } else { 0 };
10405            cb_mb_skip(&mut cab, sctx, false);
10406            if acct {
10407                crate::bitacct::add(crate::bitacct::B::SkipFlag, cab.pos() - tskip);
10408            }
10409            cs.mb_skip[addr] = false;
10410            // ---- intra-in-B (the m4 == 13 escape) ------------------------------
10411            // Same SATD heuristic as the P path: a B macroblock the inter search
10412            // cannot predict (scene cut inside the GOP, occlusion) is coded intra
10413            // instead of as a bad inter guess. Compared against the 16x16-level
10414            // winner with the same signalling penalty the P decision charges.
10415            let c_intra = fe.best_i16_satd(&sy, mb_x, mb_y)
10416                + (lme * fe.tune_intra_penalty) as i64;
10417            if c_intra < best {
10418                bstats::bump(&bstats::INTRA);
10419                fe.intra_in_p = true;
10420                let plan = plan_mb(&mut fe, mb_x, mb_y, &sy, &su, &sv);
10421                let bci = left.map_or(0, |a| (!cs.mb_direct[a]) as usize)
10422                    + top.map_or(0, |a| (!cs.mb_direct[a]) as usize);
10423                cb_mb_type_b_intra(&mut cab, bci, &plan);
10424                emit_intra_body_cabac(&mut fe, &mut cab, &mut cs, &plan, mb_x, mb_y, addr, top, left);
10425                mb_qpy[mb_idx] = fe.cur_qp;
10426                cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
10427                continue;
10428            }
10429            // ---- B 16x8 / 8x16 partition search --------------------------------
10430            // x264 puts 13.5% of its B macroblocks here (`B16..8: 31.1 13.5 8.2`);
10431            // we had none, which is why the B bucket kept reading as a CODING gap
10432            // after every constant in it had been swept flat. Each half runs the
10433            // SAME 16x16 motion search that already exists, then the 9 (p0,p1)
10434            // pairings are priced against the 16x16 winner.
10435            let mut bsplit: Option<(u8, [(u8, (i32, i32), (i32, i32)); 2])> = None;
10436            // ORACLE PROBE (RFF_BSPLIT=2/3): force a 16x8 (2) or 8x16 (3) whose two
10437            // halves carry the SAME pred and the SAME motion as the 16x16 winner.
10438            // That is semantically identical to the 16x16 macroblock, so the
10439            // reconstruction MUST match it bit for bit -- any quality loss under this
10440            // probe is emit/predict PLUMBING drift and nothing to do with the mode
10441            // decision. (Separating those two is otherwise guesswork: both present as
10442            // "quality fell at the same rate".)
10443            if bsplit_probe > 0 && dir != 0 {
10444                let m = if bsplit_probe == 2 { 1u8 } else { 2u8 };
10445                bsplit = Some((m, [(dir, mv0, mv1); 2]));
10446            } else if bsplit_on {
10447                for mvmode in 1u8..=2 {
10448                    let (rects, _) = b_part_layout(mvmode);
10449                    let mut cand = [(0u8, (0i32, 0i32), (0i32, 0i32)); 2];
10450                    let mut jsum = 0i64;
10451                    for (part, &(rx, ry, rw, rh)) in rects.iter().enumerate() {
10452                        let (px, py) = (lx + rx, ly + ry);
10453                        let (m0, c0) = fe.motion_search(l0, &sy, px, py, rw, rh, &[pmv0], lme, None);
10454                        let (m1, c1) = fe.motion_search(l1, &sy, px, py, rw, rh, &[pmv1], lme, None);
10455                        // Bi for this rect: blend distortion + both mvd rates.
10456                        let dbi = fe.bi_dist_rect(l0, l1, &sy, px, py, rw, rh, m0, m1);
10457                        let rbi = mvd_bits(m0.0 - pmv0.0) + mvd_bits(m0.1 - pmv0.1)
10458                            + mvd_bits(m1.0 - pmv1.0) + mvd_bits(m1.1 - pmv1.1);
10459                        let jbi = dbi + (lme * rbi as f64) as i64;
10460                        let (mut bp, mut bj) = (1u8, c0);
10461                        if c1 < bj { bp = 2; bj = c1; }
10462                        if jbi < bj { bp = 3; bj = jbi; }
10463                        cand[part] = (bp, m0, m1);
10464                        jsum += bj;
10465                    }
10466                    // ~4 extra bins for the longer mb_type binarization.
10467                    let jsplit = jsum + (lme * 4.0) as i64;
10468                    if jsplit < best {
10469                        best = jsplit;
10470                        bsplit = Some((mvmode, cand));
10471                    }
10472                }
10473                if bsplit.is_some() {
10474                    bstats::bump(&bstats::SPLIT);
10475                }
10476            }
10477            let bspec = if let Some((mvmode, parts2)) = bsplit {
10478                BInter { dir, l1, mv0, mv1, mvmode, parts2 }
10479            } else {
10480                BInter { dir, l1, mv0, mv1, mvmode: 0, parts2: [(0, (0, 0), (0, 0)); 2] }
10481            };
10482            let plan = fe.plan_inter_mb(refs, &sy, &su, &sv, mb_x, mb_y, 0, &[], Some(bspec), [0u8; 4]);
10483            emit_mb_cabac_b(&mut fe, &mut cab, &mut cs, dir, bsplit, &plan, mb_x, mb_y);
10484            mb_qpy[mb_idx] = fe.cur_qp;
10485            cb_term_acct(&mut cab, mb_idx + 1 == total, acct);
10486        }
10487    }
10488    enc_scratch::put_cs(cs);
10489
10490    while !w.is_byte_aligned() {
10491        w.write_bit(true);
10492    }
10493    let payload = cab.into_bytes();
10494    w.write_aligned_bytes(&payload);
10495    enc_scratch::put_payload(payload);
10496    if !is_ref {
10497        // Leaf B: non-reference — no deblock, no RefFrame (the decoder
10498        // deblocks for display).
10499        enc_scratch::put_qpy(mb_qpy);
10500        return None;
10501    }
10502    // REFERENCE B (b-pyramid): deblock and package the recon exactly like a P
10503    // anchor, but with BOTH lists' motion in the boundary-strength derivation
10504    // (raw per-block indices + single-entry index→POC maps — the two-list bS
10505    // rule compares PICTURES, and an index alone cannot cross lists).
10506    let mut ref_id = enc_scratch::take_refid();
10507    ref_id.clear();
10508    ref_id.extend(fe.ref_idx_y.iter().map(|&r| if r >= 0 { r } else { i32::MIN }));
10509    // List-1 grid from the recycled slot — was a fresh Vec per ref-B slice.
10510    let mut ref_id1 = enc_scratch::take_refid1();
10511    ref_id1.clear();
10512    ref_id1.extend(fe.ref_idx1_y.iter().map(|&r| if r >= 0 { r } else { i32::MIN }));
10513    let poc0 = [l0.poc];
10514    let poc1 = [l1.poc];
10515    let info = rusty_h264_common::deblock::BlockInfo {
10516        inter: &fe.inter_y,
10517        nnz: &fe.nnz_y,
10518        mv: &fe.mv_y,
10519        ref_id: &ref_id,
10520        mv1: &fe.mv1_y,
10521        ref_id1: &ref_id1,
10522        w4: fe.mb_w * 4,
10523        t8x8: &[],
10524        poc0: &poc0,
10525        poc1: &poc1,
10526        bs: &[],
10527        kind: &[],
10528    };
10529    rusty_h264_common::deblock::filter_frame(
10530        &mut fe.rec_y, &mut fe.rec_u, &mut fe.rec_v, fe.mb_w, fe.mb_h, &mb_qpy, 0, 0, 0, &info,
10531    );
10532    enc_scratch::put_refid(ref_id);
10533    enc_scratch::put_refid1(ref_id1);
10534    enc_scratch::put_qpy(mb_qpy);
10535    let w4 = fe.mb_w * 4;
10536    Some(crate::RefFrame {
10537        y: fe.rec_y,
10538        u: fe.rec_u,
10539        v: fe.rec_v,
10540        poc: 0,
10541        frame_num: 0,
10542        mv: fe.mv_y,
10543        ref_idx: fe.ref_idx_y,
10544        mv1: fe.mv1_y,
10545        ref_idx1: fe.ref_idx1_y,
10546        w4,
10547        hpel: std::sync::OnceLock::new(),
10548    })
10549}
10550
10551/// Minimal all-B_Skip CABAC B-slice (the rare no-bracketing-anchor fallback in
10552/// `code_picture`): every MB is mb_skip_flag = 1. B is non-reference so the recon
10553/// is irrelevant; this only needs to be a legal CABAC slice.
10554pub fn encode_all_skip_b_cabac(w: &mut BitWriter, cfg: &EncoderConfig, qp: u8, n: usize) {
10555    let mut cab =
10556        CabacEncoder::new_with_out(qp as i32, cfg.cabac_init_idc, false, enc_scratch::take_payload());
10557    for i in 0..n {
10558        // ctxInc = 24 + (left avail & not-skip) + (top avail & not-skip). Every
10559        // neighbour is either a skip (contributes 0) or unavailable (0) → always 24.
10560        cab.encode_decision(24, 1);
10561        cab.encode_terminate(i + 1 == n);
10562    }
10563    while !w.is_byte_aligned() {
10564        w.write_bit(true);
10565    }
10566    let payload = cab.into_bytes();
10567    w.write_aligned_bytes(&payload);
10568    enc_scratch::put_payload(payload);
10569}