Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 1 | /* |
Yaowu Xu | bde4ac8 | 2016-11-28 15:26:06 -0800 | [diff] [blame] | 2 | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 3 | * |
Yaowu Xu | bde4ac8 | 2016-11-28 15:26:06 -0800 | [diff] [blame] | 4 | * This source code is subject to the terms of the BSD 2 Clause License and |
| 5 | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| 6 | * was not distributed with this source code in the LICENSE file, you can |
| 7 | * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| 8 | * Media Patent License 1.0 was not distributed with this source code in the |
| 9 | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 10 | */ |
| 11 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 12 | #include "./av1_rtcd.h" |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 13 | #include "av1/common/enums.h" |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 14 | #include "av1/common/av1_txfm.h" |
| 15 | #include "av1/common/av1_inv_txfm1d.h" |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 16 | #include "av1/common/av1_inv_txfm1d_cfg.h" |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 17 | |
| 18 | static INLINE TxfmFunc inv_txfm_type_to_func(TXFM_TYPE txfm_type) { |
| 19 | switch (txfm_type) { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 20 | case TXFM_TYPE_DCT4: return av1_idct4_new; |
| 21 | case TXFM_TYPE_DCT8: return av1_idct8_new; |
| 22 | case TXFM_TYPE_DCT16: return av1_idct16_new; |
| 23 | case TXFM_TYPE_DCT32: return av1_idct32_new; |
| 24 | case TXFM_TYPE_ADST4: return av1_iadst4_new; |
| 25 | case TXFM_TYPE_ADST8: return av1_iadst8_new; |
| 26 | case TXFM_TYPE_ADST16: return av1_iadst16_new; |
| 27 | case TXFM_TYPE_ADST32: return av1_iadst32_new; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 28 | default: assert(0); return NULL; |
| 29 | } |
| 30 | } |
| 31 | |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 32 | static const TXFM_1D_CFG *inv_txfm_col_cfg_ls[TX_TYPES_1D][TX_SIZES] = { |
| 33 | // DCT |
Frank Galligan | 0b73f3e | 2017-05-03 22:43:22 +0000 | [diff] [blame] | 34 | { |
| 35 | #if CONFIG_CB4X4 |
| 36 | NULL, |
| 37 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 38 | &inv_txfm_1d_col_cfg_dct_4, &inv_txfm_1d_col_cfg_dct_8, |
| 39 | &inv_txfm_1d_col_cfg_dct_16, &inv_txfm_1d_col_cfg_dct_32 }, |
| 40 | // ADST |
Frank Galligan | 0b73f3e | 2017-05-03 22:43:22 +0000 | [diff] [blame] | 41 | { |
| 42 | #if CONFIG_CB4X4 |
| 43 | NULL, |
| 44 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 45 | &inv_txfm_1d_col_cfg_adst_4, &inv_txfm_1d_col_cfg_adst_8, |
| 46 | &inv_txfm_1d_col_cfg_adst_16, &inv_txfm_1d_col_cfg_adst_32 }, |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 47 | #if CONFIG_EXT_TX |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 48 | // FLIPADST |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 49 | { |
| 50 | #if CONFIG_CB4X4 |
| 51 | NULL, |
Frank Galligan | 0b73f3e | 2017-05-03 22:43:22 +0000 | [diff] [blame] | 52 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 53 | &inv_txfm_1d_col_cfg_adst_4, &inv_txfm_1d_col_cfg_adst_8, |
| 54 | &inv_txfm_1d_col_cfg_adst_16, &inv_txfm_1d_col_cfg_adst_32 }, |
| 55 | // IDENTITY PLACEHOLDER |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 56 | { |
| 57 | #if CONFIG_CB4X4 |
| 58 | NULL, |
| 59 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 60 | &inv_txfm_1d_col_cfg_adst_4, &inv_txfm_1d_col_cfg_adst_8, |
| 61 | &inv_txfm_1d_col_cfg_adst_16, &inv_txfm_1d_col_cfg_adst_32 }, |
| 62 | #endif // CONFIG_EXT_TX |
| 63 | }; |
| 64 | |
| 65 | static const TXFM_1D_CFG *inv_txfm_row_cfg_ls[TX_TYPES_1D][TX_SIZES] = { |
| 66 | // DCT |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 67 | { |
| 68 | #if CONFIG_CB4X4 |
| 69 | NULL, |
| 70 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 71 | &inv_txfm_1d_row_cfg_dct_4, &inv_txfm_1d_row_cfg_dct_8, |
| 72 | &inv_txfm_1d_row_cfg_dct_16, &inv_txfm_1d_row_cfg_dct_32 }, |
| 73 | // ADST |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 74 | { |
| 75 | #if CONFIG_CB4X4 |
| 76 | NULL, |
| 77 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 78 | &inv_txfm_1d_row_cfg_adst_4, &inv_txfm_1d_row_cfg_adst_8, |
| 79 | &inv_txfm_1d_row_cfg_adst_16, &inv_txfm_1d_row_cfg_adst_32 }, |
| 80 | #if CONFIG_EXT_TX |
| 81 | // FLIPADST |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 82 | { |
| 83 | #if CONFIG_CB4X4 |
| 84 | NULL, |
| 85 | #endif |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 86 | &inv_txfm_1d_row_cfg_adst_4, &inv_txfm_1d_row_cfg_adst_8, |
| 87 | &inv_txfm_1d_row_cfg_adst_16, &inv_txfm_1d_row_cfg_adst_32 }, |
| 88 | // IDENTITY PLACEHOLDER |
| 89 | { |
| 90 | #if CONFIG_CB4X4 |
| 91 | NULL, |
| 92 | #endif |
| 93 | &inv_txfm_1d_row_cfg_adst_4, &inv_txfm_1d_row_cfg_adst_8, |
| 94 | &inv_txfm_1d_row_cfg_adst_16, &inv_txfm_1d_row_cfg_adst_32 }, |
Fred BARBIER | b72ab8f | 2017-05-08 20:01:07 +0200 | [diff] [blame] | 95 | #endif // CONFIG_EXT_TX |
| 96 | }; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 97 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 98 | TXFM_2D_FLIP_CFG av1_get_inv_txfm_cfg(int tx_type, int tx_size) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 99 | TXFM_2D_FLIP_CFG cfg; |
| 100 | set_flip_cfg(tx_type, &cfg); |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 101 | int tx_type_col = vtx_tab[tx_type]; |
| 102 | int tx_type_row = htx_tab[tx_type]; |
| 103 | // TODO(sarahparker) this is currently only implemented for |
| 104 | // square transforms |
| 105 | cfg.col_cfg = inv_txfm_col_cfg_ls[tx_type_col][tx_size]; |
| 106 | cfg.row_cfg = inv_txfm_row_cfg_ls[tx_type_row][tx_size]; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 107 | return cfg; |
| 108 | } |
| 109 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 110 | TXFM_2D_FLIP_CFG av1_get_inv_txfm_64x64_cfg(int tx_type) { |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 111 | TXFM_2D_FLIP_CFG cfg = { 0, 0, NULL, NULL }; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 112 | switch (tx_type) { |
| 113 | case DCT_DCT: |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 114 | cfg.col_cfg = &inv_txfm_1d_col_cfg_dct_64; |
| 115 | cfg.row_cfg = &inv_txfm_1d_row_cfg_dct_64; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 116 | set_flip_cfg(tx_type, &cfg); |
| 117 | break; |
| 118 | default: assert(0); |
| 119 | } |
| 120 | return cfg; |
| 121 | } |
| 122 | |
| 123 | static INLINE void inv_txfm2d_add_c(const int32_t *input, int16_t *output, |
| 124 | int stride, TXFM_2D_FLIP_CFG *cfg, |
| 125 | int32_t *txfm_buf) { |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 126 | // TODO(sarahparker) must correct for rectangular transforms in follow up |
| 127 | const int txfm_size = cfg->row_cfg->txfm_size; |
| 128 | const int8_t *shift = cfg->row_cfg->shift; |
| 129 | const int8_t *stage_range_col = cfg->col_cfg->stage_range; |
| 130 | const int8_t *stage_range_row = cfg->row_cfg->stage_range; |
| 131 | const int8_t *cos_bit_col = cfg->col_cfg->cos_bit; |
| 132 | const int8_t *cos_bit_row = cfg->row_cfg->cos_bit; |
| 133 | const TxfmFunc txfm_func_col = inv_txfm_type_to_func(cfg->col_cfg->txfm_type); |
| 134 | const TxfmFunc txfm_func_row = inv_txfm_type_to_func(cfg->row_cfg->txfm_type); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 135 | |
| 136 | // txfm_buf's length is txfm_size * txfm_size + 2 * txfm_size |
| 137 | // it is used for intermediate data buffering |
| 138 | int32_t *temp_in = txfm_buf; |
| 139 | int32_t *temp_out = temp_in + txfm_size; |
| 140 | int32_t *buf = temp_out + txfm_size; |
| 141 | int32_t *buf_ptr = buf; |
| 142 | int c, r; |
| 143 | |
| 144 | // Rows |
| 145 | for (r = 0; r < txfm_size; ++r) { |
| 146 | txfm_func_row(input, buf_ptr, cos_bit_row, stage_range_row); |
| 147 | round_shift_array(buf_ptr, txfm_size, -shift[0]); |
| 148 | input += txfm_size; |
| 149 | buf_ptr += txfm_size; |
| 150 | } |
| 151 | |
| 152 | // Columns |
| 153 | for (c = 0; c < txfm_size; ++c) { |
| 154 | if (cfg->lr_flip == 0) { |
| 155 | for (r = 0; r < txfm_size; ++r) temp_in[r] = buf[r * txfm_size + c]; |
| 156 | } else { |
| 157 | // flip left right |
| 158 | for (r = 0; r < txfm_size; ++r) |
| 159 | temp_in[r] = buf[r * txfm_size + (txfm_size - c - 1)]; |
| 160 | } |
| 161 | txfm_func_col(temp_in, temp_out, cos_bit_col, stage_range_col); |
| 162 | round_shift_array(temp_out, txfm_size, -shift[1]); |
| 163 | if (cfg->ud_flip == 0) { |
| 164 | for (r = 0; r < txfm_size; ++r) output[r * stride + c] += temp_out[r]; |
| 165 | } else { |
| 166 | // flip upside down |
| 167 | for (r = 0; r < txfm_size; ++r) |
| 168 | output[r * stride + c] += temp_out[txfm_size - r - 1]; |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 173 | static INLINE void inv_txfm2d_add_facade(const int32_t *input, uint16_t *output, |
| 174 | int stride, int32_t *txfm_buf, |
| 175 | int tx_type, int tx_size, int bd) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 176 | // output contains the prediction signal which is always positive and smaller |
| 177 | // than (1 << bd) - 1 |
| 178 | // since bd < 16-1, therefore we can treat the uint16_t* output buffer as an |
| 179 | // int16_t* |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 180 | TXFM_2D_FLIP_CFG cfg = av1_get_inv_txfm_cfg(tx_type, tx_size); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 181 | inv_txfm2d_add_c(input, (int16_t *)output, stride, &cfg, txfm_buf); |
Sarah Parker | eec47e6 | 2017-05-15 20:49:22 -0700 | [diff] [blame^] | 182 | // TODO(sarahparker) just using the cfg_row->txfm_size for now because |
| 183 | // we are assumint this is only used for square transforms. This will |
| 184 | // be adjusted in a follow up |
| 185 | clamp_block((int16_t *)output, cfg.row_cfg->txfm_size, stride, 0, |
| 186 | (1 << bd) - 1); |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | void av1_inv_txfm2d_add_4x4_c(const int32_t *input, uint16_t *output, |
| 190 | int stride, int tx_type, int bd) { |
| 191 | int txfm_buf[4 * 4 + 4 + 4]; |
| 192 | inv_txfm2d_add_facade(input, output, stride, txfm_buf, tx_type, TX_4X4, bd); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 193 | } |
| 194 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 195 | void av1_inv_txfm2d_add_8x8_c(const int32_t *input, uint16_t *output, |
| 196 | int stride, int tx_type, int bd) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 197 | int txfm_buf[8 * 8 + 8 + 8]; |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 198 | inv_txfm2d_add_facade(input, output, stride, txfm_buf, tx_type, TX_8X8, bd); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 199 | } |
| 200 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 201 | void av1_inv_txfm2d_add_16x16_c(const int32_t *input, uint16_t *output, |
| 202 | int stride, int tx_type, int bd) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 203 | int txfm_buf[16 * 16 + 16 + 16]; |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 204 | inv_txfm2d_add_facade(input, output, stride, txfm_buf, tx_type, TX_16X16, bd); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 205 | } |
| 206 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 207 | void av1_inv_txfm2d_add_32x32_c(const int32_t *input, uint16_t *output, |
| 208 | int stride, int tx_type, int bd) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 209 | int txfm_buf[32 * 32 + 32 + 32]; |
Frederic Barbier | c53753f | 2017-04-25 11:05:01 +0200 | [diff] [blame] | 210 | inv_txfm2d_add_facade(input, output, stride, txfm_buf, tx_type, TX_32X32, bd); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 211 | } |
| 212 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 213 | void av1_inv_txfm2d_add_64x64_c(const int32_t *input, uint16_t *output, |
| 214 | int stride, int tx_type, int bd) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 215 | int txfm_buf[64 * 64 + 64 + 64]; |
| 216 | // output contains the prediction signal which is always positive and smaller |
| 217 | // than (1 << bd) - 1 |
| 218 | // since bd < 16-1, therefore we can treat the uint16_t* output buffer as an |
| 219 | // int16_t* |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 220 | TXFM_2D_FLIP_CFG cfg = av1_get_inv_txfm_64x64_cfg(tx_type); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 221 | inv_txfm2d_add_c(input, (int16_t *)output, stride, &cfg, txfm_buf); |
| 222 | clamp_block((int16_t *)output, 64, stride, 0, (1 << bd) - 1); |
| 223 | } |