sad_test.cc 6.43 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
20
21
22
23
24
25
26
27
28
29
30
/*
 *  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"
}

#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
31
                                        unsigned int max_sad);
Johann's avatar
Johann committed
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

using libvpx_test::ACMRandom;

namespace {
class SADTest : public PARAMS(int, int, sad_m_by_n_fn_t) {
  protected:
  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
48
  virtual unsigned int SAD(unsigned int max_sad) {
Johann's avatar
Johann committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
    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_;
  DECLARE_ALIGNED(16, uint8_t, source_data_[16*32]);
  int source_stride_;
  DECLARE_ALIGNED(16, uint8_t, reference_data_[16*32]);
  int reference_stride_;

  ACMRandom rnd_;
};

TEST_P(SADTest, MaxRef) {
  FillConstant(source_data_, source_stride_, 0);
  FillConstant(reference_data_, reference_stride_, 255);
Johann's avatar
Johann committed
114
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
115
116
117
118
119
}

TEST_P(SADTest, MaxSrc) {
  FillConstant(source_data_, source_stride_, 255);
  FillConstant(reference_data_, reference_stride_, 0);
Johann's avatar
Johann committed
120
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
121
122
123
124
125
126
127
}

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
128
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
129
130
131
132
133
134
135
136
137
138
  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
139
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
140
141
142
143
144
145
146
147
  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
148
  CheckSad(UINT_MAX);
Johann's avatar
Johann committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  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);
}

INSTANTIATE_TEST_CASE_P(C, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_c),
                        std::tr1::make_tuple(8, 16, vp8_sad8x16_c),
                        std::tr1::make_tuple(16, 8, vp8_sad16x8_c),
                        std::tr1::make_tuple(8, 8, vp8_sad8x8_c),
                        std::tr1::make_tuple(4, 4, vp8_sad4x4_c)));

// ARM tests
#if HAVE_MEDIA
INSTANTIATE_TEST_CASE_P(MEDIA, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_armv6)));

#endif
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_neon),
                        std::tr1::make_tuple(8, 16, vp8_sad8x16_neon),
                        std::tr1::make_tuple(16, 8, vp8_sad16x8_neon),
                        std::tr1::make_tuple(8, 8, vp8_sad8x8_neon),
                        std::tr1::make_tuple(4, 4, vp8_sad4x4_neon)));
#endif

// X86 tests
#if HAVE_MMX
INSTANTIATE_TEST_CASE_P(MMX, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_mmx),
                        std::tr1::make_tuple(8, 16, vp8_sad8x16_mmx),
                        std::tr1::make_tuple(16, 8, vp8_sad16x8_mmx),
                        std::tr1::make_tuple(8, 8, vp8_sad8x8_mmx),
                        std::tr1::make_tuple(4, 4, vp8_sad4x4_mmx)));
#endif
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_wmt),
                        std::tr1::make_tuple(8, 16, vp8_sad8x16_wmt),
                        std::tr1::make_tuple(16, 8, vp8_sad16x8_wmt),
                        std::tr1::make_tuple(8, 8, vp8_sad8x8_wmt),
                        std::tr1::make_tuple(4, 4, vp8_sad4x4_wmt)));
#endif
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(SSE3, SADTest, ::testing::Values(
                        std::tr1::make_tuple(16, 16, vp8_sad16x16_sse3)));
#endif

}  // namespace