diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/aom/test/temporal_filter_test.cc | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/third_party/aom/test/temporal_filter_test.cc b/third_party/aom/test/temporal_filter_test.cc new file mode 100644 index 0000000000..85f68b817e --- /dev/null +++ b/third_party/aom/test/temporal_filter_test.cc @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2019, 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 <cmath> +#include <cstdlib> +#include <memory> +#include <new> +#include <string> +#include <tuple> + +#include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" +#include "config/av1_rtcd.h" + +#include "aom_ports/mem.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/temporal_filter.h" +#include "test/acm_random.h" +#include "test/register_state_check.h" +#include "test/util.h" +#include "test/function_equivalence_test.h" + +using libaom_test::ACMRandom; +using ::testing::Combine; +using ::testing::Values; +using ::testing::ValuesIn; + +#if !CONFIG_REALTIME_ONLY +namespace { +typedef enum { + I400, // Monochrome + I420, // 4:2:0 + I422, // 4:2:2 + I444, // 4:4:4 +} ColorFormat; +static const char *color_fmt_str[] = { "I400", "I420", "I422", "I444" }; +typedef void (*TemporalFilterFunc)( + const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_level, const MV *subblock_mvs, + const int *subblock_mses, const int q_factor, const int filter_strength, + int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum, uint16_t *count); +typedef libaom_test::FuncParam<TemporalFilterFunc> TemporalFilterFuncParam; + +typedef std::tuple<TemporalFilterFuncParam, int> TemporalFilterWithParam; + +class TemporalFilterTest + : public ::testing::TestWithParam<TemporalFilterWithParam> { + public: + ~TemporalFilterTest() override = default; + void SetUp() override { + params_ = GET_PARAM(0); + tf_wgt_calc_lvl_ = GET_PARAM(1); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src1_ = reinterpret_cast<uint8_t *>( + aom_memalign(8, sizeof(uint8_t) * MAX_MB_PLANE * BH * BW)); + src2_ = reinterpret_cast<uint8_t *>( + aom_memalign(8, sizeof(uint8_t) * MAX_MB_PLANE * BH * BW)); + + ASSERT_NE(src1_, nullptr); + ASSERT_NE(src2_, nullptr); + } + + void TearDown() override { + aom_free(src1_); + aom_free(src2_); + } + void RunTest(int isRandom, int run_times, ColorFormat color_fmt); + + void GenRandomData(int width, int height, int stride, int stride2, + int num_planes, int subsampling_x, int subsampling_y) { + uint8_t *src1p = src1_; + uint8_t *src2p = src2_; + for (int plane = 0; plane < num_planes; plane++) { + int plane_w = plane ? width >> subsampling_x : width; + int plane_h = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + int plane_stride2 = plane ? stride2 >> subsampling_x : stride2; + for (int ii = 0; ii < plane_h; ii++) { + for (int jj = 0; jj < plane_w; jj++) { + src1p[jj] = rnd_.Rand8(); + src2p[jj] = rnd_.Rand8(); + } + src1p += plane_stride; + src2p += plane_stride2; + } + } + } + + void GenExtremeData(int width, int height, int stride, int stride2, + int num_planes, int subsampling_x, int subsampling_y, + uint8_t val) { + uint8_t *src1p = src1_; + uint8_t *src2p = src2_; + for (int plane = 0; plane < num_planes; plane++) { + int plane_w = plane ? width >> subsampling_x : width; + int plane_h = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + int plane_stride2 = plane ? stride2 >> subsampling_x : stride2; + for (int ii = 0; ii < plane_h; ii++) { + for (int jj = 0; jj < plane_w; jj++) { + src1p[jj] = val; + src2p[jj] = (255 - val); + } + src1p += plane_stride; + src2p += plane_stride2; + } + } + } + + protected: + TemporalFilterFuncParam params_; + int32_t tf_wgt_calc_lvl_; + uint8_t *src1_; + uint8_t *src2_; + ACMRandom rnd_; +}; +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TemporalFilterTest); + +void TemporalFilterTest::RunTest(int isRandom, int run_times, + ColorFormat color_fmt) { + aom_usec_timer ref_timer, test_timer; + const BLOCK_SIZE block_size = TF_BLOCK_SIZE; + static_assert(block_size == BLOCK_32X32, ""); + const int width = 32; + const int height = 32; + int num_planes = MAX_MB_PLANE; + int subsampling_x = 0; + int subsampling_y = 0; + if (color_fmt == I420) { + subsampling_x = 1; + subsampling_y = 1; + } else if (color_fmt == I422) { + subsampling_x = 1; + subsampling_y = 0; + } else if (color_fmt == I400) { + num_planes = 1; + } + for (int k = 0; k < 3; k++) { + const int stride = width; + const int stride2 = width; + if (isRandom) { + GenRandomData(width, height, stride, stride2, num_planes, subsampling_x, + subsampling_y); + } else { + const int msb = 8; // Up to 8 bit input + const int limit = (1 << msb) - 1; + if (k == 0) { + GenExtremeData(width, height, stride, stride2, num_planes, + subsampling_x, subsampling_y, limit); + } else { + GenExtremeData(width, height, stride, stride2, num_planes, + subsampling_x, subsampling_y, 0); + } + } + double sigma[MAX_MB_PLANE] = { 2.1002103677063437, 2.1002103677063437, + 2.1002103677063437 }; + DECLARE_ALIGNED(16, unsigned int, accumulator_ref[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_ref[1024 * 3]); + memset(accumulator_ref, 0, 1024 * 3 * sizeof(accumulator_ref[0])); + memset(count_ref, 0, 1024 * 3 * sizeof(count_ref[0])); + DECLARE_ALIGNED(16, unsigned int, accumulator_mod[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_mod[1024 * 3]); + memset(accumulator_mod, 0, 1024 * 3 * sizeof(accumulator_mod[0])); + memset(count_mod, 0, 1024 * 3 * sizeof(count_mod[0])); + + static_assert(width == 32 && height == 32, ""); + const MV subblock_mvs[4] = { { 0, 0 }, { 5, 5 }, { 7, 8 }, { 2, 10 } }; + const int subblock_mses[4] = { 15, 16, 17, 18 }; + const int q_factor = 12; + const int filter_strength = 5; + const int mb_row = 0; + const int mb_col = 0; + std::unique_ptr<YV12_BUFFER_CONFIG> frame_to_filter(new (std::nothrow) + YV12_BUFFER_CONFIG); + ASSERT_NE(frame_to_filter, nullptr); + frame_to_filter->y_crop_height = 360; + frame_to_filter->y_crop_width = 540; + frame_to_filter->heights[PLANE_TYPE_Y] = height; + frame_to_filter->heights[PLANE_TYPE_UV] = height >> subsampling_y; + frame_to_filter->strides[PLANE_TYPE_Y] = stride; + frame_to_filter->strides[PLANE_TYPE_UV] = stride >> subsampling_x; + DECLARE_ALIGNED(16, uint8_t, src[1024 * 3]); + frame_to_filter->buffer_alloc = src; + frame_to_filter->flags = 0; // Only support low bit-depth test. + memcpy(src, src1_, 1024 * 3 * sizeof(uint8_t)); + + std::unique_ptr<MACROBLOCKD> mbd(new (std::nothrow) MACROBLOCKD); + ASSERT_NE(mbd, nullptr); + mbd->bd = 8; + for (int plane = AOM_PLANE_Y; plane < num_planes; plane++) { + int plane_height = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + frame_to_filter->buffers[plane] = + frame_to_filter->buffer_alloc + plane * plane_stride * plane_height; + mbd->plane[plane].subsampling_x = plane ? subsampling_x : 0; + mbd->plane[plane].subsampling_y = plane ? subsampling_y : 0; + } + + params_.ref_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, src2_, + accumulator_ref, count_ref); + params_.tst_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, src2_, + accumulator_mod, count_mod); + + if (run_times > 1) { + aom_usec_timer_start(&ref_timer); + for (int j = 0; j < run_times; j++) { + params_.ref_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, src2_, + accumulator_ref, count_ref); + } + 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 j = 0; j < run_times; j++) { + params_.tst_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, src2_, + accumulator_mod, count_mod); + } + aom_usec_timer_mark(&test_timer); + const int elapsed_time_simd = + static_cast<int>(aom_usec_timer_elapsed(&test_timer)); + + printf( + "c_time=%d \t simd_time=%d \t " + "gain=%f\t width=%d\t height=%d\t color_format=%s\n", + elapsed_time_c, elapsed_time_simd, + (float)((float)elapsed_time_c / (float)elapsed_time_simd), width, + height, color_fmt_str[color_fmt]); + + } else { + for (int i = 0, l = 0; i < height; i++) { + for (int j = 0; j < width; j++, l++) { + EXPECT_EQ(accumulator_ref[l], accumulator_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] " << color_fmt_str[color_fmt] + << " C accumulator does not match optimized accumulator."; + EXPECT_EQ(count_ref[l], count_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] " << color_fmt_str[color_fmt] + << " count does not match optimized count."; + } + } + } + } +} + +TEST_P(TemporalFilterTest, OperationCheck) { + RunTest(1, 1, I400); + RunTest(1, 1, I420); + RunTest(1, 1, I422); + RunTest(1, 1, I444); +} + +TEST_P(TemporalFilterTest, ExtremeValues) { + RunTest(0, 1, I400); + RunTest(0, 1, I420); + RunTest(0, 1, I422); + RunTest(0, 1, I444); +} + +TEST_P(TemporalFilterTest, DISABLED_Speed) { + RunTest(1, 100000, I400); + RunTest(1, 100000, I420); + RunTest(1, 100000, I422); + RunTest(1, 100000, I444); +} + +#if HAVE_AVX2 +TemporalFilterFuncParam temporal_filter_test_avx2[] = { TemporalFilterFuncParam( + &av1_apply_temporal_filter_c, &av1_apply_temporal_filter_avx2) }; +INSTANTIATE_TEST_SUITE_P(AVX2, TemporalFilterTest, + Combine(ValuesIn(temporal_filter_test_avx2), + Values(0, 1))); +#endif // HAVE_AVX2 + +#if HAVE_SSE2 +TemporalFilterFuncParam temporal_filter_test_sse2[] = { TemporalFilterFuncParam( + &av1_apply_temporal_filter_c, &av1_apply_temporal_filter_sse2) }; +INSTANTIATE_TEST_SUITE_P(SSE2, TemporalFilterTest, + Combine(ValuesIn(temporal_filter_test_sse2), + Values(0, 1))); +#endif // HAVE_SSE2 + +#if HAVE_NEON +TemporalFilterFuncParam temporal_filter_test_neon[] = { TemporalFilterFuncParam( + &av1_apply_temporal_filter_c, &av1_apply_temporal_filter_neon) }; +INSTANTIATE_TEST_SUITE_P(NEON, TemporalFilterTest, + Combine(ValuesIn(temporal_filter_test_neon), + Values(0, 1))); +#endif // HAVE_NEON + +#if HAVE_NEON_DOTPROD +TemporalFilterFuncParam temporal_filter_test_neon_dotprod[] = { + TemporalFilterFuncParam(&av1_apply_temporal_filter_c, + &av1_apply_temporal_filter_neon_dotprod) +}; +INSTANTIATE_TEST_SUITE_P(NEON_DOTPROD, TemporalFilterTest, + Combine(ValuesIn(temporal_filter_test_neon_dotprod), + Values(0, 1))); +#endif // HAVE_NEON_DOTPROD + +#if HAVE_AVX2 || HAVE_NEON +// Width and height for which av1_estimate_noise_from_single_plane() will be +// tested. +const int kWidths[] = { 3840, 1920, 1280, 800, 640, 360, 357 }; +const int kHeights[] = { 2160, 1080, 720, 600, 480, 240, 237 }; +#endif // HAVE_AVX2 || HAVE_NEON + +typedef double (*EstimateNoiseFunc)(const uint8_t *src, int height, int width, + int stride, int edge_thresh); + +typedef std::tuple<EstimateNoiseFunc, EstimateNoiseFunc, int, int> + EstimateNoiseWithParam; + +class EstimateNoiseTest + : public ::testing::TestWithParam<EstimateNoiseWithParam> { + public: + ~EstimateNoiseTest() override = default; + void SetUp() override { + ref_func = GET_PARAM(0); + tst_func = GET_PARAM(1); + width_ = GET_PARAM(2); + height_ = GET_PARAM(3); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src1_ = reinterpret_cast<uint8_t *>( + aom_memalign(8, sizeof(uint8_t) * width_ * height_)); + GenRandomData(width_ * height_); + ASSERT_NE(src1_, nullptr); + } + + void TearDown() override { aom_free(src1_); } + + void RunTest(int run_times) { + stride_ = width_; + + for (int i = 0; i < run_times; i++) { + double ref_out = ref_func(src1_, height_, width_, stride_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + + double tst_out = tst_func(src1_, height_, width_, stride_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + + EXPECT_EQ(ref_out, tst_out); + } + } + + void SpeedTest(int run_times) { + stride_ = width_; + aom_usec_timer timer; + aom_usec_timer_start(&timer); + for (int i = 0; i < run_times; i++) { + ref_func(src1_, height_, width_, stride_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + } + aom_usec_timer_mark(&timer); + const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer)); + aom_usec_timer_start(&timer); + for (int i = 0; i < run_times; i++) { + tst_func(src1_, height_, width_, stride_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + } + aom_usec_timer_mark(&timer); + const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer)); + + printf("(%3.2f)\n", time1 / time2); + } + + void GenRandomData(int size) { + for (int ii = 0; ii < size; ii++) src1_[ii] = rnd_.Rand8(); + } + + protected: + EstimateNoiseFunc ref_func; + EstimateNoiseFunc tst_func; + ACMRandom rnd_; + uint8_t *src1_; + int width_; + int height_; + int stride_; +}; +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EstimateNoiseTest); + +TEST_P(EstimateNoiseTest, RandomValues) { RunTest(1); } + +TEST_P(EstimateNoiseTest, DISABLED_Speed) { SpeedTest(2000); } + +#if HAVE_AVX2 +INSTANTIATE_TEST_SUITE_P( + AVX2, EstimateNoiseTest, + ::testing::Combine( + ::testing::Values(av1_estimate_noise_from_single_plane_c), + ::testing::Values(av1_estimate_noise_from_single_plane_avx2), + ::testing::ValuesIn(kWidths), ::testing::ValuesIn(kHeights))); +#endif // HAVE_AVX2 + +#if HAVE_NEON +INSTANTIATE_TEST_SUITE_P( + NEON, EstimateNoiseTest, + ::testing::Combine( + ::testing::Values(av1_estimate_noise_from_single_plane_c), + ::testing::Values(av1_estimate_noise_from_single_plane_neon), + ::testing::ValuesIn(kWidths), ::testing::ValuesIn(kHeights))); +#endif // HAVE_NEON + +#if CONFIG_AV1_HIGHBITDEPTH + +typedef void (*HBDTemporalFilterFunc)( + const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_level, const MV *subblock_mvs, + const int *subblock_mses, const int q_factor, const int filter_strength, + int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum, uint16_t *count); +typedef libaom_test::FuncParam<HBDTemporalFilterFunc> + HBDTemporalFilterFuncParam; + +typedef std::tuple<HBDTemporalFilterFuncParam, int> HBDTemporalFilterWithParam; + +class HBDTemporalFilterTest + : public ::testing::TestWithParam<HBDTemporalFilterWithParam> { + public: + ~HBDTemporalFilterTest() override = default; + void SetUp() override { + params_ = GET_PARAM(0); + tf_wgt_calc_lvl_ = GET_PARAM(1); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src1_ = reinterpret_cast<uint16_t *>( + aom_memalign(16, sizeof(uint16_t) * MAX_MB_PLANE * BH * BW)); + src2_ = reinterpret_cast<uint16_t *>( + aom_memalign(16, sizeof(uint16_t) * MAX_MB_PLANE * BH * BW)); + + ASSERT_NE(src1_, nullptr); + ASSERT_NE(src2_, nullptr); + } + + void TearDown() override { + aom_free(src1_); + aom_free(src2_); + } + void RunTest(int isRandom, int run_times, int bd, ColorFormat color_fmt); + + void GenRandomData(int width, int height, int stride, int stride2, int bd, + int subsampling_x, int subsampling_y, int num_planes) { + uint16_t *src1p = src1_; + uint16_t *src2p = src2_; + for (int plane = AOM_PLANE_Y; plane < num_planes; plane++) { + int plane_w = plane ? width >> subsampling_x : width; + int plane_h = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + int plane_stride2 = plane ? stride2 >> subsampling_x : stride2; + const uint16_t max_val = (1 << bd) - 1; + for (int ii = 0; ii < plane_h; ii++) { + for (int jj = 0; jj < plane_w; jj++) { + src1p[jj] = rnd_.Rand16() & max_val; + src2p[jj] = rnd_.Rand16() & max_val; + } + src1p += plane_stride; + src2p += plane_stride2; + } + } + } + + void GenExtremeData(int width, int height, int stride, int stride2, int bd, + int subsampling_x, int subsampling_y, int num_planes, + uint16_t val) { + uint16_t *src1p = src1_; + uint16_t *src2p = src2_; + for (int plane = AOM_PLANE_Y; plane < num_planes; plane++) { + int plane_w = plane ? width >> subsampling_x : width; + int plane_h = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + int plane_stride2 = plane ? stride2 >> subsampling_x : stride2; + uint16_t max_val = (1 << bd) - 1; + for (int ii = 0; ii < plane_h; ii++) { + for (int jj = 0; jj < plane_w; jj++) { + src1p[jj] = val; + src2p[jj] = (max_val - val); + } + src1p += plane_stride; + src2p += plane_stride2; + } + } + } + + protected: + HBDTemporalFilterFuncParam params_; + int tf_wgt_calc_lvl_; + uint16_t *src1_; + uint16_t *src2_; + ACMRandom rnd_; +}; + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HBDTemporalFilterTest); + +void HBDTemporalFilterTest::RunTest(int isRandom, int run_times, int BD, + ColorFormat color_fmt) { + aom_usec_timer ref_timer, test_timer; + const BLOCK_SIZE block_size = TF_BLOCK_SIZE; + static_assert(block_size == BLOCK_32X32, ""); + const int width = 32; + const int height = 32; + int num_planes = MAX_MB_PLANE; + int subsampling_x = 0; + int subsampling_y = 0; + if (color_fmt == I420) { + subsampling_x = 1; + subsampling_y = 1; + } else if (color_fmt == I422) { + subsampling_x = 1; + subsampling_y = 0; + } else if (color_fmt == I400) { + num_planes = 1; + } + for (int k = 0; k < 3; k++) { + const int stride = width; + const int stride2 = width; + if (isRandom) { + GenRandomData(width, height, stride, stride2, BD, subsampling_x, + subsampling_y, num_planes); + } else { + const int msb = BD; + const uint16_t limit = (1 << msb) - 1; + if (k == 0) { + GenExtremeData(width, height, stride, stride2, BD, subsampling_x, + subsampling_y, num_planes, limit); + } else { + GenExtremeData(width, height, stride, stride2, BD, subsampling_x, + subsampling_y, num_planes, 0); + } + } + double sigma[MAX_MB_PLANE] = { 2.1002103677063437, 2.1002103677063437, + 2.1002103677063437 }; + DECLARE_ALIGNED(16, unsigned int, accumulator_ref[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_ref[1024 * 3]); + memset(accumulator_ref, 0, 1024 * 3 * sizeof(accumulator_ref[0])); + memset(count_ref, 0, 1024 * 3 * sizeof(count_ref[0])); + DECLARE_ALIGNED(16, unsigned int, accumulator_mod[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_mod[1024 * 3]); + memset(accumulator_mod, 0, 1024 * 3 * sizeof(accumulator_mod[0])); + memset(count_mod, 0, 1024 * 3 * sizeof(count_mod[0])); + + static_assert(width == 32 && height == 32, ""); + const MV subblock_mvs[4] = { { 0, 0 }, { 5, 5 }, { 7, 8 }, { 2, 10 } }; + const int subblock_mses[4] = { 15, 16, 17, 18 }; + const int q_factor = 12; + const int filter_strength = 5; + const int mb_row = 0; + const int mb_col = 0; + std::unique_ptr<YV12_BUFFER_CONFIG> frame_to_filter(new (std::nothrow) + YV12_BUFFER_CONFIG); + ASSERT_NE(frame_to_filter, nullptr); + frame_to_filter->y_crop_height = 360; + frame_to_filter->y_crop_width = 540; + frame_to_filter->heights[PLANE_TYPE_Y] = height; + frame_to_filter->heights[PLANE_TYPE_UV] = height >> subsampling_y; + frame_to_filter->strides[PLANE_TYPE_Y] = stride; + frame_to_filter->strides[PLANE_TYPE_UV] = stride >> subsampling_x; + DECLARE_ALIGNED(16, uint16_t, src[1024 * 3]); + frame_to_filter->buffer_alloc = CONVERT_TO_BYTEPTR(src); + frame_to_filter->flags = + YV12_FLAG_HIGHBITDEPTH; // Only Hihgbd bit-depth test. + memcpy(src, src1_, 1024 * 3 * sizeof(uint16_t)); + + std::unique_ptr<MACROBLOCKD> mbd(new (std::nothrow) MACROBLOCKD); + ASSERT_NE(mbd, nullptr); + mbd->bd = BD; + for (int plane = AOM_PLANE_Y; plane < num_planes; plane++) { + int plane_height = plane ? height >> subsampling_y : height; + int plane_stride = plane ? stride >> subsampling_x : stride; + frame_to_filter->buffers[plane] = + frame_to_filter->buffer_alloc + plane * plane_stride * plane_height; + mbd->plane[plane].subsampling_x = plane ? subsampling_x : 0; + mbd->plane[plane].subsampling_y = plane ? subsampling_y : 0; + } + + params_.ref_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, + CONVERT_TO_BYTEPTR(src2_), accumulator_ref, count_ref); + params_.tst_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, + CONVERT_TO_BYTEPTR(src2_), accumulator_mod, count_mod); + + if (run_times > 1) { + aom_usec_timer_start(&ref_timer); + for (int j = 0; j < run_times; j++) { + params_.ref_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, + CONVERT_TO_BYTEPTR(src2_), accumulator_ref, count_ref); + } + 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 j = 0; j < run_times; j++) { + params_.tst_func(frame_to_filter.get(), mbd.get(), block_size, mb_row, + mb_col, num_planes, sigma, subblock_mvs, subblock_mses, + q_factor, filter_strength, tf_wgt_calc_lvl_, + CONVERT_TO_BYTEPTR(src2_), accumulator_mod, count_mod); + } + aom_usec_timer_mark(&test_timer); + const int elapsed_time_simd = + static_cast<int>(aom_usec_timer_elapsed(&test_timer)); + + printf( + "c_time=%d \t simd_time=%d \t " + "gain=%f\t width=%d\t height=%d\t color_format=%s\n", + elapsed_time_c, elapsed_time_simd, + (float)((float)elapsed_time_c / (float)elapsed_time_simd), width, + height, color_fmt_str[color_fmt]); + + } else { + for (int i = 0, l = 0; i < height; i++) { + for (int j = 0; j < width; j++, l++) { + EXPECT_EQ(accumulator_ref[l], accumulator_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] " << color_fmt_str[color_fmt] + << " C accumulator does not match optimized accumulator."; + EXPECT_EQ(count_ref[l], count_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] " << color_fmt_str[color_fmt] + << " C count does not match optimized count."; + } + } + } + } +} + +TEST_P(HBDTemporalFilterTest, OperationCheck) { + RunTest(1, 1, 10, I400); + RunTest(1, 1, 10, I420); + RunTest(1, 1, 10, I422); + RunTest(1, 1, 10, I444); +} + +TEST_P(HBDTemporalFilterTest, ExtremeValues) { + RunTest(0, 1, 10, I400); + RunTest(0, 1, 10, I420); + RunTest(0, 1, 10, I422); + RunTest(0, 1, 10, I444); +} + +TEST_P(HBDTemporalFilterTest, DISABLED_Speed) { + RunTest(1, 100000, 10, I400); + RunTest(1, 100000, 10, I420); + RunTest(1, 100000, 10, I422); + RunTest(1, 100000, 10, I444); +} +#if HAVE_SSE2 +HBDTemporalFilterFuncParam HBDtemporal_filter_test_sse2[] = { + HBDTemporalFilterFuncParam(&av1_highbd_apply_temporal_filter_c, + &av1_highbd_apply_temporal_filter_sse2) +}; +INSTANTIATE_TEST_SUITE_P(SSE2, HBDTemporalFilterTest, + Combine(ValuesIn(HBDtemporal_filter_test_sse2), + Values(0, 1))); +#endif // HAVE_SSE2 +#if HAVE_AVX2 +HBDTemporalFilterFuncParam HBDtemporal_filter_test_avx2[] = { + HBDTemporalFilterFuncParam(&av1_highbd_apply_temporal_filter_c, + &av1_highbd_apply_temporal_filter_avx2) +}; +INSTANTIATE_TEST_SUITE_P(AVX2, HBDTemporalFilterTest, + Combine(ValuesIn(HBDtemporal_filter_test_avx2), + Values(0, 1))); +#endif // HAVE_AVX2 + +#if HAVE_NEON +HBDTemporalFilterFuncParam HBDtemporal_filter_test_neon[] = { + HBDTemporalFilterFuncParam(&av1_highbd_apply_temporal_filter_c, + &av1_highbd_apply_temporal_filter_neon) +}; +INSTANTIATE_TEST_SUITE_P(NEON, HBDTemporalFilterTest, + Combine(ValuesIn(HBDtemporal_filter_test_neon), + Values(0, 1))); +#endif // HAVE_NEON + +using HBDEstimateNoiseFunc = double (*)(const uint16_t *src, int height, + int width, int stride, int bit_depth, + int edge_thresh); + +using HBDEstimateNoiseWithParam = + std::tuple<HBDEstimateNoiseFunc, HBDEstimateNoiseFunc, int, int, int>; + +class HBDEstimateNoiseTest + : public ::testing::TestWithParam<HBDEstimateNoiseWithParam> { + public: + HBDEstimateNoiseTest() + : ref_func_(GET_PARAM(0)), tst_func_(GET_PARAM(1)), + rnd_(libaom_test::ACMRandom::DeterministicSeed()), width_(GET_PARAM(2)), + height_(GET_PARAM(3)), bitdepth_(GET_PARAM(4)) {} + ~HBDEstimateNoiseTest() override = default; + void SetUp() override { + src1_ = reinterpret_cast<uint16_t *>( + aom_memalign(16, sizeof(uint16_t) * width_ * height_)); + ASSERT_NE(src1_, nullptr); + GenRandomData(width_ * height_); + } + + void TearDown() override { aom_free(src1_); } + + void RunTest() { + stride_ = width_; + + double ref_out = ref_func_(src1_, height_, width_, stride_, bitdepth_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + + double tst_out = tst_func_(src1_, height_, width_, stride_, bitdepth_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + + EXPECT_EQ(ref_out, tst_out); + } + + void SpeedTest(int run_times) { + stride_ = width_; + aom_usec_timer timer; + aom_usec_timer_start(&timer); + for (int i = 0; i < run_times; i++) { + ref_func_(src1_, height_, width_, stride_, bitdepth_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + } + aom_usec_timer_mark(&timer); + const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer)); + aom_usec_timer_start(&timer); + for (int i = 0; i < run_times; i++) { + tst_func_(src1_, height_, width_, stride_, bitdepth_, + NOISE_ESTIMATION_EDGE_THRESHOLD); + } + aom_usec_timer_mark(&timer); + const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer)); + + printf("%d %dx%d :%7.2f/%7.2f (%3.2f)\n", bitdepth_, width_, height_, time1, + time2, time1 / time2); + } + + void GenRandomData(int size) { + for (int ii = 0; ii < size; ii++) src1_[ii] = rnd_.Rand12(); + } + + private: + HBDEstimateNoiseFunc ref_func_; + HBDEstimateNoiseFunc tst_func_; + ACMRandom rnd_; + uint16_t *src1_; + int width_; + int height_; + int stride_; + int bitdepth_; +}; +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HBDEstimateNoiseTest); + +TEST_P(HBDEstimateNoiseTest, RandomValues) { RunTest(); } + +TEST_P(HBDEstimateNoiseTest, DISABLED_Speed) { SpeedTest(2000); } + +#if HAVE_NEON +INSTANTIATE_TEST_SUITE_P( + NEON, HBDEstimateNoiseTest, + ::testing::Combine( + ::testing::Values(av1_highbd_estimate_noise_from_single_plane_c), + ::testing::Values(av1_highbd_estimate_noise_from_single_plane_neon), + ::testing::ValuesIn(kWidths), ::testing::ValuesIn(kHeights), + ::testing::ValuesIn({ 8, 10, 12 }))); +#endif // HAVE_NEON +#endif // CONFIG_AV1_HIGHBITDEPTH +} // namespace +#endif |