selfguided_filter_test.cc 8.99 KB
Newer Older
David Barker's avatar
David Barker 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include <ctime>

#include "third_party/googletest/src/googletest/include/gtest/gtest.h"

#include "./av1_rtcd.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"

#include "av1/common/mv.h"
#include "av1/common/restoration.h"

namespace {

using std::tr1::tuple;
using std::tr1::make_tuple;
using libaom_test::ACMRandom;

typedef tuple<> FilterTestParam;

class AV1SelfguidedFilterTest
    : public ::testing::TestWithParam<FilterTestParam> {
 public:
  virtual ~AV1SelfguidedFilterTest() {}
  virtual void SetUp() {}

  virtual void TearDown() { libaom_test::ClearSystemState(); }

 protected:
  void RunSpeedTest() {
    const int w = 256, h = 256;
    const int NUM_ITERS = 2000;
    int i, j;

47
48
    uint8_t *input = (uint8_t *)aom_memalign(16, w * h * sizeof(uint8_t));
    uint8_t *output = (uint8_t *)aom_memalign(16, w * h * sizeof(uint8_t));
49
    int32_t *tmpbuf = (int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE);
David Barker's avatar
David Barker committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63

    ACMRandom rnd(ACMRandom::DeterministicSeed());

    for (i = 0; i < h; ++i)
      for (j = 0; j < w; ++j) input[i * w + j] = rnd.Rand16() & 0xFF;

    int xqd[2] = {
      SGRPROJ_PRJ_MIN0 +
          rnd.PseudoUniform(SGRPROJ_PRJ_MAX0 + 1 - SGRPROJ_PRJ_MIN0),
      SGRPROJ_PRJ_MIN1 +
          rnd.PseudoUniform(SGRPROJ_PRJ_MAX1 + 1 - SGRPROJ_PRJ_MIN1)
    };
    // Fix a parameter set, since the speed depends slightly on r.
    // Change this to test different combinations of values of r.
64
    int eps = 15;
David Barker's avatar
David Barker committed
65
66
67
68
69

    av1_loop_restoration_precal();

    std::clock_t start = std::clock();
    for (i = 0; i < NUM_ITERS; ++i) {
70
      apply_selfguided_restoration(input, w, h, w, eps, xqd, output, w, tmpbuf);
David Barker's avatar
David Barker committed
71
72
73
74
75
76
77
    }
    std::clock_t end = std::clock();
    double elapsed = ((end - start) / (double)CLOCKS_PER_SEC);

    printf("%5d %dx%d blocks in %7.3fs = %7.3fus/block\n", NUM_ITERS, w, h,
           elapsed, elapsed * 1000000. / NUM_ITERS);

78
79
    aom_free(input);
    aom_free(output);
David Barker's avatar
David Barker committed
80
81
82
83
    aom_free(tmpbuf);
  }

  void RunCorrectnessTest() {
David Barker's avatar
David Barker committed
84
85
86
87
    // Set the maximum width/height to test here. We actually test a small
    // range of sizes *up to* this size, so that we can check, eg.,
    // the behaviour on tiles which are not a multiple of 4 wide.
    const int max_w = 260, max_h = 260, stride = 672, out_stride = 672;
88
    const int NUM_ITERS = 81;
David Barker's avatar
David Barker committed
89
90
    int i, j, k;

91
92
93
94
95
96
    uint8_t *input =
        (uint8_t *)aom_memalign(16, stride * max_h * sizeof(uint8_t));
    uint8_t *output =
        (uint8_t *)aom_memalign(16, out_stride * max_h * sizeof(uint8_t));
    uint8_t *output2 =
        (uint8_t *)aom_memalign(16, out_stride * max_h * sizeof(uint8_t));
97
    int32_t *tmpbuf = (int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE);
David Barker's avatar
David Barker committed
98
99
100
101
102
103

    ACMRandom rnd(ACMRandom::DeterministicSeed());

    av1_loop_restoration_precal();

    for (i = 0; i < NUM_ITERS; ++i) {
David Barker's avatar
David Barker committed
104
105
      for (j = 0; j < max_h; ++j)
        for (k = 0; k < max_w; ++k) input[j * stride + k] = rnd.Rand16() & 0xFF;
David Barker's avatar
David Barker committed
106
107
108
109
110
111
112
113
114

      int xqd[2] = {
        SGRPROJ_PRJ_MIN0 +
            rnd.PseudoUniform(SGRPROJ_PRJ_MAX0 + 1 - SGRPROJ_PRJ_MIN0),
        SGRPROJ_PRJ_MIN1 +
            rnd.PseudoUniform(SGRPROJ_PRJ_MAX1 + 1 - SGRPROJ_PRJ_MIN1)
      };
      int eps = rnd.PseudoUniform(1 << SGRPROJ_PARAMS_BITS);

115
      // Test various tile sizes around 256x256
David Barker's avatar
David Barker committed
116
117
      int test_w = max_w - (i / 9);
      int test_h = max_h - (i % 9);
118

119
      apply_selfguided_restoration(input, test_w, test_h, stride, eps, xqd,
120
                                   output, out_stride, tmpbuf);
121
      apply_selfguided_restoration_c(input, test_w, test_h, stride, eps, xqd,
122
123
124
                                     output2, out_stride, tmpbuf);
      for (j = 0; j < test_h; ++j)
        for (k = 0; k < test_w; ++k)
David Barker's avatar
David Barker committed
125
126
127
          ASSERT_EQ(output[j * out_stride + k], output2[j * out_stride + k]);
    }

128
129
130
    aom_free(input);
    aom_free(output);
    aom_free(output2);
David Barker's avatar
David Barker committed
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    aom_free(tmpbuf);
  }
};

TEST_P(AV1SelfguidedFilterTest, SpeedTest) { RunSpeedTest(); }
TEST_P(AV1SelfguidedFilterTest, CorrectnessTest) { RunCorrectnessTest(); }

const FilterTestParam params[] = { make_tuple() };

#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1SelfguidedFilterTest,
                        ::testing::ValuesIn(params));
