1#![allow(non_camel_case_types)]
11#![allow(dead_code)]
12
13use self::BlockSize::*;
14use self::TxSize::*;
15use crate::context::*;
16use crate::frame::*;
17use crate::predict::*;
18use crate::recon_intra::*;
19use crate::serialize::{Deserialize, Serialize};
20use crate::tiling::*;
21use crate::transform::TxSize;
22use crate::util::*;
23use thiserror::Error;
24
25use std::mem::transmute;
26use std::mem::MaybeUninit;
27
28#[derive(PartialEq, Eq, PartialOrd, Copy, Clone, Debug)]
30pub enum RefType {
31 INTRA_FRAME = 0,
32 LAST_FRAME = 1,
33 LAST2_FRAME = 2,
34 LAST3_FRAME = 3,
35 GOLDEN_FRAME = 4,
36 BWDREF_FRAME = 5,
37 ALTREF2_FRAME = 6,
38 ALTREF_FRAME = 7,
39 NONE_FRAME = 8,
40}
41
42impl RefType {
43 #[inline]
49 pub fn to_index(self) -> usize {
50 match self {
51 NONE_FRAME => {
52 panic!("Tried to get slot of NONE_FRAME");
53 }
54 INTRA_FRAME => {
55 panic!("Tried to get slot of INTRA_FRAME");
56 }
57 _ => (self as usize) - 1,
58 }
59 }
60 #[inline]
61 pub const fn is_fwd_ref(self) -> bool {
62 (self as usize) < 5
63 }
64 #[inline]
65 pub const fn is_bwd_ref(self) -> bool {
66 (self as usize) >= 5
67 }
68}
69
70use self::RefType::*;
71use std::fmt;
72use std::fmt::Display;
73
74pub const ALL_INTER_REFS: [RefType; 7] = [
75 LAST_FRAME,
76 LAST2_FRAME,
77 LAST3_FRAME,
78 GOLDEN_FRAME,
79 BWDREF_FRAME,
80 ALTREF2_FRAME,
81 ALTREF_FRAME,
82];
83
84pub const LAST_LAST2_FRAMES: usize = 0; pub const LAST_LAST3_FRAMES: usize = 1; pub const LAST_GOLDEN_FRAMES: usize = 2; pub const BWDREF_ALTREF_FRAMES: usize = 3; pub const LAST2_LAST3_FRAMES: usize = 4; pub const LAST2_GOLDEN_FRAMES: usize = 5; pub const LAST3_GOLDEN_FRAMES: usize = 6; pub const BWDREF_ALTREF2_FRAMES: usize = 7; pub const ALTREF2_ALTREF_FRAMES: usize = 8; pub const TOTAL_UNIDIR_COMP_REFS: usize = 9;
94
95pub const UNIDIR_COMP_REFS: usize = BWDREF_ALTREF_FRAMES + 1;
98
99pub const FWD_REFS: usize = 4;
100pub const BWD_REFS: usize = 3;
101pub const SINGLE_REFS: usize = 7;
102pub const TOTAL_REFS_PER_FRAME: usize = 8;
103pub const INTER_REFS_PER_FRAME: usize = 7;
104pub const TOTAL_COMP_REFS: usize =
105 FWD_REFS * BWD_REFS + TOTAL_UNIDIR_COMP_REFS;
106
107pub const REF_FRAMES_LOG2: usize = 3;
108pub const REF_FRAMES: usize = 1 << REF_FRAMES_LOG2;
109
110pub const REF_CONTEXTS: usize = 3;
111pub const MVREF_ROW_COLS: usize = 3;
112
113#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
114pub enum PartitionType {
115 PARTITION_NONE,
116 PARTITION_HORZ,
117 PARTITION_VERT,
118 PARTITION_SPLIT,
119 PARTITION_HORZ_A, PARTITION_HORZ_B, PARTITION_VERT_A, PARTITION_VERT_B, PARTITION_HORZ_4, PARTITION_VERT_4, PARTITION_INVALID,
126}
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
129#[cfg_attr(test, derive(Default))]
130pub enum BlockSize {
131 BLOCK_4X4,
132 BLOCK_4X8,
133 BLOCK_8X4,
134 BLOCK_8X8,
135 BLOCK_8X16,
136 BLOCK_16X8,
137 BLOCK_16X16,
138 BLOCK_16X32,
139 BLOCK_32X16,
140 BLOCK_32X32,
141 BLOCK_32X64,
142 BLOCK_64X32,
143 #[cfg_attr(test, default)]
144 BLOCK_64X64,
145 BLOCK_64X128,
146 BLOCK_128X64,
147 BLOCK_128X128,
148 BLOCK_4X16,
149 BLOCK_16X4,
150 BLOCK_8X32,
151 BLOCK_32X8,
152 BLOCK_16X64,
153 BLOCK_64X16,
154}
155
156#[derive(Debug, Error, Copy, Clone, Eq, PartialEq)]
157pub struct InvalidBlockSize;
158
159impl Display for InvalidBlockSize {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 f.write_str("invalid block size")
162 }
163}
164
165impl PartialOrd for BlockSize {
166 #[inline(always)]
167 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
168 use std::cmp::Ordering::{Equal, Greater, Less};
169 match (
170 self.width().cmp(&other.width()),
171 self.height().cmp(&other.height()),
172 ) {
173 (Greater, Less) | (Less, Greater) => None,
174 (Equal, Equal) => Some(Equal),
175 (Greater, _) | (_, Greater) => Some(Greater),
176 (Less, _) | (_, Less) => Some(Less),
177 }
178 }
179}
180
181impl BlockSize {
182 pub const BLOCK_SIZES_ALL: usize = 22;
183 pub const BLOCK_SIZES: usize = BlockSize::BLOCK_SIZES_ALL - 6; #[inline]
186 pub fn from_width_and_height_opt(
191 w: usize, h: usize,
192 ) -> Result<BlockSize, InvalidBlockSize> {
193 match (w, h) {
194 (4, 4) => Ok(BLOCK_4X4),
195 (4, 8) => Ok(BLOCK_4X8),
196 (4, 16) => Ok(BLOCK_4X16),
197 (8, 4) => Ok(BLOCK_8X4),
198 (8, 8) => Ok(BLOCK_8X8),
199 (8, 16) => Ok(BLOCK_8X16),
200 (8, 32) => Ok(BLOCK_8X32),
201 (16, 4) => Ok(BLOCK_16X4),
202 (16, 8) => Ok(BLOCK_16X8),
203 (16, 16) => Ok(BLOCK_16X16),
204 (16, 32) => Ok(BLOCK_16X32),
205 (16, 64) => Ok(BLOCK_16X64),
206 (32, 8) => Ok(BLOCK_32X8),
207 (32, 16) => Ok(BLOCK_32X16),
208 (32, 32) => Ok(BLOCK_32X32),
209 (32, 64) => Ok(BLOCK_32X64),
210 (64, 16) => Ok(BLOCK_64X16),
211 (64, 32) => Ok(BLOCK_64X32),
212 (64, 64) => Ok(BLOCK_64X64),
213 (64, 128) => Ok(BLOCK_64X128),
214 (128, 64) => Ok(BLOCK_128X64),
215 (128, 128) => Ok(BLOCK_128X128),
216 _ => Err(InvalidBlockSize),
217 }
218 }
219
220 pub fn from_width_and_height(w: usize, h: usize) -> BlockSize {
224 Self::from_width_and_height_opt(w, h).unwrap()
225 }
226
227 #[inline]
228 pub fn cfl_allowed(self) -> bool {
229 self <= BlockSize::BLOCK_32X32
231 }
232
233 #[inline]
234 pub const fn width(self) -> usize {
235 1 << self.width_log2()
236 }
237
238 #[inline]
240 pub const fn area(self) -> usize {
241 self.width() * self.height()
242 }
243
244 #[inline]
245 pub const fn width_log2(self) -> usize {
246 match self {
247 BLOCK_4X4 | BLOCK_4X8 | BLOCK_4X16 => 2,
248 BLOCK_8X4 | BLOCK_8X8 | BLOCK_8X16 | BLOCK_8X32 => 3,
249 BLOCK_16X4 | BLOCK_16X8 | BLOCK_16X16 | BLOCK_16X32 | BLOCK_16X64 => 4,
250 BLOCK_32X8 | BLOCK_32X16 | BLOCK_32X32 | BLOCK_32X64 => 5,
251 BLOCK_64X16 | BLOCK_64X32 | BLOCK_64X64 | BLOCK_64X128 => 6,
252 BLOCK_128X64 | BLOCK_128X128 => 7,
253 }
254 }
255
256 #[inline]
257 pub const fn width_mi_log2(self) -> usize {
258 self.width_log2() - 2
259 }
260
261 #[inline]
262 pub const fn width_mi(self) -> usize {
263 self.width() >> MI_SIZE_LOG2
264 }
265
266 #[inline]
267 pub fn width_imp_b(self) -> usize {
268 (self.width() >> (IMPORTANCE_BLOCK_TO_BLOCK_SHIFT + BLOCK_TO_PLANE_SHIFT))
269 .max(1)
270 }
271
272 #[inline]
273 pub const fn height(self) -> usize {
274 1 << self.height_log2()
275 }
276
277 #[inline]
278 pub const fn height_log2(self) -> usize {
279 match self {
280 BLOCK_4X4 | BLOCK_8X4 | BLOCK_16X4 => 2,
281 BLOCK_4X8 | BLOCK_8X8 | BLOCK_16X8 | BLOCK_32X8 => 3,
282 BLOCK_4X16 | BLOCK_8X16 | BLOCK_16X16 | BLOCK_32X16 | BLOCK_64X16 => 4,
283 BLOCK_8X32 | BLOCK_16X32 | BLOCK_32X32 | BLOCK_64X32 => 5,
284 BLOCK_16X64 | BLOCK_32X64 | BLOCK_64X64 | BLOCK_128X64 => 6,
285 BLOCK_64X128 | BLOCK_128X128 => 7,
286 }
287 }
288
289 #[inline]
290 pub const fn height_mi_log2(self) -> usize {
291 self.height_log2() - 2
292 }
293
294 #[inline]
295 pub const fn height_mi(self) -> usize {
296 self.height() >> MI_SIZE_LOG2
297 }
298
299 #[inline]
300 pub fn height_imp_b(self) -> usize {
301 (self.height() >> (IMPORTANCE_BLOCK_TO_BLOCK_SHIFT + BLOCK_TO_PLANE_SHIFT))
302 .max(1)
303 }
304
305 #[inline]
306 pub const fn tx_size(self) -> TxSize {
307 match self {
308 BLOCK_4X4 => TX_4X4,
309 BLOCK_4X8 => TX_4X8,
310 BLOCK_8X4 => TX_8X4,
311 BLOCK_8X8 => TX_8X8,
312 BLOCK_8X16 => TX_8X16,
313 BLOCK_16X8 => TX_16X8,
314 BLOCK_16X16 => TX_16X16,
315 BLOCK_16X32 => TX_16X32,
316 BLOCK_32X16 => TX_32X16,
317 BLOCK_32X32 => TX_32X32,
318 BLOCK_32X64 => TX_32X64,
319 BLOCK_64X32 => TX_64X32,
320 BLOCK_4X16 => TX_4X16,
321 BLOCK_16X4 => TX_16X4,
322 BLOCK_8X32 => TX_8X32,
323 BLOCK_32X8 => TX_32X8,
324 BLOCK_16X64 => TX_16X64,
325 BLOCK_64X16 => TX_64X16,
326 _ => TX_64X64,
327 }
328 }
329
330 #[inline]
337 pub const fn subsampled_size(
338 self, xdec: usize, ydec: usize,
339 ) -> Result<BlockSize, InvalidBlockSize> {
340 Ok(match (xdec, ydec) {
341 (0, 0) => self,
342 (1, 0) => match self {
343 BLOCK_4X4 | BLOCK_8X4 => BLOCK_4X4,
344 BLOCK_8X8 => BLOCK_4X8,
345 BLOCK_16X4 => BLOCK_8X4,
346 BLOCK_16X8 => BLOCK_8X8,
347 BLOCK_16X16 => BLOCK_8X16,
348 BLOCK_32X8 => BLOCK_16X8,
349 BLOCK_32X16 => BLOCK_16X16,
350 BLOCK_32X32 => BLOCK_16X32,
351 BLOCK_64X16 => BLOCK_32X16,
352 BLOCK_64X32 => BLOCK_32X32,
353 BLOCK_64X64 => BLOCK_32X64,
354 BLOCK_128X64 => BLOCK_64X64,
355 BLOCK_128X128 => BLOCK_64X128,
356 _ => return Err(InvalidBlockSize),
357 },
358 (1, 1) => match self {
359 BLOCK_4X4 | BLOCK_4X8 | BLOCK_8X4 | BLOCK_8X8 => BLOCK_4X4,
360 BLOCK_4X16 | BLOCK_8X16 => BLOCK_4X8,
361 BLOCK_8X32 => BLOCK_4X16,
362 BLOCK_16X4 | BLOCK_16X8 => BLOCK_8X4,
363 BLOCK_16X16 => BLOCK_8X8,
364 BLOCK_16X32 => BLOCK_8X16,
365 BLOCK_16X64 => BLOCK_8X32,
366 BLOCK_32X8 => BLOCK_16X4,
367 BLOCK_32X16 => BLOCK_16X8,
368 BLOCK_32X32 => BLOCK_16X16,
369 BLOCK_32X64 => BLOCK_16X32,
370 BLOCK_64X16 => BLOCK_32X8,
371 BLOCK_64X32 => BLOCK_32X16,
372 BLOCK_64X64 => BLOCK_32X32,
373 BLOCK_64X128 => BLOCK_32X64,
374 BLOCK_128X64 => BLOCK_64X32,
375 BLOCK_128X128 => BLOCK_64X64,
376 },
377 _ => return Err(InvalidBlockSize),
378 })
379 }
380
381 #[inline]
385 pub fn largest_chroma_tx_size(self, xdec: usize, ydec: usize) -> TxSize {
386 let plane_bsize = self
387 .subsampled_size(xdec, ydec)
388 .expect("invalid block size for this subsampling mode");
389
390 let chroma_tx_size = max_txsize_rect_lookup[plane_bsize as usize];
391
392 av1_get_coded_tx_size(chroma_tx_size)
393 }
394
395 #[inline]
396 pub const fn is_sqr(self) -> bool {
397 self.width_log2() == self.height_log2()
398 }
399
400 #[inline]
401 pub const fn is_sub8x8(self, xdec: usize, ydec: usize) -> bool {
402 xdec != 0 && self.width_log2() == 2 || ydec != 0 && self.height_log2() == 2
403 }
404
405 #[inline]
406 pub const fn sub8x8_offset(
407 self, xdec: usize, ydec: usize,
408 ) -> (isize, isize) {
409 let offset_x = if xdec != 0 && self.width_log2() == 2 { -1 } else { 0 };
410 let offset_y = if ydec != 0 && self.height_log2() == 2 { -1 } else { 0 };
411
412 (offset_x, offset_y)
413 }
414
415 pub const fn subsize(
420 self, partition: PartitionType,
421 ) -> Result<BlockSize, InvalidBlockSize> {
422 use PartitionType::*;
423
424 Ok(match partition {
425 PARTITION_NONE => self,
426 PARTITION_SPLIT => match self {
427 BLOCK_8X8 => BLOCK_4X4,
428 BLOCK_16X16 => BLOCK_8X8,
429 BLOCK_32X32 => BLOCK_16X16,
430 BLOCK_64X64 => BLOCK_32X32,
431 BLOCK_128X128 => BLOCK_64X64,
432 _ => return Err(InvalidBlockSize),
433 },
434 PARTITION_HORZ | PARTITION_HORZ_A | PARTITION_HORZ_B => match self {
435 BLOCK_8X8 => BLOCK_8X4,
436 BLOCK_16X16 => BLOCK_16X8,
437 BLOCK_32X32 => BLOCK_32X16,
438 BLOCK_64X64 => BLOCK_64X32,
439 BLOCK_128X128 => BLOCK_128X64,
440 _ => return Err(InvalidBlockSize),
441 },
442 PARTITION_VERT | PARTITION_VERT_A | PARTITION_VERT_B => match self {
443 BLOCK_8X8 => BLOCK_4X8,
444 BLOCK_16X16 => BLOCK_8X16,
445 BLOCK_32X32 => BLOCK_16X32,
446 BLOCK_64X64 => BLOCK_32X64,
447 BLOCK_128X128 => BLOCK_64X128,
448 _ => return Err(InvalidBlockSize),
449 },
450 PARTITION_HORZ_4 => match self {
451 BLOCK_16X16 => BLOCK_16X4,
452 BLOCK_32X32 => BLOCK_32X8,
453 BLOCK_64X64 => BLOCK_64X16,
454 _ => return Err(InvalidBlockSize),
455 },
456 PARTITION_VERT_4 => match self {
457 BLOCK_16X16 => BLOCK_4X16,
458 BLOCK_32X32 => BLOCK_8X32,
459 BLOCK_64X64 => BLOCK_16X64,
460 _ => return Err(InvalidBlockSize),
461 },
462 _ => return Err(InvalidBlockSize),
463 })
464 }
465
466 pub const fn is_rect_tx_allowed(self) -> bool {
467 !matches!(
468 self,
469 BLOCK_4X4
470 | BLOCK_8X8
471 | BLOCK_16X16
472 | BLOCK_32X32
473 | BLOCK_64X64
474 | BLOCK_64X128
475 | BLOCK_128X64
476 | BLOCK_128X128
477 )
478 }
479}
480
481impl fmt::Display for BlockSize {
482 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
483 write!(
484 f,
485 "{}",
486 match self {
487 BlockSize::BLOCK_4X4 => "4x4",
488 BlockSize::BLOCK_4X8 => "4x8",
489 BlockSize::BLOCK_8X4 => "8x4",
490 BlockSize::BLOCK_8X8 => "8x8",
491 BlockSize::BLOCK_8X16 => "8x16",
492 BlockSize::BLOCK_16X8 => "16x8",
493 BlockSize::BLOCK_16X16 => "16x16",
494 BlockSize::BLOCK_16X32 => "16x32",
495 BlockSize::BLOCK_32X16 => "32x16",
496 BlockSize::BLOCK_32X32 => "32x32",
497 BlockSize::BLOCK_32X64 => "32x64",
498 BlockSize::BLOCK_64X32 => "64x32",
499 BlockSize::BLOCK_64X64 => "64x64",
500 BlockSize::BLOCK_64X128 => "64x128",
501 BlockSize::BLOCK_128X64 => "128x64",
502 BlockSize::BLOCK_128X128 => "128x128",
503 BlockSize::BLOCK_4X16 => "4x16",
504 BlockSize::BLOCK_16X4 => "16x4",
505 BlockSize::BLOCK_8X32 => "8x32",
506 BlockSize::BLOCK_32X8 => "32x8",
507 BlockSize::BLOCK_16X64 => "16x64",
508 BlockSize::BLOCK_64X16 => "64x16",
509 }
510 )
511 }
512}
513
514pub const NEWMV_MODE_CONTEXTS: usize = 7;
515pub const GLOBALMV_MODE_CONTEXTS: usize = 2;
516pub const REFMV_MODE_CONTEXTS: usize = 6;
517pub const INTER_COMPOUND_MODES: usize = 8;
518
519pub const REFMV_OFFSET: usize = 4;
520pub const GLOBALMV_OFFSET: usize = 3;
521pub const NEWMV_CTX_MASK: usize = (1 << GLOBALMV_OFFSET) - 1;
522pub const GLOBALMV_CTX_MASK: usize =
523 (1 << (REFMV_OFFSET - GLOBALMV_OFFSET)) - 1;
524pub const REFMV_CTX_MASK: usize = (1 << (8 - REFMV_OFFSET)) - 1;
525
526pub static RAV1E_PARTITION_TYPES: &[PartitionType] = &[
527 PartitionType::PARTITION_NONE,
528 PartitionType::PARTITION_HORZ,
529 PartitionType::PARTITION_VERT,
530 PartitionType::PARTITION_SPLIT,
531];
532
533#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
534pub enum GlobalMVMode {
535 IDENTITY = 0, TRANSLATION = 1, ROTZOOM = 2, AFFINE = 3, }
540
541#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
542pub enum MvSubpelPrecision {
543 MV_SUBPEL_NONE = -1,
544 MV_SUBPEL_LOW_PRECISION = 0,
545 MV_SUBPEL_HIGH_PRECISION,
546}
547
548pub const MV_JOINTS: usize = 4;
550
551#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
552pub enum MvJointType {
553 MV_JOINT_ZERO = 0, MV_JOINT_HNZVZ = 1, MV_JOINT_HZVNZ = 2, MV_JOINT_HNZVNZ = 3, }
558
559fn supersample_chroma_bsize(
560 bsize: BlockSize, ss_x: usize, ss_y: usize,
561) -> BlockSize {
562 debug_assert!(ss_x < 2);
563 debug_assert!(ss_y < 2);
564
565 match bsize {
566 BLOCK_4X4 => match (ss_x, ss_y) {
567 (1, 1) => BLOCK_8X8,
568 (1, 0) => BLOCK_8X4,
569 (0, 1) => BLOCK_4X8,
570 _ => bsize,
571 },
572 BLOCK_4X8 => match (ss_x, ss_y) {
573 (1, 1) => BLOCK_8X8,
574 (1, 0) => BLOCK_8X8,
575 (0, 1) => BLOCK_4X8,
576 _ => bsize,
577 },
578 BLOCK_8X4 => match (ss_x, ss_y) {
579 (1, 1) => BLOCK_8X8,
580 (1, 0) => BLOCK_8X4,
581 (0, 1) => BLOCK_8X8,
582 _ => bsize,
583 },
584 BLOCK_4X16 => match (ss_x, ss_y) {
585 (1, 1) => BLOCK_8X16,
586 (1, 0) => BLOCK_8X16,
587 (0, 1) => BLOCK_4X16,
588 _ => bsize,
589 },
590 BLOCK_16X4 => match (ss_x, ss_y) {
591 (1, 1) => BLOCK_16X8,
592 (1, 0) => BLOCK_16X4,
593 (0, 1) => BLOCK_16X8,
594 _ => bsize,
595 },
596 _ => bsize,
597 }
598}
599
600type IntraEdgeBuffer<T> = Aligned<[MaybeUninit<T>; 4 * MAX_TX_SIZE + 1]>;
601
602#[cfg(any(test, feature = "bench"))]
603type IntraEdgeMock<T> = Aligned<[T; 4 * MAX_TX_SIZE + 1]>;
604
605pub struct IntraEdge<'a, T: Pixel>(&'a [T], &'a [T], &'a [T]);
606
607impl<'a, T: Pixel> IntraEdge<'a, T> {
608 fn new(
609 edge_buf: &'a mut IntraEdgeBuffer<T>, init_left: usize, init_above: usize,
610 ) -> Self {
611 let left = unsafe {
613 let begin_left = 2 * MAX_TX_SIZE - init_left;
614 let end_above = 2 * MAX_TX_SIZE + 1 + init_above;
615 slice_assume_init_mut(&mut edge_buf.data[begin_left..end_above])
616 };
617 let (left, top_left) = left.split_at(init_left);
618 let (top_left, above) = top_left.split_at(1);
619 Self(left, top_left, above)
620 }
621
622 pub const fn as_slices(&self) -> (&'a [T], &'a [T], &'a [T]) {
623 (self.0, self.1, self.2)
624 }
625
626 pub const fn top_left_ptr(&self) -> *const T {
627 self.1.as_ptr()
628 }
629
630 #[cfg(any(test, feature = "bench"))]
631 pub fn mock(edge_buf: &'a IntraEdgeMock<T>) -> Self {
632 let left = &edge_buf.data[..];
633 let (left, top_left) = left.split_at(2 * MAX_TX_SIZE);
634 let (top_left, above) = top_left.split_at(1);
635 Self(left, top_left, above)
636 }
637}
638
639pub fn get_intra_edges<'a, T: Pixel>(
640 edge_buf: &'a mut IntraEdgeBuffer<T>,
641 dst: &PlaneRegion<'_, T>,
642 partition_bo: TileBlockOffset, bx: usize,
644 by: usize,
645 partition_size: BlockSize, po: PlaneOffset,
647 tx_size: TxSize,
648 bit_depth: usize,
649 opt_mode: Option<PredictionMode>,
650 enable_intra_edge_filter: bool,
651 intra_param: IntraParam,
652) -> IntraEdge<'a, T> {
653 let mut init_left: usize = 0;
654 let mut init_above: usize = 0;
655
656 let plane_cfg = &dst.plane_cfg;
657
658 let base = 128u16 << (bit_depth - 8);
659
660 {
661 let (left, not_left) = edge_buf.data.split_at_mut(2 * MAX_TX_SIZE);
663 let (top_left, above) = not_left.split_at_mut(1);
664
665 let x = po.x as usize;
666 let y = po.y as usize;
667
668 let mut needs_left = true;
669 let mut needs_topleft = true;
670 let mut needs_top = true;
671 let mut needs_topright = true;
672 let mut needs_bottomleft = true;
673 let mut needs_topleft_filter = false;
674
675 if let Some(mut mode) = opt_mode {
676 mode = match mode {
677 PredictionMode::PAETH_PRED => match (x, y) {
678 (0, 0) => PredictionMode::DC_PRED,
679 (0, _) => PredictionMode::V_PRED,
680 (_, 0) => PredictionMode::H_PRED,
681 _ => PredictionMode::PAETH_PRED,
682 },
683 _ => mode,
684 };
685
686 let p_angle = intra_mode_to_angle(mode)
687 + match intra_param {
688 IntraParam::AngleDelta(val) => (val * ANGLE_STEP) as isize,
689 _ => 0,
690 };
691
692 let dc_or_cfl =
693 mode == PredictionMode::DC_PRED || mode == PredictionMode::UV_CFL_PRED;
694
695 needs_left = (!dc_or_cfl || x != 0) || (p_angle > 90 && p_angle != 180);
696 needs_topleft = mode == PredictionMode::PAETH_PRED
697 || (mode.is_directional() && p_angle != 90 && p_angle != 180);
698 needs_top = (!dc_or_cfl || y != 0) || (p_angle != 90 && p_angle < 180);
699 needs_topright = mode.is_directional() && p_angle < 90;
700 needs_bottomleft = mode.is_directional() && p_angle > 180;
701 needs_topleft_filter =
702 enable_intra_edge_filter && p_angle > 90 && p_angle < 180;
703 }
704
705 let rect_w =
706 dst.rect().width.min(dst.plane_cfg.width - dst.rect().x as usize);
707 let rect_h =
708 dst.rect().height.min(dst.plane_cfg.height - dst.rect().y as usize);
709
710 if needs_left {
712 let txh = if y + tx_size.height() > rect_h {
713 rect_h - y
714 } else {
715 tx_size.height()
716 };
717 if x != 0 {
718 for i in 0..txh {
719 debug_assert!(y + i < rect_h);
720 left[2 * MAX_TX_SIZE - 1 - i].write(dst[y + i][x - 1]);
721 }
722 if txh < tx_size.height() {
723 let val = dst[y + txh - 1][x - 1];
724 for i in txh..tx_size.height() {
725 left[2 * MAX_TX_SIZE - 1 - i].write(val);
726 }
727 }
728 } else {
729 let val = if y != 0 { dst[y - 1][0] } else { T::cast_from(base + 1) };
730 for v in left[2 * MAX_TX_SIZE - tx_size.height()..].iter_mut() {
731 v.write(val);
732 }
733 }
734 init_left += tx_size.height();
735 }
736
737 if needs_top {
739 let txw = if x + tx_size.width() > rect_w {
740 rect_w - x
741 } else {
742 tx_size.width()
743 };
744 if y != 0 {
745 above[..txw].copy_from_slice(
746 unsafe {
748 transmute::<&[T], &[MaybeUninit<T>]>(&dst[y - 1][x..x + txw])
749 },
750 );
751 if txw < tx_size.width() {
752 let val = dst[y - 1][x + txw - 1];
753 for i in txw..tx_size.width() {
754 above[i].write(val);
755 }
756 }
757 } else {
758 let val = if x != 0 { dst[0][x - 1] } else { T::cast_from(base - 1) };
759 for v in above[..tx_size.width()].iter_mut() {
760 v.write(val);
761 }
762 }
763 init_above += tx_size.width();
764 }
765
766 let bx4 = bx * (tx_size.width() >> MI_SIZE_LOG2); let by4 = by * (tx_size.height() >> MI_SIZE_LOG2);
768
769 let have_top = by4 != 0
770 || if plane_cfg.ydec != 0 {
771 partition_bo.0.y > 1
772 } else {
773 partition_bo.0.y > 0
774 };
775 let have_left = bx4 != 0
776 || if plane_cfg.xdec != 0 {
777 partition_bo.0.x > 1
778 } else {
779 partition_bo.0.x > 0
780 };
781
782 let right_available = x + tx_size.width() < rect_w;
783 let bottom_available = y + tx_size.height() < rect_h;
784
785 let scaled_partition_size =
786 supersample_chroma_bsize(partition_size, plane_cfg.xdec, plane_cfg.ydec);
787
788 if needs_topright {
790 debug_assert!(plane_cfg.xdec <= 1 && plane_cfg.ydec <= 1);
791
792 let num_avail = if y != 0
793 && has_top_right(
794 scaled_partition_size,
795 partition_bo,
796 have_top,
797 right_available,
798 tx_size,
799 by4,
800 bx4,
801 plane_cfg.xdec,
802 plane_cfg.ydec,
803 ) {
804 tx_size.width().min(rect_w - x - tx_size.width())
805 } else {
806 0
807 };
808 if num_avail > 0 {
809 above[tx_size.width()..][..num_avail].copy_from_slice(
810 unsafe {
812 transmute::<&[T], &[MaybeUninit<T>]>(
813 &dst[y - 1][x + tx_size.width()..][..num_avail],
814 )
815 },
816 );
817 }
818 if num_avail < tx_size.height() {
819 let val = above[tx_size.width() + num_avail - 1];
820 for v in above
821 [tx_size.width() + num_avail..tx_size.width() + tx_size.height()]
822 .iter_mut()
823 {
824 *v = val;
825 }
826 }
827 init_above += tx_size.height();
828 }
829
830 let above = unsafe { slice_assume_init_mut(&mut above[..init_above]) };
832
833 if needs_bottomleft {
835 debug_assert!(plane_cfg.xdec <= 1 && plane_cfg.ydec <= 1);
836
837 let num_avail = if x != 0
838 && has_bottom_left(
839 scaled_partition_size,
840 partition_bo,
841 bottom_available,
842 have_left,
843 tx_size,
844 by4,
845 bx4,
846 plane_cfg.xdec,
847 plane_cfg.ydec,
848 ) {
849 tx_size.height().min(rect_h - y - tx_size.height())
850 } else {
851 0
852 };
853 if num_avail > 0 {
854 for i in 0..num_avail {
855 left[2 * MAX_TX_SIZE - tx_size.height() - 1 - i]
856 .write(dst[y + tx_size.height() + i][x - 1]);
857 }
858 }
859 if num_avail < tx_size.width() {
860 let val = left[2 * MAX_TX_SIZE - tx_size.height() - num_avail];
861 for v in left[(2 * MAX_TX_SIZE - tx_size.height() - tx_size.width())
862 ..(2 * MAX_TX_SIZE - tx_size.height() - num_avail)]
863 .iter_mut()
864 {
865 *v = val;
866 }
867 }
868 init_left += tx_size.width();
869 }
870
871 let left = unsafe {
873 slice_assume_init_mut(&mut left[2 * MAX_TX_SIZE - init_left..])
874 };
875
876 if needs_topleft {
878 let top_left = top_left[0].write(match (x, y) {
879 (0, 0) => T::cast_from(base),
880 (_, 0) => dst[0][x - 1],
881 (0, _) => dst[y - 1][0],
882 _ => dst[y - 1][x - 1],
883 });
884
885 let (w, h) = (tx_size.width(), tx_size.height());
886 if needs_topleft_filter && w + h >= 24 {
887 let (l, a, tl): (u32, u32, u32) =
888 (left[left.len() - 1].into(), above[0].into(), (*top_left).into());
889 let s = l * 5 + tl * 6 + a * 5;
890
891 *top_left = T::cast_from((s + (1 << 3)) >> 4);
892 }
893 } else {
894 top_left[0].write(T::cast_from(base));
895 }
896 }
897 IntraEdge::new(edge_buf, init_left, init_above)
898}
899
900pub fn has_tr(bo: TileBlockOffset, bsize: BlockSize) -> bool {
901 let sb_mi_size = BLOCK_64X64.width_mi(); let mask_row = bo.0.y & LOCAL_BLOCK_MASK;
903 let mask_col = bo.0.x & LOCAL_BLOCK_MASK;
904 let target_n4_w = bsize.width_mi();
905 let target_n4_h = bsize.height_mi();
906
907 let mut bs = target_n4_w.max(target_n4_h);
908
909 if bs > BLOCK_64X64.width_mi() {
910 return false;
911 }
912
913 let mut has_tr = !((mask_row & bs) != 0 && (mask_col & bs) != 0);
914
915 while bs < sb_mi_size {
918 if (mask_col & bs) != 0 {
919 if (mask_col & (2 * bs) != 0) && (mask_row & (2 * bs) != 0) {
920 has_tr = false;
921 break;
922 }
923 } else {
924 break;
925 }
926 bs <<= 1;
927 }
928
929 if (target_n4_w < target_n4_h) && (bo.0.x & target_n4_w) == 0 {
932 has_tr = true;
933 }
934
935 if (target_n4_w > target_n4_h) && (bo.0.y & target_n4_h) != 0 {
938 has_tr = false;
939 }
940
941 has_tr
955}
956
957pub fn has_bl(bo: TileBlockOffset, bsize: BlockSize) -> bool {
958 let sb_mi_size = BLOCK_64X64.width_mi(); let mask_row = bo.0.y & LOCAL_BLOCK_MASK;
960 let mask_col = bo.0.x & LOCAL_BLOCK_MASK;
961 let target_n4_w = bsize.width_mi();
962 let target_n4_h = bsize.height_mi();
963
964 let mut bs = target_n4_w.max(target_n4_h);
965
966 if bs > BLOCK_64X64.width_mi() {
967 return false;
968 }
969
970 let mut has_bl =
971 (mask_row & bs) == 0 && (mask_col & bs) == 0 && bs < sb_mi_size;
972
973 while 2 * bs < sb_mi_size {
976 if (mask_col & bs) == 0 {
977 if (mask_col & (2 * bs) == 0) && (mask_row & (2 * bs) == 0) {
978 has_bl = true;
979 break;
980 }
981 } else {
982 break;
983 }
984 bs <<= 1;
985 }
986
987 if (target_n4_w < target_n4_h) && (bo.0.x & target_n4_w) != 0 {
990 has_bl = false;
991 }
992
993 if (target_n4_w > target_n4_h) && (bo.0.y & target_n4_h) == 0 {
996 has_bl = true;
997 }
998
999 has_bl
1013}
1014
1015#[cfg(test)]
1016mod tests {
1017 use crate::partition::BlockSize::*;
1018 use crate::partition::{BlockSize, InvalidBlockSize};
1019
1020 #[test]
1021 fn from_wh_matches_naive() {
1022 fn from_wh_opt_naive(
1023 w: usize, h: usize,
1024 ) -> Result<BlockSize, InvalidBlockSize> {
1025 match (w, h) {
1026 (4, 4) => Ok(BLOCK_4X4),
1027 (4, 8) => Ok(BLOCK_4X8),
1028 (8, 4) => Ok(BLOCK_8X4),
1029 (8, 8) => Ok(BLOCK_8X8),
1030 (8, 16) => Ok(BLOCK_8X16),
1031 (16, 8) => Ok(BLOCK_16X8),
1032 (16, 16) => Ok(BLOCK_16X16),
1033 (16, 32) => Ok(BLOCK_16X32),
1034 (32, 16) => Ok(BLOCK_32X16),
1035 (32, 32) => Ok(BLOCK_32X32),
1036 (32, 64) => Ok(BLOCK_32X64),
1037 (64, 32) => Ok(BLOCK_64X32),
1038 (64, 64) => Ok(BLOCK_64X64),
1039 (64, 128) => Ok(BLOCK_64X128),
1040 (128, 64) => Ok(BLOCK_128X64),
1041 (128, 128) => Ok(BLOCK_128X128),
1042 (4, 16) => Ok(BLOCK_4X16),
1043 (16, 4) => Ok(BLOCK_16X4),
1044 (8, 32) => Ok(BLOCK_8X32),
1045 (32, 8) => Ok(BLOCK_32X8),
1046 (16, 64) => Ok(BLOCK_16X64),
1047 (64, 16) => Ok(BLOCK_64X16),
1048 _ => Err(InvalidBlockSize),
1049 }
1050 }
1051
1052 for w in 0..256 {
1053 for h in 0..256 {
1054 let a = BlockSize::from_width_and_height_opt(w, h);
1055 let b = from_wh_opt_naive(w, h);
1056
1057 assert_eq!(a, b);
1058 }
1059 }
1060 }
1061}