• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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