#endif

145
#if CONFIG_HIGHBITDEPTH
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

typedef tuple<int> HighbdFilterTestParam;

class AV1HighbdSelfguidedFilterTest
    : public ::testing::TestWithParam<HighbdFilterTestParam> {
 public:
  virtual ~AV1HighbdSelfguidedFilterTest() {}
  virtual void SetUp() {}

  virtual void TearDown() { libaom_test::ClearSystemState(); }

 protected:
  void RunSpeedTest() {
    const int w = 256, h = 256;
    const int NUM_ITERS = 2000;
    int i, j;
    int bit_depth = GET_PARAM(0);
    int mask = (1 << bit_depth) - 1;

165
166
    uint16_t *input = (uint16_t *)aom_memalign(16, w * h * sizeof(uint16_t));
    uint16_t *output = (uint16_t *)aom_memalign(16, w * h * sizeof(uint16_t));
167
    int32_t *tmpbuf = (int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE);
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

    ACMRandom rnd(ACMRandom::DeterministicSeed());

    for (i = 0; i < h; ++i)
      for (j = 0; j < w; ++j) input[i * w + j] = rnd.Rand16() & mask;

    int xqd[2] = {
      SGRPROJ_PRJ_MIN0 +
          rnd.PseudoUniform(SGRPROJ_PRJ_MAX0 + 1 - SGRPROJ_PRJ_MIN0),
      SGRPROJ_PRJ_MIN1 +
          rnd.PseudoUniform(SGRPROJ_PRJ_MAX1 + 1 - SGRPROJ_PRJ_MIN1)
    };
    // Fix a parameter set, since the speed depends slightly on r.
    // Change this to test different combinations of values of r.
    int eps = 15;

    av1_loop_restoration_precal();

    std::clock_t start = std::clock();
    for (i = 0; i < NUM_ITERS; ++i) {
      apply_selfguided_restoration_highbd(input, w, h, w, bit_depth, eps, xqd,
                                          output, w, tmpbuf);
    }
    std::clock_t end = std::clock();
    double elapsed = ((end - start) / (double)CLOCKS_PER_SEC);

    printf("%5d %dx%d blocks in %7.3fs = %7.3fus/block\n", NUM_ITERS, w, h,
           elapsed, elapsed * 1000000. / NUM_ITERS);

197
198
    aom_free(input);
    aom_free(output);
199
200
201
202
    aom_free(tmpbuf);
  }

  void RunCorrectnessTest() {
David Barker's avatar
David Barker committed
203
204
205
206
    // Set the maximum width/height to test here. We actually test a small
    // range of sizes *up to* this size, so that we can check, eg.,
    // the behaviour on tiles which are not a multiple of 4 wide.
    const int max_w = 260, max_h = 260, stride = 672, out_stride = 672;
207
208
209
210
211
    const int NUM_ITERS = 81;
    int i, j, k;
    int bit_depth = GET_PARAM(0);
    int mask = (1 << bit_depth) - 1;

212
213
214
215
216
217
    uint16_t *input =
        (uint16_t *)aom_memalign(16, stride * max_h * sizeof(uint16_t));
    uint16_t *output =
        (uint16_t *)aom_memalign(16, out_stride * max_h * sizeof(uint16_t));
    uint16_t *output2 =
        (uint16_t *)aom_memalign(16, out_stride * max_h * sizeof(uint16_t));
218
    int32_t *tmpbuf = (int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE);
219
220
221
222
223
224

    ACMRandom rnd(ACMRandom::DeterministicSeed());

    av1_loop_restoration_precal();

    for (i = 0; i < NUM_ITERS; ++i) {
David Barker's avatar
David Barker committed
225
226
      for (j = 0; j < max_h; ++j)
        for (k = 0; k < max_w; ++k) input[j * stride + k] = rnd.Rand16() & mask;
227
228
229
230
231
232
233
234
235
236

      int xqd[2] = {
        SGRPROJ_PRJ_MIN0 +
            rnd.PseudoUniform(SGRPROJ_PRJ_MAX0 + 1 - SGRPROJ_PRJ_MIN0),
        SGRPROJ_PRJ_MIN1 +
            rnd.PseudoUniform(SGRPROJ_PRJ_MAX1 + 1 - SGRPROJ_PRJ_MIN1)
      };
      int eps = rnd.PseudoUniform(1 << SGRPROJ_PARAMS_BITS);

      // Test various tile sizes around 256x256
David Barker's avatar
David Barker committed
237
238
      int test_w = max_w - (i / 9);
      int test_h = max_h - (i % 9);
239
240
241
242
243
244
245
246
247
248
249
250

      apply_selfguided_restoration_highbd(input, test_w, test_h, stride,
                                          bit_depth, eps, xqd, output,
                                          out_stride, tmpbuf);
      apply_selfguided_restoration_highbd_c(input, test_w, test_h, stride,
                                            bit_depth, eps, xqd, output2,
                                            out_stride, tmpbuf);
      for (j = 0; j < test_h; ++j)
        for (k = 0; k < test_w; ++k)
          ASSERT_EQ(output[j * out_stride + k], output2[j * out_stride + k]);
    }

251
252
253
    aom_free(input);
    aom_free(output);
    aom_free(output2);
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    aom_free(tmpbuf);
  }
};

TEST_P(AV1HighbdSelfguidedFilterTest, SpeedTest) { RunSpeedTest(); }
TEST_P(AV1HighbdSelfguidedFilterTest, CorrectnessTest) { RunCorrectnessTest(); }

const HighbdFilterTestParam highbd_params[] = { make_tuple(8), make_tuple(10),
                                                make_tuple(12) };

#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdSelfguidedFilterTest,
                        ::testing::ValuesIn(highbd_params));
#endif
#endif

David Barker's avatar
David Barker committed
270
}  // namespace