sad_test.cc 7.88 KB
Newer Older
Johann's avatar
Johann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


#include <string.h>
#include <limits.h>
#include <stdio.h>

extern "C" {
#include "./vpx_config.h"
#include "./vpx_rtcd.h"
#include "vp8/common/blockd.h"
20
#include "vpx_mem/vpx_mem.h"
Johann's avatar
Johann committed
21
22
23
24
25
26
27
28
29
30
31
}

#include "test/acm_random.h"
#include "test/util.h"
#include "third_party/googletest/src/include/gtest/gtest.h"


typedef unsigned int (*sad_m_by_n_fn_t)(const unsigned char *source_ptr,
                                        int source_stride,
                                        const unsigned char *reference_ptr,
                                        int reference_stride,
Johann's avatar
Johann committed
32
                                        unsigned int max_sad);
Johann's avatar
Johann committed
33
34
35
36
37

using libvpx_test::ACMRandom;

namespace {
class SADTest : public PARAMS(int, int, sad_m_by_n_fn_t) {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 public:
  static void SetUpTestCase() {
    source_data_ = reinterpret_cast<uint8_t*>(
        vpx_memalign(kDataAlignment, kDataBufferSize));
    reference_data_ = reinterpret_cast<uint8_t*>(
        vpx_memalign(kDataAlignment, kDataBufferSize));
  }

  static void TearDownTestCase() {
    vpx_free(source_data_);
    source_data_ = NULL;
    vpx_free(reference_data_);
    reference_data_ = NULL;
  }

 protected:
  static const int kDataAlignment = 16;
  static const int kDataBufferSize = 16 * 32;

Johann's avatar
Johann committed
57
58
59
60
61
62
63
64
65
66
  virtual void SetUp() {
    sad_fn_ = GET_PARAM(2);
    height_ = GET_PARAM(1);
    width_ = GET_PARAM(0);
    source_stride_ = width_ * 2;
    reference_stride_ = width_ * 2;
    rnd_.Reset(ACMRandom::DeterministicSeed());
  }

  sad_m_by_n_fn_t sad_fn_;
Johann's avatar
Johann committed
67
  virtual unsigned int SAD(unsigned int max_sad) {
Johann's avatar
Johann committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    return sad_fn_(source_data_, source_stride_,
                   reference_data_, reference_stride_,
                   max_sad);
  }

  // Sum of Absolute Differences. Given two blocks, calculate the absolute
  // difference between two pixels in the same relative location; accumulate.
  unsigned int ReferenceSAD(unsigned int max_sad) {
    unsigned int sad = 0;

    for (int h = 0; h < height_; ++h) {
      for (int w = 0; w < width_; ++w) {
        sad += abs(source_data_[h * source_stride_ + w]
               - reference_data_[h * reference_stride_ + w]);
      }
      if (sad > max_sad) {
        break;
      }
    }
    return sad;
  }

  void FillConstant(uint8_t *data, int stride, uint8_t fill_constant) {
    for (int h = 0; h < height_; ++h) {
      for (int w = 0; w < width_; ++w) {
        data[h * stride + w] = fill_constant;
      }
    }
  }

  void FillRandom(uint8_t *data, int stride) {
    for (int h = 0; h < height_; ++h) {
      for (int w = 0; w < width_; ++w) {
        data[h * stride + w] = rnd_.Rand8();
      }
    }
  }

  void CheckSad(unsigned int max_sad) {
    unsigned int reference_sad, exp_sad;

    reference_sad = ReferenceSAD(max_sad);
    exp_sad = SAD(max_sad);

    if (reference_sad <= max_sad) {
      ASSERT_EQ(exp_sad, reference_sad);
    } else {
      // Alternative implementations are not required to check max_sad
      ASSERT_GE(exp_sad, reference_sad);
    }
  }

  // Handle blocks up to 16x16 with stride up to 32
  int height_, width_;
122
  static uint8_t* source_data_;
Johann's avatar
Johann committed
123
  int source_stride_;
124
  static uint8_t* reference_data_;
Johann's avatar
Johann committed
125
126
127
128
129
  int reference_stride_;

  ACMRandom rnd_;
};

130
131
132
uint8_t* SADTest::source_data_ = NULL;
uint8_t* SADTest::reference_data_ = NULL;

Johann's avatar
Johann committed
133
134
135
TEST_P(SADTest, MaxRef) {
  FillConstant(source_data_, source_stride_, 0);
  FillConstant(reference_data_, reference_stride_, 255);
Johann's avatar
Johann committed
136
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
137
138
139
140
141
}

TEST_P(SADTest, MaxSrc) {
  FillConstant(source_data_, source_stride_, 255);
  FillConstant(reference_data_, reference_stride_, 0);
Johann's avatar
Johann committed
142
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
143
144
145
146
147
148
149
}

TEST_P(SADTest, ShortRef) {
  int tmp_stride = reference_stride_;
  reference_stride_ >>= 1;
  FillRandom(source_data_, source_stride_);
  FillRandom(reference_data_, reference_stride_);
Johann's avatar
Johann committed
150
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
151
152
153
154
155
156
157
158
159
160
  reference_stride_ = tmp_stride;
}

TEST_P(SADTest, UnalignedRef) {
  // The reference frame, but not the source frame, may be unaligned for
  // certain types of searches.
  int tmp_stride = reference_stride_;
  reference_stride_ -= 1;
  FillRandom(source_data_, source_stride_);
  FillRandom(reference_data_, reference_stride_);
Johann's avatar
Johann committed
161
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
162
163
164
165
166
167
168
169
  reference_stride_ = tmp_stride;
}

TEST_P(SADTest, ShortSrc) {
  int tmp_stride = source_stride_;
  source_stride_ >>= 1;
  FillRandom(source_data_, source_stride_);
  FillRandom(reference_data_, reference_stride_);
Johann's avatar
Johann committed
170
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
171
172
173
174
175
176
177
178
179
180
181
  source_stride_ = tmp_stride;
}

TEST_P(SADTest, MaxSAD) {
  // Verify that, when max_sad is set, the implementation does not return a
  // value lower than the reference.
  FillConstant(source_data_, source_stride_, 255);
  FillConstant(reference_data_, reference_stride_, 0);
  CheckSad(128);
}

James Zern's avatar
James Zern committed
182
183
184
185
186
187
188
using std::tr1::make_tuple;

const sad_m_by_n_fn_t sad_16x16_c = vp8_sad16x16_c;
const sad_m_by_n_fn_t sad_8x16_c = vp8_sad8x16_c;
const sad_m_by_n_fn_t sad_16x8_c = vp8_sad16x8_c;
const sad_m_by_n_fn_t sad_8x8_c = vp8_sad8x8_c;
const sad_m_by_n_fn_t sad_4x4_c = vp8_sad4x4_c;
Johann's avatar
Johann committed
189
INSTANTIATE_TEST_CASE_P(C, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
190
191
192
193
194
                        make_tuple(16, 16, sad_16x16_c),
                        make_tuple(8, 16, sad_8x16_c),
                        make_tuple(16, 8, sad_16x8_c),
                        make_tuple(8, 8, sad_8x8_c),
                        make_tuple(4, 4, sad_4x4_c)));
