xref: /aosp_15_r20/external/libaom/test/frame_resize_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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 typedef tuple<int, int> FrameDimension;
34 
35 // Check that two 8-bit output buffers are identical.
AssertOutputBufferEq(const uint8_t * p1,const uint8_t * p2,int width,int height)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 typedef bool (*LowBDResizeFunc)(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 typedef tuple<LowBDResizeFunc, FrameDimension> ResizeTestParams;
59 
60 class AV1ResizeYTest : public ::testing::TestWithParam<ResizeTestParams> {
61  public:
SetUp()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 
RunTest()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 
SpeedTest()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 
TEST_P(AV1ResizeYTest,RunTest)140 TEST_P(AV1ResizeYTest, RunTest) { RunTest(); }
141 
TEST_P(AV1ResizeYTest,DISABLED_SpeedTest)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 typedef void (*LowBDResize_x_Func)(const uint8_t *const input, int in_stride,
170                                    uint8_t *intbuf, int height,
171                                    int filtered_length, int width2);
172 
173 typedef tuple<LowBDResize_x_Func, FrameDimension> Resize_x_TestParams;
174 
175 class AV1ResizeXTest : public ::testing::TestWithParam<Resize_x_TestParams> {
176  public:
SetUp()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 
RunTest()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 
SpeedTest()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 
TEST_P(AV1ResizeXTest,RunTest)254 TEST_P(AV1ResizeXTest, RunTest) { RunTest(); }
255 
TEST_P(AV1ResizeXTest,DISABLED_SpeedTest)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
273