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 #ifndef AOM_AV1_COMMON_FILTER_H_
13 #define AOM_AV1_COMMON_FILTER_H_
14
15 #include <assert.h>
16
17 #include "config/aom_config.h"
18
19 #include "aom/aom_integer.h"
20 #include "aom_dsp/aom_filter.h"
21 #include "aom_ports/mem.h"
22 #include "av1/common/enums.h"
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 #define MAX_FILTER_TAP 12
29
30 typedef enum ATTRIBUTE_PACKED {
31 EIGHTTAP_REGULAR,
32 EIGHTTAP_SMOOTH,
33 MULTITAP_SHARP,
34 BILINEAR,
35 // Encoder side only filters
36 MULTITAP_SHARP2,
37
38 INTERP_FILTERS_ALL,
39 SWITCHABLE_FILTERS = BILINEAR,
40 SWITCHABLE = SWITCHABLE_FILTERS + 1, /* the last switchable one */
41 EXTRA_FILTERS = INTERP_FILTERS_ALL - SWITCHABLE_FILTERS,
42 INTERP_INVALID = 0xff,
43 } InterpFilter;
44
45 enum {
46 USE_2_TAPS_ORIG = 0, // This is used in temporal filtering.
47 USE_2_TAPS,
48 USE_4_TAPS,
49 USE_8_TAPS,
50 } UENUM1BYTE(SUBPEL_SEARCH_TYPE);
51
52 enum {
53 INTERP_EVAL_LUMA_EVAL_CHROMA = 0,
54 INTERP_SKIP_LUMA_EVAL_CHROMA,
55 INTERP_EVAL_INVALID,
56 INTERP_SKIP_LUMA_SKIP_CHROMA,
57 } UENUM1BYTE(INTERP_EVAL_PLANE);
58
59 enum {
60 INTERP_HORZ_NEQ_VERT_NEQ = 0,
61 INTERP_HORZ_EQ_VERT_NEQ,
62 INTERP_HORZ_NEQ_VERT_EQ,
63 INTERP_HORZ_EQ_VERT_EQ,
64 INTERP_PRED_TYPE_ALL,
65 } UENUM1BYTE(INTERP_PRED_TYPE);
66 // Pack two InterpFilter's into a uint32_t: since there are at most 10 filters,
67 // we can use 16 bits for each and have more than enough space. This reduces
68 // argument passing and unifies the operation of setting a (pair of) filters.
69 typedef struct InterpFilters {
70 uint16_t y_filter;
71 uint16_t x_filter;
72 } InterpFilters;
73
74 typedef union int_interpfilters {
75 uint32_t as_int;
76 InterpFilters as_filters;
77 } int_interpfilters;
78
av1_extract_interp_filter(int_interpfilters filters,int dir)79 static inline InterpFilter av1_extract_interp_filter(int_interpfilters filters,
80 int dir) {
81 return (InterpFilter)((dir) ? filters.as_filters.x_filter
82 : filters.as_filters.y_filter);
83 }
84
av1_broadcast_interp_filter(InterpFilter filter)85 static inline int_interpfilters av1_broadcast_interp_filter(
86 InterpFilter filter) {
87 int_interpfilters filters;
88 filters.as_filters.x_filter = filter;
89 filters.as_filters.y_filter = filter;
90 return filters;
91 }
92
av1_unswitchable_filter(InterpFilter filter)93 static inline InterpFilter av1_unswitchable_filter(InterpFilter filter) {
94 return filter == SWITCHABLE ? EIGHTTAP_REGULAR : filter;
95 }
96
97 /* (1 << LOG_SWITCHABLE_FILTERS) > SWITCHABLE_FILTERS */
98 #define LOG_SWITCHABLE_FILTERS 2
99
100 #define SWITCHABLE_FILTER_CONTEXTS ((SWITCHABLE_FILTERS + 1) * 4)
101 #define INTER_FILTER_COMP_OFFSET (SWITCHABLE_FILTERS + 1)
102 #define INTER_FILTER_DIR_OFFSET ((SWITCHABLE_FILTERS + 1) * 2)
103 #define ALLOW_ALL_INTERP_FILT_MASK (0x01ff)
104
105 typedef struct InterpFilterParams {
106 const int16_t *filter_ptr;
107 uint16_t taps;
108 InterpFilter interp_filter;
109 } InterpFilterParams;
110
111 DECLARE_ALIGNED(256, static const InterpKernel,
112 av1_bilinear_filters[SUBPEL_SHIFTS]) = {
113 { 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 0, 0, 120, 8, 0, 0, 0 },
114 { 0, 0, 0, 112, 16, 0, 0, 0 }, { 0, 0, 0, 104, 24, 0, 0, 0 },
115 { 0, 0, 0, 96, 32, 0, 0, 0 }, { 0, 0, 0, 88, 40, 0, 0, 0 },
116 { 0, 0, 0, 80, 48, 0, 0, 0 }, { 0, 0, 0, 72, 56, 0, 0, 0 },
117 { 0, 0, 0, 64, 64, 0, 0, 0 }, { 0, 0, 0, 56, 72, 0, 0, 0 },
118 { 0, 0, 0, 48, 80, 0, 0, 0 }, { 0, 0, 0, 40, 88, 0, 0, 0 },
119 { 0, 0, 0, 32, 96, 0, 0, 0 }, { 0, 0, 0, 24, 104, 0, 0, 0 },
120 { 0, 0, 0, 16, 112, 0, 0, 0 }, { 0, 0, 0, 8, 120, 0, 0, 0 }
121 };
122
123 DECLARE_ALIGNED(256, static const InterpKernel,
124 av1_sub_pel_filters_8[SUBPEL_SHIFTS]) = {
125 { 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 2, -6, 126, 8, -2, 0, 0 },
126 { 0, 2, -10, 122, 18, -4, 0, 0 }, { 0, 2, -12, 116, 28, -8, 2, 0 },
127 { 0, 2, -14, 110, 38, -10, 2, 0 }, { 0, 2, -14, 102, 48, -12, 2, 0 },
128 { 0, 2, -16, 94, 58, -12, 2, 0 }, { 0, 2, -14, 84, 66, -12, 2, 0 },
129 { 0, 2, -14, 76, 76, -14, 2, 0 }, { 0, 2, -12, 66, 84, -14, 2, 0 },
130 { 0, 2, -12, 58, 94, -16, 2, 0 }, { 0, 2, -12, 48, 102, -14, 2, 0 },
131 { 0, 2, -10, 38, 110, -14, 2, 0 }, { 0, 2, -8, 28, 116, -12, 2, 0 },
132 { 0, 0, -4, 18, 122, -10, 2, 0 }, { 0, 0, -2, 8, 126, -6, 2, 0 }
133 };
134
135 DECLARE_ALIGNED(256, static const InterpKernel,
136 av1_sub_pel_filters_8sharp[SUBPEL_SHIFTS]) = {
137 { 0, 0, 0, 128, 0, 0, 0, 0 }, { -2, 2, -6, 126, 8, -2, 2, 0 },
138 { -2, 6, -12, 124, 16, -6, 4, -2 }, { -2, 8, -18, 120, 26, -10, 6, -2 },
139 { -4, 10, -22, 116, 38, -14, 6, -2 }, { -4, 10, -22, 108, 48, -18, 8, -2 },
140 { -4, 10, -24, 100, 60, -20, 8, -2 }, { -4, 10, -24, 90, 70, -22, 10, -2 },
141 { -4, 12, -24, 80, 80, -24, 12, -4 }, { -2, 10, -22, 70, 90, -24, 10, -4 },
142 { -2, 8, -20, 60, 100, -24, 10, -4 }, { -2, 8, -18, 48, 108, -22, 10, -4 },
143 { -2, 6, -14, 38, 116, -22, 10, -4 }, { -2, 6, -10, 26, 120, -18, 8, -2 },
144 { -2, 4, -6, 16, 124, -12, 6, -2 }, { 0, 2, -2, 8, 126, -6, 2, -2 }
145 };
146
147 DECLARE_ALIGNED(256, static const InterpKernel,
148 av1_sub_pel_filters_8smooth[SUBPEL_SHIFTS]) = {
149 { 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 2, 28, 62, 34, 2, 0, 0 },
150 { 0, 0, 26, 62, 36, 4, 0, 0 }, { 0, 0, 22, 62, 40, 4, 0, 0 },
151 { 0, 0, 20, 60, 42, 6, 0, 0 }, { 0, 0, 18, 58, 44, 8, 0, 0 },
152 { 0, 0, 16, 56, 46, 10, 0, 0 }, { 0, -2, 16, 54, 48, 12, 0, 0 },
153 { 0, -2, 14, 52, 52, 14, -2, 0 }, { 0, 0, 12, 48, 54, 16, -2, 0 },
154 { 0, 0, 10, 46, 56, 16, 0, 0 }, { 0, 0, 8, 44, 58, 18, 0, 0 },
155 { 0, 0, 6, 42, 60, 20, 0, 0 }, { 0, 0, 4, 40, 62, 22, 0, 0 },
156 { 0, 0, 4, 36, 62, 26, 0, 0 }, { 0, 0, 2, 34, 62, 28, 2, 0 }
157 };
158
159 DECLARE_ALIGNED(256, static const int16_t,
160 av1_sub_pel_filters_12sharp[SUBPEL_SHIFTS][12]) = {
161 { 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 },
162 { 0, 1, -2, 3, -7, 127, 8, -4, 2, -1, 1, 0 },
163 { -1, 2, -3, 6, -13, 124, 18, -8, 4, -2, 2, -1 },
164 { -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1 },
165 { -1, 3, -6, 10, -21, 115, 38, -15, 8, -5, 3, -1 },
166 { -2, 4, -6, 12, -24, 108, 49, -18, 10, -6, 3, -2 },
167 { -2, 4, -7, 13, -25, 100, 60, -21, 11, -7, 4, -2 },
168 { -2, 4, -7, 13, -26, 91, 71, -24, 13, -7, 4, -2 },
169 { -2, 4, -7, 13, -25, 81, 81, -25, 13, -7, 4, -2 },
170 { -2, 4, -7, 13, -24, 71, 91, -26, 13, -7, 4, -2 },
171 { -2, 4, -7, 11, -21, 60, 100, -25, 13, -7, 4, -2 },
172 { -2, 3, -6, 10, -18, 49, 108, -24, 12, -6, 4, -2 },
173 { -1, 3, -5, 8, -15, 38, 115, -21, 10, -6, 3, -1 },
174 { -1, 2, -4, 7, -12, 28, 120, -18, 8, -4, 3, -1 },
175 { -1, 2, -2, 4, -8, 18, 124, -13, 6, -3, 2, -1 },
176 { 0, 1, -1, 2, -4, 8, 127, -7, 3, -2, 1, 0 }
177 };
178
179 static const InterpFilterParams
180 av1_interp_filter_params_list[INTERP_FILTERS_ALL] = {
181 { (const int16_t *)av1_sub_pel_filters_8, SUBPEL_TAPS, EIGHTTAP_REGULAR },
182 { (const int16_t *)av1_sub_pel_filters_8smooth, SUBPEL_TAPS,
183 EIGHTTAP_SMOOTH },
184 { (const int16_t *)av1_sub_pel_filters_8sharp, SUBPEL_TAPS,
185 MULTITAP_SHARP },
186 { (const int16_t *)av1_bilinear_filters, SUBPEL_TAPS, BILINEAR },
187
188 // The following filters are for encoder only, and now they are used in
189 // temporal filtering. The predictor block size >= 16 in temporal filter.
190 { (const int16_t *)av1_sub_pel_filters_12sharp, 12, MULTITAP_SHARP2 },
191 };
192
193 // A special 2-tap bilinear filter for IntraBC chroma. IntraBC uses full pixel
194 // MV for luma. If sub-sampling exists, chroma may possibly use half-pel MV.
195 DECLARE_ALIGNED(256, static const int16_t,
196 av1_intrabc_bilinear_filter[2 * SUBPEL_SHIFTS]) = {
197 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
198 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199 };
200
201 static const InterpFilterParams av1_intrabc_filter_params = {
202 av1_intrabc_bilinear_filter, 2, BILINEAR
203 };
204
205 DECLARE_ALIGNED(256, static const InterpKernel,
206 av1_sub_pel_filters_4[SUBPEL_SHIFTS]) = {
207 { 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 0, -4, 126, 8, -2, 0, 0 },
208 { 0, 0, -8, 122, 18, -4, 0, 0 }, { 0, 0, -10, 116, 28, -6, 0, 0 },
209 { 0, 0, -12, 110, 38, -8, 0, 0 }, { 0, 0, -12, 102, 48, -10, 0, 0 },
210 { 0, 0, -14, 94, 58, -10, 0, 0 }, { 0, 0, -12, 84, 66, -10, 0, 0 },
211 { 0, 0, -12, 76, 76, -12, 0, 0 }, { 0, 0, -10, 66, 84, -12, 0, 0 },
212 { 0, 0, -10, 58, 94, -14, 0, 0 }, { 0, 0, -10, 48, 102, -12, 0, 0 },
213 { 0, 0, -8, 38, 110, -12, 0, 0 }, { 0, 0, -6, 28, 116, -10, 0, 0 },
214 { 0, 0, -4, 18, 122, -8, 0, 0 }, { 0, 0, -2, 8, 126, -4, 0, 0 }
215 };
216 DECLARE_ALIGNED(256, static const InterpKernel,
217 av1_sub_pel_filters_4smooth[SUBPEL_SHIFTS]) = {
218 { 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 0, 30, 62, 34, 2, 0, 0 },
219 { 0, 0, 26, 62, 36, 4, 0, 0 }, { 0, 0, 22, 62, 40, 4, 0, 0 },
220 { 0, 0, 20, 60, 42, 6, 0, 0 }, { 0, 0, 18, 58, 44, 8, 0, 0 },
221 { 0, 0, 16, 56, 46, 10, 0, 0 }, { 0, 0, 14, 54, 48, 12, 0, 0 },
222 { 0, 0, 12, 52, 52, 12, 0, 0 }, { 0, 0, 12, 48, 54, 14, 0, 0 },
223 { 0, 0, 10, 46, 56, 16, 0, 0 }, { 0, 0, 8, 44, 58, 18, 0, 0 },
224 { 0, 0, 6, 42, 60, 20, 0, 0 }, { 0, 0, 4, 40, 62, 22, 0, 0 },
225 { 0, 0, 4, 36, 62, 26, 0, 0 }, { 0, 0, 2, 34, 62, 30, 0, 0 }
226 };
227
228 static const uint16_t
229 av1_interp_dual_filt_mask[INTERP_PRED_TYPE_ALL - 2][SWITCHABLE_FILTERS] = {
230 { (1 << REG_REG) | (1 << SMOOTH_REG) | (1 << SHARP_REG),
231 (1 << REG_SMOOTH) | (1 << SMOOTH_SMOOTH) | (1 << SHARP_SMOOTH),
232 (1 << REG_SHARP) | (1 << SMOOTH_SHARP) | (1 << SHARP_SHARP) },
233 { (1 << REG_REG) | (1 << REG_SMOOTH) | (1 << REG_SHARP),
234 (1 << SMOOTH_REG) | (1 << SMOOTH_SMOOTH) | (1 << SMOOTH_SHARP),
235 (1 << SHARP_REG) | (1 << SHARP_SMOOTH) | (1 << SHARP_SHARP) }
236 };
237
238 // For w<=4, MULTITAP_SHARP is the same as EIGHTTAP_REGULAR
239 static const InterpFilterParams av1_interp_4tap[SWITCHABLE_FILTERS + 1] = {
240 { (const int16_t *)av1_sub_pel_filters_4, SUBPEL_TAPS, EIGHTTAP_REGULAR },
241 { (const int16_t *)av1_sub_pel_filters_4smooth, SUBPEL_TAPS,
242 EIGHTTAP_SMOOTH },
243 { (const int16_t *)av1_sub_pel_filters_4, SUBPEL_TAPS, EIGHTTAP_REGULAR },
244 { (const int16_t *)av1_bilinear_filters, SUBPEL_TAPS, BILINEAR },
245 };
246
247 static inline const InterpFilterParams *
av1_get_interp_filter_params_with_block_size(const InterpFilter interp_filter,const int w)248 av1_get_interp_filter_params_with_block_size(const InterpFilter interp_filter,
249 const int w) {
250 if (w <= 4 && interp_filter != MULTITAP_SHARP2)
251 return &av1_interp_4tap[interp_filter];
252 return &av1_interp_filter_params_list[interp_filter];
253 }
254
av1_get_interp_filter_kernel(const InterpFilter interp_filter,int subpel_search)255 static inline const int16_t *av1_get_interp_filter_kernel(
256 const InterpFilter interp_filter, int subpel_search) {
257 assert(subpel_search >= USE_2_TAPS);
258 return (subpel_search == USE_2_TAPS)
259 ? av1_interp_4tap[BILINEAR].filter_ptr
260 : ((subpel_search == USE_4_TAPS)
261 ? av1_interp_4tap[interp_filter].filter_ptr
262 : av1_interp_filter_params_list[interp_filter].filter_ptr);
263 }
264
av1_get_interp_filter_subpel_kernel(const InterpFilterParams * const filter_params,const int subpel)265 static inline const int16_t *av1_get_interp_filter_subpel_kernel(
266 const InterpFilterParams *const filter_params, const int subpel) {
267 return filter_params->filter_ptr + filter_params->taps * subpel;
268 }
269
av1_get_filter(int subpel_search)270 static inline const InterpFilterParams *av1_get_filter(int subpel_search) {
271 assert(subpel_search >= USE_2_TAPS);
272
273 switch (subpel_search) {
274 case USE_2_TAPS: return &av1_interp_4tap[BILINEAR];
275 case USE_4_TAPS: return &av1_interp_4tap[EIGHTTAP_REGULAR];
276 case USE_8_TAPS: return &av1_interp_filter_params_list[EIGHTTAP_REGULAR];
277 default: assert(0); return NULL;
278 }
279 }
280
reset_interp_filter_allowed_mask(uint16_t * allow_interp_mask,DUAL_FILTER_TYPE filt_type)281 static inline void reset_interp_filter_allowed_mask(
282 uint16_t *allow_interp_mask, DUAL_FILTER_TYPE filt_type) {
283 uint16_t tmp = (~(1 << filt_type)) & 0xffff;
284 *allow_interp_mask &= (tmp & ALLOW_ALL_INTERP_FILT_MASK);
285 }
286
set_interp_filter_allowed_mask(uint16_t * allow_interp_mask,DUAL_FILTER_TYPE filt_type)287 static inline void set_interp_filter_allowed_mask(uint16_t *allow_interp_mask,
288 DUAL_FILTER_TYPE filt_type) {
289 *allow_interp_mask |= (1 << filt_type);
290 }
291
get_interp_filter_allowed_mask(uint16_t allow_interp_mask,DUAL_FILTER_TYPE filt_type)292 static inline uint8_t get_interp_filter_allowed_mask(
293 uint16_t allow_interp_mask, DUAL_FILTER_TYPE filt_type) {
294 return (allow_interp_mask >> filt_type) & 1;
295 }
296
get_filter_tap(const InterpFilterParams * const filter_params,int subpel_qn)297 static inline int get_filter_tap(const InterpFilterParams *const filter_params,
298 int subpel_qn) {
299 const int16_t *const filter = av1_get_interp_filter_subpel_kernel(
300 filter_params, subpel_qn & SUBPEL_MASK);
301 if (filter_params->taps == 12) {
302 return 12;
303 }
304 if (filter[0] | filter[7]) {
305 return 8;
306 }
307 if (filter[1] | filter[6]) {
308 return 6;
309 }
310 #if CONFIG_SVT_AV1
311 if (filter[2] | filter[5]) {
312 return 4;
313 }
314 return 2;
315 #else
316 return 4;
317 #endif
318 }
319
320 #ifdef __cplusplus
321 } // extern "C"
322 #endif
323
324 #endif // AOM_AV1_COMMON_FILTER_H_
325