Browse / github.com/storytold/filmcraft / patch
vp9: token loop monomorphised on counting, cheaper sign read
vp9: token loop monomorphised on counting, cheaper sign read Part of #3290 (P4 only; P2 is #3295, P5 is not done) ## What Token loop micro-work in `tile/recon.rs` and `boolcoder.rs`: - `tokens` dispatches to `tokens_impl::<COUNTING>`, so the non-counting path has no per-symbol branch. - The `more_coefs` / `token` count tables are indexed by `[tx][ptype][rtype]` once per call, not per symbol. - `sc`, `nb` and `bands` are re-sliced to `seg_eob`, so the loop has no bounds checks on them. - The sign bit uses `BoolDecoder::read_bool_half`: `read_bool(128)` with `split = (range + 1) >> 1`, which equals `1 + (((range - 1) * 128) >> 8)`. ## Proof of identica
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- vangel76 (imported from pull request #3296, open)
- Base
a504f3c5adc4cd60d9c1120916cddb50c9b24b86- Size
- +49 −10 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
adf795671574327342ed011c
How it went
No other operator has reported using it yet.
Diff
raw · crates/vp9/src/boolcoder.rs crates/vp9/src/tile/recon.rs
@@ -75,6 +75,26 @@ impl<'a> BoolDecoder<'a> { bit } + /// `read_bool(128)`: the split is `1 + ((range - 1) >> 1) == (range + 1) >> 1`.+ #[inline(always)]+ pub fn read_bool_half(&mut self) -> bool {+ if self.count < 8 {+ self.fill();+ }+ let split = (self.range + 1) >> 1;+ let bigsplit = (split as u64) << 56;+ let bit = self.value >= bigsplit;+ let m = (bit as u64).wrapping_neg();+ self.value -= bigsplit & m;+ let m32 = m as u32;+ self.range = ((self.range - split) & m32) | (split & !m32);+ let shift = self.range.leading_zeros() - 24;+ self.range <<= shift;+ self.value <<= shift;+ self.count -= shift as i32;+ bit+ }+ /// read_literal (9.2.4). pub fn read_literal(&mut self, n: u32) -> u32 { let mut x = 0;@@ -127,10 +127,29 @@ impl<'a> TileDecoder<'a> { /// of block position and the number of leading coefficient rows that may be non-zero. #[allow(clippy::too_many_arguments)] fn tokens(&mut self, bd: &mut BoolDecoder, b: &Blk, plane: usize, start_x: usize, start_y: usize, tx_sz: u8, tx_type: u8) -> (usize, usize) {+ if self.s.counting {+ self.tokens_impl::<true>(bd, b, plane, start_x, start_y, tx_sz, tx_type)+ } else {+ self.tokens_impl::<false>(bd, b, plane, start_x, start_y, tx_sz, tx_type)+ }+ }++ #[allow(clippy::too_many_arguments)]+ fn tokens_impl<const COUNTING: bool>(+ &mut self,+ bd: &mut BoolDecoder,+ b: &Blk,+ plane: usize,+ start_x: usize,+ start_y: usize,+ tx_sz: u8,+ tx_type: u8,+ ) -> (usize, usize) { let seg_eob = 16usize << (tx_sz << 1); let sc = scan(tx_sz, tx_type); let nb = neighbors(tx_sz, tx_type); let bands: &[u8] = if tx_sz == 0 { &COEFBAND_4X4 } else { &COEFBAND_8X8PLUS };+ let (sc, nb, bands) = (&sc[..seg_eob], &nb[..seg_eob], &bands[..seg_eob]); let ptype = (plane > 0) as usize; let rtype = b.is_inter as usize; let probs = &self.fc.coef[tx_sz as usize][ptype][rtype];@@ -153,7 +172,6 @@ impl<'a> TileDecoder<'a> { let q = self.s.seg_q[b.seg_id as usize][ptype]; let dq_shift = (tx_sz == TX_32X32) as u32; let pareto = pareto_full();- let counting = self.s.counting; let log2n = 2 + tx_sz as usize; let bit_depth = self.bit_depth; let mut max_row = 0usize;@@ -162,6 +180,7 @@ impl<'a> TileDecoder<'a> { let tc = &mut self.token_cache; let coefs = &mut self.coefs; let counts = &mut self.strip.counts;+ let (more_counts, token_counts) = (&mut counts.more_coefs[tx_sz as usize][ptype][rtype], &mut counts.token[tx_sz as usize][ptype][rtype]); while c < seg_eob { let pos = sc[c] as usize; let band = bands[c] as usize;@@ -174,8 +193,8 @@ impl<'a> TileDecoder<'a> { let p = &probs[band][ctx]; if check_eob { let more = bd.read_bool(p[0]);- if counting {- counts.more_coefs[tx_sz as usize][ptype][rtype][band][ctx][more as usize] += 1;+ if COUNTING {+ more_counts[band][ctx][more as usize] += 1; } if !more { break;@@ -183,8 +202,8 @@ impl<'a> TileDecoder<'a> { } if !bd.read_bool(p[1]) { tc[pos] = 0;- if counting {- counts.token[tx_sz as usize][ptype][rtype][band][ctx][0] += 1;+ if COUNTING {+ token_counts[band][ctx][0] += 1; } check_eob = false; c += 1;@@ -194,14 +213,14 @@ impl<'a> TileDecoder<'a> { let token: usize; let coef: i64; if !bd.read_bool(p[2]) {- if counting {- counts.token[tx_sz as usize][ptype][rtype][band][ctx][1] += 1;+ if COUNTING {+ token_counts[band][ctx][1] += 1; } token = 1; coef = 1; } else {- if counting {- counts.token[tx_sz as usize][ptype][rtype][band][ctx][2] += 1;+ if COUNTING {+ token_counts[band][ctx][2] += 1; } let pp = &pareto[p[2].max(1) as usize - 1]; token = if !bd.read_bool(pp[0]) {@@ -240,7 +259,7 @@ impl<'a> TileDecoder<'a> { coef = v; } tc[pos] = ENERGY_CLASS[token];- let sign = bd.read_bool(128);+ let sign = bd.read_bool_half(); let qv = if pos == 0 { q[0] } else { q[1] } as i64; let d = ((coef * qv) >> dq_shift) as i32; coefs[pos] = if sign { d.wrapping_neg() } else { d };