vp9_convolve.c 10.6 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
2
3
4
5
6
7
8
9
/*
 *  Copyright (c) 2013 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.
 */
Christian Duvivier's avatar
Christian Duvivier committed
10
11
#include "vp9/common/vp9_convolve.h"

John Koleszar's avatar
John Koleszar committed
12
13
14
15
16
#include <assert.h>

#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_common.h"
17
#include "vp9/common/vp9_filter.h"
John Koleszar's avatar
John Koleszar committed
18
#include "vpx/vpx_integer.h"
Christian Duvivier's avatar
Christian Duvivier committed
19
#include "vpx_ports/mem.h"
John Koleszar's avatar
John Koleszar committed
20

21
22
static void convolve_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
                             uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
23
24
25
                             const int16_t *filter_x0, int x_step_q4,
                             const int16_t *filter_y, int y_step_q4,
                             int w, int h, int taps) {
26
  int x, y, k;
John Koleszar's avatar
John Koleszar committed
27

28
29
30
31
  /* NOTE: This assumes that the filter table is 256-byte aligned. */
  /* TODO(agrange) Modify to make independent of table alignment. */
  const int16_t *const filter_x_base =
      (const int16_t *)(((intptr_t)filter_x0) & ~(intptr_t)0xff);
John Koleszar's avatar
John Koleszar committed
32
33
34
35
36
37

  /* Adjust base pointer address for this source line */
  src -= taps / 2 - 1;

  for (y = 0; y < h; ++y) {
    /* Initial phase offset */
38
    int x_q4 = (filter_x0 - filter_x_base) / taps;
John Koleszar's avatar
John Koleszar committed
39
40
41

    for (x = 0; x < w; ++x) {
      /* Per-pixel src offset */
42
      const int src_x = x_q4 >> SUBPEL_BITS;
43
      int sum = 0;
John Koleszar's avatar
John Koleszar committed
44

45
46
47
48
      /* Pointer to filter to use */
      const int16_t *const filter_x = filter_x_base +
          (x_q4 & SUBPEL_MASK) * taps;

49
      for (k = 0; k < taps; ++k)
John Koleszar's avatar
John Koleszar committed
50
        sum += src[src_x + k] * filter_x[k];
51

52
      dst[x] = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
John Koleszar's avatar
John Koleszar committed
53

54
      /* Move to the next source pixel */
John Koleszar's avatar
John Koleszar committed
55
56
57
58
59
60
61
      x_q4 += x_step_q4;
    }
    src += src_stride;
    dst += dst_stride;
  }
}

62
63
static void convolve_avg_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
                                 uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
64
65
66
                                 const int16_t *filter_x0, int x_step_q4,
                                 const int16_t *filter_y, int y_step_q4,
                                 int w, int h, int taps) {
67
  int x, y, k;
John Koleszar's avatar
John Koleszar committed
68

69
70
71
72
  /* NOTE: This assumes that the filter table is 256-byte aligned. */
  /* TODO(agrange) Modify to make independent of table alignment. */
  const int16_t *const filter_x_base =
      (const int16_t *)(((intptr_t)filter_x0) & ~(intptr_t)0xff);
John Koleszar's avatar
John Koleszar committed
73
74
75
76
77
78

  /* Adjust base pointer address for this source line */
  src -= taps / 2 - 1;

  for (y = 0; y < h; ++y) {
    /* Initial phase offset */
79
    int x_q4 = (filter_x0 - filter_x_base) / taps;
John Koleszar's avatar
John Koleszar committed
80
81
82

    for (x = 0; x < w; ++x) {
      /* Per-pixel src offset */
83
      const int src_x = x_q4 >> SUBPEL_BITS;
84
      int sum = 0;
John Koleszar's avatar
John Koleszar committed
85

86
87
88
89
      /* Pointer to filter to use */
      const int16_t *const filter_x = filter_x_base +
          (x_q4 & SUBPEL_MASK) * taps;

90
      for (k = 0; k < taps; ++k)
John Koleszar's avatar
John Koleszar committed
91
        sum += src[src_x + k] * filter_x[k];
92
93

      dst[x] = ROUND_POWER_OF_TWO(dst[x] +
94
                   clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS)), 1);
John Koleszar's avatar
John Koleszar committed
95

96
      /* Move to the next source pixel */
John Koleszar's avatar
John Koleszar committed
97
98
99
100
101
102
103
      x_q4 += x_step_q4;
    }
    src += src_stride;
    dst += dst_stride;
  }
}

