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 | #[macro_use ] |
14 | pub mod forward_shared; |
15 | |
16 | pub use self::forward::forward_transform; |
17 | pub use self::inverse::inverse_transform_add; |
18 | |
19 | use crate::context::MI_SIZE_LOG2; |
20 | use crate::partition::{BlockSize, BlockSize::*}; |
21 | use crate::util::*; |
22 | |
23 | use TxSize::*; |
24 | |
25 | pub mod forward; |
26 | pub mod inverse; |
27 | |
28 | pub static RAV1E_TX_TYPES: &[TxType] = &[ |
29 | TxType::DCT_DCT, |
30 | TxType::ADST_DCT, |
31 | TxType::DCT_ADST, |
32 | TxType::ADST_ADST, |
33 | // TODO: Add a speed setting for FLIPADST |
34 | // TxType::FLIPADST_DCT, |
35 | // TxType::DCT_FLIPADST, |
36 | // TxType::FLIPADST_FLIPADST, |
37 | // TxType::ADST_FLIPADST, |
38 | // TxType::FLIPADST_ADST, |
39 | TxType::IDTX, |
40 | TxType::V_DCT, |
41 | TxType::H_DCT, |
42 | //TxType::V_FLIPADST, |
43 | //TxType::H_FLIPADST, |
44 | ]; |
45 | |
46 | pub mod consts { |
47 | pub static SQRT2_BITS: usize = 12; |
48 | pub static SQRT2: i32 = 5793; // 2^12 * sqrt(2) |
49 | pub static INV_SQRT2: i32 = 2896; // 2^12 / sqrt(2) |
50 | } |
51 | |
52 | pub const TX_TYPES: usize = 16; |
53 | pub const TX_TYPES_PLUS_LL: usize = 17; |
54 | |
55 | #[derive (Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] |
56 | pub enum TxType { |
57 | DCT_DCT = 0, // DCT in both horizontal and vertical |
58 | ADST_DCT = 1, // ADST in vertical, DCT in horizontal |
59 | DCT_ADST = 2, // DCT in vertical, ADST in horizontal |
60 | ADST_ADST = 3, // ADST in both directions |
61 | FLIPADST_DCT = 4, |
62 | DCT_FLIPADST = 5, |
63 | FLIPADST_FLIPADST = 6, |
64 | ADST_FLIPADST = 7, |
65 | FLIPADST_ADST = 8, |
66 | IDTX = 9, |
67 | V_DCT = 10, |
68 | H_DCT = 11, |
69 | V_ADST = 12, |
70 | H_ADST = 13, |
71 | V_FLIPADST = 14, |
72 | H_FLIPADST = 15, |
73 | WHT_WHT = 16, |
74 | } |
75 | |
76 | impl TxType { |
77 | /// Compute transform type for inter chroma. |
78 | /// |
79 | /// <https://aomediacodec.github.io/av1-spec/#compute-transform-type-function> |
80 | #[inline ] |
81 | pub fn uv_inter(self, uv_tx_size: TxSize) -> Self { |
82 | use TxType::*; |
83 | if uv_tx_size.sqr_up() == TX_32X32 { |
84 | match self { |
85 | IDTX => IDTX, |
86 | _ => DCT_DCT, |
87 | } |
88 | } else if uv_tx_size.sqr() == TX_16X16 { |
89 | match self { |
90 | V_ADST | H_ADST | V_FLIPADST | H_FLIPADST => DCT_DCT, |
91 | _ => self, |
92 | } |
93 | } else { |
94 | self |
95 | } |
96 | } |
97 | } |
98 | |
99 | /// Transform Size |
100 | #[derive (Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] |
101 | pub enum TxSize { |
102 | TX_4X4, |
103 | TX_8X8, |
104 | TX_16X16, |
105 | TX_32X32, |
106 | TX_64X64, |
107 | |
108 | TX_4X8, |
109 | TX_8X4, |
110 | TX_8X16, |
111 | TX_16X8, |
112 | TX_16X32, |
113 | TX_32X16, |
114 | TX_32X64, |
115 | TX_64X32, |
116 | |
117 | TX_4X16, |
118 | TX_16X4, |
119 | TX_8X32, |
120 | TX_32X8, |
121 | TX_16X64, |
122 | TX_64X16, |
123 | } |
124 | |
125 | impl TxSize { |
126 | /// Number of square transform sizes |
127 | pub const TX_SIZES: usize = 5; |
128 | |
129 | /// Number of transform sizes (including non-square sizes) |
130 | pub const TX_SIZES_ALL: usize = 14 + 5; |
131 | |
132 | #[inline ] |
133 | pub const fn width(self) -> usize { |
134 | 1 << self.width_log2() |
135 | } |
136 | |
137 | #[inline ] |
138 | pub const fn width_log2(self) -> usize { |
139 | match self { |
140 | TX_4X4 | TX_4X8 | TX_4X16 => 2, |
141 | TX_8X8 | TX_8X4 | TX_8X16 | TX_8X32 => 3, |
142 | TX_16X16 | TX_16X8 | TX_16X32 | TX_16X4 | TX_16X64 => 4, |
143 | TX_32X32 | TX_32X16 | TX_32X64 | TX_32X8 => 5, |
144 | TX_64X64 | TX_64X32 | TX_64X16 => 6, |
145 | } |
146 | } |
147 | |
148 | #[inline ] |
149 | pub const fn width_index(self) -> usize { |
150 | self.width_log2() - TX_4X4.width_log2() |
151 | } |
152 | |
153 | #[inline ] |
154 | pub const fn height(self) -> usize { |
155 | 1 << self.height_log2() |
156 | } |
157 | |
158 | #[inline ] |
159 | pub const fn height_log2(self) -> usize { |
160 | match self { |
161 | TX_4X4 | TX_8X4 | TX_16X4 => 2, |
162 | TX_8X8 | TX_4X8 | TX_16X8 | TX_32X8 => 3, |
163 | TX_16X16 | TX_8X16 | TX_32X16 | TX_4X16 | TX_64X16 => 4, |
164 | TX_32X32 | TX_16X32 | TX_64X32 | TX_8X32 => 5, |
165 | TX_64X64 | TX_32X64 | TX_16X64 => 6, |
166 | } |
167 | } |
168 | |
169 | #[inline ] |
170 | pub const fn height_index(self) -> usize { |
171 | self.height_log2() - TX_4X4.height_log2() |
172 | } |
173 | |
174 | #[inline ] |
175 | pub const fn width_mi(self) -> usize { |
176 | self.width() >> MI_SIZE_LOG2 |
177 | } |
178 | |
179 | #[inline ] |
180 | pub const fn area(self) -> usize { |
181 | 1 << self.area_log2() |
182 | } |
183 | |
184 | #[inline ] |
185 | pub const fn area_log2(self) -> usize { |
186 | self.width_log2() + self.height_log2() |
187 | } |
188 | |
189 | #[inline ] |
190 | pub const fn height_mi(self) -> usize { |
191 | self.height() >> MI_SIZE_LOG2 |
192 | } |
193 | |
194 | #[inline ] |
195 | pub const fn block_size(self) -> BlockSize { |
196 | match self { |
197 | TX_4X4 => BLOCK_4X4, |
198 | TX_8X8 => BLOCK_8X8, |
199 | TX_16X16 => BLOCK_16X16, |
200 | TX_32X32 => BLOCK_32X32, |
201 | TX_64X64 => BLOCK_64X64, |
202 | TX_4X8 => BLOCK_4X8, |
203 | TX_8X4 => BLOCK_8X4, |
204 | TX_8X16 => BLOCK_8X16, |
205 | TX_16X8 => BLOCK_16X8, |
206 | TX_16X32 => BLOCK_16X32, |
207 | TX_32X16 => BLOCK_32X16, |
208 | TX_32X64 => BLOCK_32X64, |
209 | TX_64X32 => BLOCK_64X32, |
210 | TX_4X16 => BLOCK_4X16, |
211 | TX_16X4 => BLOCK_16X4, |
212 | TX_8X32 => BLOCK_8X32, |
213 | TX_32X8 => BLOCK_32X8, |
214 | TX_16X64 => BLOCK_16X64, |
215 | TX_64X16 => BLOCK_64X16, |
216 | } |
217 | } |
218 | |
219 | #[inline ] |
220 | pub const fn sqr(self) -> TxSize { |
221 | match self { |
222 | TX_4X4 | TX_4X8 | TX_8X4 | TX_4X16 | TX_16X4 => TX_4X4, |
223 | TX_8X8 | TX_8X16 | TX_16X8 | TX_8X32 | TX_32X8 => TX_8X8, |
224 | TX_16X16 | TX_16X32 | TX_32X16 | TX_16X64 | TX_64X16 => TX_16X16, |
225 | TX_32X32 | TX_32X64 | TX_64X32 => TX_32X32, |
226 | TX_64X64 => TX_64X64, |
227 | } |
228 | } |
229 | |
230 | #[inline ] |
231 | pub const fn sqr_up(self) -> TxSize { |
232 | match self { |
233 | TX_4X4 => TX_4X4, |
234 | TX_8X8 | TX_4X8 | TX_8X4 => TX_8X8, |
235 | TX_16X16 | TX_8X16 | TX_16X8 | TX_4X16 | TX_16X4 => TX_16X16, |
236 | TX_32X32 | TX_16X32 | TX_32X16 | TX_8X32 | TX_32X8 => TX_32X32, |
237 | TX_64X64 | TX_32X64 | TX_64X32 | TX_16X64 | TX_64X16 => TX_64X64, |
238 | } |
239 | } |
240 | |
241 | #[inline ] |
242 | pub fn by_dims(w: usize, h: usize) -> TxSize { |
243 | match (w, h) { |
244 | (4, 4) => TX_4X4, |
245 | (8, 8) => TX_8X8, |
246 | (16, 16) => TX_16X16, |
247 | (32, 32) => TX_32X32, |
248 | (64, 64) => TX_64X64, |
249 | (4, 8) => TX_4X8, |
250 | (8, 4) => TX_8X4, |
251 | (8, 16) => TX_8X16, |
252 | (16, 8) => TX_16X8, |
253 | (16, 32) => TX_16X32, |
254 | (32, 16) => TX_32X16, |
255 | (32, 64) => TX_32X64, |
256 | (64, 32) => TX_64X32, |
257 | (4, 16) => TX_4X16, |
258 | (16, 4) => TX_16X4, |
259 | (8, 32) => TX_8X32, |
260 | (32, 8) => TX_32X8, |
261 | (16, 64) => TX_16X64, |
262 | (64, 16) => TX_64X16, |
263 | _ => unreachable!(), |
264 | } |
265 | } |
266 | |
267 | #[inline ] |
268 | pub const fn is_rect(self) -> bool { |
269 | self.width_log2() != self.height_log2() |
270 | } |
271 | } |
272 | |
273 | #[derive (Copy, Clone, PartialEq, Eq, PartialOrd)] |
274 | pub enum TxSet { |
275 | // DCT only |
276 | TX_SET_DCTONLY, |
277 | // DCT + Identity only |
278 | TX_SET_INTER_3, // TX_SET_DCT_IDTX |
279 | // Discrete Trig transforms w/o flip (4) + Identity (1) |
280 | TX_SET_INTRA_2, // TX_SET_DTT4_IDTX |
281 | // Discrete Trig transforms w/o flip (4) + Identity (1) + 1D Hor/vert DCT (2) |
282 | TX_SET_INTRA_1, // TX_SET_DTT4_IDTX_1DDCT |
283 | // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2) |
284 | TX_SET_INTER_2, // TX_SET_DTT9_IDTX_1DDCT |
285 | // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6) |
286 | TX_SET_INTER_1, // TX_SET_ALL16 |
287 | } |
288 | |
289 | /// Utility function that returns the log of the ratio of the col and row sizes. |
290 | #[inline ] |
291 | pub fn get_rect_tx_log_ratio(col: usize, row: usize) -> i8 { |
292 | debug_assert!(col > 0 && row > 0); |
293 | ILog::ilog(self:col) as i8 - ILog::ilog(self:row) as i8 |
294 | } |
295 | |
296 | // performs half a butterfly |
297 | #[inline ] |
298 | const fn half_btf(w0: i32, in0: i32, w1: i32, in1: i32, bit: usize) -> i32 { |
299 | // Ensure defined behaviour for when w0*in0 + w1*in1 is negative and |
300 | // overflows, but w0*in0 + w1*in1 + rounding isn't. |
301 | let result: i32 = (w0 * in0).wrapping_add(w1 * in1); |
302 | // Implement a version of round_shift with wrapping |
303 | if bit == 0 { |
304 | result |
305 | } else { |
306 | result.wrapping_add(1 << (bit - 1)) >> bit |
307 | } |
308 | } |
309 | |
310 | // clamps value to a signed integer type of bit bits |
311 | #[inline ] |
312 | fn clamp_value(value: i32, bit: usize) -> i32 { |
313 | let max_value: i32 = ((1i64 << (bit - 1)) - 1) as i32; |
314 | let min_value: i32 = (-(1i64 << (bit - 1))) as i32; |
315 | clamp(input:value, min_value, max_value) |
316 | } |
317 | |
318 | pub fn av1_round_shift_array(arr: &mut [i32], size: usize, bit: i8) { |
319 | if bit == 0 { |
320 | return; |
321 | } |
322 | if bit > 0 { |
323 | let bit: usize = bit as usize; |
324 | arr.iter_mut().take(size).for_each(|i: &mut i32| { |
325 | *i = round_shift(*i, bit); |
326 | }) |
327 | } else { |
328 | arr.iter_mut().take(size).for_each(|i: &mut i32| { |
329 | *i <<= -bit; |
330 | }) |
331 | } |
332 | } |
333 | |
334 | #[derive (Debug, Clone, Copy)] |
335 | enum TxType1D { |
336 | DCT, |
337 | ADST, |
338 | FLIPADST, |
339 | IDTX, |
340 | WHT, |
341 | } |
342 | |
343 | const fn get_1d_tx_types(tx_type: TxType) -> (TxType1D, TxType1D) { |
344 | match tx_type { |
345 | TxType::DCT_DCT => (TxType1D::DCT, TxType1D::DCT), |
346 | TxType::ADST_DCT => (TxType1D::ADST, TxType1D::DCT), |
347 | TxType::DCT_ADST => (TxType1D::DCT, TxType1D::ADST), |
348 | TxType::ADST_ADST => (TxType1D::ADST, TxType1D::ADST), |
349 | TxType::FLIPADST_DCT => (TxType1D::FLIPADST, TxType1D::DCT), |
350 | TxType::DCT_FLIPADST => (TxType1D::DCT, TxType1D::FLIPADST), |
351 | TxType::FLIPADST_FLIPADST => (TxType1D::FLIPADST, TxType1D::FLIPADST), |
352 | TxType::ADST_FLIPADST => (TxType1D::ADST, TxType1D::FLIPADST), |
353 | TxType::FLIPADST_ADST => (TxType1D::FLIPADST, TxType1D::ADST), |
354 | TxType::IDTX => (TxType1D::IDTX, TxType1D::IDTX), |
355 | TxType::V_DCT => (TxType1D::DCT, TxType1D::IDTX), |
356 | TxType::H_DCT => (TxType1D::IDTX, TxType1D::DCT), |
357 | TxType::V_ADST => (TxType1D::ADST, TxType1D::IDTX), |
358 | TxType::H_ADST => (TxType1D::IDTX, TxType1D::ADST), |
359 | TxType::V_FLIPADST => (TxType1D::FLIPADST, TxType1D::IDTX), |
360 | TxType::H_FLIPADST => (TxType1D::IDTX, TxType1D::FLIPADST), |
361 | TxType::WHT_WHT => (TxType1D::WHT, TxType1D::WHT), |
362 | } |
363 | } |
364 | |
365 | const VTX_TAB: [TxType1D; TX_TYPES_PLUS_LL] = [ |
366 | TxType1D::DCT, |
367 | TxType1D::ADST, |
368 | TxType1D::DCT, |
369 | TxType1D::ADST, |
370 | TxType1D::FLIPADST, |
371 | TxType1D::DCT, |
372 | TxType1D::FLIPADST, |
373 | TxType1D::ADST, |
374 | TxType1D::FLIPADST, |
375 | TxType1D::IDTX, |
376 | TxType1D::DCT, |
377 | TxType1D::IDTX, |
378 | TxType1D::ADST, |
379 | TxType1D::IDTX, |
380 | TxType1D::FLIPADST, |
381 | TxType1D::IDTX, |
382 | TxType1D::WHT, |
383 | ]; |
384 | |
385 | const HTX_TAB: [TxType1D; TX_TYPES_PLUS_LL] = [ |
386 | TxType1D::DCT, |
387 | TxType1D::DCT, |
388 | TxType1D::ADST, |
389 | TxType1D::ADST, |
390 | TxType1D::DCT, |
391 | TxType1D::FLIPADST, |
392 | TxType1D::FLIPADST, |
393 | TxType1D::FLIPADST, |
394 | TxType1D::ADST, |
395 | TxType1D::IDTX, |
396 | TxType1D::IDTX, |
397 | TxType1D::DCT, |
398 | TxType1D::IDTX, |
399 | TxType1D::ADST, |
400 | TxType1D::IDTX, |
401 | TxType1D::FLIPADST, |
402 | TxType1D::WHT, |
403 | ]; |
404 | |
405 | #[inline ] |
406 | pub const fn valid_av1_transform(tx_size: TxSize, tx_type: TxType) -> bool { |
407 | let size_sq: TxSize = tx_size.sqr_up(); |
408 | use TxSize::*; |
409 | use TxType::*; |
410 | match (size_sq, tx_type) { |
411 | (TX_64X64, DCT_DCT) => true, |
412 | (TX_64X64, _) => false, |
413 | (TX_32X32, DCT_DCT) => true, |
414 | (TX_32X32, IDTX) => true, |
415 | (TX_32X32, _) => false, |
416 | (_, _) => true, |
417 | } |
418 | } |
419 | |
420 | #[cfg (any(test, feature = "bench" ))] |
421 | pub fn get_valid_txfm_types(tx_size: TxSize) -> &'static [TxType] { |
422 | let size_sq = tx_size.sqr_up(); |
423 | use TxType::*; |
424 | if size_sq == TxSize::TX_64X64 { |
425 | &[DCT_DCT] |
426 | } else if size_sq == TxSize::TX_32X32 { |
427 | &[DCT_DCT, IDTX] |
428 | } else if size_sq == TxSize::TX_4X4 { |
429 | &[ |
430 | DCT_DCT, |
431 | ADST_DCT, |
432 | DCT_ADST, |
433 | ADST_ADST, |
434 | FLIPADST_DCT, |
435 | DCT_FLIPADST, |
436 | FLIPADST_FLIPADST, |
437 | ADST_FLIPADST, |
438 | FLIPADST_ADST, |
439 | IDTX, |
440 | V_DCT, |
441 | H_DCT, |
442 | V_ADST, |
443 | H_ADST, |
444 | V_FLIPADST, |
445 | H_FLIPADST, |
446 | WHT_WHT, |
447 | ] |
448 | } else { |
449 | &[ |
450 | DCT_DCT, |
451 | ADST_DCT, |
452 | DCT_ADST, |
453 | ADST_ADST, |
454 | FLIPADST_DCT, |
455 | DCT_FLIPADST, |
456 | FLIPADST_FLIPADST, |
457 | ADST_FLIPADST, |
458 | FLIPADST_ADST, |
459 | IDTX, |
460 | V_DCT, |
461 | H_DCT, |
462 | V_ADST, |
463 | H_ADST, |
464 | V_FLIPADST, |
465 | H_FLIPADST, |
466 | ] |
467 | } |
468 | } |
469 | |
470 | #[cfg (test)] |
471 | mod test { |
472 | use super::TxType::*; |
473 | use super::*; |
474 | use crate::context::av1_get_coded_tx_size; |
475 | use crate::cpu_features::CpuFeatureLevel; |
476 | use crate::frame::*; |
477 | use rand::random; |
478 | use std::mem::MaybeUninit; |
479 | |
480 | fn test_roundtrip<T: Pixel>( |
481 | tx_size: TxSize, tx_type: TxType, tolerance: i16, |
482 | ) { |
483 | let cpu = CpuFeatureLevel::default(); |
484 | |
485 | let coeff_area: usize = av1_get_coded_tx_size(tx_size).area(); |
486 | let mut src_storage = [T::cast_from(0); 64 * 64]; |
487 | let src = &mut src_storage[..tx_size.area()]; |
488 | let mut dst = Plane::from_slice( |
489 | &[T::zero(); 64 * 64][..tx_size.area()], |
490 | tx_size.width(), |
491 | ); |
492 | let mut res_storage = [0i16; 64 * 64]; |
493 | let res = &mut res_storage[..tx_size.area()]; |
494 | let mut freq_storage = [MaybeUninit::uninit(); 64 * 64]; |
495 | let freq = &mut freq_storage[..tx_size.area()]; |
496 | for ((r, s), d) in |
497 | res.iter_mut().zip(src.iter_mut()).zip(dst.data.iter_mut()) |
498 | { |
499 | *s = T::cast_from(random::<u8>()); |
500 | *d = T::cast_from(random::<u8>()); |
501 | *r = i16::cast_from(*s) - i16::cast_from(*d); |
502 | } |
503 | forward_transform(res, freq, tx_size.width(), tx_size, tx_type, 8, cpu); |
504 | // SAFETY: forward_transform initialized freq |
505 | let freq = unsafe { slice_assume_init_mut(freq) }; |
506 | inverse_transform_add( |
507 | freq, |
508 | &mut dst.as_region_mut(), |
509 | coeff_area.try_into().unwrap(), |
510 | tx_size, |
511 | tx_type, |
512 | 8, |
513 | cpu, |
514 | ); |
515 | |
516 | for (s, d) in src.iter().zip(dst.data.iter()) { |
517 | assert!(i16::abs(i16::cast_from(*s) - i16::cast_from(*d)) <= tolerance); |
518 | } |
519 | } |
520 | |
521 | #[test ] |
522 | fn log_tx_ratios() { |
523 | let combinations = [ |
524 | (TxSize::TX_4X4, 0), |
525 | (TxSize::TX_8X8, 0), |
526 | (TxSize::TX_16X16, 0), |
527 | (TxSize::TX_32X32, 0), |
528 | (TxSize::TX_64X64, 0), |
529 | (TxSize::TX_4X8, -1), |
530 | (TxSize::TX_8X4, 1), |
531 | (TxSize::TX_8X16, -1), |
532 | (TxSize::TX_16X8, 1), |
533 | (TxSize::TX_16X32, -1), |
534 | (TxSize::TX_32X16, 1), |
535 | (TxSize::TX_32X64, -1), |
536 | (TxSize::TX_64X32, 1), |
537 | (TxSize::TX_4X16, -2), |
538 | (TxSize::TX_16X4, 2), |
539 | (TxSize::TX_8X32, -2), |
540 | (TxSize::TX_32X8, 2), |
541 | (TxSize::TX_16X64, -2), |
542 | (TxSize::TX_64X16, 2), |
543 | ]; |
544 | |
545 | for &(tx_size, expected) in combinations.iter() { |
546 | println!( |
547 | "Testing combination {:?}, {:?}" , |
548 | tx_size.width(), |
549 | tx_size.height() |
550 | ); |
551 | assert!( |
552 | get_rect_tx_log_ratio(tx_size.width(), tx_size.height()) == expected |
553 | ); |
554 | } |
555 | } |
556 | |
557 | fn roundtrips<T: Pixel>() { |
558 | let combinations = [ |
559 | (TX_4X4, WHT_WHT, 0), |
560 | (TX_4X4, DCT_DCT, 0), |
561 | (TX_4X4, ADST_DCT, 0), |
562 | (TX_4X4, DCT_ADST, 0), |
563 | (TX_4X4, ADST_ADST, 0), |
564 | (TX_4X4, FLIPADST_DCT, 0), |
565 | (TX_4X4, DCT_FLIPADST, 0), |
566 | (TX_4X4, IDTX, 0), |
567 | (TX_4X4, V_DCT, 0), |
568 | (TX_4X4, H_DCT, 0), |
569 | (TX_4X4, V_ADST, 0), |
570 | (TX_4X4, H_ADST, 0), |
571 | (TX_8X8, DCT_DCT, 1), |
572 | (TX_8X8, ADST_DCT, 1), |
573 | (TX_8X8, DCT_ADST, 1), |
574 | (TX_8X8, ADST_ADST, 1), |
575 | (TX_8X8, FLIPADST_DCT, 1), |
576 | (TX_8X8, DCT_FLIPADST, 1), |
577 | (TX_8X8, IDTX, 0), |
578 | (TX_8X8, V_DCT, 0), |
579 | (TX_8X8, H_DCT, 0), |
580 | (TX_8X8, V_ADST, 0), |
581 | (TX_8X8, H_ADST, 1), |
582 | (TX_16X16, DCT_DCT, 1), |
583 | (TX_16X16, ADST_DCT, 1), |
584 | (TX_16X16, DCT_ADST, 1), |
585 | (TX_16X16, ADST_ADST, 1), |
586 | (TX_16X16, FLIPADST_DCT, 1), |
587 | (TX_16X16, DCT_FLIPADST, 1), |
588 | (TX_16X16, IDTX, 0), |
589 | (TX_16X16, V_DCT, 1), |
590 | (TX_16X16, H_DCT, 1), |
591 | // 32x transforms only use DCT_DCT and IDTX |
592 | (TX_32X32, DCT_DCT, 2), |
593 | (TX_32X32, IDTX, 0), |
594 | // 64x transforms only use DCT_DCT and IDTX |
595 | //(TX_64X64, DCT_DCT, 0), |
596 | (TX_4X8, DCT_DCT, 1), |
597 | (TX_8X4, DCT_DCT, 1), |
598 | (TX_4X16, DCT_DCT, 1), |
599 | (TX_16X4, DCT_DCT, 1), |
600 | (TX_8X16, DCT_DCT, 1), |
601 | (TX_16X8, DCT_DCT, 1), |
602 | (TX_8X32, DCT_DCT, 2), |
603 | (TX_32X8, DCT_DCT, 2), |
604 | (TX_16X32, DCT_DCT, 2), |
605 | (TX_32X16, DCT_DCT, 2), |
606 | ]; |
607 | for &(tx_size, tx_type, tolerance) in combinations.iter() { |
608 | println!("Testing combination {:?}, {:?}" , tx_size, tx_type); |
609 | test_roundtrip::<T>(tx_size, tx_type, tolerance); |
610 | } |
611 | } |
612 | |
613 | #[test ] |
614 | fn roundtrips_u8() { |
615 | roundtrips::<u8>(); |
616 | } |
617 | |
618 | #[test ] |
619 | fn roundtrips_u16() { |
620 | roundtrips::<u16>(); |
621 | } |
622 | } |
623 | |