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
/*
 *  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"
18
#include "./vp8_rtcd.h"
Johann's avatar
Johann committed
19
#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