| /* | 
 |  * Copyright (c) 2021, Alliance for Open Media. All rights reserved | 
 |  * | 
 |  * This source code is subject to the terms of the BSD 3-Clause Clear License | 
 |  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear | 
 |  * License was not distributed with this source code in the LICENSE file, you | 
 |  * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  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 | 
 |  * aomedia.org/license/patent-license/. | 
 |  */ | 
 |  | 
 | #include <math.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <tuple> | 
 | #include <vector> | 
 |  | 
 | #include "config/av1_rtcd.h" | 
 |  | 
 | #include "test/acm_random.h" | 
 | #include "test/util.h" | 
 | #include "test/av1_txfm_test.h" | 
 | #include "test/function_equivalence_test.h" | 
 | #include "av1/common/av1_txfm.h" | 
 | #include "av1/encoder/hybrid_fwd_txfm.h" | 
 |  | 
 | using libaom_test::ACMRandom; | 
 | using libaom_test::bd; | 
 | using libaom_test::compute_avg_abs_error; | 
 | using libaom_test::input_base; | 
 | using libaom_test::TYPE_TXFM; | 
 |  | 
 | using std::vector; | 
 |  | 
 | namespace { | 
 | /////////////////////////////////////////////////////////////// | 
 | //       unit-test for 'fwd_stxfm'                           // | 
 | /////////////////////////////////////////////////////////////// | 
 |  | 
 | typedef void (*FwdSTxfmFunc)(tran_low_t *src, tran_low_t *dst, | 
 |                              const PREDICTION_MODE mode, const uint8_t stx_idx, | 
 |                              const int size, const int bd); | 
 | class AV1FwdSecTxfmTest : public ::testing::TestWithParam<FwdSTxfmFunc> { | 
 |  public: | 
 |   AV1FwdSecTxfmTest() : fwd_stxfm_func_(GetParam()) {} | 
 |   void AV1FwdSecTxfmMatchTest() { | 
 |     av1_init_stxfm_kernels(); | 
 |     for (int set_id = 0; set_id < IST_DIR_SIZE; ++set_id) { | 
 |       for (uint8_t stx = 0; stx < STX_TYPES - 1; ++stx) { | 
 |         for (int sb_size = 0; sb_size < 3; ++sb_size) { | 
 |           DECLARE_ALIGNED(32, tran_low_t, input[IST_8x8_WIDTH]) = { 0 }; | 
 |           DECLARE_ALIGNED(32, tran_low_t, output[IST_8x8_HEIGHT]) = { 0 }; | 
 |           DECLARE_ALIGNED(32, tran_low_t, ref_output[IST_8x8_HEIGHT]) = { 0 }; | 
 |           ACMRandom rnd(ACMRandom::DeterministicSeed()); | 
 |           const int coeff_range = (1 << (bd + 7)) - 1; | 
 |           for (int cnt = 0; cnt < 3; ++cnt) { | 
 |             if (cnt == 0) { | 
 |               for (int r = 0; r < IST_8x8_WIDTH; ++r) { | 
 |                 input[r] = coeff_range; | 
 |               } | 
 |             } else if (cnt == 1) { | 
 |               for (int r = 0; r < IST_8x8_WIDTH; ++r) { | 
 |                 input[r] = -coeff_range; | 
 |               } | 
 |             } else { | 
 |               for (int r = 0; r < IST_8x8_WIDTH; ++r) { | 
 |                 input[r] = rnd(2) ? rnd(coeff_range) : -rnd(coeff_range); | 
 |               } | 
 |             } | 
 |             fwd_stxfm_c(input, ref_output, set_id, stx, sb_size, bd); | 
 |             fwd_stxfm_func_(input, output, set_id, stx, sb_size, bd); | 
 |             int check_rows = (sb_size == 0)   ? IST_4x4_HEIGHT | 
 |                              : (sb_size == 1) ? IST_8x8_HEIGHT_RED | 
 |                                               : IST_8x8_HEIGHT; | 
 |             for (int r = 0; r < check_rows; ++r) { | 
 |               ASSERT_EQ(ref_output[r], output[r]) | 
 |                   << "[" << r << "] cnt:" << cnt | 
 |                   << " ref_output: " << ref_output[r] | 
 |                   << " mod_output: " << output[r]; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void AV1FwdSecTxfmSpeedTest() { | 
 |     av1_init_stxfm_kernels(); | 
 |     for (int sb_size = 0; sb_size < 3; ++sb_size) { | 
 |       DECLARE_ALIGNED(32, tran_low_t, input[IST_8x8_WIDTH]) = { 0 }; | 
 |       DECLARE_ALIGNED(32, tran_low_t, output[IST_8x8_HEIGHT]) = { 0 }; | 
 |       ACMRandom rnd(ACMRandom::DeterministicSeed()); | 
 |       const int coeff_range = (1 << (bd + 7)) - 1; | 
 |       for (int r = 0; r < IST_8x8_WIDTH; ++r) { | 
 |         input[r] = rnd(2) ? rnd(coeff_range) : -rnd(coeff_range); | 
 |       } | 
 |       aom_usec_timer ref_timer, test_timer; | 
 |       const int knum_loops = 100000000; | 
 |       aom_usec_timer_start(&ref_timer); | 
 |       for (int i = 0; i < knum_loops; ++i) { | 
 |         fwd_stxfm_c(input, output, 0, 0, sb_size, bd); | 
 |       } | 
 |       aom_usec_timer_mark(&ref_timer); | 
 |       const int elapsed_time_c = | 
 |           static_cast<int>(aom_usec_timer_elapsed(&ref_timer)); | 
 |  | 
 |       aom_usec_timer_start(&test_timer); | 
 |       for (int i = 0; i < knum_loops; ++i) { | 
 |         fwd_stxfm_func_(input, output, 0, 0, sb_size, bd); | 
 |       } | 
 |       aom_usec_timer_mark(&test_timer); | 
 |       const int elapsed_time_simd = | 
 |           static_cast<int>(aom_usec_timer_elapsed(&test_timer)); | 
 |  | 
 |       printf( | 
 |           "sb_size[%d] \t c_time=%d \t simd_time=%d \t " | 
 |           "gain=%f \n", | 
 |           sb_size, elapsed_time_c, elapsed_time_simd, | 
 |           ((1.0 * elapsed_time_c) / elapsed_time_simd)); | 
 |     } | 
 |   } | 
 |   FwdSTxfmFunc fwd_stxfm_func_; | 
 | }; | 
 | GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1FwdSecTxfmTest); | 
 |  | 
 | TEST_P(AV1FwdSecTxfmTest, match) { AV1FwdSecTxfmMatchTest(); } | 
 | TEST_P(AV1FwdSecTxfmTest, DISABLED_Speed) { AV1FwdSecTxfmSpeedTest(); } | 
 |  | 
 | #if HAVE_SSE4_1 | 
 | INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1FwdSecTxfmTest, | 
 |                          ::testing::Values(fwd_stxfm_sse4_1)); | 
 | #endif  // HAVE_SSE4_1 | 
 |  | 
 | #if HAVE_AVX2 | 
 | INSTANTIATE_TEST_SUITE_P(AVX2, AV1FwdSecTxfmTest, | 
 |                          ::testing::Values(fwd_stxfm_avx2)); | 
 | #endif  // HAVE_AVX2 | 
 |  | 
 | /////////////////////////////////////////////////////////////// | 
 | //       unit-test for 'inv_stxfm'                           // | 
 | /////////////////////////////////////////////////////////////// | 
 |  | 
 | typedef void (*InvSTxfmFunc)(tran_low_t *src, tran_low_t *dst, | 
 |                              const PREDICTION_MODE mode, const uint8_t stx_idx, | 
 |                              const int size, const int bd); | 
 | class AV1InvSecTxfmTest : public ::testing::TestWithParam<InvSTxfmFunc> { | 
 |  public: | 
 |   AV1InvSecTxfmTest() : inv_stxfm_func_(GetParam()) {} | 
 |   void AV1InvSecTxfmMatchTest() { | 
 |     av1_init_stxfm_kernels(); | 
 |     for (int set_id = 0; set_id < IST_DIR_SIZE; ++set_id) { | 
 |       for (uint8_t stx = 0; stx < STX_TYPES - 1; ++stx) { | 
 |         for (int sb_size = 0; sb_size < 3; ++sb_size) { | 
 |           DECLARE_ALIGNED(32, tran_low_t, input[IST_8x8_HEIGHT]) = { 0 }; | 
 |           DECLARE_ALIGNED(32, tran_low_t, output[IST_8x8_WIDTH]) = { 0 }; | 
 |           DECLARE_ALIGNED(32, tran_low_t, ref_output[IST_8x8_WIDTH]) = { 0 }; | 
 |           ACMRandom rnd(ACMRandom::DeterministicSeed()); | 
 |           const int coeff_range = ((1 << (bd + 7)) - 1); | 
 |           for (int r = 0; r < IST_8x8_HEIGHT; r++) { | 
 |             input[r] = rnd(2) ? rnd(coeff_range) : -rnd(coeff_range); | 
 |           } | 
 |           inv_stxfm_c(input, ref_output, set_id, stx, sb_size, bd); | 
 |           inv_stxfm_func_(input, output, set_id, stx, sb_size, bd); | 
 |           int check_rows = (sb_size == 0) ? IST_4x4_WIDTH : IST_8x8_WIDTH; | 
 |           for (int r = 0; r < check_rows; ++r) { | 
 |             ASSERT_EQ(ref_output[r], output[r]) | 
 |                 << "[" << r << "] " << " ref_output: " << ref_output[r] | 
 |                 << " mod_output: " << output[r]; | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void AV1InvSecTxfmSpeedTest() { | 
 |     av1_init_stxfm_kernels(); | 
 |     for (int sb_size = 0; sb_size < 3; ++sb_size) { | 
 |       DECLARE_ALIGNED(32, tran_low_t, input[IST_8x8_HEIGHT]) = { 0 }; | 
 |       DECLARE_ALIGNED(32, tran_low_t, output[IST_8x8_WIDTH]) = { 0 }; | 
 |       ACMRandom rnd(ACMRandom::DeterministicSeed()); | 
 |       const int coeff_range = ((1 << (bd + 7)) - 1); | 
 |       for (int r = 0; r < IST_8x8_HEIGHT; ++r) { | 
 |         input[r] = rnd(2) ? rnd(coeff_range) : -rnd(coeff_range); | 
 |       } | 
 |       aom_usec_timer ref_timer, test_timer; | 
 |       const int knum_loops = 100000000; | 
 |       aom_usec_timer_start(&ref_timer); | 
 |       for (int i = 0; i < knum_loops; ++i) { | 
 |         fwd_stxfm_c(input, output, 0, 0, sb_size, bd); | 
 |       } | 
 |       aom_usec_timer_mark(&ref_timer); | 
 |       const int elapsed_time_c = | 
 |           static_cast<int>(aom_usec_timer_elapsed(&ref_timer)); | 
 |  | 
 |       aom_usec_timer_start(&test_timer); | 
 |       for (int i = 0; i < knum_loops; ++i) { | 
 |         inv_stxfm_func_(input, output, 0, 0, sb_size, bd); | 
 |       } | 
 |       aom_usec_timer_mark(&test_timer); | 
 |       const int elapsed_time_simd = | 
 |           static_cast<int>(aom_usec_timer_elapsed(&test_timer)); | 
 |  | 
 |       printf( | 
 |           "sb_size[%d] \t c_time=%d \t simd_time=%d \t " | 
 |           "gain=%f \n", | 
 |           sb_size, elapsed_time_c, elapsed_time_simd, | 
 |           ((1.0 * elapsed_time_c) / elapsed_time_simd)); | 
 |     } | 
 |   } | 
 |   InvSTxfmFunc inv_stxfm_func_; | 
 | }; | 
 |  | 
 | GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1InvSecTxfmTest); | 
 |  | 
 | TEST_P(AV1InvSecTxfmTest, match) { AV1InvSecTxfmMatchTest(); } | 
 | TEST_P(AV1InvSecTxfmTest, DISABLED_Speed) { AV1InvSecTxfmSpeedTest(); } | 
 |  | 
 | #if HAVE_SSE4_1 | 
 | INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1InvSecTxfmTest, | 
 |                          ::testing::Values(inv_stxfm_sse4_1)); | 
 | #endif  // HAVE_SSE4_1 | 
 |  | 
 | #if HAVE_AVX2 | 
 | INSTANTIATE_TEST_SUITE_P(AVX2, AV1InvSecTxfmTest, | 
 |                          ::testing::Values(inv_stxfm_avx2)); | 
 | #endif  // HAVE_AVX2 | 
 | }  // namespace |