/* * Copyright (c) 2024, 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 #include #include "config/av1_rtcd.h" #include "aom_ports/aom_timer.h" #include "aom_ports/bitops.h" #include "gtest/gtest.h" #include "test/acm_random.h" #include "test/util.h" namespace { using ::testing::Combine; using ::testing::Values; using ::testing::ValuesIn; using std::make_tuple; using std::tuple; const int kIters = 1000; typedef tuple FrameDimension; // Check that two 8-bit output buffers are identical. void AssertOutputBufferEq(const uint8_t *p1, const uint8_t *p2, int width, int height) { ASSERT_TRUE(p1 != p2) << "Buffers must be at different memory locations"; for (int j = 0; j < height; ++j) { if (memcmp(p1, p2, sizeof(*p1) * width) == 0) { p1 += width; p2 += width; continue; } for (int i = 0; i < width; ++i) { ASSERT_EQ(p1[i], p2[i]) << width << "x" << height << " Pixel mismatch at (" << i << ", " << j << ")"; } } } typedef bool (*LowBDResizeFunc)(uint8_t *intbuf, uint8_t *output, int out_stride, int height, int height2, int stride, int start_wd); // Test parameter list: // typedef tuple ResizeTestParams; class AV1ResizeYTest : public ::testing::TestWithParam { public: void SetUp() { test_fun_ = GET_PARAM(0); frame_dim_ = GET_PARAM(1); width_ = std::get<0>(frame_dim_); height_ = std::get<1>(frame_dim_); const int msb = get_msb(AOMMIN(width_, height_)); n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); const int src_buf_size = (width_ / 2) * height_; const int dest_buf_size = (width_ * height_) / 4; src_ = std::unique_ptr(new (std::nothrow) uint8_t[src_buf_size]); ASSERT_NE(src_, nullptr); ref_dest_ = std::unique_ptr(new (std::nothrow) uint8_t[dest_buf_size]); ASSERT_NE(ref_dest_, nullptr); test_dest_ = std::unique_ptr(new (std::nothrow) uint8_t[dest_buf_size]); ASSERT_NE(test_dest_, nullptr); } void RunTest() { for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8(); for (int level = 1; level < n_levels_; level++) { const int width2 = (width_ >> level); const int height2 = (height_ >> level); av1_resize_vert_dir_c(src_.get(), ref_dest_.get(), width2, height2 << 1, height2, width2, 0); test_fun_(src_.get(), test_dest_.get(), width2, height2 << 1, height2, width2, 0); AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), width2, height2); } } void SpeedTest() { for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8(); for (int level = 1; level < n_levels_; level++) { const int width2 = (width_ >> level); const int height2 = (height_ >> level); aom_usec_timer ref_timer; aom_usec_timer_start(&ref_timer); for (int j = 0; j < kIters; j++) { av1_resize_vert_dir_c(src_.get(), ref_dest_.get(), width2, height2 << 1, height2, width2, 0); } aom_usec_timer_mark(&ref_timer); const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer); aom_usec_timer tst_timer; aom_usec_timer_start(&tst_timer); for (int j = 0; j < kIters; j++) { test_fun_(src_.get(), test_dest_.get(), width2, height2 << 1, height2, width2, 0); } aom_usec_timer_mark(&tst_timer); const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer); std::cout << "level: " << level << " [" << width2 << " x " << height2 << "] C time = " << ref_time << " , SIMD time = " << tst_time << " scaling=" << float(1.00) * ref_time / tst_time << "x \n"; } } private: LowBDResizeFunc test_fun_; FrameDimension frame_dim_; int width_; int height_; int n_levels_; std::unique_ptr src_; std::unique_ptr ref_dest_; std::unique_ptr test_dest_; libaom_test::ACMRandom rng_; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeYTest); TEST_P(AV1ResizeYTest, RunTest) { RunTest(); } TEST_P(AV1ResizeYTest, DISABLED_SpeedTest) { SpeedTest(); } #if HAVE_AVX2 || HAVE_SSE2 // Resolutions (width x height) to be tested for resizing. const FrameDimension kFrameDim[] = { make_tuple(3840, 2160), make_tuple(2560, 1440), make_tuple(1920, 1080), make_tuple(1280, 720), make_tuple(640, 480), make_tuple(640, 360), make_tuple(286, 286), make_tuple(284, 284), make_tuple(282, 282), make_tuple(280, 280), make_tuple(262, 262), make_tuple(258, 258), make_tuple(256, 256), make_tuple(34, 34), }; #endif #if HAVE_AVX2 INSTANTIATE_TEST_SUITE_P( AVX2, AV1ResizeYTest, ::testing::Combine(::testing::Values(av1_resize_vert_dir_avx2), ::testing::ValuesIn(kFrameDim))); #endif #if HAVE_SSE2 INSTANTIATE_TEST_SUITE_P( SSE2, AV1ResizeYTest, ::testing::Combine(::testing::Values(av1_resize_vert_dir_sse2), ::testing::ValuesIn(kFrameDim))); #endif typedef void (*LowBDResize_x_Func)(const uint8_t *const input, int in_stride, uint8_t *intbuf, int height, int filtered_length, int width2); typedef tuple Resize_x_TestParams; class AV1ResizeXTest : public ::testing::TestWithParam { public: void SetUp() { test_fun_ = GET_PARAM(0); frame_dim_ = GET_PARAM(1); width_ = std::get<0>(frame_dim_); height_ = std::get<1>(frame_dim_); const int msb = get_msb(AOMMIN(width_, height_)); n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); const int src_buf_size = width_ * height_; const int dest_buf_size = (width_ * height_) / 2; src_ = std::unique_ptr(new (std::nothrow) uint8_t[src_buf_size]); ASSERT_NE(src_, nullptr); ref_dest_ = std::unique_ptr(new (std::nothrow) uint8_t[dest_buf_size]); ASSERT_NE(ref_dest_, nullptr); test_dest_ = std::unique_ptr(new (std::nothrow) uint8_t[dest_buf_size]); ASSERT_NE(test_dest_, nullptr); } void RunTest() { for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8(); for (int level = 1; level < n_levels_; ++level) { const int width2 = (width_ >> level); av1_resize_horz_dir_c(src_.get(), width_, ref_dest_.get(), height_, width2 << 1, width2); test_fun_(src_.get(), width_, test_dest_.get(), height_, width2 << 1, width2); AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), width2, height_); } } void SpeedTest() { for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8(); for (int level = 1; level < n_levels_; ++level) { const int width2 = (width_ >> level); aom_usec_timer ref_timer; aom_usec_timer_start(&ref_timer); for (int j = 0; j < kIters; ++j) { av1_resize_horz_dir_c(src_.get(), width_, ref_dest_.get(), height_, width2 << 1, width2); } aom_usec_timer_mark(&ref_timer); const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer); aom_usec_timer tst_timer; aom_usec_timer_start(&tst_timer); for (int j = 0; j < kIters; ++j) { test_fun_(src_.get(), width_, test_dest_.get(), height_, width2 << 1, width2); } aom_usec_timer_mark(&tst_timer); const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer); std::cout << "level: " << level << " [" << width2 << " x " << height_ << "] C time = " << ref_time << " , SIMD time = " << tst_time << " scaling=" << float(1.00) * ref_time / tst_time << "x \n"; } } private: LowBDResize_x_Func test_fun_; FrameDimension frame_dim_; int width_; int height_; int n_levels_; std::unique_ptr src_; std::unique_ptr ref_dest_; std::unique_ptr test_dest_; libaom_test::ACMRandom rng_; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeXTest); TEST_P(AV1ResizeXTest, RunTest) { RunTest(); } TEST_P(AV1ResizeXTest, DISABLED_SpeedTest) { SpeedTest(); } #if HAVE_SSE2 INSTANTIATE_TEST_SUITE_P( SSE2, AV1ResizeXTest, ::testing::Combine(::testing::Values(av1_resize_horz_dir_sse2), ::testing::ValuesIn(kFrameDim))); #endif #if HAVE_AVX2 INSTANTIATE_TEST_SUITE_P( AVX2, AV1ResizeXTest, ::testing::Combine(::testing::Values(av1_resize_horz_dir_avx2), ::testing::ValuesIn(kFrameDim))); #endif } // namespace