vp9_convolve.c 10.7 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
   * Maximum intermediate_height is 324, for y_step_q4 == 80,
195
   * h == 64, taps == 8.
196
   * y_step_q4 of 80 allows for 1/10 scale for 5 layer svc
197
   */
198
  uint8_t temp[64 * 324];
199
  int intermediate_height = (((h - 1) * y_step_q4 + 15) >> 4) + taps;
200

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

  if (intermediate_height < h)
    intermediate_height = h;
209

210 211 212 213 214
  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
215 216
}

217 218
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
219 220 221 222
                           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,
223
                   filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
224 225
}

226 227
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
228 229 230 231
                               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,
232
                       filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
233 234
}

235 236
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
237 238 239 240
                          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,
241
                  filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
242 243
}

244 245
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
246 247 248 249
                              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,
250
                      filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
251 252
}

253 254
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
255 256 257 258
                     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,
259
             filter_x, x_step_q4, filter_y, y_step_q4, w, h, 8);
John Koleszar's avatar
John Koleszar committed
260 261
}

262 263
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
264 265 266
                         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
267
  /* Fixed size intermediate buffer places limits on parameters. */
268 269 270
  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp, 64 * 64);
  assert(w <= 64);
  assert(h <= 64);
Christian Duvivier's avatar
Christian Duvivier committed
271

272 273 274
  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
275
}
276

277 278 279 280 281 282 283 284 285 286 287
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;
288 289 290
  }
}

291 292 293 294 295
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) {
296 297 298
  int x, y;

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

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