Partial IDCT 16x16 avx2
- Function level improvement:
functions sse2 avx2 percentage
idct16x16_256 365 226 38%
idct16x16_38 n/a 136 n/a
idct16x16_10 171 110 35%
idct16x16_1 34 26 23%
- Integrated in AV1 for default scan order.
Change-Id: Ieb1a8e730bea9c371ebc0e5f4a748640d8f5e921
diff --git a/aom_dsp/aom_dsp.cmake b/aom_dsp/aom_dsp.cmake
index f00348c..75ee564 100644
--- a/aom_dsp/aom_dsp.cmake
+++ b/aom_dsp/aom_dsp.cmake
@@ -62,8 +62,10 @@
set(AOM_DSP_COMMON_INTRIN_AVX2
"${AOM_ROOT}/aom_dsp/x86/aom_subpixel_8t_intrin_avx2.c"
- "${AOM_ROOT}/aom_dsp/x86/fwd_txfm_avx2.c"
- "${AOM_ROOT}/aom_dsp/x86/loopfilter_avx2.c")
+ "${AOM_ROOT}/aom_dsp/x86/loopfilter_avx2.c"
+ "${AOM_ROOT}/aom_dsp/x86/inv_txfm_avx2.c"
+ "${AOM_ROOT}/aom_dsp/x86/inv_txfm_common_avx2.h"
+ "${AOM_ROOT}/aom_dsp/x86/txfm_common_avx2.h")
set(AOM_DSP_COMMON_ASM_NEON
"${AOM_ROOT}/aom_dsp/arm/aom_convolve8_avg_neon_asm.asm"
@@ -282,6 +284,9 @@
set(AOM_DSP_ENCODER_ASM_SSE4_1 "${AOM_ROOT}/aom_dsp/x86/sad_sse4.asm")
set(AOM_DSP_ENCODER_INTRIN_AVX2
+ "${AOM_ROOT}/aom_dsp/x86/fwd_dct32x32_impl_avx2.h"
+ "${AOM_ROOT}/aom_dsp/x86/fwd_txfm_avx2.c"
+ "${AOM_ROOT}/aom_dsp/x86/fwd_txfm_avx2.h"
"${AOM_ROOT}/aom_dsp/x86/sad4d_avx2.c"
"${AOM_ROOT}/aom_dsp/x86/sad_avx2.c"
"${AOM_ROOT}/aom_dsp/x86/sad_impl_avx2.c"
diff --git a/aom_dsp/aom_dsp.mk b/aom_dsp/aom_dsp.mk
index 5980b81..0d96f71 100644
--- a/aom_dsp/aom_dsp.mk
+++ b/aom_dsp/aom_dsp.mk
@@ -240,6 +240,8 @@
DSP_SRCS-$(HAVE_SSE2) += x86/inv_txfm_sse2.c
DSP_SRCS-$(HAVE_SSE2) += x86/inv_wht_sse2.asm
DSP_SRCS-$(HAVE_SSSE3) += x86/inv_txfm_ssse3.c
+DSP_SRCS-$(HAVE_AVX2) += x86/inv_txfm_common_avx2.h
+DSP_SRCS-$(HAVE_AVX2) += x86/inv_txfm_avx2.c
ifeq ($(HAVE_NEON_ASM),yes)
DSP_SRCS-yes += arm/save_reg_neon$(ASM)
diff --git a/aom_dsp/aom_dsp_rtcd_defs.pl b/aom_dsp/aom_dsp_rtcd_defs.pl
index 4929de7..008a857 100755
--- a/aom_dsp/aom_dsp_rtcd_defs.pl
+++ b/aom_dsp/aom_dsp_rtcd_defs.pl
@@ -437,15 +437,16 @@
specialize qw/aom_idct8x8_1_add sse2/;
add_proto qw/void aom_idct16x16_256_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_256_add sse2/;
+ specialize qw/aom_idct16x16_256_add sse2 avx2/;
add_proto qw/void aom_idct16x16_38_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
+ specialize qw/aom_idct16x16_38_add avx2/;
add_proto qw/void aom_idct16x16_10_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_10_add sse2/;
+ specialize qw/aom_idct16x16_10_add sse2 avx2/;
add_proto qw/void aom_idct16x16_1_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_1_add sse2/;
+ specialize qw/aom_idct16x16_1_add sse2 avx2/;
add_proto qw/void aom_idct32x32_1024_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
specialize qw/aom_idct32x32_1024_add sse2 ssse3/;
@@ -482,15 +483,16 @@
specialize qw/aom_idct8x8_12_add sse2 ssse3 neon dspr2 msa/;
add_proto qw/void aom_idct16x16_1_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_1_add sse2 neon dspr2 msa/;
+ specialize qw/aom_idct16x16_1_add sse2 avx2 neon dspr2 msa/;
add_proto qw/void aom_idct16x16_256_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_256_add sse2 neon dspr2 msa/;
+ specialize qw/aom_idct16x16_256_add sse2 avx2 neon dspr2 msa/;
add_proto qw/void aom_idct16x16_38_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
+ specialize qw/aom_idct16x16_38_add avx2/;
add_proto qw/void aom_idct16x16_10_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/aom_idct16x16_10_add sse2 neon dspr2 msa/;
+ specialize qw/aom_idct16x16_10_add sse2 avx2 neon dspr2 msa/;
add_proto qw/void aom_idct32x32_1024_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
specialize qw/aom_idct32x32_1024_add sse2 ssse3 neon dspr2 msa/;
diff --git a/aom_dsp/x86/inv_txfm_avx2.c b/aom_dsp/x86/inv_txfm_avx2.c
new file mode 100644
index 0000000..098e019
--- /dev/null
+++ b/aom_dsp/x86/inv_txfm_avx2.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2017, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#include <immintrin.h>
+
+#include "./aom_dsp_rtcd.h"
+#include "aom_dsp/inv_txfm.h"
+#include "aom_dsp/x86/inv_txfm_common_avx2.h"
+#include "aom_dsp/x86/txfm_common_avx2.h"
+
+void aom_idct16x16_256_add_avx2(const tran_low_t *input, uint8_t *dest,
+ int stride) {
+ __m256i in[16];
+ load_buffer_16x16(input, in);
+ mm256_transpose_16x16(in);
+ av1_idct16_avx2(in);
+ mm256_transpose_16x16(in);
+ av1_idct16_avx2(in);
+ write_buffer_16x16(in, stride, dest);
+}
+
+static INLINE void transpose_col_to_row_nz4x4(__m256i *in /*in[4]*/) {
+ const __m256i u0 = _mm256_unpacklo_epi16(in[0], in[1]);
+ const __m256i u1 = _mm256_unpacklo_epi16(in[2], in[3]);
+ const __m256i v0 = _mm256_unpacklo_epi32(u0, u1);
+ const __m256i v1 = _mm256_unpackhi_epi32(u0, u1);
+ in[0] = _mm256_permute4x64_epi64(v0, 0xA8);
+ in[1] = _mm256_permute4x64_epi64(v0, 0xA9);
+ in[2] = _mm256_permute4x64_epi64(v1, 0xA8);
+ in[3] = _mm256_permute4x64_epi64(v1, 0xA9);
+}
+
+#define SHUFFLE_EPI64(x0, x1, imm8) \
+ (__m256i) _mm256_shuffle_pd((__m256d)x0, (__m256d)x1, imm8)
+
+static INLINE void transpose_col_to_row_nz4x16(__m256i *in /*in[16]*/) {
+ int i;
+ for (i = 0; i < 16; i += 4) {
+ transpose_col_to_row_nz4x4(&in[i]);
+ }
+
+ for (i = 0; i < 4; ++i) {
+ in[i] = SHUFFLE_EPI64(in[i], in[i + 4], 0);
+ in[i + 8] = SHUFFLE_EPI64(in[i + 8], in[i + 12], 0);
+ }
+
+ for (i = 0; i < 4; ++i) {
+ in[i] = _mm256_permute2x128_si256(in[i], in[i + 8], 0x20);
+ }
+}
+
+// Coefficients 0-7 before the final butterfly
+static INLINE void idct16_10_first_half(const __m256i *in, __m256i *out) {
+ const __m256i c2p28 = pair256_set_epi16(2 * cospi_28_64, 2 * cospi_28_64);
+ const __m256i c2p04 = pair256_set_epi16(2 * cospi_4_64, 2 * cospi_4_64);
+ const __m256i v4 = _mm256_mulhrs_epi16(in[2], c2p28);
+ const __m256i v7 = _mm256_mulhrs_epi16(in[2], c2p04);
+
+ const __m256i c2p16 = pair256_set_epi16(2 * cospi_16_64, 2 * cospi_16_64);
+ const __m256i v0 = _mm256_mulhrs_epi16(in[0], c2p16);
+ const __m256i v1 = v0;
+
+ const __m256i cospi_p16_p16 = _mm256_set1_epi16((int16_t)cospi_16_64);
+ const __m256i cospi_p16_m16 = pair256_set_epi16(cospi_16_64, -cospi_16_64);
+ __m256i v5, v6;
+ unpack_butter_fly(&v7, &v4, &cospi_p16_m16, &cospi_p16_p16, &v5, &v6);
+
+ out[0] = _mm256_add_epi16(v0, v7);
+ out[1] = _mm256_add_epi16(v1, v6);
+ out[2] = _mm256_add_epi16(v1, v5);
+ out[3] = _mm256_add_epi16(v0, v4);
+ out[4] = _mm256_sub_epi16(v0, v4);
+ out[5] = _mm256_sub_epi16(v1, v5);
+ out[6] = _mm256_sub_epi16(v1, v6);
+ out[7] = _mm256_sub_epi16(v0, v7);
+}
+
+// Coefficients 8-15 before the final butterfly
+static INLINE void idct16_10_second_half(const __m256i *in, __m256i *out) {
+ const __m256i c2p30 = pair256_set_epi16(2 * cospi_30_64, 2 * cospi_30_64);
+ const __m256i c2p02 = pair256_set_epi16(2 * cospi_2_64, 2 * cospi_2_64);
+ const __m256i t0 = _mm256_mulhrs_epi16(in[1], c2p30);
+ const __m256i t7 = _mm256_mulhrs_epi16(in[1], c2p02);
+
+ const __m256i c2m26 = pair256_set_epi16(-2 * cospi_26_64, -2 * cospi_26_64);
+ const __m256i c2p06 = pair256_set_epi16(2 * cospi_6_64, 2 * cospi_6_64);
+ const __m256i t3 = _mm256_mulhrs_epi16(in[3], c2m26);
+ const __m256i t4 = _mm256_mulhrs_epi16(in[3], c2p06);
+
+ const __m256i cospi_m08_p24 = pair256_set_epi16(-cospi_8_64, cospi_24_64);
+ const __m256i cospi_p24_p08 = pair256_set_epi16(cospi_24_64, cospi_8_64);
+ const __m256i cospi_m24_m08 = pair256_set_epi16(-cospi_24_64, -cospi_8_64);
+
+ __m256i t1, t2, t5, t6;
+ unpack_butter_fly(&t0, &t7, &cospi_m08_p24, &cospi_p24_p08, &t1, &t6);
+ unpack_butter_fly(&t3, &t4, &cospi_m24_m08, &cospi_m08_p24, &t2, &t5);
+
+ out[0] = _mm256_add_epi16(t0, t3);
+ out[1] = _mm256_add_epi16(t1, t2);
+ out[6] = _mm256_add_epi16(t6, t5);
+ out[7] = _mm256_add_epi16(t7, t4);
+
+ const __m256i v2 = _mm256_sub_epi16(t1, t2);
+ const __m256i v3 = _mm256_sub_epi16(t0, t3);
+ const __m256i v4 = _mm256_sub_epi16(t7, t4);
+ const __m256i v5 = _mm256_sub_epi16(t6, t5);
+ const __m256i cospi_p16_p16 = _mm256_set1_epi16((int16_t)cospi_16_64);
+ const __m256i cospi_p16_m16 = pair256_set_epi16(cospi_16_64, -cospi_16_64);
+ unpack_butter_fly(&v5, &v2, &cospi_p16_m16, &cospi_p16_p16, &out[2], &out[5]);
+ unpack_butter_fly(&v4, &v3, &cospi_p16_m16, &cospi_p16_p16, &out[3], &out[4]);
+}
+
+static INLINE void add_sub_butterfly(const __m256i *in, __m256i *out,
+ int size) {
+ int i = 0;
+ const int num = size >> 1;
+ const int bound = size - 1;
+ while (i < num) {
+ out[i] = _mm256_add_epi16(in[i], in[bound - i]);
+ out[bound - i] = _mm256_sub_epi16(in[i], in[bound - i]);
+ i++;
+ }
+}
+
+static INLINE void idct16_10(__m256i *in /*in[16]*/) {
+ __m256i out[16];
+ idct16_10_first_half(in, out);
+ idct16_10_second_half(in, &out[8]);
+ add_sub_butterfly(out, in, 16);
+}
+
+void aom_idct16x16_10_add_avx2(const tran_low_t *input, uint8_t *dest,
+ int stride) {
+ __m256i in[16];
+
+ load_coeff(input, &in[0]);
+ load_coeff(input + 16, &in[1]);
+ load_coeff(input + 32, &in[2]);
+ load_coeff(input + 48, &in[3]);
+
+ transpose_col_to_row_nz4x4(in);
+ idct16_10(in);
+
+ transpose_col_to_row_nz4x16(in);
+ idct16_10(in);
+
+ write_buffer_16x16(in, stride, dest);
+}
+
+// Note:
+// For 16x16 int16_t matrix
+// transpose first 8 columns into first 8 rows.
+// Since only upper-left 8x8 are non-zero, the input are first 8 rows (in[8]).
+// After transposing, the 8 row vectors are in in[8].
+void transpose_col_to_row_nz8x8(__m256i *in /*in[8]*/) {
+ __m256i u0 = _mm256_unpacklo_epi16(in[0], in[1]);
+ __m256i u1 = _mm256_unpackhi_epi16(in[0], in[1]);
+ __m256i u2 = _mm256_unpacklo_epi16(in[2], in[3]);
+ __m256i u3 = _mm256_unpackhi_epi16(in[2], in[3]);
+
+ const __m256i v0 = _mm256_unpacklo_epi32(u0, u2);
+ const __m256i v1 = _mm256_unpackhi_epi32(u0, u2);
+ const __m256i v2 = _mm256_unpacklo_epi32(u1, u3);
+ const __m256i v3 = _mm256_unpackhi_epi32(u1, u3);
+
+ u0 = _mm256_unpacklo_epi16(in[4], in[5]);
+ u1 = _mm256_unpackhi_epi16(in[4], in[5]);
+ u2 = _mm256_unpacklo_epi16(in[6], in[7]);
+ u3 = _mm256_unpackhi_epi16(in[6], in[7]);
+
+ const __m256i v4 = _mm256_unpacklo_epi32(u0, u2);
+ const __m256i v5 = _mm256_unpackhi_epi32(u0, u2);
+ const __m256i v6 = _mm256_unpacklo_epi32(u1, u3);
+ const __m256i v7 = _mm256_unpackhi_epi32(u1, u3);
+
+ in[0] = SHUFFLE_EPI64(v0, v4, 0);
+ in[1] = SHUFFLE_EPI64(v0, v4, 3);
+ in[2] = SHUFFLE_EPI64(v1, v5, 0);
+ in[3] = SHUFFLE_EPI64(v1, v5, 3);
+ in[4] = SHUFFLE_EPI64(v2, v6, 0);
+ in[5] = SHUFFLE_EPI64(v2, v6, 3);
+ in[6] = SHUFFLE_EPI64(v3, v7, 0);
+ in[7] = SHUFFLE_EPI64(v3, v7, 3);
+}
+
+// Note:
+// For 16x16 int16_t matrix
+// transpose first 8 columns into first 8 rows.
+// Since only matrix left 8x16 are non-zero, the input are total 16 rows
+// (in[16]).
+// After transposing, the 8 row vectors are in in[8]. All else are zero.
+static INLINE void transpose_col_to_row_nz8x16(__m256i *in /*in[16]*/) {
+ transpose_col_to_row_nz8x8(in);
+ transpose_col_to_row_nz8x8(&in[8]);
+
+ int i;
+ for (i = 0; i < 8; ++i) {
+ in[i] = _mm256_permute2x128_si256(in[i], in[i + 8], 0x20);
+ }
+}
+
+static INLINE void idct16_38_first_half(const __m256i *in, __m256i *out) {
+ const __m256i c2p28 = pair256_set_epi16(2 * cospi_28_64, 2 * cospi_28_64);
+ const __m256i c2p04 = pair256_set_epi16(2 * cospi_4_64, 2 * cospi_4_64);
+ __m256i t4 = _mm256_mulhrs_epi16(in[2], c2p28);
+ __m256i t7 = _mm256_mulhrs_epi16(in[2], c2p04);
+
+ const __m256i c2m20 = pair256_set_epi16(-2 * cospi_20_64, -2 * cospi_20_64);
+ const __m256i c2p12 = pair256_set_epi16(2 * cospi_12_64, 2 * cospi_12_64);
+ __m256i t5 = _mm256_mulhrs_epi16(in[6], c2m20);
+ __m256i t6 = _mm256_mulhrs_epi16(in[6], c2p12);
+
+ const __m256i c2p16 = pair256_set_epi16(2 * cospi_16_64, 2 * cospi_16_64);
+ const __m256i c2p24 = pair256_set_epi16(2 * cospi_24_64, 2 * cospi_24_64);
+ const __m256i c2p08 = pair256_set_epi16(2 * cospi_8_64, 2 * cospi_8_64);
+ const __m256i u0 = _mm256_mulhrs_epi16(in[0], c2p16);
+ const __m256i u1 = _mm256_mulhrs_epi16(in[0], c2p16);
+ const __m256i u2 = _mm256_mulhrs_epi16(in[4], c2p24);
+ const __m256i u3 = _mm256_mulhrs_epi16(in[4], c2p08);
+
+ const __m256i u4 = _mm256_add_epi16(t4, t5);
+ const __m256i u5 = _mm256_sub_epi16(t4, t5);
+ const __m256i u6 = _mm256_sub_epi16(t7, t6);
+ const __m256i u7 = _mm256_add_epi16(t7, t6);
+
+ const __m256i t0 = _mm256_add_epi16(u0, u3);
+ const __m256i t1 = _mm256_add_epi16(u1, u2);
+ const __m256i t2 = _mm256_sub_epi16(u1, u2);
+ const __m256i t3 = _mm256_sub_epi16(u0, u3);
+
+ t4 = u4;
+ t7 = u7;
+
+ const __m256i cospi_p16_p16 = _mm256_set1_epi16((int16_t)cospi_16_64);
+ const __m256i cospi_p16_m16 = pair256_set_epi16(cospi_16_64, -cospi_16_64);
+ unpack_butter_fly(&u6, &u5, &cospi_p16_m16, &cospi_p16_p16, &t5, &t6);
+
+ out[0] = _mm256_add_epi16(t0, t7);
+ out[1] = _mm256_add_epi16(t1, t6);
+ out[2] = _mm256_add_epi16(t2, t5);
+ out[3] = _mm256_add_epi16(t3, t4);
+ out[4] = _mm256_sub_epi16(t3, t4);
+ out[5] = _mm256_sub_epi16(t2, t5);
+ out[6] = _mm256_sub_epi16(t1, t6);
+ out[7] = _mm256_sub_epi16(t0, t7);
+}
+
+static INLINE void idct16_38_second_half(const __m256i *in, __m256i *out) {
+ const __m256i c2p30 = pair256_set_epi16(2 * cospi_30_64, 2 * cospi_30_64);
+ const __m256i c2p02 = pair256_set_epi16(2 * cospi_2_64, 2 * cospi_2_64);
+ __m256i t0 = _mm256_mulhrs_epi16(in[1], c2p30);
+ __m256i t7 = _mm256_mulhrs_epi16(in[1], c2p02);
+
+ const __m256i c2m18 = pair256_set_epi16(-2 * cospi_18_64, -2 * cospi_18_64);
+ const __m256i c2p14 = pair256_set_epi16(2 * cospi_14_64, 2 * cospi_14_64);
+ __m256i t1 = _mm256_mulhrs_epi16(in[7], c2m18);
+ __m256i t6 = _mm256_mulhrs_epi16(in[7], c2p14);
+
+ const __m256i c2p22 = pair256_set_epi16(2 * cospi_22_64, 2 * cospi_22_64);
+ const __m256i c2p10 = pair256_set_epi16(2 * cospi_10_64, 2 * cospi_10_64);
+ __m256i t2 = _mm256_mulhrs_epi16(in[5], c2p22);
+ __m256i t5 = _mm256_mulhrs_epi16(in[5], c2p10);
+
+ const __m256i c2m26 = pair256_set_epi16(-2 * cospi_26_64, -2 * cospi_26_64);
+ const __m256i c2p06 = pair256_set_epi16(2 * cospi_6_64, 2 * cospi_6_64);
+ __m256i t3 = _mm256_mulhrs_epi16(in[3], c2m26);
+ __m256i t4 = _mm256_mulhrs_epi16(in[3], c2p06);
+
+ __m256i v0, v1, v2, v3, v4, v5, v6, v7;
+ v0 = _mm256_add_epi16(t0, t1);
+ v1 = _mm256_sub_epi16(t0, t1);
+ v2 = _mm256_sub_epi16(t3, t2);
+ v3 = _mm256_add_epi16(t2, t3);
+ v4 = _mm256_add_epi16(t4, t5);
+ v5 = _mm256_sub_epi16(t4, t5);
+ v6 = _mm256_sub_epi16(t7, t6);
+ v7 = _mm256_add_epi16(t6, t7);
+
+ t0 = v0;
+ t7 = v7;
+ t3 = v3;
+ t4 = v4;
+ const __m256i cospi_m08_p24 = pair256_set_epi16(-cospi_8_64, cospi_24_64);
+ const __m256i cospi_p24_p08 = pair256_set_epi16(cospi_24_64, cospi_8_64);
+ const __m256i cospi_m24_m08 = pair256_set_epi16(-cospi_24_64, -cospi_8_64);
+ unpack_butter_fly(&v1, &v6, &cospi_m08_p24, &cospi_p24_p08, &t1, &t6);
+ unpack_butter_fly(&v2, &v5, &cospi_m24_m08, &cospi_m08_p24, &t2, &t5);
+
+ v0 = _mm256_add_epi16(t0, t3);
+ v1 = _mm256_add_epi16(t1, t2);
+ v2 = _mm256_sub_epi16(t1, t2);
+ v3 = _mm256_sub_epi16(t0, t3);
+ v4 = _mm256_sub_epi16(t7, t4);
+ v5 = _mm256_sub_epi16(t6, t5);
+ v6 = _mm256_add_epi16(t6, t5);
+ v7 = _mm256_add_epi16(t7, t4);
+
+ // stage 6, (8-15)
+ out[0] = v0;
+ out[1] = v1;
+ out[6] = v6;
+ out[7] = v7;
+ const __m256i cospi_p16_p16 = _mm256_set1_epi16((int16_t)cospi_16_64);
+ const __m256i cospi_p16_m16 = pair256_set_epi16(cospi_16_64, -cospi_16_64);
+ unpack_butter_fly(&v5, &v2, &cospi_p16_m16, &cospi_p16_p16, &out[2], &out[5]);
+ unpack_butter_fly(&v4, &v3, &cospi_p16_m16, &cospi_p16_p16, &out[3], &out[4]);
+}
+
+static INLINE void idct16_38(__m256i *in /*in[16]*/) {
+ __m256i out[16];
+ idct16_38_first_half(in, out);
+ idct16_38_second_half(in, &out[8]);
+ add_sub_butterfly(out, in, 16);
+}
+
+void aom_idct16x16_38_add_avx2(const tran_low_t *input, uint8_t *dest,
+ int stride) {
+ __m256i in[16];
+
+ int i;
+ for (i = 0; i < 8; ++i) {
+ load_coeff(input + (i << 4), &in[i]);
+ }
+
+ transpose_col_to_row_nz8x8(in);
+ idct16_38(in);
+
+ transpose_col_to_row_nz8x16(in);
+ idct16_38(in);
+
+ write_buffer_16x16(in, stride, dest);
+}
+
+void aom_idct16x16_1_add_avx2(const tran_low_t *input, uint8_t *dest,
+ int stride) {
+ __m256i dc_value;
+ int a, i;
+
+ a = (int)dct_const_round_shift(input[0] * cospi_16_64);
+ a = (int)dct_const_round_shift(a * cospi_16_64);
+ a = ROUND_POWER_OF_TWO(a, IDCT_ROUNDING_POS);
+
+ if (a == 0) return;
+
+ dc_value = _mm256_set1_epi16(a);
+
+ for (i = 0; i < 16; ++i) {
+ recon_and_store(&dc_value, dest);
+ dest += stride;
+ }
+}
diff --git a/aom_dsp/x86/inv_txfm_common_avx2.h b/aom_dsp/x86/inv_txfm_common_avx2.h
new file mode 100644
index 0000000..7e99be9
--- /dev/null
+++ b/aom_dsp/x86/inv_txfm_common_avx2.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_DSP_X86_INV_TXFM_COMMON_AVX2_H
+#define AOM_DSP_X86_INV_TXFM_COMMON_AVX2_H
+
+#include <immintrin.h>
+
+#include "aom_dsp/txfm_common.h"
+#include "aom_dsp/x86/txfm_common_avx2.h"
+
+static INLINE void load_coeff(const tran_low_t *coeff, __m256i *in) {
+#if CONFIG_HIGHBITDEPTH
+ *in = _mm256_setr_epi16(
+ (int16_t)coeff[0], (int16_t)coeff[1], (int16_t)coeff[2],
+ (int16_t)coeff[3], (int16_t)coeff[4], (int16_t)coeff[5],
+ (int16_t)coeff[6], (int16_t)coeff[7], (int16_t)coeff[8],
+ (int16_t)coeff[9], (int16_t)coeff[10], (int16_t)coeff[11],
+ (int16_t)coeff[12], (int16_t)coeff[13], (int16_t)coeff[14],
+ (int16_t)coeff[15]);
+#else
+ *in = _mm256_loadu_si256((const __m256i *)coeff);
+#endif
+}
+
+static INLINE void load_buffer_16x16(const tran_low_t *coeff, __m256i *in) {
+ int i = 0;
+ while (i < 16) {
+ load_coeff(coeff + (i << 4), &in[i]);
+ i += 1;
+ }
+}
+
+static INLINE void recon_and_store(const __m256i *res, uint8_t *output) {
+ const __m128i zero = _mm_setzero_si128();
+ __m128i x = _mm_loadu_si128((__m128i const *)output);
+ __m128i p0 = _mm_unpacklo_epi8(x, zero);
+ __m128i p1 = _mm_unpackhi_epi8(x, zero);
+
+ p0 = _mm_add_epi16(p0, _mm256_castsi256_si128(*res));
+ p1 = _mm_add_epi16(p1, _mm256_extractf128_si256(*res, 1));
+ x = _mm_packus_epi16(p0, p1);
+ _mm_storeu_si128((__m128i *)output, x);
+}
+
+#define IDCT_ROUNDING_POS (6)
+static INLINE void write_buffer_16x16(__m256i *in, const int stride,
+ uint8_t *output) {
+ const __m256i rounding = _mm256_set1_epi16(1 << (IDCT_ROUNDING_POS - 1));
+ int i = 0;
+
+ while (i < 16) {
+ in[i] = _mm256_add_epi16(in[i], rounding);
+ in[i] = _mm256_srai_epi16(in[i], IDCT_ROUNDING_POS);
+ recon_and_store(&in[i], output + i * stride);
+ i += 1;
+ }
+}
+
+static INLINE void unpack_butter_fly(const __m256i *a0, const __m256i *a1,
+ const __m256i *c0, const __m256i *c1,
+ __m256i *b0, __m256i *b1) {
+ __m256i x0, x1;
+ x0 = _mm256_unpacklo_epi16(*a0, *a1);
+ x1 = _mm256_unpackhi_epi16(*a0, *a1);
+ *b0 = butter_fly(x0, x1, *c0);
+ *b1 = butter_fly(x0, x1, *c1);
+}
+
+void av1_idct16_avx2(__m256i *in);
+
+#endif // AOM_DSP_X86_INV_TXFM_COMMON_AVX2_H
diff --git a/av1/common/idct.c b/av1/common/idct.c
index 2c960cd..c7d69e8 100644
--- a/av1/common/idct.c
+++ b/av1/common/idct.c
@@ -1255,6 +1255,8 @@
#if !CONFIG_ADAPT_SCAN
else if (eob <= 10)
aom_idct16x16_10_add(input, dest, stride);
+ else if (eob <= 38)
+ aom_idct16x16_38_add(input, dest, stride);
#endif
else
aom_idct16x16_256_add(input, dest, stride);
diff --git a/av1/common/x86/hybrid_inv_txfm_avx2.c b/av1/common/x86/hybrid_inv_txfm_avx2.c
index efc8d1e..1186d60 100644
--- a/av1/common/x86/hybrid_inv_txfm_avx2.c
+++ b/av1/common/x86/hybrid_inv_txfm_avx2.c
@@ -14,67 +14,9 @@
#include "./aom_config.h"
#include "./av1_rtcd.h"
-#include "aom_dsp/x86/txfm_common_avx2.h"
+#include "aom_dsp/x86/inv_txfm_common_avx2.h"
-static INLINE void load_coeff(const tran_low_t *coeff, __m256i *in) {
-#if CONFIG_HIGHBITDEPTH
- *in = _mm256_setr_epi16(
- (int16_t)coeff[0], (int16_t)coeff[1], (int16_t)coeff[2],
- (int16_t)coeff[3], (int16_t)coeff[4], (int16_t)coeff[5],
- (int16_t)coeff[6], (int16_t)coeff[7], (int16_t)coeff[8],
- (int16_t)coeff[9], (int16_t)coeff[10], (int16_t)coeff[11],
- (int16_t)coeff[12], (int16_t)coeff[13], (int16_t)coeff[14],
- (int16_t)coeff[15]);
-#else
- *in = _mm256_loadu_si256((const __m256i *)coeff);
-#endif
-}
-
-static void load_buffer_16x16(const tran_low_t *coeff, __m256i *in) {
- int i = 0;
- while (i < 16) {
- load_coeff(coeff + (i << 4), &in[i]);
- i += 1;
- }
-}
-
-static void recon_and_store(const __m256i *res, uint8_t *output) {
- const __m128i zero = _mm_setzero_si128();
- __m128i x = _mm_loadu_si128((__m128i const *)output);
- __m128i p0 = _mm_unpacklo_epi8(x, zero);
- __m128i p1 = _mm_unpackhi_epi8(x, zero);
-
- p0 = _mm_add_epi16(p0, _mm256_castsi256_si128(*res));
- p1 = _mm_add_epi16(p1, _mm256_extractf128_si256(*res, 1));
- x = _mm_packus_epi16(p0, p1);
- _mm_storeu_si128((__m128i *)output, x);
-}
-
-#define IDCT_ROUNDING_POS (6)
-
-static void write_buffer_16x16(__m256i *in, const int stride, uint8_t *output) {
- const __m256i rounding = _mm256_set1_epi16(1 << (IDCT_ROUNDING_POS - 1));
- int i = 0;
-
- while (i < 16) {
- in[i] = _mm256_add_epi16(in[i], rounding);
- in[i] = _mm256_srai_epi16(in[i], IDCT_ROUNDING_POS);
- recon_and_store(&in[i], output + i * stride);
- i += 1;
- }
-}
-
-static INLINE void unpack_butter_fly(const __m256i *a0, const __m256i *a1,
- const __m256i *c0, const __m256i *c1,
- __m256i *b0, __m256i *b1) {
- __m256i x0, x1;
- x0 = _mm256_unpacklo_epi16(*a0, *a1);
- x1 = _mm256_unpackhi_epi16(*a0, *a1);
- *b0 = butter_fly(x0, x1, *c0);
- *b1 = butter_fly(x0, x1, *c1);
-}
-
-static void idct16_avx2(__m256i *in) {
+void av1_idct16_avx2(__m256i *in) {
const __m256i cospi_p30_m02 = pair256_set_epi16(cospi_30_64, -cospi_2_64);
const __m256i cospi_p02_p30 = pair256_set_epi16(cospi_2_64, cospi_30_64);
const __m256i cospi_p14_m18 = pair256_set_epi16(cospi_14_64, -cospi_18_64);
@@ -217,7 +159,7 @@
static void idct16(__m256i *in) {
mm256_transpose_16x16(in);
- idct16_avx2(in);
+ av1_idct16_avx2(in);
}
static INLINE void butterfly_32b(const __m256i *a0, const __m256i *a1,
diff --git a/test/partial_idct_test.cc b/test/partial_idct_test.cc
index 4648cf9..872f33a 100644
--- a/test/partial_idct_test.cc
+++ b/test/partial_idct_test.cc
@@ -418,6 +418,22 @@
::testing::ValuesIn(ssse3_partial_idct_tests));
#endif // HAVE_SSSE3
+#if HAVE_AVX2
+const PartialInvTxfmParam avx2_partial_idct_tests[] = {
+ make_tuple(&aom_fdct16x16_c, &wrapper<aom_idct16x16_256_add_c>,
+ &wrapper<aom_idct16x16_256_add_avx2>, TX_16X16, 256, 8, 1),
+ make_tuple(&aom_fdct16x16_c, &wrapper<aom_idct16x16_256_add_c>,
+ &wrapper<aom_idct16x16_38_add_avx2>, TX_16X16, 38, 8, 1),
+ make_tuple(&aom_fdct16x16_c, &wrapper<aom_idct16x16_256_add_c>,
+ &wrapper<aom_idct16x16_10_add_avx2>, TX_16X16, 10, 8, 1),
+ make_tuple(&aom_fdct16x16_c, &wrapper<aom_idct16x16_256_add_c>,
+ &wrapper<aom_idct16x16_1_add_avx2>, TX_16X16, 1, 8, 1),
+};
+
+INSTANTIATE_TEST_CASE_P(AVX2, PartialIDctTest,
+ ::testing::ValuesIn(avx2_partial_idct_tests));
+#endif // HAVE_AVX2
+
#if HAVE_DSPR2 && !CONFIG_HIGHBITDEPTH
const PartialInvTxfmParam dspr2_partial_idct_tests[] = {
make_tuple(&aom_fdct32x32_c, &wrapper<aom_idct32x32_1024_add_c>,