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