1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 #include <assert.h>
13 #include <string.h>
14
15 #include "config/aom_config.h"
16 #include "config/aom_dsp_rtcd.h"
17
18 #include "aom/aom_integer.h"
19 #include "aom_dsp/aom_dsp_common.h"
20 #include "aom_dsp/aom_filter.h"
21 #include "aom_ports/mem.h"
22
horz_scalar_product(const uint8_t * a,const int16_t * b)23 static INLINE int horz_scalar_product(const uint8_t *a, const int16_t *b) {
24 int sum = 0;
25 for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k] * b[k];
26 return sum;
27 }
28
vert_scalar_product(const uint8_t * a,ptrdiff_t a_stride,const int16_t * b)29 static INLINE int vert_scalar_product(const uint8_t *a, ptrdiff_t a_stride,
30 const int16_t *b) {
31 int sum = 0;
32 for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k * a_stride] * b[k];
33 return sum;
34 }
35
convolve_horiz(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const InterpKernel * x_filters,int x0_q4,int x_step_q4,int w,int h)36 static void convolve_horiz(const uint8_t *src, ptrdiff_t src_stride,
37 uint8_t *dst, ptrdiff_t dst_stride,
38 const InterpKernel *x_filters, int x0_q4,
39 int x_step_q4, int w, int h) {
40 src -= SUBPEL_TAPS / 2 - 1;
41 for (int y = 0; y < h; ++y) {
42 int x_q4 = x0_q4;
43 for (int x = 0; x < w; ++x) {
44 const uint8_t *const src_x = &src[x_q4 >> SUBPEL_BITS];
45 const int16_t *const x_filter = x_filters[x_q4 & SUBPEL_MASK];
46 const int sum = horz_scalar_product(src_x, x_filter);
47 dst[x] = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
48 x_q4 += x_step_q4;
49 }
50 src += src_stride;
51 dst += dst_stride;
52 }
53 }
54
convolve_vert(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const InterpKernel * y_filters,int y0_q4,int y_step_q4,int w,int h)55 static void convolve_vert(const uint8_t *src, ptrdiff_t src_stride,
56 uint8_t *dst, ptrdiff_t dst_stride,
57 const InterpKernel *y_filters, int y0_q4,
58 int y_step_q4, int w, int h) {
59 src -= src_stride * (SUBPEL_TAPS / 2 - 1);
60
61 for (int x = 0; x < w; ++x) {
62 int y_q4 = y0_q4;
63 for (int y = 0; y < h; ++y) {
64 const unsigned char *src_y = &src[(y_q4 >> SUBPEL_BITS) * src_stride];
65 const int16_t *const y_filter = y_filters[y_q4 & SUBPEL_MASK];
66 const int sum = vert_scalar_product(src_y, src_stride, y_filter);
67 dst[y * dst_stride] = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
68 y_q4 += y_step_q4;
69 }
70 ++src;
71 ++dst;
72 }
73 }
74
get_filter_base(const int16_t * filter)75 static const InterpKernel *get_filter_base(const int16_t *filter) {
76 // NOTE: This assumes that the filter table is 256-byte aligned.
77 return (const InterpKernel *)(((intptr_t)filter) & ~((intptr_t)0xFF));
78 }
79
get_filter_offset(const int16_t * f,const InterpKernel * base)80 static int get_filter_offset(const int16_t *f, const InterpKernel *base) {
81 return (int)((const InterpKernel *)(intptr_t)f - base);
82 }
83
aom_convolve8_horiz_c(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)84 void aom_convolve8_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
85 uint8_t *dst, ptrdiff_t dst_stride,
86 const int16_t *filter_x, int x_step_q4,
87 const int16_t *filter_y, int y_step_q4, int w,
88 int h) {
89 const InterpKernel *const filters_x = get_filter_base(filter_x);
90 const int x0_q4 = get_filter_offset(filter_x, filters_x);
91
92 (void)filter_y;
93 (void)y_step_q4;
94
95 convolve_horiz(src, src_stride, dst, dst_stride, filters_x, x0_q4, x_step_q4,
96 w, h);
97 }
98
aom_convolve8_vert_c(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)99 void aom_convolve8_vert_c(const uint8_t *src, ptrdiff_t src_stride,
100 uint8_t *dst, ptrdiff_t dst_stride,
101 const int16_t *filter_x, int x_step_q4,
102 const int16_t *filter_y, int y_step_q4, int w,
103 int h) {
104 const InterpKernel *const filters_y = get_filter_base(filter_y);
105 const int y0_q4 = get_filter_offset(filter_y, filters_y);
106
107 (void)filter_x;
108 (void)x_step_q4;
109
110 convolve_vert(src, src_stride, dst, dst_stride, filters_y, y0_q4, y_step_q4,
111 w, h);
112 }
113
aom_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)114 void aom_convolve_copy_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
115 ptrdiff_t dst_stride, const int16_t *filter_x,
116 int filter_x_stride, const int16_t *filter_y,
117 int filter_y_stride, int w, int h) {
118 int r;
119
120 (void)filter_x;
121 (void)filter_x_stride;
122 (void)filter_y;
123 (void)filter_y_stride;
124
125 for (r = h; r > 0; --r) {
126 memcpy(dst, src, w);
127 src += src_stride;
128 dst += dst_stride;
129 }
130 }
131
132 #if CONFIG_AV1_HIGHBITDEPTH
highbd_vert_scalar_product(const uint16_t * a,ptrdiff_t a_stride,const int16_t * b)133 static INLINE int highbd_vert_scalar_product(const uint16_t *a,
134 ptrdiff_t a_stride,
135 const int16_t *b) {
136 int sum = 0;
137 for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k * a_stride] * b[k];
138 return sum;
139 }
140
highbd_horz_scalar_product(const uint16_t * a,const int16_t * b)141 static INLINE int highbd_horz_scalar_product(const uint16_t *a,
142 const int16_t *b) {
143 int sum = 0;
144 for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k] * b[k];
145 return sum;
146 }
147
highbd_convolve_horiz(const uint8_t * src8,ptrdiff_t src_stride,uint8_t * dst8,ptrdiff_t dst_stride,const InterpKernel * x_filters,int x0_q4,int x_step_q4,int w,int h,int bd)148 static void highbd_convolve_horiz(const uint8_t *src8, ptrdiff_t src_stride,
149 uint8_t *dst8, ptrdiff_t dst_stride,
150 const InterpKernel *x_filters, int x0_q4,
151 int x_step_q4, int w, int h, int bd) {
152 uint16_t *src = CONVERT_TO_SHORTPTR(src8);
153 uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
154 src -= SUBPEL_TAPS / 2 - 1;
155 for (int y = 0; y < h; ++y) {
156 int x_q4 = x0_q4;
157 for (int x = 0; x < w; ++x) {
158 const uint16_t *const src_x = &src[x_q4 >> SUBPEL_BITS];
159 const int16_t *const x_filter = x_filters[x_q4 & SUBPEL_MASK];
160 const int sum = highbd_horz_scalar_product(src_x, x_filter);
161 dst[x] = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
162 x_q4 += x_step_q4;
163 }
164 src += src_stride;
165 dst += dst_stride;
166 }
167 }
168
highbd_convolve_vert(const uint8_t * src8,ptrdiff_t src_stride,uint8_t * dst8,ptrdiff_t dst_stride,const InterpKernel * y_filters,int y0_q4,int y_step_q4,int w,int h,int bd)169 static void highbd_convolve_vert(const uint8_t *src8, ptrdiff_t src_stride,
170 uint8_t *dst8, ptrdiff_t dst_stride,
171 const InterpKernel *y_filters, int y0_q4,
172 int y_step_q4, int w, int h, int bd) {
173 uint16_t *src = CONVERT_TO_SHORTPTR(src8);
174 uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
175 src -= src_stride * (SUBPEL_TAPS / 2 - 1);
176 for (int x = 0; x < w; ++x) {
177 int y_q4 = y0_q4;
178 for (int y = 0; y < h; ++y) {
179 const uint16_t *src_y = &src[(y_q4 >> SUBPEL_BITS) * src_stride];
180 const int16_t *const y_filter = y_filters[y_q4 & SUBPEL_MASK];
181 const int sum = highbd_vert_scalar_product(src_y, src_stride, y_filter);
182 dst[y * dst_stride] =
183 clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
184 y_q4 += y_step_q4;
185 }
186 ++src;
187 ++dst;
188 }
189 }
190
aom_highbd_convolve8_horiz_c(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h,int bd)191 void aom_highbd_convolve8_horiz_c(const uint8_t *src, ptrdiff_t src_stride,
192 uint8_t *dst, ptrdiff_t dst_stride,
193 const int16_t *filter_x, int x_step_q4,
194 const int16_t *filter_y, int y_step_q4, int w,
195 int h, int bd) {
196 const InterpKernel *const filters_x = get_filter_base(filter_x);
197 const int x0_q4 = get_filter_offset(filter_x, filters_x);
198 (void)filter_y;
199 (void)y_step_q4;
200
201 highbd_convolve_horiz(src, src_stride, dst, dst_stride, filters_x, x0_q4,
202 x_step_q4, w, h, bd);
203 }
204
aom_highbd_convolve8_vert_c(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h,int bd)205 void aom_highbd_convolve8_vert_c(const uint8_t *src, ptrdiff_t src_stride,
206 uint8_t *dst, ptrdiff_t dst_stride,
207 const int16_t *filter_x, int x_step_q4,
208 const int16_t *filter_y, int y_step_q4, int w,
209 int h, int bd) {
210 const InterpKernel *const filters_y = get_filter_base(filter_y);
211 const int y0_q4 = get_filter_offset(filter_y, filters_y);
212 (void)filter_x;
213 (void)x_step_q4;
214
215 highbd_convolve_vert(src, src_stride, dst, dst_stride, filters_y, y0_q4,
216 y_step_q4, w, h, bd);
217 }
218
aom_highbd_convolve_copy_c(const uint8_t * src8,ptrdiff_t src_stride,uint8_t * dst8,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 bd)219 void aom_highbd_convolve_copy_c(const uint8_t *src8, ptrdiff_t src_stride,
220 uint8_t *dst8, ptrdiff_t dst_stride,
221 const int16_t *filter_x, int filter_x_stride,
222 const int16_t *filter_y, int filter_y_stride,
223 int w, int h, int bd) {
224 int r;
225 uint16_t *src = CONVERT_TO_SHORTPTR(src8);
226 uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
227 (void)filter_x;
228 (void)filter_y;
229 (void)filter_x_stride;
230 (void)filter_y_stride;
231 (void)bd;
232
233 for (r = h; r > 0; --r) {
234 memcpy(dst, src, w * sizeof(uint16_t));
235 src += src_stride;
236 dst += dst_stride;
237 }
238 }
239 #endif // CONFIG_AV1_HIGHBITDEPTH
240