1 /*
2 * Copyright (c) 2019, 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 <math.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <tuple>
16
17 #include "config/av1_rtcd.h"
18
19 #include "aom_mem/aom_mem.h"
20 #include "aom_ports/aom_timer.h"
21 #include "aom_ports/mem.h"
22 #include "test/acm_random.h"
23 #include "test/util.h"
24 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
25
26 namespace {
27 typedef int64_t (*frame_error_func)(const uint8_t *const ref, int stride,
28 const uint8_t *const dst, int p_width,
29 int p_height, int p_stride);
30 #if HAVE_AVX2 || HAVE_SSE2
31 const int kBlockWidth[] = {
32 832, 834, 640, 1280, 1920,
33 };
34 const int kBlockHeight[] = {
35 480, 482, 360, 720, 1080,
36 };
37 #endif
38 typedef std::tuple<frame_error_func, int, int> FrameErrorParam;
39
40 class AV1FrameErrorTest : public ::testing::TestWithParam<FrameErrorParam> {
41 public:
~AV1FrameErrorTest()42 virtual ~AV1FrameErrorTest() {}
SetUp()43 virtual void SetUp() {
44 rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
45 }
TearDown()46 virtual void TearDown() {}
47
48 protected:
49 void RandomValues(frame_error_func test_impl, int width, int height);
50 void ExtremeValues(frame_error_func test_impl, int width, int height);
51 void RunSpeedTest(frame_error_func test_impl, int width, int height);
52 libaom_test::ACMRandom rnd_;
53 };
54 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1FrameErrorTest);
55
RandomValues(frame_error_func test_impl,int width,int height)56 void AV1FrameErrorTest::RandomValues(frame_error_func test_impl, int width,
57 int height) {
58 const int stride = (((width * 3) / 2) + 15) & ~15;
59 const int max_blk_size = stride * height;
60 uint8_t *const dst =
61 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*dst)));
62 uint8_t *const ref =
63 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*ref)));
64 ASSERT_NE(dst, nullptr);
65 ASSERT_NE(ref, nullptr);
66 for (int i = 0; i < max_blk_size; ++i) {
67 dst[i] = rnd_.Rand8();
68 ref[i] = rnd_.Rand8();
69 }
70 const int64_t ref_error =
71 av1_calc_frame_error_c(ref, stride, dst, width, height, stride);
72 const int64_t test_error = test_impl(ref, stride, dst, width, height, stride);
73 ASSERT_EQ(test_error, ref_error) << width << "x" << height;
74 aom_free(dst);
75 aom_free(ref);
76 }
77
ExtremeValues(frame_error_func test_impl,int width,int height)78 void AV1FrameErrorTest::ExtremeValues(frame_error_func test_impl, int width,
79 int height) {
80 const int stride = (((width * 3) / 2) + 15) & ~15;
81 const int max_blk_size = stride * height;
82 uint8_t *const dst =
83 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*dst)));
84 uint8_t *const ref =
85 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*ref)));
86 ASSERT_NE(dst, nullptr);
87 ASSERT_NE(ref, nullptr);
88 for (int r = 0; r < 2; r++) {
89 if (r == 0) {
90 memset(dst, 0, max_blk_size);
91 memset(ref, 255, max_blk_size);
92 } else if (r == 1) {
93 memset(dst, 255, max_blk_size);
94 memset(ref, 0, max_blk_size);
95 }
96 const int64_t ref_error =
97 av1_calc_frame_error_c(ref, stride, dst, width, height, stride);
98 const int64_t test_error =
99 test_impl(ref, stride, dst, width, height, stride);
100 ASSERT_EQ(test_error, ref_error) << width << "x" << height;
101 }
102 aom_free(dst);
103 aom_free(ref);
104 }
105
RunSpeedTest(frame_error_func test_impl,int width,int height)106 void AV1FrameErrorTest::RunSpeedTest(frame_error_func test_impl, int width,
107 int height) {
108 const int stride = (((width * 3) / 2) + 15) & ~15;
109 const int max_blk_size = stride * height;
110 uint8_t *const dst =
111 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*dst)));
112 uint8_t *const ref =
113 static_cast<uint8_t *>(aom_memalign(16, max_blk_size * sizeof(*ref)));
114 ASSERT_NE(dst, nullptr);
115 ASSERT_NE(ref, nullptr);
116 for (int i = 0; i < max_blk_size; ++i) {
117 dst[i] = ref[i] = rnd_.Rand8();
118 }
119 const int num_loops = 10000000 / (width + height);
120 frame_error_func funcs[2] = { av1_calc_frame_error_c, test_impl };
121 double elapsed_time[2] = { 0 };
122 for (int i = 0; i < 2; ++i) {
123 aom_usec_timer timer;
124 aom_usec_timer_start(&timer);
125 frame_error_func func = funcs[i];
126 for (int j = 0; j < num_loops; ++j) {
127 func(ref, stride, dst, width, height, stride);
128 }
129 aom_usec_timer_mark(&timer);
130 double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
131 elapsed_time[i] = 1000.0 * time / num_loops;
132 }
133 aom_free(dst);
134 aom_free(ref);
135 printf("av1_calc_frame_error %3dx%-3d: %7.2f/%7.2fns", width, height,
136 elapsed_time[0], elapsed_time[1]);
137 printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
138 }
139
TEST_P(AV1FrameErrorTest,CheckOutput)140 TEST_P(AV1FrameErrorTest, CheckOutput) {
141 RandomValues(GET_PARAM(0), GET_PARAM(1), GET_PARAM(2));
142 ExtremeValues(GET_PARAM(0), GET_PARAM(1), GET_PARAM(2));
143 }
144
TEST_P(AV1FrameErrorTest,DISABLED_Speed)145 TEST_P(AV1FrameErrorTest, DISABLED_Speed) {
146 RunSpeedTest(GET_PARAM(0), GET_PARAM(1), GET_PARAM(2));
147 }
148
149 #if HAVE_SSE2
150 INSTANTIATE_TEST_SUITE_P(
151 SSE2, AV1FrameErrorTest,
152 ::testing::Combine(::testing::Values(&av1_calc_frame_error_sse2),
153 ::testing::ValuesIn(kBlockWidth),
154 ::testing::ValuesIn(kBlockHeight)));
155 #endif
156
157 #if HAVE_AVX2
158 INSTANTIATE_TEST_SUITE_P(
159 AVX2, AV1FrameErrorTest,
160 ::testing::Combine(::testing::Values(&av1_calc_frame_error_avx2),
161 ::testing::ValuesIn(kBlockWidth),
162 ::testing::ValuesIn(kBlockHeight)));
163 #endif
164 } // namespace
165