Add HBD data path for av1_block_error_avx2 - Add unit test for av1_block_error. - Fix av1_dist_block logic for calling av1_block_error. Change-Id: Id8a47ee113417360a29fc2334d9ca72b5793e2d7
diff --git a/av1/common/av1_rtcd_defs.pl b/av1/common/av1_rtcd_defs.pl index 19f4204..6be2be0 100755 --- a/av1/common/av1_rtcd_defs.pl +++ b/av1/common/av1_rtcd_defs.pl
@@ -278,6 +278,7 @@ # the transform coefficients are held in 32-bit # values, so the assembler code for av1_block_error can no longer be used. add_proto qw/int64_t av1_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz"; + specialize qw/av1_block_error avx2/; add_proto qw/void av1_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, const qm_val_t * qm_ptr, const qm_val_t *iqm_ptr"; @@ -310,6 +311,7 @@ # the transform coefficients are held in 32-bit # values, so the assembler code for av1_block_error can no longer be used. add_proto qw/int64_t av1_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz"; + specialize qw/av1_block_error avx2/; add_proto qw/void av1_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; specialize qw/av1_quantize_fp sse2/;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 396c0a0..8ca465c 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -1292,14 +1292,16 @@ &this_sse) >> shift; #endif // CONFIG_HIGHBITDEPTH -#elif CONFIG_HIGHBITDEPTH - const int bd = (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) ? xd->bd : 8; - *out_dist = - av1_highbd_block_error(coeff, dqcoeff, buffer_length, &this_sse, bd) >> - shift; -#else - *out_dist = - av1_block_error(coeff, dqcoeff, buffer_length, &this_sse) >> shift; +#else // !CONFIG_PVQ +#if CONFIG_HIGHBITDEPTH + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) + *out_dist = av1_highbd_block_error(coeff, dqcoeff, buffer_length, + &this_sse, xd->bd) >> + shift; + else +#endif + *out_dist = + av1_block_error(coeff, dqcoeff, buffer_length, &this_sse) >> shift; #endif // CONFIG_PVQ *out_sse = this_sse >> shift; } else {
diff --git a/av1/encoder/x86/error_intrin_avx2.c b/av1/encoder/x86/error_intrin_avx2.c index ae733a1..20ba414 100644 --- a/av1/encoder/x86/error_intrin_avx2.c +++ b/av1/encoder/x86/error_intrin_avx2.c
@@ -14,7 +14,20 @@ #include "./av1_rtcd.h" #include "aom/aom_integer.h" -int64_t av1_block_error_avx2(const int16_t *coeff, const int16_t *dqcoeff, +static INLINE void read_coeff(const tran_low_t *coeff, intptr_t offset, + __m256i *c) { + const tran_low_t *addr = coeff + offset; +#if CONFIG_HIGHBITDEPTH + const __m256i x0 = _mm256_loadu_si256((const __m256i *)addr); + const __m256i x1 = _mm256_loadu_si256((const __m256i *)addr + 1); + const __m256i y = _mm256_packs_epi32(x0, x1); + *c = _mm256_permute4x64_epi64(y, 0xD8); +#else + *c = _mm256_loadu_si256((const __m256i *)addr); +#endif +} + +int64_t av1_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz) { __m256i sse_reg, ssz_reg, coeff_reg, dqcoeff_reg; __m256i exp_dqcoeff_lo, exp_dqcoeff_hi, exp_coeff_lo, exp_coeff_hi; @@ -22,16 +35,16 @@ __m128i sse_reg128, ssz_reg128; int64_t sse; int i; - const __m256i zero_reg = _mm256_set1_epi16(0); + const __m256i zero_reg = _mm256_setzero_si256(); // init sse and ssz registerd to zero - sse_reg = _mm256_set1_epi16(0); - ssz_reg = _mm256_set1_epi16(0); + sse_reg = _mm256_setzero_si256(); + ssz_reg = _mm256_setzero_si256(); for (i = 0; i < block_size; i += 16) { // load 32 bytes from coeff and dqcoeff - coeff_reg = _mm256_loadu_si256((const __m256i *)(coeff + i)); - dqcoeff_reg = _mm256_loadu_si256((const __m256i *)(dqcoeff + i)); + read_coeff(coeff, i, &coeff_reg); + read_coeff(dqcoeff, i, &dqcoeff_reg); // dqcoeff - coeff dqcoeff_reg = _mm256_sub_epi16(dqcoeff_reg, coeff_reg); // madd (dqcoeff - coeff)
diff --git a/test/block_error_test.cc b/test/block_error_test.cc new file mode 100644 index 0000000..4364af4 --- /dev/null +++ b/test/block_error_test.cc
@@ -0,0 +1,136 @@ +/* + * 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 "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "./aom_config.h" +#include "./av1_rtcd.h" + +#include "test/acm_random.h" +#include "test/clear_system_state.h" +#include "test/register_state_check.h" +#include "test/util.h" + +namespace { +using libaom_test::ACMRandom; + +typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff, + const tran_low_t *dqcoeff, intptr_t size, + int64_t *ssz); +#if CONFIG_HIGHBITDEPTH +typedef int64_t (*HbdBlockErrorFunc)(const tran_low_t *coeff, + const tran_low_t *dqcoeff, intptr_t size, + int64_t *ssz, int bd); +#endif + +typedef std::tr1::tuple<BlockErrorFunc, BlockErrorFunc, TX_SIZE, + aom_bit_depth_t> + BlockErrorParam; + +const int kTestNum = 10000; + +class BlockErrorTest : public ::testing::TestWithParam<BlockErrorParam> { + public: + BlockErrorTest() + : blk_err_ref_(GET_PARAM(0)), blk_err_(GET_PARAM(1)), + tx_size_(GET_PARAM(2)), bd_(GET_PARAM(3)) {} + + virtual ~BlockErrorTest() {} + + virtual void SetUp() { + const intptr_t block_size = getCoeffNum(); + coeff_ = reinterpret_cast<tran_low_t *>( + aom_memalign(16, 2 * block_size * sizeof(tran_low_t))); + } + + virtual void TearDown() { + aom_free(coeff_); + coeff_ = NULL; + libaom_test::ClearSystemState(); + } + + void BlockErrorRun(int testNum) { + int i; + int64_t error_ref, error; + int64_t sse_ref, sse; + const intptr_t block_size = getCoeffNum(); + tran_low_t *dqcoeff = coeff_ + block_size; + for (i = 0; i < testNum; ++i) { + FillRandomData(); + + error_ref = blk_err_ref_(coeff_, dqcoeff, block_size, &sse_ref); + ASM_REGISTER_STATE_CHECK(error = + blk_err_(coeff_, dqcoeff, block_size, &sse)); + + EXPECT_EQ(error_ref, error) << "Error doesn't match on test: " << i; + EXPECT_EQ(sse_ref, sse) << "SSE doesn't match on test: " << i; + } + } + + intptr_t getCoeffNum() { return tx_size_2d[tx_size_]; } + + void FillRandomData() { + const intptr_t block_size = getCoeffNum(); + tran_low_t *dqcoeff = coeff_ + block_size; + intptr_t i; + int16_t margin = 512; + for (i = 0; i < block_size; ++i) { + coeff_[i] = GetRandomNumWithRange(INT16_MIN + margin, INT16_MAX - margin); + dqcoeff[i] = coeff_[i] + GetRandomDeltaWithRange(margin); + } + } + + void FillConstantData() { + const intptr_t block_size = getCoeffNum(); + tran_low_t *dqcoeff = coeff_ + block_size; + intptr_t i; + for (i = 0; i < block_size; ++i) { + coeff_[i] = 5; + dqcoeff[i] = 7; + } + } + + tran_low_t GetRandomNumWithRange(int16_t min, int16_t max) { + return clamp((int16_t)rnd_.Rand16(), min, max); + } + + tran_low_t GetRandomDeltaWithRange(int16_t delta) { + tran_low_t value = (int16_t)rnd_.Rand16(); + value %= delta; + return value; + } + + BlockErrorFunc blk_err_ref_; + BlockErrorFunc blk_err_; + TX_SIZE tx_size_; + aom_bit_depth_t bd_; + ACMRandom rnd_; + tran_low_t *coeff_; +}; + +TEST_P(BlockErrorTest, BitExact) { BlockErrorRun(kTestNum); } + +using std::tr1::make_tuple; + +#if !CONFIG_HIGHBITDEPTH && HAVE_SSE2 +const BlockErrorParam kBlkErrParamArraySse2[] = { make_tuple( + &av1_block_error_c, &av1_block_error_sse2, TX_32X32, AOM_BITS_8) }; +INSTANTIATE_TEST_CASE_P(SSE2, BlockErrorTest, + ::testing::ValuesIn(kBlkErrParamArraySse2)); +#endif + +#if HAVE_AVX2 +const BlockErrorParam kBlkErrParamArrayAvx2[] = { make_tuple( + &av1_block_error_c, &av1_block_error_avx2, TX_32X32, AOM_BITS_8) }; +INSTANTIATE_TEST_CASE_P(AVX2, BlockErrorTest, + ::testing::ValuesIn(kBlkErrParamArrayAvx2)); +#endif +} // namespace
diff --git a/test/test.mk b/test/test.mk index 45bb212..26d65c8 100644 --- a/test/test.mk +++ b/test/test.mk
@@ -167,6 +167,7 @@ LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += quantize_func_test.cc endif endif +LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += block_error_test.cc LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += av1_inv_txfm_test.cc LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += av1_dct_test.cc