xref: /aosp_15_r20/external/libgav1/src/dsp/motion_vector_search_test.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 // Copyright 2021 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dsp/motion_vector_search.h"
16 
17 #include <cstdint>
18 #include <string>
19 
20 #include "absl/strings/match.h"
21 #include "absl/strings/str_format.h"
22 #include "absl/time/clock.h"
23 #include "absl/time/time.h"
24 #include "gtest/gtest.h"
25 #include "src/dsp/dsp.h"
26 #include "src/utils/common.h"
27 #include "src/utils/constants.h"
28 #include "src/utils/cpu.h"
29 #include "src/utils/memory.h"
30 #include "src/utils/types.h"
31 #include "tests/third_party/libvpx/acm_random.h"
32 #include "tests/utils.h"
33 
34 namespace libgav1 {
35 namespace dsp {
36 namespace {
37 
38 // The 'int' parameter is unused but required to allow for instantiations of C,
39 // NEON, etc.
40 class MotionVectorSearchTest : public testing::TestWithParam<int>,
41                                public test_utils::MaxAlignedAllocable {
42  public:
43   MotionVectorSearchTest() = default;
44   MotionVectorSearchTest(const MotionVectorSearchTest&) = delete;
45   MotionVectorSearchTest& operator=(const MotionVectorSearchTest&) = delete;
46   ~MotionVectorSearchTest() override = default;
47 
SetUp()48   void SetUp() override {
49     test_utils::ResetDspTable(8);
50     MotionVectorSearchInit_C();
51     const testing::TestInfo* const test_info =
52         testing::UnitTest::GetInstance()->current_test_info();
53     const char* const test_case = test_info->test_suite_name();
54     if (absl::StartsWith(test_case, "C/")) {
55     } else if (absl::StartsWith(test_case, "NEON/")) {
56       MotionVectorSearchInit_NEON();
57     } else if (absl::StartsWith(test_case, "SSE41/")) {
58       if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
59       MotionVectorSearchInit_SSE4_1();
60     } else {
61       FAIL() << "Unrecognized architecture prefix in test case name: "
62              << test_case;
63     }
64     const Dsp* const dsp = GetDspTable(8);
65     ASSERT_NE(dsp, nullptr);
66     mv_projection_compound_[0] = dsp->mv_projection_compound[0];
67     mv_projection_compound_[1] = dsp->mv_projection_compound[1];
68     mv_projection_compound_[2] = dsp->mv_projection_compound[2];
69     mv_projection_single_[0] = dsp->mv_projection_single[0];
70     mv_projection_single_[1] = dsp->mv_projection_single[1];
71     mv_projection_single_[2] = dsp->mv_projection_single[2];
72   }
73 
74   void SetInputData(libvpx_test::ACMRandom* rnd);
75   void TestRandomValues(bool speed);
76 
77  private:
78   MvProjectionCompoundFunc mv_projection_compound_[3];
79   MvProjectionSingleFunc mv_projection_single_[3];
80   int reference_offsets_[2];
81   alignas(kMaxAlignment)
82       MotionVector temporal_mvs_[kMaxTemporalMvCandidatesWithPadding];
83   int8_t temporal_reference_offsets_[kMaxTemporalMvCandidatesWithPadding];
84   CompoundMotionVector compound_mv_org_[kMaxTemporalMvCandidates + 1]
85                                        [kMaxTemporalMvCandidatesWithPadding];
86   alignas(kMaxAlignment)
87       CompoundMotionVector compound_mv_[kMaxTemporalMvCandidates + 1]
88                                        [kMaxTemporalMvCandidatesWithPadding];
89   MotionVector single_mv_org_[kMaxTemporalMvCandidates + 1]
90                              [kMaxTemporalMvCandidatesWithPadding];
91   alignas(kMaxAlignment)
92       MotionVector single_mv_[kMaxTemporalMvCandidates + 1]
93                              [kMaxTemporalMvCandidatesWithPadding];
94 };
95 
SetInputData(libvpx_test::ACMRandom * const rnd)96 void MotionVectorSearchTest::SetInputData(libvpx_test::ACMRandom* const rnd) {
97   reference_offsets_[0] =
98       Clip3(rnd->Rand16(), -kMaxFrameDistance, kMaxFrameDistance);
99   reference_offsets_[1] =
100       Clip3(rnd->Rand16(), -kMaxFrameDistance, kMaxFrameDistance);
101   for (int i = 0; i < kMaxTemporalMvCandidatesWithPadding; ++i) {
102     temporal_reference_offsets_[i] = rnd->RandRange(kMaxFrameDistance);
103     for (auto& mv : temporal_mvs_[i].mv) {
104       mv = rnd->Rand16Signed() / 8;
105     }
106   }
107   for (int i = 0; i <= kMaxTemporalMvCandidates; ++i) {
108     for (int j = 0; j < kMaxTemporalMvCandidatesWithPadding; ++j) {
109       for (int k = 0; k < 2; ++k) {
110         single_mv_[i][j].mv[k] = rnd->Rand16Signed();
111         for (auto& mv : compound_mv_[i][j].mv[k].mv) {
112           mv = rnd->Rand16Signed();
113         }
114       }
115       compound_mv_org_[i][j] = compound_mv_[i][j];
116       single_mv_org_[i][j] = single_mv_[i][j];
117     }
118   }
119 }
120 
TestRandomValues(bool speed)121 void MotionVectorSearchTest::TestRandomValues(bool speed) {
122   static const char* const kDigestCompound[3] = {
123       "74c055b06c3701b2e50f2c964a6130b9", "cab21dd54f0a1bf6e80b58cdcf1fe0a9",
124       "e42de30cd84fa4e7b8581a330ed08a8b"};
125   static const char* const kDigestSingle[3] = {
126       "265ffbb59d0895183f8e2d90b6652c71", "5068d980c4ce42ed3f11963b8aece6cc",
127       "7e699d58df3954a38ff11c8e34151e66"};
128   const int num_tests = speed ? 1000000 : 1;
129   libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
130   for (int function_index = 0; function_index < 3; ++function_index) {
131     SetInputData(&rnd);
132     if (mv_projection_compound_[function_index] == nullptr) continue;
133     const absl::Time start = absl::Now();
134     for (int count = 1; count <= kMaxTemporalMvCandidates; ++count) {
135       const int total_count = count + (count & 1);
136       for (int i = 0; i < num_tests; ++i) {
137         mv_projection_compound_[function_index](
138             temporal_mvs_, temporal_reference_offsets_, reference_offsets_,
139             count, compound_mv_[count]);
140       }
141       // One more element could be calculated in SIMD implementations.
142       // Restore the original values if any.
143       for (int i = count; i < total_count; ++i) {
144         compound_mv_[count][i] = compound_mv_org_[count][i];
145       }
146     }
147     const absl::Duration elapsed_time = absl::Now() - start;
148     test_utils::CheckMd5Digest(
149         "MvProjectionCompound",
150         absl::StrFormat("function_index %d", function_index).c_str(),
151         kDigestCompound[function_index], compound_mv_, sizeof(compound_mv_),
152         elapsed_time);
153   }
154   for (int function_index = 0; function_index < 3; ++function_index) {
155     SetInputData(&rnd);
156     if (mv_projection_single_[function_index] == nullptr) continue;
157     const absl::Time start = absl::Now();
158     for (int count = 1; count <= kMaxTemporalMvCandidates; ++count) {
159       const int total_count = (count + 3) & ~3;
160       for (int i = 0; i < num_tests; ++i) {
161         mv_projection_single_[function_index](
162             temporal_mvs_, temporal_reference_offsets_, reference_offsets_[0],
163             count, single_mv_[count]);
164       }
165       // Up to three more elements could be calculated in SIMD implementations.
166       // Restore the original values if any.
167       for (int i = count; i < total_count; ++i) {
168         single_mv_[count][i] = single_mv_org_[count][i];
169       }
170     }
171     const absl::Duration elapsed_time = absl::Now() - start;
172     test_utils::CheckMd5Digest(
173         "MvProjectionSingle",
174         absl::StrFormat("function_index %d", function_index).c_str(),
175         kDigestSingle[function_index], single_mv_, sizeof(single_mv_),
176         elapsed_time);
177   }
178 }
179 
TEST_P(MotionVectorSearchTest,Correctness)180 TEST_P(MotionVectorSearchTest, Correctness) { TestRandomValues(false); }
181 
TEST_P(MotionVectorSearchTest,DISABLED_Speed)182 TEST_P(MotionVectorSearchTest, DISABLED_Speed) { TestRandomValues(true); }
183 
184 INSTANTIATE_TEST_SUITE_P(C, MotionVectorSearchTest, testing::Values(0));
185 
186 #if LIBGAV1_ENABLE_NEON
187 INSTANTIATE_TEST_SUITE_P(NEON, MotionVectorSearchTest, testing::Values(0));
188 #endif
189 
190 #if LIBGAV1_ENABLE_SSE4_1
191 INSTANTIATE_TEST_SUITE_P(SSE41, MotionVectorSearchTest, testing::Values(0));
192 #endif
193 
194 }  // namespace
195 }  // namespace dsp
196 }  // namespace libgav1
197