sad_test.cc 8.02 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
}

#include "test/acm_random.h"
24
#include "test/register_state_check.h"
Johann's avatar
Johann committed
25
26
27
28
29
30
31
32
#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
33
                                        unsigned int max_sad);
Johann's avatar
Johann committed
34
35
36
37
38

using libvpx_test::ACMRandom;

namespace {
class SADTest : public PARAMS(int, int, sad_m_by_n_fn_t) {
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 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
58
59
60
61
62
63
64
65
66
67
  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
68
  virtual unsigned int SAD(unsigned int max_sad) {
69
70
71
72
73
    unsigned int ret;
    REGISTER_STATE_CHECK(ret = sad_fn_(source_data_, source_stride_,
                                       reference_data_, reference_stride_,
                                       max_sad));
    return ret;
Johann's avatar
Johann committed
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
122
123
124
  }

  // 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_;
125
  static uint8_t* source_data_;
Johann's avatar
Johann committed
126
  int source_stride_;
127
  static uint8_t* reference_data_;
Johann's avatar
Johann committed
128
129
130
131
132
  int reference_stride_;

  ACMRandom rnd_;
};

133
134
135
uint8_t* SADTest::source_data_ = NULL;
uint8_t* SADTest::reference_data_ = NULL;

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

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

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
153
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
154
155
156
157
158
159
160
161
162
163
  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
164
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
165
166
167
168
169
170
171
172
  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
173
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
174
175
176
177
178
179
180
181
182
183
184
  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
185
186
187
188
189
190
191
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
192
INSTANTIATE_TEST_CASE_P(C, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
193
194
195
196
197
                        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
198
199
200

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

#endif
#if HAVE_NEON
James Zern's avatar
James Zern committed
207
208
209
210
211
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
212
INSTANTIATE_TEST_CASE_P(NEON, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
213
214
215
216
217
                        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
218
219
220
221
#endif

// X86 tests
#if HAVE_MMX
James Zern's avatar
James Zern committed
222
223
224
225
226
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
227
INSTANTIATE_TEST_CASE_P(MMX, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
228
229
230
231
232
                        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
233
234
#endif
#if HAVE_SSE2
James Zern's avatar
James Zern committed
235
236
237
238
239
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
240
INSTANTIATE_TEST_CASE_P(SSE2, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
241
242
243
244
245
                        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
246
247
#endif
#if HAVE_SSSE3
James Zern's avatar
James Zern committed
248
const sad_m_by_n_fn_t sad_16x16_sse3 = vp8_sad16x16_sse3;
Johann's avatar
Johann committed
249
INSTANTIATE_TEST_CASE_P(SSE3, SADTest, ::testing::Values(
James Zern's avatar
James Zern committed
250
                        make_tuple(16, 16, sad_16x16_sse3)));
Johann's avatar
Johann committed
251
252
253
#endif

}  // namespace