frame_resize_test.cc (9314B)
1 /* 2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include <memory> 13 #include <new> 14 15 #include "config/av1_rtcd.h" 16 #include "aom_ports/aom_timer.h" 17 #include "aom_ports/bitops.h" 18 #include "gtest/gtest.h" 19 #include "test/acm_random.h" 20 #include "test/util.h" 21 22 namespace { 23 24 using ::testing::Combine; 25 using ::testing::Values; 26 using ::testing::ValuesIn; 27 28 using std::make_tuple; 29 using std::tuple; 30 31 const int kIters = 1000; 32 33 using FrameDimension = tuple<int, int>; 34 35 // Check that two 8-bit output buffers are identical. 36 void AssertOutputBufferEq(const uint8_t *p1, const uint8_t *p2, int width, 37 int height) { 38 ASSERT_TRUE(p1 != p2) << "Buffers must be at different memory locations"; 39 for (int j = 0; j < height; ++j) { 40 if (memcmp(p1, p2, sizeof(*p1) * width) == 0) { 41 p1 += width; 42 p2 += width; 43 continue; 44 } 45 for (int i = 0; i < width; ++i) { 46 ASSERT_EQ(p1[i], p2[i]) 47 << width << "x" << height << " Pixel mismatch at (" << i << ", " << j 48 << ")"; 49 } 50 } 51 } 52 53 using LowBDResizeFunc = bool (*)(uint8_t *intbuf, uint8_t *output, 54 int out_stride, int height, int height2, 55 int stride, int start_wd); 56 // Test parameter list: 57 // <tst_fun, dims> 58 using ResizeTestParams = tuple<LowBDResizeFunc, FrameDimension>; 59 60 class AV1ResizeYTest : public ::testing::TestWithParam<ResizeTestParams> { 61 public: 62 void SetUp() { 63 test_fun_ = GET_PARAM(0); 64 frame_dim_ = GET_PARAM(1); 65 width_ = std::get<0>(frame_dim_); 66 height_ = std::get<1>(frame_dim_); 67 const int msb = get_msb(AOMMIN(width_, height_)); 68 n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); 69 const int src_buf_size = (width_ / 2) * height_; 70 const int dest_buf_size = (width_ * height_) / 4; 71 src_ = std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[src_buf_size]); 72 ASSERT_NE(src_, nullptr); 73 74 ref_dest_ = 75 std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]); 76 ASSERT_NE(ref_dest_, nullptr); 77 78 test_dest_ = 79 std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]); 80 ASSERT_NE(test_dest_, nullptr); 81 } 82 83 void RunTest() { 84 for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8(); 85 for (int level = 1; level < n_levels_; level++) { 86 const int width2 = (width_ >> level); 87 const int height2 = (height_ >> level); 88 av1_resize_vert_dir_c(src_.get(), ref_dest_.get(), width2, height2 << 1, 89 height2, width2, 0); 90 test_fun_(src_.get(), test_dest_.get(), width2, height2 << 1, height2, 91 width2, 0); 92 93 AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), width2, height2); 94 } 95 } 96 97 void SpeedTest() { 98 for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8(); 99 for (int level = 1; level < n_levels_; level++) { 100 const int width2 = (width_ >> level); 101 const int height2 = (height_ >> level); 102 aom_usec_timer ref_timer; 103 aom_usec_timer_start(&ref_timer); 104 for (int j = 0; j < kIters; j++) { 105 av1_resize_vert_dir_c(src_.get(), ref_dest_.get(), width2, height2 << 1, 106 height2, width2, 0); 107 } 108 aom_usec_timer_mark(&ref_timer); 109 const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer); 110 111 aom_usec_timer tst_timer; 112 aom_usec_timer_start(&tst_timer); 113 for (int j = 0; j < kIters; j++) { 114 test_fun_(src_.get(), test_dest_.get(), width2, height2 << 1, height2, 115 width2, 0); 116 } 117 aom_usec_timer_mark(&tst_timer); 118 const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer); 119 120 std::cout << "level: " << level << " [" << width2 << " x " << height2 121 << "] C time = " << ref_time << " , SIMD time = " << tst_time 122 << " scaling=" << float(1.00) * ref_time / tst_time << "x \n"; 123 } 124 } 125 126 private: 127 LowBDResizeFunc test_fun_; 128 FrameDimension frame_dim_; 129 int width_; 130 int height_; 131 int n_levels_; 132 std::unique_ptr<uint8_t[]> src_; 133 std::unique_ptr<uint8_t[]> ref_dest_; 134 std::unique_ptr<uint8_t[]> test_dest_; 135 libaom_test::ACMRandom rng_; 136 }; 137 138 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeYTest); 139 140 TEST_P(AV1ResizeYTest, RunTest) { RunTest(); } 141 142 TEST_P(AV1ResizeYTest, DISABLED_SpeedTest) { SpeedTest(); } 143 144 #if HAVE_AVX2 || HAVE_SSE2 145 // Resolutions (width x height) to be tested for resizing. 146 const FrameDimension kFrameDim[] = { 147 make_tuple(3840, 2160), make_tuple(2560, 1440), make_tuple(1920, 1080), 148 make_tuple(1280, 720), make_tuple(640, 480), make_tuple(640, 360), 149 make_tuple(286, 286), make_tuple(284, 284), make_tuple(282, 282), 150 make_tuple(280, 280), make_tuple(262, 262), make_tuple(258, 258), 151 make_tuple(256, 256), make_tuple(34, 34), 152 }; 153 #endif 154 155 #if HAVE_AVX2 156 INSTANTIATE_TEST_SUITE_P( 157 AVX2, AV1ResizeYTest, 158 ::testing::Combine(::testing::Values(av1_resize_vert_dir_avx2), 159 ::testing::ValuesIn(kFrameDim))); 160 #endif 161 162 #if HAVE_SSE2 163 INSTANTIATE_TEST_SUITE_P( 164 SSE2, AV1ResizeYTest, 165 ::testing::Combine(::testing::Values(av1_resize_vert_dir_sse2), 166 ::testing::ValuesIn(kFrameDim))); 167 #endif 168 169 using LowBDResize_x_Func = void (*)(const uint8_t *const input, int in_stride, 170 uint8_t *intbuf, int height, 171 int filtered_length, int width2); 172 173 using Resize_x_TestParams = tuple<LowBDResize_x_Func, FrameDimension>; 174 175 class AV1ResizeXTest : public ::testing::TestWithParam<Resize_x_TestParams> { 176 public: 177 void SetUp() { 178 test_fun_ = GET_PARAM(0); 179 frame_dim_ = GET_PARAM(1); 180 width_ = std::get<0>(frame_dim_); 181 height_ = std::get<1>(frame_dim_); 182 const int msb = get_msb(AOMMIN(width_, height_)); 183 n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); 184 const int src_buf_size = width_ * height_; 185 const int dest_buf_size = (width_ * height_) / 2; 186 src_ = std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[src_buf_size]); 187 ASSERT_NE(src_, nullptr); 188 189 ref_dest_ = 190 std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]); 191 ASSERT_NE(ref_dest_, nullptr); 192 193 test_dest_ = 194 std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]); 195 ASSERT_NE(test_dest_, nullptr); 196 } 197 198 void RunTest() { 199 for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8(); 200 201 for (int level = 1; level < n_levels_; ++level) { 202 const int width2 = (width_ >> level); 203 av1_resize_horz_dir_c(src_.get(), width_, ref_dest_.get(), height_, 204 width2 << 1, width2); 205 test_fun_(src_.get(), width_, test_dest_.get(), height_, width2 << 1, 206 width2); 207 AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), width2, height_); 208 } 209 } 210 211 void SpeedTest() { 212 for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8(); 213 214 for (int level = 1; level < n_levels_; ++level) { 215 const int width2 = (width_ >> level); 216 aom_usec_timer ref_timer; 217 aom_usec_timer_start(&ref_timer); 218 for (int j = 0; j < kIters; ++j) { 219 av1_resize_horz_dir_c(src_.get(), width_, ref_dest_.get(), height_, 220 width2 << 1, width2); 221 } 222 aom_usec_timer_mark(&ref_timer); 223 const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer); 224 225 aom_usec_timer tst_timer; 226 aom_usec_timer_start(&tst_timer); 227 for (int j = 0; j < kIters; ++j) { 228 test_fun_(src_.get(), width_, test_dest_.get(), height_, width2 << 1, 229 width2); 230 } 231 aom_usec_timer_mark(&tst_timer); 232 const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer); 233 234 std::cout << "level: " << level << " [" << width2 << " x " << height_ 235 << "] C time = " << ref_time << " , SIMD time = " << tst_time 236 << " scaling=" << float(1.00) * ref_time / tst_time << "x \n"; 237 } 238 } 239 240 private: 241 LowBDResize_x_Func test_fun_; 242 FrameDimension frame_dim_; 243 int width_; 244 int height_; 245 int n_levels_; 246 std::unique_ptr<uint8_t[]> src_; 247 std::unique_ptr<uint8_t[]> ref_dest_; 248 std::unique_ptr<uint8_t[]> test_dest_; 249 libaom_test::ACMRandom rng_; 250 }; 251 252 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeXTest); 253 254 TEST_P(AV1ResizeXTest, RunTest) { RunTest(); } 255 256 TEST_P(AV1ResizeXTest, DISABLED_SpeedTest) { SpeedTest(); } 257 258 #if HAVE_SSE2 259 INSTANTIATE_TEST_SUITE_P( 260 SSE2, AV1ResizeXTest, 261 ::testing::Combine(::testing::Values(av1_resize_horz_dir_sse2), 262 ::testing::ValuesIn(kFrameDim))); 263 #endif 264 265 #if HAVE_AVX2 266 INSTANTIATE_TEST_SUITE_P( 267 AVX2, AV1ResizeXTest, 268 ::testing::Combine(::testing::Values(av1_resize_horz_dir_avx2), 269 ::testing::ValuesIn(kFrameDim))); 270 #endif 271 272 } // namespace