1 /*
2  * This file is part of libplacebo.
3  *
4  * libplacebo is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * libplacebo is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef LIBPLACEBO_FILTER_KERNELS_H_
19 #define LIBPLACEBO_FILTER_KERNELS_H_
20 
21 #include <stdbool.h>
22 #include <libplacebo/log.h>
23 
24 PL_API_BEGIN
25 
26 #define PL_FILTER_MAX_PARAMS 2
27 
28 // Represents a single filter function, i.e. kernel or windowing function.
29 // To invoke a filter with a different configuration than the default, you can
30 // make a copy of this struct and modify the non-const fields before passing it
31 // to pl_filter_initialize.
32 struct pl_filter_function {
33     // These bools indicate whether or not `radius` and `params` may be
34     // modified by the user.
35     bool resizable;
36     bool tunable[PL_FILTER_MAX_PARAMS];
37 
38     // The underlying filter function itself: Computes the weight as a function
39     // of the offset. All filter functions must be normalized such that x=0 is
40     // the center point, and in particular weight(0) = 1.0. The functions may
41     // be undefined for values of x outside [0, radius].
42     double (*weight)(const struct pl_filter_function *k, double x);
43 
44     // This field may be used to adjust the function's radius. Defaults to the
45     // the radius needed to represent a single filter lobe (tap). If the
46     // function is not resizable, this field must not be modified - otherwise
47     // the result of filter evaluation is undefined.
48     float radius;
49 
50     // These fields may be used to adjust the function. Defaults to the
51     // function's preferred defaults. if the relevant setting is not tunable,
52     // they are ignored entirely.
53     float params[PL_FILTER_MAX_PARAMS];
54 };
55 
56 bool pl_filter_function_eq(const struct pl_filter_function *a,
57                            const struct pl_filter_function *b);
58 
59 // Box filter: Entirely 1.0 within the radius, entirely 0.0 outside of it.
60 // This is also sometimes called a Dirichlet window
61 extern const struct pl_filter_function pl_filter_function_box;
62 
63 // Triangle filter: Linear transitions from 1.0 at x=0 to 0.0 at x=radius.
64 // This is also sometimes called a Bartlett window.
65 extern const struct pl_filter_function pl_filter_function_triangle;
66 
67 // Cosine filter: Ordinary cosine function, single lobe.
68 extern const struct pl_filter_function pl_filter_function_cosine;
69 
70 // Hann function: Cosine filter named after Julius von Hann. Also commonly
71 // mislabeled as a "Hanning" function, due to its similarly to the Hamming
72 // function.
73 extern const struct pl_filter_function pl_filter_function_hann;
74 
75 // Hamming function: Cosine filter named after Richard Hamming.
76 extern const struct pl_filter_function pl_filter_function_hamming;
77 
78 // Welch filter: Polynomial function consisting of a single parabolic section.
79 extern const struct pl_filter_function pl_filter_function_welch;
80 
81 // Kaiser filter: Approximation of the DPSS window using Bessel functions.
82 // Also sometimes called a Kaiser-Bessel window.
83 // Parameter [0]: Shape (alpha). Determines the trade-off between the main lobe
84 //                and the side lobes.
85 extern const struct pl_filter_function pl_filter_function_kaiser;
86 
87 // Blackman filter: Cosine filter named after Ralph Beebe Blackman.
88 // Parameter [0]: Scale (alpha). Influences the shape. The defaults result in
89 //                zeros at the third and fourth sidelobes.
90 extern const struct pl_filter_function pl_filter_function_blackman;
91 
92 // Bohman filter: 2nd order Cosine filter.
93 extern const struct pl_filter_function pl_filter_function_bohman;
94 
95 // Gaussian function: Similar to the Gaussian distribution, this defines a
96 // bell curve function.
97 // Parameter [0]: Scale (t), increasing makes the result blurrier.
98 extern const struct pl_filter_function pl_filter_function_gaussian;
99 
100 // Quadratic function: 2nd order approximation of the gaussian function. Also
101 // sometimes called a "quadric" window.
102 extern const struct pl_filter_function pl_filter_function_quadratic;
103 
104 // Sinc function: Widely used for both kernels and windows, sinc(x) = sin(x)/x.
105 extern const struct pl_filter_function pl_filter_function_sinc;
106 
107 // Jinc function: Similar to sinc, but extended to the 2D domain. Widely
108 // used as the kernel of polar (EWA) filters. Also sometimes called a Sombrero
109 // function.
110 extern const struct pl_filter_function pl_filter_function_jinc;
111 
112 // Sphinx function: Similar to sinc and jinx, but extended to the 3D domain.
113 // The name is derived from "spherical" sinc. Can be used to filter 3D signals
114 // in theory.
115 extern const struct pl_filter_function pl_filter_function_sphinx;
116 
117 // B/C-tunable Spline function: This is a family of commonly used spline
118 // functions with two tunable parameters. Does not need to be windowed.
119 // Parameter [0]: "B"
120 // Parameter [1]: "C"
121 // Due to its populariy, this function is available in several variants.
122 // B = 0.0,  C = 0.0:  "base" bcspline, AKA Hermite spline (blocky)
123 // B = 0.0,  C = 0.5:  Catmull-Rom filter (sharp)
124 // B = 1/3,  C = 1/3:  Mitchell-Netravali filter (soft, doesn't ring)
125 // B ≈ 0.37, C ≈ 0.31: Robidoux filter (used by ImageMagick)
126 // B ≈ 0.26, C ≈ 0.37: RobidouxSharp filter. (sharper variant of Robidoux)
127 extern const struct pl_filter_function pl_filter_function_bcspline;
128 extern const struct pl_filter_function pl_filter_function_catmull_rom;
129 extern const struct pl_filter_function pl_filter_function_mitchell;
130 extern const struct pl_filter_function pl_filter_function_robidoux;
131 extern const struct pl_filter_function pl_filter_function_robidouxsharp;
132 
133 // Bicubic function: Very smooth and free of ringing, but very blurry. Does not
134 // need to be windowed.
135 extern const struct pl_filter_function pl_filter_function_bicubic;
136 
137 // Piecewise approximations of the Lanczos filter function (sinc-windowed
138 // sinc). Referred to as "spline16", "spline36" and "spline64" mainly for
139 // historical reasons, based on their fixed radii of 2, 3 and 4 (respectively).
140 // These do not need to be windowed.
141 extern const struct pl_filter_function pl_filter_function_spline16;
142 extern const struct pl_filter_function pl_filter_function_spline36;
143 extern const struct pl_filter_function pl_filter_function_spline64;
144 
145 struct pl_filter_function_preset {
146     const char *name;
147     const struct pl_filter_function *function;
148 };
149 
150 // A list of built-in filter function presets, terminated by {0}
151 extern const struct pl_filter_function_preset pl_filter_function_presets[];
152 extern const int pl_num_filter_function_presets; // excluding trailing {0}
153 
154 // Find the filter function preset with the given name, or NULL on failure.
155 const struct pl_filter_function_preset *pl_find_filter_function_preset(const char *name);
156 
157 // Backwards compatibility
158 #define pl_named_filter_function        pl_filter_function_preset
159 #define pl_named_filter_functions       pl_filter_function_presets
160 #define pl_find_named_filter_function   pl_find_filter_function_preset
161 
162 // Represents a particular configuration/combination of filter functions to
163 // form a filter.
164 struct pl_filter_config {
165     const struct pl_filter_function *kernel; // The kernel function
166     const struct pl_filter_function *window; // The windowing function. Optional
167 
168     // Represents a clamping coefficient for negative weights. A value of 0.0
169     // (the default) represents no clamping. A value of 1.0 represents full
170     // clamping, i.e. all negative weights will be clamped to 0. Values in
171     // between will be linearly scaled.
172     float clamp;
173 
174     // Additional blur coefficient. This effectively stretches the kernel,
175     // without changing the effective radius of the filter radius. Setting this
176     // to a value of 0.0 is equivalent to disabling it. Values significantly
177     // below 1.0 may seriously degrade the visual output, and should be used
178     // with care.
179     float blur;
180 
181     // Additional taper coefficient. This essentially flattens the function's
182     // center. The values within [-taper, taper] will return 1.0, with the
183     // actual function being squished into the remainder of [taper, radius].
184     // Defaults to 0.0.
185     float taper;
186 
187     // If true, this filter is intended to be used as a polar/2D filter (EWA)
188     // instead of a separable/1D filter. Does not affect the actual sampling,
189     // but provides information about how the results are to be interpreted.
190     bool polar;
191 };
192 
193 bool pl_filter_config_eq(const struct pl_filter_config *a,
194                          const struct pl_filter_config *b);
195 
196 // Samples a given filter configuration at a given x coordinate, while
197 // respecting all parameters of the configuration.
198 double pl_filter_sample(const struct pl_filter_config *c, double x);
199 
200 // A list of built-in filter configurations. Since they are just combinations
201 // of the above filter functions, they are not described in much further
202 // detail.
203 extern const struct pl_filter_config pl_filter_spline16;    // 2 taps
204 extern const struct pl_filter_config pl_filter_spline36;    // 3 taps
205 extern const struct pl_filter_config pl_filter_spline64;    // 4 taps
206 extern const struct pl_filter_config pl_filter_nearest;     // AKA box
207 extern const struct pl_filter_config pl_filter_bilinear;    // AKA triangle
208 extern const struct pl_filter_config pl_filter_gaussian;
209 // Sinc family (all configured to 3 taps):
210 extern const struct pl_filter_config pl_filter_sinc;        // unwindowed,
211 extern const struct pl_filter_config pl_filter_lanczos;     // sinc-sinc
212 extern const struct pl_filter_config pl_filter_ginseng;     // sinc-jinc
213 extern const struct pl_filter_config pl_filter_ewa_jinc;    // unwindowed
214 extern const struct pl_filter_config pl_filter_ewa_lanczos; // jinc-jinc
215 extern const struct pl_filter_config pl_filter_ewa_ginseng; // jinc-sinc
216 extern const struct pl_filter_config pl_filter_ewa_hann;    // jinc-hann
217 extern const struct pl_filter_config pl_filter_haasnsoft PL_DEPRECATED;
218 // Spline family
219 extern const struct pl_filter_config pl_filter_bicubic;
220 extern const struct pl_filter_config pl_filter_catmull_rom;
221 extern const struct pl_filter_config pl_filter_mitchell;
222 extern const struct pl_filter_config pl_filter_mitchell_clamp; // clamp = 1.0
223 extern const struct pl_filter_config pl_filter_robidoux;
224 extern const struct pl_filter_config pl_filter_robidouxsharp;
225 extern const struct pl_filter_config pl_filter_ewa_robidoux;
226 extern const struct pl_filter_config pl_filter_ewa_robidouxsharp;
227 
228 // Backwards compatibility
229 #define pl_filter_box       pl_filter_nearest
230 #define pl_filter_triangle  pl_filter_bilinear
231 
232 struct pl_filter_preset {
233     const char *name;
234     const struct pl_filter_config *filter;
235 
236     // Longer / friendly name, or NULL for aliases
237     const char *description;
238 };
239 
240 // A list of built-in filter presets, terminated by {0}
241 extern const struct pl_filter_preset pl_filter_presets[];
242 extern const int pl_num_filter_presets; // excluding trailing {0}
243 
244 // Find the filter preset with the given name, or NULL on failure.
245 const struct pl_filter_preset *pl_find_filter_preset(const char *name);
246 
247 // Backwards compatibility
248 #define pl_named_filter_config  pl_filter_preset
249 #define pl_named_filters        pl_filter_presets
250 #define pl_find_named_filter    pl_find_filter_preset
251 
252 // Parameters for filter generation.
253 struct pl_filter_params {
254     // The particular filter configuration to be sampled. config.kernel must
255     // be set to a valid pl_filter_function.
256     struct pl_filter_config config;
257 
258     // The precision of the resulting LUT. A value of 64 should be fine for
259     // most practical purposes, but higher or lower values may be justified
260     // depending on the use case. This value must be set to something > 0.
261     int lut_entries;
262 
263     // When set to values above 1.0, the filter will be computed at a size
264     // larger than the radius would otherwise require, in order to prevent
265     // aliasing when downscaling. In practice, this should be set to the
266     // inverse of the scaling ratio, i.e. src_size / dst_size.
267     float filter_scale;
268 
269     // --- polar filers only (config.polar)
270 
271     // As a micro-optimization, all samples below this cutoff value will be
272     // ignored when updating the cutoff radius. Setting it to a value of 0.0
273     // disables this optimization.
274     float cutoff;
275 
276     // --- separable filters only (!config.polar)
277 
278     // Indicates the maximum row size that is supported by the calling code, or
279     // 0 for no limit.
280     int max_row_size;
281 
282     // Indicates the row stride alignment. For some use cases (e.g. uploading
283     // the weights as a texture), there are certain alignment requirements for
284     // each row. The chosen row_size will always be a multiple of this value.
285     // Specifying 0 indicates no alignment requirements.
286     int row_stride_align;
287 };
288 
289 // Represents an initialized instance of a particular filter, with a
290 // precomputed LUT. The interpretation of the LUT depends on the type of the
291 // filter (polar or separable).
292 typedef const PL_STRUCT(pl_filter) {
293     // Deep copy of the parameters, for convenience.
294     struct pl_filter_params params;
295 
296     // Contains the true radius of the computed filter. This may be
297     // larger than `config.kernel->radius` depending on the `scale` passed to
298     // pl_filter_generate. This is only relevant for polar filters, where it
299     // affects the value range of *weights.
300     float radius;
301 
302     // The computed look-up table (LUT). For polar filters, this is interpreted
303     // as a 1D array with dimensions [lut_entries] containing the raw filter
304     // samples on the scale [0, radius]. For separable (non-polar) filters,
305     // this is interpreted as a 2D array with dimensions
306     // [lut_entries][row_stride]. The inner rows contain the `row_size` samples
307     // to convolve with the corresponding input pixels. The outer coordinate is
308     // used to very the fractional offset (phase). So for example, if the
309     // sample position to reconstruct is directly aligned with the source
310     // texels, you would use the values from weights[0]. If the sample position
311     // to reconstruct is exactly half-way between two source texels (180° out
312     // of phase), you would use the values from weights[lut_entries/2].
313     const float *weights;
314 
315     // --- polar filters only (params.config.polar)
316 
317     // Contains the effective cut-off radius for this filter. Samples outside
318     // of this cutoff radius may be discarded. Computed based on the `cutoff`
319     // value specified at filter generation. Only relevant for polar filters
320     // since skipping samples outside of the radius can be a significant
321     // performance gain for EWA sampling.
322     float radius_cutoff;
323 
324     // --- separable filters only (!params.config.polar)
325 
326     // The number of source texels to convolve over for each row. This value
327     // will never exceed the given `max_row_size`. If the filter ends up
328     // cut off because of this, the bool `insufficient` will be set to true.
329     int row_size;
330     bool insufficient;
331 
332     // The separation (in *weights) between each row of the filter. Always
333     // a multiple of params.row_stride_align.
334     int row_stride;
335 } *pl_filter;
336 
337 // Generate (compute) a filter instance based on a given filter configuration.
338 // The resulting pl_filter must be freed with `pl_filter_free` when no longer
339 // needed. Returns NULL if filter generation fails due to invalid parameters
340 // (i.e. missing a required parameter).
341 pl_filter pl_filter_generate(pl_log log, const struct pl_filter_params *params);
342 void pl_filter_free(pl_filter *filter);
343 
344 PL_API_END
345 
346 #endif // LIBPLACEBO_FILTER_KERNELS_H_
347