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/arm/common_neon.h"
16
17 #include "gtest/gtest.h"
18 #include "src/utils/cpu.h"
19
20 #if LIBGAV1_ENABLE_NEON
21 #include <cstdint>
22
23 #include "tests/block_utils.h"
24
25 namespace libgav1 {
26 namespace dsp {
27 namespace {
28
29 constexpr int kMaxBlockWidth = 16;
30 constexpr int kMaxBlockHeight = 16;
31
32 template <typename Pixel>
33 class TransposeTest : public testing::Test {
34 public:
TransposeTest()35 TransposeTest() {
36 for (int y = 0; y < kMaxBlockHeight; ++y) {
37 for (int x = 0; x < kMaxBlockWidth; ++x) {
38 src_block_[y][x] = y * 16 + x;
39 expected_transpose_[y][x] = x * 16 + y;
40 }
41 }
42 }
43
44 TransposeTest(const TransposeTest&) = delete;
45 TransposeTest& operator=(const TransposeTest&) = delete;
46 ~TransposeTest() override = default;
47
48 protected:
49 Pixel src_block_[kMaxBlockHeight][kMaxBlockWidth];
50 Pixel expected_transpose_[kMaxBlockHeight][kMaxBlockWidth];
51 };
52
53 using TransposeTestLowBitdepth = TransposeTest<uint8_t>;
54
TEST_F(TransposeTestLowBitdepth,Transpose4x4Test)55 TEST_F(TransposeTestLowBitdepth, Transpose4x4Test) {
56 uint8x8_t a = Load4<1>(src_block_[1], Load4(src_block_[0]));
57 uint8x8_t b = Load4<1>(src_block_[3], Load4(src_block_[2]));
58 Transpose4x4(&a, &b);
59 uint8_t output_4x4[4][4];
60 StoreLo4(output_4x4[0], a);
61 StoreLo4(output_4x4[1], b);
62 StoreHi4(output_4x4[2], a);
63 StoreHi4(output_4x4[3], b);
64 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x4[0],
65 4, 4, kMaxBlockWidth, 4, false));
66 }
67
TEST_F(TransposeTestLowBitdepth,Transpose8x4Test)68 TEST_F(TransposeTestLowBitdepth, Transpose8x4Test) {
69 uint8x8_t a0 = Load4<1>(src_block_[4], Load4(src_block_[0]));
70 uint8x8_t a1 = Load4<1>(src_block_[5], Load4(src_block_[1]));
71 uint8x8_t a2 = Load4<1>(src_block_[6], Load4(src_block_[2]));
72 uint8x8_t a3 = Load4<1>(src_block_[7], Load4(src_block_[3]));
73 Transpose8x4(&a0, &a1, &a2, &a3);
74 uint8_t output_8x4[4][8];
75 vst1_u8(output_8x4[0], a0);
76 vst1_u8(output_8x4[1], a1);
77 vst1_u8(output_8x4[2], a2);
78 vst1_u8(output_8x4[3], a3);
79 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x4[0],
80 8, 4, kMaxBlockWidth, 8, false));
81 }
82
TEST_F(TransposeTestLowBitdepth,Transpose8x8Test)83 TEST_F(TransposeTestLowBitdepth, Transpose8x8Test) {
84 uint8x8_t input_8x8[8];
85 for (int i = 0; i < 8; ++i) {
86 input_8x8[i] = vld1_u8(src_block_[i]);
87 }
88 Transpose8x8(input_8x8);
89 uint8_t output_8x8[8][8];
90 for (int i = 0; i < 8; ++i) {
91 vst1_u8(output_8x8[i], input_8x8[i]);
92 }
93 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
94 8, 8, kMaxBlockWidth, 8, false));
95 }
96
TEST_F(TransposeTestLowBitdepth,Transpose8x16Test)97 TEST_F(TransposeTestLowBitdepth, Transpose8x16Test) {
98 uint8x16_t input_8x16[8];
99 for (int i = 0; i < 8; ++i) {
100 input_8x16[i] =
101 vcombine_u8(vld1_u8(src_block_[i]), vld1_u8(src_block_[i + 8]));
102 }
103 Transpose8x16(input_8x16);
104 uint8_t output_16x8[8][16];
105 for (int i = 0; i < 8; ++i) {
106 vst1q_u8(output_16x8[i], input_8x16[i]);
107 }
108 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_16x8[0],
109 16, 8, kMaxBlockWidth, 16, false));
110 }
111
112 using TransposeTestHighBitdepth = TransposeTest<uint16_t>;
113
TEST_F(TransposeTestHighBitdepth,Transpose4x4Test)114 TEST_F(TransposeTestHighBitdepth, Transpose4x4Test) {
115 uint16x4_t input_4x4[4];
116 input_4x4[0] = vld1_u16(src_block_[0]);
117 input_4x4[1] = vld1_u16(src_block_[1]);
118 input_4x4[2] = vld1_u16(src_block_[2]);
119 input_4x4[3] = vld1_u16(src_block_[3]);
120 Transpose4x4(input_4x4);
121 uint16_t output_4x4[4][4];
122 for (int i = 0; i < 4; ++i) {
123 vst1_u16(output_4x4[i], input_4x4[i]);
124 }
125 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x4[0],
126 4, 4, kMaxBlockWidth, 4, false));
127 }
128
TEST_F(TransposeTestHighBitdepth,Transpose4x8Test)129 TEST_F(TransposeTestHighBitdepth, Transpose4x8Test) {
130 uint16x8_t input_4x8[4];
131 for (int i = 0; i < 4; ++i) {
132 input_4x8[i] = vld1q_u16(src_block_[i]);
133 }
134 Transpose4x8(input_4x8);
135 uint16_t output_4x8[4][8];
136 for (int i = 0; i < 4; ++i) {
137 vst1q_u16(output_4x8[i], input_4x8[i]);
138 memcpy(&expected_transpose_[i][4], &expected_transpose_[i + 4][0],
139 4 * sizeof(expected_transpose_[0][0]));
140 }
141 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x8[0],
142 8, 4, kMaxBlockWidth, 8, false));
143 }
144
TEST_F(TransposeTestHighBitdepth,LoopFilterTranspose4x8Test)145 TEST_F(TransposeTestHighBitdepth, LoopFilterTranspose4x8Test) {
146 uint16x8_t input_4x8[4];
147 for (int i = 0; i < 4; ++i) {
148 input_4x8[i] = vld1q_u16(src_block_[i]);
149 }
150 LoopFilterTranspose4x8(input_4x8);
151 uint16_t output_4x8[4][8];
152 for (int i = 0; i < 4; ++i) {
153 vst1q_u16(output_4x8[i], input_4x8[i]);
154 }
155 // a[0]: 03 13 23 33 04 14 24 34 p0q0
156 // a[1]: 02 12 22 32 05 15 25 35 p1q1
157 // a[2]: 01 11 21 31 06 16 26 36 p2q2
158 // a[3]: 00 10 20 30 07 17 27 37 p3q3
159 static constexpr uint16_t expected_output[4][8] = {
160 {0x03, 0x13, 0x23, 0x33, 0x04, 0x14, 0x24, 0x34},
161 {0x02, 0x12, 0x22, 0x32, 0x05, 0x15, 0x25, 0x35},
162 {0x01, 0x11, 0x21, 0x31, 0x06, 0x16, 0x26, 0x36},
163 {0x00, 0x10, 0x20, 0x30, 0x07, 0x17, 0x27, 0x37},
164 };
165 EXPECT_TRUE(test_utils::CompareBlocks(expected_output[0], output_4x8[0], 8, 4,
166 8, 8, false));
167 }
168
TEST_F(TransposeTestHighBitdepth,Transpose8x8Test)169 TEST_F(TransposeTestHighBitdepth, Transpose8x8Test) {
170 uint16x8_t input_8x8[8];
171 for (int i = 0; i < 8; ++i) {
172 input_8x8[i] = vld1q_u16(src_block_[i]);
173 }
174 Transpose8x8(input_8x8);
175 uint16_t output_8x8[8][8];
176 for (int i = 0; i < 8; ++i) {
177 vst1q_u16(output_8x8[i], input_8x8[i]);
178 }
179 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
180 8, 8, kMaxBlockWidth, 8, false));
181 }
182
TEST_F(TransposeTestHighBitdepth,Transpose8x8SignedTest)183 TEST_F(TransposeTestHighBitdepth, Transpose8x8SignedTest) {
184 int16x8_t input_8x8[8];
185 for (int i = 0; i < 8; ++i) {
186 input_8x8[i] = vreinterpretq_s16_u16(vld1q_u16(src_block_[i]));
187 }
188 Transpose8x8(input_8x8);
189 uint16_t output_8x8[8][8];
190 for (int i = 0; i < 8; ++i) {
191 vst1q_u16(output_8x8[i], vreinterpretq_u16_s16(input_8x8[i]));
192 }
193 EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
194 8, 8, kMaxBlockWidth, 8, false));
195 }
196
197 } // namespace
198 } // namespace dsp
199 } // namespace libgav1
200
201 #else // !LIBGAV1_ENABLE_NEON
202
TEST(CommonDspTest,NEON)203 TEST(CommonDspTest, NEON) {
204 GTEST_SKIP()
205 << "Build this module for Arm with NEON enabled to enable the tests.";
206 }
207
208 #endif // LIBGAV1_ENABLE_NEON
209