xref: /aosp_15_r20/external/libaom/av1/common/filter.h (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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