104
105
static void convolve_vert_c(const uint8_t *src, ptrdiff_t src_stride,
                            uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
106
107
108
                            const int16_t *filter_x, int x_step_q4,
                            const int16_t *filter_y0, int y_step_q4,
                            int w, int h, int taps) {
109
  int x, y, k;
John Koleszar's avatar
John Koleszar committed
110

111
112
113
114
  /* NOTE: This assumes that the filter table is 256-byte aligned. */
  /* TODO(agrange) Modify to make independent of table alignment. */
  const int16_t *const filter_y_base =
      (const int16_t *)(((intptr_t)filter_y0) & ~(intptr_t)0xff);
John Koleszar's avatar
John Koleszar committed
115
116
117
118

  /* Adjust base pointer address for this source column */
  src -= src_stride * (taps / 2 - 1);

119
  for (x = 0; x < w; ++x) {
John Koleszar's avatar
John Koleszar committed
120
    /* Initial phase offset */
121
    int y_q4 = (filter_y0 - filter_y_base) / taps;
John Koleszar's avatar
John Koleszar committed
122
123
124

    for (y = 0; y < h; ++y) {
      /* Per-pixel src offset */
125
      const int src_y = y_q4 >> SUBPEL_BITS;
126
      int sum = 0;
John Koleszar's avatar
John Koleszar committed
127

128
129
130
131
      /* Pointer to filter to use */
      const int16_t *const filter_y = filter_y_base +
          (y_q4 & SUBPEL_MASK) * taps;

132
      for (k = 0; k < taps; ++k)
John Koleszar's avatar
John Koleszar committed
133
        sum += src[(src_y + k) * src_stride] * filter_y[k];
134
135

      dst[y * dst_stride] =
136
          clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
John Koleszar's avatar
John Koleszar committed
137

138
      /* Move to the next source pixel */
John Koleszar's avatar
John Koleszar committed
139
140
141
142
143
144
145
      y_q4 += y_step_q4;
    }
    ++src;
    ++dst;
  }
}

146
147
static void convolve_avg_vert_c(const uint8_t *src, ptrdiff_t src_stride,
                                uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
148
149
150
                                const int16_t *filter_x, int x_step_q4,
                                const int16_t *filter_y0, int y_step_q4,
                                int w, int h, int taps) {
151
  int x, y, k;
John Koleszar's avatar
John Koleszar committed
152

153
154
155
156
  /* NOTE: This assumes that the filter table is 256-byte aligned. */
  /* TODO(agrange) Modify to make independent of table alignment. */
  const int16_t *const filter_y_base =
      (const int16_t *)(((intptr_t)filter_y0) & ~(intptr_t)0xff);
John Koleszar's avatar
John Koleszar committed
157
158
159
160

  /* Adjust base pointer address for this source column */
  src -= src_stride * (taps / 2 - 1);

161
  for (x = 0; x < w; ++x) {
John Koleszar's avatar
John Koleszar committed
162
    /* Initial phase offset */
163
    int y_q4 = (filter_y0 - filter_y_base) / taps;
John Koleszar's avatar
John Koleszar committed
164
165
166

    for (y = 0; y < h; ++y) {
      /* Per-pixel src offset */
167
      const int src_y = y_q4 >> SUBPEL_BITS;
168
      int sum = 0;
John Koleszar's avatar
John Koleszar committed
169

170
171
172
173
      /* Pointer to filter to use */
      const int16_t *const filter_y = filter_y_base +
          (y_q4 & SUBPEL_MASK) * taps;

174
      for (k = 0; k < taps; ++k)
John Koleszar's avatar
John Koleszar committed
175
        sum += src[(src_y + k) * src_stride] * filter_y[k];
176
177

      dst[y * dst_stride] = ROUND_POWER_OF_TWO(dst[y * dst_stride] +
178
           clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS)), 1);
John Koleszar's avatar
John Koleszar committed
179

180
      /* Move to the next source pixel */
John Koleszar's avatar
John Koleszar committed
181
182
183
184
185
186
187
      y_q4 += y_step_q4;
    }
    ++src;
    ++dst;
  }
}

188
189
static void convolve_c(const uint8_t *src, ptrdiff_t src_stride,
                       uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
190
191
192
                       const int16_t *filter_x, int x_step_q4,
                       const int16_t *filter_y, int y_step_q4,
                       int w, int h, int taps) {
193
  /* Fixed size intermediate buffer places limits on parameters.
194
195
   * Maximum intermediate_height is 135, for y_step_q4 == 32,
   * h == 64, taps == 8.
196
   */
197
  uint8_t temp[64 * 135];
198
  int intermediate_height = MAX(((h * y_step_q4) >> 4), 1) + taps - 1;
199

200
201
  assert(w <= 64);
  assert(h <= 64);
John Koleszar's avatar
John Koleszar committed
202
  assert(taps <= 8);
203
  assert(y_step_q4 <= 32);
204
  assert(x_step_q4 <= 32);
205
206
207

  if (intermediate_height < h)
    intermediate_height = h;
John Koleszar's avatar
John Koleszar committed
208

209
210
211
212
213
  convolve_horiz_c(src - src_stride * (taps / 2 - 1), src_stride, temp, 64,
                   filter_x, x_step_q4, filter_y, y_step_q4, w,
                   intermediate_height, taps);
  convolve_vert_c(temp + 64 * (taps / 2 - 1), 64, dst, dst_stride, filter_x,
                  x_step_q4, filter_y, y_step_q4, w, h, taps);
John Koleszar's avatar
John Koleszar committed
214
215
}

