• 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 <limits.h>
14 #include <stdio.h>
15 
16 extern "C" {
17 #include "./vpx_config.h"
18 #include "./vpx_rtcd.h"
19 #include "vp8/common/blockd.h"
20 #include "vpx_mem/vpx_mem.h"
21 }
22 
23 #include "test/acm_random.h"
24 #include "test/util.h"
25 #include "third_party/googletest/src/include/gtest/gtest.h"
26 
27 
28 typedef unsigned int (*sad_m_by_n_fn_t)(const unsigned char *source_ptr,
29                                         int source_stride,
30                                         const unsigned char *reference_ptr,
31                                         int reference_stride,
32                                         unsigned int max_sad);
33 
34 using libvpx_test::ACMRandom;
35 
36 namespace {
37 class SADTest : public PARAMS(int, int, sad_m_by_n_fn_t) {
38  public:
SetUpTestCase()39   static void SetUpTestCase() {
40     source_data_ = reinterpret_cast<uint8_t*>(
41         vpx_memalign(kDataAlignment, kDataBufferSize));
42     reference_data_ = reinterpret_cast<uint8_t*>(
43         vpx_memalign(kDataAlignment, kDataBufferSize));
44   }
45 
TearDownTestCase()46   static void TearDownTestCase() {
47     vpx_free(source_data_);
48     source_data_ = NULL;
49     vpx_free(reference_data_);
50     reference_data_ = NULL;
51   }
52 
53  protected:
54   static const int kDataAlignment = 16;
55   static const int kDataBufferSize = 16 * 32;
56 
SetUp()57   virtual void SetUp() {
58     sad_fn_ = GET_PARAM(2);
59     height_ = GET_PARAM(1);
60     width_ = GET_PARAM(0);
61     source_stride_ = width_ * 2;
62     reference_stride_ = width_ * 2;
63     rnd_.Reset(ACMRandom::DeterministicSeed());
64   }
65 
66   sad_m_by_n_fn_t sad_fn_;
SAD(unsigned int max_sad)67   virtual unsigned int SAD(unsigned int max_sad) {
68     return sad_fn_(source_data_, source_stride_,
69                    reference_data_, reference_stride_,
70                    max_sad);
71   }
72 
73   // Sum of Absolute Differences. Given two blocks, calculate the absolute
74   // difference between two pixels in the same relative location; accumulate.
ReferenceSAD(unsigned int max_sad)75   unsigned int ReferenceSAD(unsigned int max_sad) {
76     unsigned int sad = 0;
77 
78     for (int h = 0; h < height_; ++h) {
79       for (int w = 0; w < width_; ++w) {
80         sad += abs(source_data_[h * source_stride_ + w]
81                - reference_data_[h * reference_stride_ + w]);
82       }
83       if (sad > max_sad) {
84         break;
85       }
86     }
87     return sad;
88   }
89 
FillConstant(uint8_t * data,int stride,uint8_t fill_constant)90   void FillConstant(uint8_t *data, int stride, uint8_t fill_constant) {
91     for (int h = 0; h < height_; ++h) {
92       for (int w = 0; w < width_; ++w) {
93         data[h * stride + w] = fill_constant;
94       }
95     }
96   }
97 
FillRandom(uint8_t * data,int stride)98   void FillRandom(uint8_t *data, int stride) {
99     for (int h = 0; h < height_; ++h) {
100       for (int w = 0; w < width_; ++w) {
101         data[h * stride + w] = rnd_.Rand8();
102       }
103     }
104   }
105 
CheckSad(unsigned int max_sad)106   void CheckSad(unsigned int max_sad) {
107     unsigned int reference_sad, exp_sad;
108 
109     reference_sad = ReferenceSAD(max_sad);
110     exp_sad = SAD(max_sad);
111 
112     if (reference_sad <= max_sad) {
113       ASSERT_EQ(exp_sad, reference_sad);
114     } else {
115       // Alternative implementations are not required to check max_sad
116       ASSERT_GE(exp_sad, reference_sad);
117     }
118   }
119 
120   // Handle blocks up to 16x16 with stride up to 32
121   int height_, width_;
122   static uint8_t* source_data_;
123   int source_stride_;
124   static uint8_t* reference_data_;
125   int reference_stride_;
126 
127   ACMRandom rnd_;
128 };
129 
130 uint8_t* SADTest::source_data_ = NULL;
131 uint8_t* SADTest::reference_data_ = NULL;
132 
TEST_P(SADTest,MaxRef)133 TEST_P(SADTest, MaxRef) {
134   FillConstant(source_data_, source_stride_, 0);
135   FillConstant(reference_data_, reference_stride_, 255);
136   CheckSad(UINT_MAX);
137 }
138 
TEST_P(SADTest,MaxSrc)139 TEST_P(SADTest, MaxSrc) {
140   FillConstant(source_data_, source_stride_, 255);
141   FillConstant(reference_data_, reference_stride_, 0);
142   CheckSad(UINT_MAX);
143 }
144 
TEST_P(SADTest,ShortRef)145 TEST_P(SADTest, ShortRef) {
146   int tmp_stride = reference_stride_;
147   reference_stride_ >>= 1;
148   FillRandom(source_data_, source_stride_);
149   FillRandom(reference_data_, reference_stride_);
150   CheckSad(UINT_MAX);
151   reference_stride_ = tmp_stride;
152 }
153 
TEST_P(SADTest,UnalignedRef)154 TEST_P(SADTest, UnalignedRef) {
155   // The reference frame, but not the source frame, may be unaligned for
156   // certain types of searches.
157   int tmp_stride = reference_stride_;
158   reference_stride_ -= 1;
159   FillRandom(source_data_, source_stride_);
160   FillRandom(reference_data_, reference_stride_);
161   CheckSad(UINT_MAX);
162   reference_stride_ = tmp_stride;
163 }
164 
TEST_P(SADTest,ShortSrc)165 TEST_P(SADTest, ShortSrc) {
166   int tmp_stride = source_stride_;
167   source_stride_ >>= 1;
168   FillRandom(source_data_, source_stride_);
169   FillRandom(reference_data_, reference_stride_);
170   CheckSad(UINT_MAX);
171   source_stride_ = tmp_stride;
172 }
173 
TEST_P(SADTest,MaxSAD)174 TEST_P(SADTest, MaxSAD) {
175   // Verify that, when max_sad is set, the implementation does not return a
176   // value lower than the reference.
177   FillConstant(source_data_, source_stride_, 255);
178   FillConstant(reference_data_, reference_stride_, 0);
179   CheckSad(128);
180 }
181 
182 using std::tr1::make_tuple;
183 
184 const sad_m_by_n_fn_t sad_16x16_c = vp8_sad16x16_c;
185 const sad_m_by_n_fn_t sad_8x16_c = vp8_sad8x16_c;
186 const sad_m_by_n_fn_t sad_16x8_c = vp8_sad16x8_c;
187 const sad_m_by_n_fn_t sad_8x8_c = vp8_sad8x8_c;
188 const sad_m_by_n_fn_t sad_4x4_c = vp8_sad4x4_c;
189 INSTANTIATE_TEST_CASE_P(C, SADTest, ::testing::Values(
190                         make_tuple(16, 16, sad_16x16_c),
191                         make_tuple(8, 16, sad_8x16_c),
192                         make_tuple(16, 8, sad_16x8_c),
193                         make_tuple(8, 8, sad_8x8_c),
194                         make_tuple(4, 4, sad_4x4_c)));
195 
196 // ARM tests
197 #if HAVE_MEDIA
198 const sad_m_by_n_fn_t sad_16x16_armv6 = vp8_sad16x16_armv6;
199 INSTANTIATE_TEST_CASE_P(MEDIA, SADTest, ::testing::Values(
200                         make_tuple(16, 16, sad_16x16_armv6)));
201 
202 #endif
203 #if HAVE_NEON
204 const sad_m_by_n_fn_t sad_16x16_neon = vp8_sad16x16_neon;
205 const sad_m_by_n_fn_t sad_8x16_neon = vp8_sad8x16_neon;
206 const sad_m_by_n_fn_t sad_16x8_neon = vp8_sad16x8_neon;
207 const sad_m_by_n_fn_t sad_8x8_neon = vp8_sad8x8_neon;
208 const sad_m_by_n_fn_t sad_4x4_neon = vp8_sad4x4_neon;
209 INSTANTIATE_TEST_CASE_P(NEON, SADTest, ::testing::Values(
210                         make_tuple(16, 16, sad_16x16_neon),
211                         make_tuple(8, 16, sad_8x16_neon),
212                         make_tuple(16, 8, sad_16x8_neon),
213                         make_tuple(8, 8, sad_8x8_neon),
214                         make_tuple(4, 4, sad_4x4_neon)));
215 #endif
216 
217 // X86 tests
218 #if HAVE_MMX
219 const sad_m_by_n_fn_t sad_16x16_mmx = vp8_sad16x16_mmx;
220 const sad_m_by_n_fn_t sad_8x16_mmx = vp8_sad8x16_mmx;
221 const sad_m_by_n_fn_t sad_16x8_mmx = vp8_sad16x8_mmx;
222 const sad_m_by_n_fn_t sad_8x8_mmx = vp8_sad8x8_mmx;
223 const sad_m_by_n_fn_t sad_4x4_mmx = vp8_sad4x4_mmx;
224 INSTANTIATE_TEST_CASE_P(MMX, SADTest, ::testing::Values(
225                         make_tuple(16, 16, sad_16x16_mmx),
226                         make_tuple(8, 16, sad_8x16_mmx),
227                         make_tuple(16, 8, sad_16x8_mmx),
228                         make_tuple(8, 8, sad_8x8_mmx),
229                         make_tuple(4, 4, sad_4x4_mmx)));
230 #endif
231 #if HAVE_SSE2
232 const sad_m_by_n_fn_t sad_16x16_wmt = vp8_sad16x16_wmt;
233 const sad_m_by_n_fn_t sad_8x16_wmt = vp8_sad8x16_wmt;
234 const sad_m_by_n_fn_t sad_16x8_wmt = vp8_sad16x8_wmt;
235 const sad_m_by_n_fn_t sad_8x8_wmt = vp8_sad8x8_wmt;
236 const sad_m_by_n_fn_t sad_4x4_wmt = vp8_sad4x4_wmt;
237 INSTANTIATE_TEST_CASE_P(SSE2, SADTest, ::testing::Values(
238                         make_tuple(16, 16, sad_16x16_wmt),
239                         make_tuple(8, 16, sad_8x16_wmt),
240                         make_tuple(16, 8, sad_16x8_wmt),
241                         make_tuple(8, 8, sad_8x8_wmt),
242                         make_tuple(4, 4, sad_4x4_wmt)));
243 #endif
244 #if HAVE_SSSE3
245 const sad_m_by_n_fn_t sad_16x16_sse3 = vp8_sad16x16_sse3;
246 INSTANTIATE_TEST_CASE_P(SSE3, SADTest, ::testing::Values(
247                         make_tuple(16, 16, sad_16x16_sse3)));
248 #endif
249 
250 }  // namespace
251