1 /*
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11
12 #include <string.h>
13 #include "test/acm_random.h"
14 #include "test/clear_system_state.h"
15 #include "test/register_state_check.h"
16 #include "third_party/googletest/src/include/gtest/gtest.h"
17
18 #include "./vpx_config.h"
19 #include "./vp8_rtcd.h"
20 #include "vp8/common/blockd.h"
21 #include "vpx_mem/vpx_mem.h"
22
23 namespace {
24
25 using libvpx_test::ACMRandom;
26
27 class IntraPredBase {
28 public:
~IntraPredBase()29 virtual ~IntraPredBase() { libvpx_test::ClearSystemState(); }
30
31 protected:
SetupMacroblock(MACROBLOCKD * mbptr,MODE_INFO * miptr,uint8_t * data,int block_size,int stride,int num_planes)32 void SetupMacroblock(MACROBLOCKD *mbptr,
33 MODE_INFO *miptr,
34 uint8_t *data,
35 int block_size,
36 int stride,
37 int num_planes) {
38 mbptr_ = mbptr;
39 miptr_ = miptr;
40 mbptr_->up_available = 1;
41 mbptr_->left_available = 1;
42 mbptr_->mode_info_context = miptr_;
43 stride_ = stride;
44 block_size_ = block_size;
45 num_planes_ = num_planes;
46 for (int p = 0; p < num_planes; p++)
47 data_ptr_[p] = data + stride * (block_size + 1) * p +
48 stride + block_size;
49 }
50
FillRandom()51 void FillRandom() {
52 // Fill edges with random data
53 ACMRandom rnd(ACMRandom::DeterministicSeed());
54 for (int p = 0; p < num_planes_; p++) {
55 for (int x = -1 ; x <= block_size_; x++)
56 data_ptr_[p][x - stride_] = rnd.Rand8();
57 for (int y = 0; y < block_size_; y++)
58 data_ptr_[p][y * stride_ - 1] = rnd.Rand8();
59 }
60 }
61
62 virtual void Predict(MB_PREDICTION_MODE mode) = 0;
63
SetLeftUnavailable()64 void SetLeftUnavailable() {
65 mbptr_->left_available = 0;
66 for (int p = 0; p < num_planes_; p++)
67 for (int i = -1; i < block_size_; ++i)
68 data_ptr_[p][stride_ * i - 1] = 129;
69 }
70
SetTopUnavailable()71 void SetTopUnavailable() {
72 mbptr_->up_available = 0;
73 for (int p = 0; p < num_planes_; p++)
74 memset(&data_ptr_[p][-1 - stride_], 127, block_size_ + 2);
75 }
76
SetTopLeftUnavailable()77 void SetTopLeftUnavailable() {
78 SetLeftUnavailable();
79 SetTopUnavailable();
80 }
81
BlockSizeLog2Min1() const82 int BlockSizeLog2Min1() const {
83 switch (block_size_) {
84 case 16:
85 return 3;
86 case 8:
87 return 2;
88 default:
89 return 0;
90 }
91 }
92
93 // check DC prediction output against a reference
CheckDCPrediction() const94 void CheckDCPrediction() const {
95 for (int p = 0; p < num_planes_; p++) {
96 // calculate expected DC
97 int expected;
98 if (mbptr_->up_available || mbptr_->left_available) {
99 int sum = 0, shift = BlockSizeLog2Min1() + mbptr_->up_available +
100 mbptr_->left_available;
101 if (mbptr_->up_available)
102 for (int x = 0; x < block_size_; x++)
103 sum += data_ptr_[p][x - stride_];
104 if (mbptr_->left_available)
105 for (int y = 0; y < block_size_; y++)
106 sum += data_ptr_[p][y * stride_ - 1];
107 expected = (sum + (1 << (shift - 1))) >> shift;
108 } else {
109 expected = 0x80;
110 }
111 // check that all subsequent lines are equal to the first
112 for (int y = 1; y < block_size_; ++y)
113 ASSERT_EQ(0, memcmp(data_ptr_[p], &data_ptr_[p][y * stride_],
114 block_size_));
115 // within the first line, ensure that each pixel has the same value
116 for (int x = 1; x < block_size_; ++x)
117 ASSERT_EQ(data_ptr_[p][0], data_ptr_[p][x]);
118 // now ensure that that pixel has the expected (DC) value
119 ASSERT_EQ(expected, data_ptr_[p][0]);
120 }
121 }
122
123 // check V prediction output against a reference
CheckVPrediction() const124 void CheckVPrediction() const {
125 // check that all lines equal the top border
126 for (int p = 0; p < num_planes_; p++)
127 for (int y = 0; y < block_size_; y++)
128 ASSERT_EQ(0, memcmp(&data_ptr_[p][-stride_],
129 &data_ptr_[p][y * stride_], block_size_));
130 }
131
132 // check H prediction output against a reference
CheckHPrediction() const133 void CheckHPrediction() const {
134 // for each line, ensure that each pixel is equal to the left border
135 for (int p = 0; p < num_planes_; p++)
136 for (int y = 0; y < block_size_; y++)
137 for (int x = 0; x < block_size_; x++)
138 ASSERT_EQ(data_ptr_[p][-1 + y * stride_],
139 data_ptr_[p][x + y * stride_]);
140 }
141
ClipByte(int value)142 static int ClipByte(int value) {
143 if (value > 255)
144 return 255;
145 else if (value < 0)
146 return 0;
147 return value;
148 }
149
150 // check TM prediction output against a reference
CheckTMPrediction() const151 void CheckTMPrediction() const {
152 for (int p = 0; p < num_planes_; p++)
153 for (int y = 0; y < block_size_; y++)
154 for (int x = 0; x < block_size_; x++) {
155 const int expected = ClipByte(data_ptr_[p][x - stride_]
156 + data_ptr_[p][stride_ * y - 1]
157 - data_ptr_[p][-1 - stride_]);
158 ASSERT_EQ(expected, data_ptr_[p][y * stride_ + x]);
159 }
160 }
161
162 // Actual test
RunTest()163 void RunTest() {
164 {
165 SCOPED_TRACE("DC_PRED");
166 FillRandom();
167 Predict(DC_PRED);
168 CheckDCPrediction();
169 }
170 {
171 SCOPED_TRACE("DC_PRED LEFT");
172 FillRandom();
173 SetLeftUnavailable();
174 Predict(DC_PRED);
175 CheckDCPrediction();
176 }
177 {
178 SCOPED_TRACE("DC_PRED TOP");
179 FillRandom();
180 SetTopUnavailable();
181 Predict(DC_PRED);
182 CheckDCPrediction();
183 }
184 {
185 SCOPED_TRACE("DC_PRED TOP_LEFT");
186 FillRandom();
187 SetTopLeftUnavailable();
188 Predict(DC_PRED);
189 CheckDCPrediction();
190 }
191 {
192 SCOPED_TRACE("H_PRED");
193 FillRandom();
194 Predict(H_PRED);
195 CheckHPrediction();
196 }
197 {
198 SCOPED_TRACE("V_PRED");
199 FillRandom();
200 Predict(V_PRED);
201 CheckVPrediction();
202 }
203 {
204 SCOPED_TRACE("TM_PRED");
205 FillRandom();
206 Predict(TM_PRED);
207 CheckTMPrediction();
208 }
209 }
210
211 MACROBLOCKD *mbptr_;
212 MODE_INFO *miptr_;
213 uint8_t *data_ptr_[2]; // in the case of Y, only [0] is used
214 int stride_;
215 int block_size_;
216 int num_planes_;
217 };
218
219 typedef void (*intra_pred_y_fn_t)(MACROBLOCKD *x,
220 uint8_t *yabove_row,
221 uint8_t *yleft,
222 int left_stride,
223 uint8_t *ypred_ptr,
224 int y_stride);
225
226 class IntraPredYTest
227 : public IntraPredBase,
228 public ::testing::TestWithParam<intra_pred_y_fn_t> {
229 public:
SetUpTestCase()230 static void SetUpTestCase() {
231 mb_ = reinterpret_cast<MACROBLOCKD*>(
232 vpx_memalign(32, sizeof(MACROBLOCKD)));
233 mi_ = reinterpret_cast<MODE_INFO*>(
234 vpx_memalign(32, sizeof(MODE_INFO)));
235 data_array_ = reinterpret_cast<uint8_t*>(
236 vpx_memalign(kDataAlignment, kDataBufferSize));
237 }
238
TearDownTestCase()239 static void TearDownTestCase() {
240 vpx_free(data_array_);
241 vpx_free(mi_);
242 vpx_free(mb_);
243 data_array_ = NULL;
244 }
245
246 protected:
247 static const int kBlockSize = 16;
248 static const int kDataAlignment = 16;
249 static const int kStride = kBlockSize * 3;
250 // We use 48 so that the data pointer of the first pixel in each row of
251 // each macroblock is 16-byte aligned, and this gives us access to the
252 // top-left and top-right corner pixels belonging to the top-left/right
253 // macroblocks.
254 // We use 17 lines so we have one line above us for top-prediction.
255 static const int kDataBufferSize = kStride * (kBlockSize + 1);
256
SetUp()257 virtual void SetUp() {
258 pred_fn_ = GetParam();
259 SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 1);
260 }
261
Predict(MB_PREDICTION_MODE mode)262 virtual void Predict(MB_PREDICTION_MODE mode) {
263 mbptr_->mode_info_context->mbmi.mode = mode;
264 REGISTER_STATE_CHECK(pred_fn_(mbptr_,
265 data_ptr_[0] - kStride,
266 data_ptr_[0] - 1, kStride,
267 data_ptr_[0], kStride));
268 }
269
270 intra_pred_y_fn_t pred_fn_;
271 static uint8_t* data_array_;
272 static MACROBLOCKD * mb_;
273 static MODE_INFO *mi_;
274 };
275
276 MACROBLOCKD* IntraPredYTest::mb_ = NULL;
277 MODE_INFO* IntraPredYTest::mi_ = NULL;
278 uint8_t* IntraPredYTest::data_array_ = NULL;
279
TEST_P(IntraPredYTest,IntraPredTests)280 TEST_P(IntraPredYTest, IntraPredTests) {
281 RunTest();
282 }
283
284 INSTANTIATE_TEST_CASE_P(C, IntraPredYTest,
285 ::testing::Values(
286 vp8_build_intra_predictors_mby_s_c));
287 #if HAVE_SSE2
288 INSTANTIATE_TEST_CASE_P(SSE2, IntraPredYTest,
289 ::testing::Values(
290 vp8_build_intra_predictors_mby_s_sse2));
291 #endif
292 #if HAVE_SSSE3
293 INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredYTest,
294 ::testing::Values(
295 vp8_build_intra_predictors_mby_s_ssse3));
296 #endif
297
298 typedef void (*intra_pred_uv_fn_t)(MACROBLOCKD *x,
299 uint8_t *uabove_row,
300 uint8_t *vabove_row,
301 uint8_t *uleft,
302 uint8_t *vleft,
303 int left_stride,
304 uint8_t *upred_ptr,
305 uint8_t *vpred_ptr,
306 int pred_stride);
307
308 class IntraPredUVTest
309 : public IntraPredBase,
310 public ::testing::TestWithParam<intra_pred_uv_fn_t> {
311 public:
SetUpTestCase()312 static void SetUpTestCase() {
313 mb_ = reinterpret_cast<MACROBLOCKD*>(
314 vpx_memalign(32, sizeof(MACROBLOCKD)));
315 mi_ = reinterpret_cast<MODE_INFO*>(
316 vpx_memalign(32, sizeof(MODE_INFO)));
317 data_array_ = reinterpret_cast<uint8_t*>(
318 vpx_memalign(kDataAlignment, kDataBufferSize));
319 }
320
TearDownTestCase()321 static void TearDownTestCase() {
322 vpx_free(data_array_);
323 vpx_free(mi_);
324 vpx_free(mb_);
325 data_array_ = NULL;
326 }
327
328 protected:
329 static const int kBlockSize = 8;
330 static const int kDataAlignment = 8;
331 static const int kStride = kBlockSize * 3;
332 // We use 24 so that the data pointer of the first pixel in each row of
333 // each macroblock is 8-byte aligned, and this gives us access to the
334 // top-left and top-right corner pixels belonging to the top-left/right
335 // macroblocks.
336 // We use 9 lines so we have one line above us for top-prediction.
337 // [0] = U, [1] = V
338 static const int kDataBufferSize = 2 * kStride * (kBlockSize + 1);
339
SetUp()340 virtual void SetUp() {
341 pred_fn_ = GetParam();
342 SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 2);
343 }
344
Predict(MB_PREDICTION_MODE mode)345 virtual void Predict(MB_PREDICTION_MODE mode) {
346 mbptr_->mode_info_context->mbmi.uv_mode = mode;
347 pred_fn_(mbptr_, data_ptr_[0] - kStride, data_ptr_[1] - kStride,
348 data_ptr_[0] - 1, data_ptr_[1] - 1, kStride,
349 data_ptr_[0], data_ptr_[1], kStride);
350 }
351
352 intra_pred_uv_fn_t pred_fn_;
353 // We use 24 so that the data pointer of the first pixel in each row of
354 // each macroblock is 8-byte aligned, and this gives us access to the
355 // top-left and top-right corner pixels belonging to the top-left/right
356 // macroblocks.
357 // We use 9 lines so we have one line above us for top-prediction.
358 // [0] = U, [1] = V
359 static uint8_t* data_array_;
360 static MACROBLOCKD* mb_;
361 static MODE_INFO* mi_;
362 };
363
364 MACROBLOCKD* IntraPredUVTest::mb_ = NULL;
365 MODE_INFO* IntraPredUVTest::mi_ = NULL;
366 uint8_t* IntraPredUVTest::data_array_ = NULL;
367
TEST_P(IntraPredUVTest,IntraPredTests)368 TEST_P(IntraPredUVTest, IntraPredTests) {
369 RunTest();
370 }
371
372 INSTANTIATE_TEST_CASE_P(C, IntraPredUVTest,
373 ::testing::Values(
374 vp8_build_intra_predictors_mbuv_s_c));
375 #if HAVE_SSE2
376 INSTANTIATE_TEST_CASE_P(SSE2, IntraPredUVTest,
377 ::testing::Values(
378 vp8_build_intra_predictors_mbuv_s_sse2));
379 #endif
380 #if HAVE_SSSE3
381 INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredUVTest,
382 ::testing::Values(
383 vp8_build_intra_predictors_mbuv_s_ssse3));
384 #endif
385
386 } // namespace
387