Johann's avatar
Johann committed
195
196
197

// ARM tests
#if HAVE_MEDIA
James Zern's avatar
James Zern committed
198
const sad_m_by_n_fn_t sad_16x16_armv6 = vp8_sad16x16_armv6;
Johann's avatar
Johann committed
199
INSTANTIATE_TEST_CASE_P(MEDIA, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
200
                        make_tuple(16, 16, sad_16x16_armv6)));
Johann's avatar
Johann committed
201
202
203

#endif
#if HAVE_NEON
James Zern's avatar
James Zern committed
204
205
206
207
208
const sad_m_by_n_fn_t sad_16x16_neon = vp8_sad16x16_neon;
const sad_m_by_n_fn_t sad_8x16_neon = vp8_sad8x16_neon;
const sad_m_by_n_fn_t sad_16x8_neon = vp8_sad16x8_neon;
const sad_m_by_n_fn_t sad_8x8_neon = vp8_sad8x8_neon;
const sad_m_by_n_fn_t sad_4x4_neon = vp8_sad4x4_neon;
Johann's avatar
Johann committed
209
INSTANTIATE_TEST_CASE_P(NEON, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
210
211
212
213
214
                        make_tuple(16, 16, sad_16x16_neon),
                        make_tuple(8, 16, sad_8x16_neon),
                        make_tuple(16, 8, sad_16x8_neon),
                        make_tuple(8, 8, sad_8x8_neon),
                        make_tuple(4, 4, sad_4x4_neon)));
Johann's avatar
Johann committed
215
216
217
218
#endif

// X86 tests
#if HAVE_MMX
James Zern's avatar
James Zern committed
219
220
221
222
223
const sad_m_by_n_fn_t sad_16x16_mmx = vp8_sad16x16_mmx;
const sad_m_by_n_fn_t sad_8x16_mmx = vp8_sad8x16_mmx;
const sad_m_by_n_fn_t sad_16x8_mmx = vp8_sad16x8_mmx;
const sad_m_by_n_fn_t sad_8x8_mmx = vp8_sad8x8_mmx;
const sad_m_by_n_fn_t sad_4x4_mmx = vp8_sad4x4_mmx;
Johann's avatar
Johann committed
224
INSTANTIATE_TEST_CASE_P(MMX, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
225
226
227
228
229
                        make_tuple(16, 16, sad_16x16_mmx),
                        make_tuple(8, 16, sad_8x16_mmx),
                        make_tuple(16, 8, sad_16x8_mmx),
                        make_tuple(8, 8, sad_8x8_mmx),
                        make_tuple(4, 4, sad_4x4_mmx)));
Johann's avatar
Johann committed
230
231
#endif
#if HAVE_SSE2
James Zern's avatar
James Zern committed
232
233
234
235
236
const sad_m_by_n_fn_t sad_16x16_wmt = vp8_sad16x16_wmt;
const sad_m_by_n_fn_t sad_8x16_wmt = vp8_sad8x16_wmt;
const sad_m_by_n_fn_t sad_16x8_wmt = vp8_sad16x8_wmt;
const sad_m_by_n_fn_t sad_8x8_wmt = vp8_sad8x8_wmt;
const sad_m_by_n_fn_t sad_4x4_wmt = vp8_sad4x4_wmt;
Johann's avatar
Johann committed
237
INSTANTIATE_TEST_CASE_P(SSE2, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
238
239
240
241
242
                        make_tuple(16, 16, sad_16x16_wmt),
                        make_tuple(8, 16, sad_8x16_wmt),
                        make_tuple(16, 8, sad_16x8_wmt),
                        make_tuple(8, 8, sad_8x8_wmt),
                        make_tuple(4, 4, sad_4x4_wmt)));
Johann's avatar
Johann committed
243
244
#endif
#if HAVE_SSSE3
James Zern's avatar
James Zern committed
245
const sad_m_by_n_fn_t sad_16x16_sse3 = vp8_sad16x16_sse3;
Johann's avatar
Johann committed
246
INSTANTIATE_TEST_CASE_P(SSE3, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
247
                        make_tuple(16, 16, sad_16x16_sse3)));
Johann's avatar
Johann committed
248
249
250
#endif

}  // namespace