216
217
void vp9_convolve8_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
                           uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
218
219
220
221
                           const int16_t *filter_x, int x_step_q4,
                           const int16_t *filter_y, int y_step_q4,
                           int w, int h) {
  convolve_horiz_c(src, src_stride, dst, dst_stride,
222
                   filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
223
224
}

225
226
void vp9_convolve8_avg_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
                               uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
227
228
229
230
                               const int16_t *filter_x, int x_step_q4,
                               const int16_t *filter_y, int y_step_q4,
                               int w, int h) {
  convolve_avg_horiz_c(src, src_stride, dst, dst_stride,
231
                       filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
232
233
}

234
235
void vp9_convolve8_vert_c(const uint8_t *src, ptrdiff_t src_stride,
                          uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
236
237
238
239
                          const int16_t *filter_x, int x_step_q4,
                          const int16_t *filter_y, int y_step_q4,
                          int w, int h) {
  convolve_vert_c(src, src_stride, dst, dst_stride,
240
                  filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
241
242
}

243
244
void vp9_convolve8_avg_vert_c(const uint8_t *src, ptrdiff_t src_stride,
                              uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
245
246
247
248
                              const int16_t *filter_x, int x_step_q4,
                              const int16_t *filter_y, int y_step_q4,
                              int w, int h) {
  convolve_avg_vert_c(src, src_stride, dst, dst_stride,
249
                      filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
250
251
}

252
253
void vp9_convolve8_c(const uint8_t *src, ptrdiff_t src_stride,
                     uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
254
255
256
257
                     const int16_t *filter_x, int x_step_q4,
                     const int16_t *filter_y, int y_step_q4,
                     int w, int h) {
  convolve_c(src, src_stride, dst, dst_stride,
258
             filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
259
260
}

261
262
void vp9_convolve8_avg_c(const uint8_t *src, ptrdiff_t src_stride,
                         uint8_t *dst, ptrdiff_t dst_stride,
John Koleszar's avatar
John Koleszar committed
263
264
265
                         const int16_t *filter_x, int x_step_q4,
                         const int16_t *filter_y, int y_step_q4,
                         int w, int h) {
Christian Duvivier's avatar
Christian Duvivier committed
266
  /* Fixed size intermediate buffer places limits on parameters. */
267
268
269
  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp, 64 * 64);
  assert(w <= 64);
  assert(h <= 64);
Christian Duvivier's avatar
Christian Duvivier committed
270

271
272
273
  vp9_convolve8(src, src_stride, temp, 64,
               filter_x, x_step_q4, filter_y, y_step_q4, w, h);
  vp9_convolve_avg(temp, 64, dst, dst_stride, NULL, 0, NULL, 0, w, h);
John Koleszar's avatar
John Koleszar committed
274
}
275

276
277
278
279
280
281
282
283
284
285
286
void vp9_convolve_copy_c(const uint8_t *src, ptrdiff_t src_stride,
                         uint8_t *dst, ptrdiff_t dst_stride,
                         const int16_t *filter_x, int filter_x_stride,
                         const int16_t *filter_y, int filter_y_stride,
                         int w, int h) {
  int r;

  for (r = h; r > 0; --r) {
    memcpy(dst, src, w);
    src += src_stride;
    dst += dst_stride;
287
288
289
  }
}

290
291
292
293
294
void vp9_convolve_avg_c(const uint8_t *src, ptrdiff_t src_stride,
                        uint8_t *dst, ptrdiff_t dst_stride,
                        const int16_t *filter_x, int filter_x_stride,
                        const int16_t *filter_y, int filter_y_stride,
                        int w, int h) {
295
296
297
  int x, y;

  for (y = 0; y < h; ++y) {
298
299
300
    for (x = 0; x < w; ++x)
      dst[x] = ROUND_POWER_OF_TWO(dst[x] + src[x], 1);

301
302
303
304
    src += src_stride;
    dst += dst_stride;
  }
}