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