Coverage Report

Created: 2025-07-12 07:18

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