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