summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/filters.h
blob: a95649da788f3469dbf553b8c59a67642be644d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/*
 * This file is part of libplacebo.
 *
 * libplacebo is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * libplacebo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBPLACEBO_FILTER_KERNELS_H_
#define LIBPLACEBO_FILTER_KERNELS_H_

#include <stdbool.h>
#include <libplacebo/log.h>

PL_API_BEGIN

#define PL_FILTER_MAX_PARAMS 2

// Invocation parameters for a given kernel
struct pl_filter_ctx {
    float radius;
    float params[PL_FILTER_MAX_PARAMS];
};

// Represents a single filter function, i.e. kernel or windowing function.
struct pl_filter_function {
    // The cosmetic name associated with this filter function.
    const char *name;

    // The radius of the filter function. For resizable filters, this gives
    // the radius needed to represent a single filter lobe (tap).
    float radius;

    // If true, the filter function is resizable (see pl_filter_config.radius)
    bool resizable;

    // If true, the filter function is tunable (see pl_filter_config.params)
    bool tunable[PL_FILTER_MAX_PARAMS];

    // If the relevant parameter is tunable, this contains the default values.
    float params[PL_FILTER_MAX_PARAMS];

    // The underlying filter function itself: Computes the weight as a function
    // of the offset. All filter functions must be normalized such that x=0 is
    // the center point, and in particular weight(0) = 1.0. The functions may
    // be undefined for values of x outside [0, radius].
    double (*weight)(const struct pl_filter_ctx *f, double x);

    // If true, this filter represents an opaque placeholder for a more
    // sophisticated filter function which does not fit into the pl_filter
    // framework. `weight()` will always return 0.0.
    bool opaque;
};

// Deprecated function, merely checks a->weight == b->weight
PL_DEPRECATED PL_API bool
pl_filter_function_eq(const struct pl_filter_function *a,
                      const struct pl_filter_function *b);

// Box filter: Entirely 1.0 within the radius, entirely 0.0 outside of it.
// This is also sometimes called a Dirichlet window
PL_API extern const struct pl_filter_function pl_filter_function_box;

// Triangle filter: Linear transitions from 1.0 at x=0 to 0.0 at x=radius.
// This is also sometimes called a Bartlett window.
PL_API extern const struct pl_filter_function pl_filter_function_triangle;

// Cosine filter: Ordinary cosine function, single lobe.
PL_API extern const struct pl_filter_function pl_filter_function_cosine;

// Hann function: Cosine filter named after Julius von Hann. Also commonly
// mislabeled as a "Hanning" function, due to its similarly to the Hamming
// function.
PL_API extern const struct pl_filter_function pl_filter_function_hann;

// Hamming function: Cosine filter named after Richard Hamming.
PL_API extern const struct pl_filter_function pl_filter_function_hamming;

// Welch filter: Polynomial function consisting of a single parabolic section.
PL_API extern const struct pl_filter_function pl_filter_function_welch;

// Kaiser filter: Approximation of the DPSS window using Bessel functions.
// Also sometimes called a Kaiser-Bessel window.
// Parameter [0]: Shape (alpha). Determines the trade-off between the main lobe
//                and the side lobes.
PL_API extern const struct pl_filter_function pl_filter_function_kaiser;

// Blackman filter: Cosine filter named after Ralph Beebe Blackman.
// Parameter [0]: Scale (alpha). Influences the shape. The defaults result in
//                zeros at the third and fourth sidelobes.
PL_API extern const struct pl_filter_function pl_filter_function_blackman;

// Bohman filter: 2nd order Cosine filter.
PL_API extern const struct pl_filter_function pl_filter_function_bohman;

// Gaussian function: Similar to the Gaussian distribution, this defines a
// bell curve function.
// Parameter [0]: Scale (t), increasing makes the result blurrier.
PL_API extern const struct pl_filter_function pl_filter_function_gaussian;

// Quadratic function: 2nd order approximation of the gaussian function. Also
// sometimes called a "quadric" window.
PL_API extern const struct pl_filter_function pl_filter_function_quadratic;

// Sinc function: Widely used for both kernels and windows, sinc(x) = sin(x)/x.
PL_API extern const struct pl_filter_function pl_filter_function_sinc;

// Jinc function: Similar to sinc, but extended to the 2D domain. Widely
// used as the kernel of polar (EWA) filters. Also sometimes called a Sombrero
// function.
PL_API extern const struct pl_filter_function pl_filter_function_jinc;

// Sphinx function: Similar to sinc and jinx, but extended to the 3D domain.
// The name is derived from "spherical" sinc. Can be used to filter 3D signals
// in theory.
PL_API extern const struct pl_filter_function pl_filter_function_sphinx;

// B/C-tunable Spline function: This is a family of commonly used spline
// functions with two tunable parameters. Does not need to be windowed.
// Parameter [0]: "B"
// Parameter [1]: "C"
// Some popular variants of this function are:
// B = 1.0,  C = 0.0:  "base" Cubic (blurry)
// B = 0.0,  C = 0.0:  Hermite filter (blocky)
// B = 0.0,  C = 0.5:  Catmull-Rom filter (sharp)
// B = 1/3,  C = 1/3:  Mitchell-Netravali filter (soft, doesn't ring)
// B ≈ 0.37, C ≈ 0.31: Robidoux filter (used by ImageMagick)
// B ≈ 0.26, C ≈ 0.37: RobidouxSharp filter (sharper variant of Robidoux)
PL_API extern const struct pl_filter_function pl_filter_function_cubic;
PL_API extern const struct pl_filter_function pl_filter_function_hermite;
#define pl_filter_function_bicubic pl_filter_function_cubic
#define pl_filter_function_bcspline pl_filter_function_cubic

// Cubic splines with 2/3/4 taps. Referred to as "spline16", "spline36", and
// "spline64" mainly for historical reasons, based on the number of pixels in
// their window when using them as 2D orthogonal filters. Do not need to be
// windowed.
PL_API extern const struct pl_filter_function pl_filter_function_spline16;
PL_API extern const struct pl_filter_function pl_filter_function_spline36;
PL_API extern const struct pl_filter_function pl_filter_function_spline64;

// Special filter function for the built-in oversampling algorithm. This is an
// opaque filter with no meaningful representation. though it has one tunable
// parameter controlling the threshold at which to switch back to ordinary
// nearest neighbour sampling. (See `pl_shader_sample_oversample`)
PL_API extern const struct pl_filter_function pl_filter_function_oversample;

// A list of built-in filter functions, terminated by NULL
//
// Note: May contain extra aliases for the above functions.
PL_API extern const struct pl_filter_function * const pl_filter_functions[];
PL_API extern const int pl_num_filter_functions; // excluding trailing NULL

// Find the filter function with the given name, or NULL on failure.
PL_API const struct pl_filter_function *pl_find_filter_function(const char *name);

// Backwards compatibility with the older configuration API. Redundant with
// `pl_filter_function.name`. May be formally deprecated in the future.

struct pl_filter_function_preset {
    const char *name;
    const struct pl_filter_function *function;
};

// A list of built-in filter function presets, terminated by {0}
PL_API extern const struct pl_filter_function_preset pl_filter_function_presets[];
PL_API extern const int pl_num_filter_function_presets; // excluding trailing {0}

// Find the filter function preset with the given name, or NULL on failure.
PL_API const struct pl_filter_function_preset *pl_find_filter_function_preset(const char *name);

// Different usage domains for a filter
enum pl_filter_usage {
    PL_FILTER_UPSCALING    = (1 << 0),
    PL_FILTER_DOWNSCALING  = (1 << 1),
    PL_FILTER_FRAME_MIXING = (1 << 2),

    PL_FILTER_SCALING = PL_FILTER_UPSCALING | PL_FILTER_DOWNSCALING,
    PL_FILTER_ALL     = PL_FILTER_SCALING | PL_FILTER_FRAME_MIXING,
};

// Represents a tuned combination of filter functions, plus parameters
struct pl_filter_config {
    // The cosmetic name associated with this filter config. Optional for
    // user-provided configs, but always set by built-in configurations.
    const char *name;

    // Longer / friendly name. Always set for built-in configurations,
    // except for names which are merely aliases of other filters.
    const char *description;

    // Allowed and recommended usage domains (respectively)
    //
    // When it is desired to maintain a simpler user interface, it may be
    // recommended to include only scalers whose recommended usage domains
    // includes the relevant context in which it will be used.
    enum pl_filter_usage allowed;
    enum pl_filter_usage recommended;

    // The kernel function and (optionally) windowing function.
    const struct pl_filter_function *kernel;
    const struct pl_filter_function *window;

    // The radius. Ignored if !kernel->resizable. Optional, defaults to
    // kernel->radius if unset.
    float radius;

    // Parameters for the respective filter function. Ignored if not tunable.
    float params[PL_FILTER_MAX_PARAMS];
    float wparams[PL_FILTER_MAX_PARAMS];

    // Represents a clamping coefficient for negative weights. A value of 0.0
    // (the default) represents no clamping. A value of 1.0 represents full
    // clamping, i.e. all negative weights will be clamped to 0. Values in
    // between will be linearly scaled.
    float clamp;

    // Additional blur coefficient. This effectively stretches the kernel,
    // without changing the effective radius of the filter radius. Setting this
    // to a value of 0.0 is equivalent to disabling it. Values significantly
    // below 1.0 may seriously degrade the visual output, and should be used
    // with care.
    float blur;

    // Additional taper coefficient. This essentially flattens the function's
    // center. The values within [-taper, taper] will return 1.0, with the
    // actual function being squished into the remainder of [taper, radius].
    // Defaults to 0.0.
    float taper;

    // If true, this filter is intended to be used as a polar/2D filter (EWA)
    // instead of a separable/1D filter. Does not affect the actual sampling,
    // but provides information about how the results are to be interpreted.
    bool polar;

    // Antiringing strength. A value of 0.0 disables antiringing, and a value
    // of 1.0 enables full-strength antiringing. Defaults to 0.0 if
    // unspecified.
    //
    // Note: This is only included in `pl_filter_config` for convenience. Does
    // not affect the actual filter sampling, but provides information to the
    // downstream consumer of the `pl_filter`.
    float antiring;
};

PL_API bool pl_filter_config_eq(const struct pl_filter_config *a,
                                const struct pl_filter_config *b);

// Samples a given filter configuration at a given x coordinate, while
// respecting all parameters of the configuration.
PL_API double pl_filter_sample(const struct pl_filter_config *c, double x);

// A list of built-in filter configurations. Since they are just combinations
// of the above filter functions, they are not described in much further
// detail.
PL_API extern const struct pl_filter_config pl_filter_spline16;    // 2 taps
PL_API extern const struct pl_filter_config pl_filter_spline36;    // 3 taps
PL_API extern const struct pl_filter_config pl_filter_spline64;    // 4 taps
PL_API extern const struct pl_filter_config pl_filter_nearest;
PL_API extern const struct pl_filter_config pl_filter_box;
PL_API extern const struct pl_filter_config pl_filter_bilinear;
PL_API extern const struct pl_filter_config pl_filter_gaussian;
// Sinc family (all configured to 3 taps):
PL_API extern const struct pl_filter_config pl_filter_sinc;        // unwindowed
PL_API extern const struct pl_filter_config pl_filter_lanczos;     // sinc-sinc
PL_API extern const struct pl_filter_config pl_filter_ginseng;     // sinc-jinc
PL_API extern const struct pl_filter_config pl_filter_ewa_jinc;    // unwindowed
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczos; // jinc-jinc
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczossharp;
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczos4sharpest;
PL_API extern const struct pl_filter_config pl_filter_ewa_ginseng; // jinc-sinc
PL_API extern const struct pl_filter_config pl_filter_ewa_hann;    // jinc-hann
// Spline family
PL_API extern const struct pl_filter_config pl_filter_bicubic;
PL_API extern const struct pl_filter_config pl_filter_hermite;
PL_API extern const struct pl_filter_config pl_filter_catmull_rom;
PL_API extern const struct pl_filter_config pl_filter_mitchell;
PL_API extern const struct pl_filter_config pl_filter_mitchell_clamp; // clamp = 1.0
PL_API extern const struct pl_filter_config pl_filter_robidoux;
PL_API extern const struct pl_filter_config pl_filter_robidouxsharp;
PL_API extern const struct pl_filter_config pl_filter_ewa_robidoux;
PL_API extern const struct pl_filter_config pl_filter_ewa_robidouxsharp;
// Special/opaque filters
PL_API extern const struct pl_filter_config pl_filter_oversample;

// Backwards compatibility
#define pl_filter_triangle          pl_filter_bilinear
#define pl_oversample_frame_mixer   pl_filter_oversample

// A list of built-in filter configs, terminated by NULL
PL_API extern const struct pl_filter_config * const pl_filter_configs[];
PL_API extern const int pl_num_filter_configs; // excluding trailing NULL

// Find the filter config with the given name, or NULL on failure.
// `usage` restricts the valid usage (based on `pl_filter_config.allowed`).
PL_API const struct pl_filter_config *
pl_find_filter_config(const char *name, enum pl_filter_usage usage);

// Backward compatibility with the previous filter configuration API. Redundant
// with pl_filter_config.name/description. May be deprecated in the future.
struct pl_filter_preset {
    const char *name;
    const struct pl_filter_config *filter;

    // Longer / friendly name, or NULL for aliases
    const char *description;
};

// A list of built-in filter presets, terminated by {0}
PL_API extern const struct pl_filter_preset pl_filter_presets[];
PL_API extern const int pl_num_filter_presets; // excluding trailing {0}

// Find the filter preset with the given name, or NULL on failure.
PL_API const struct pl_filter_preset *pl_find_filter_preset(const char *name);

// Parameters for filter generation.
struct pl_filter_params {
    // The particular filter configuration to be sampled. config.kernel must
    // be set to a valid pl_filter_function.
    struct pl_filter_config config;

    // The precision of the resulting LUT. A value of 64 should be fine for
    // most practical purposes, but higher or lower values may be justified
    // depending on the use case. This value must be set to something > 0.
    int lut_entries;

    // --- Polar filers only (config.polar)

    // As a micro-optimization, all samples below this cutoff value will be
    // ignored when updating the cutoff radius. Setting it to a value of 0.0
    // disables this optimization.
    float cutoff;

    // --- Separable filters only (!config.polar)

    // Indicates the maximum row size that is supported by the calling code, or
    // 0 for no limit.
    int max_row_size;

    // Indicates the row stride alignment. For some use cases (e.g. uploading
    // the weights as a texture), there are certain alignment requirements for
    // each row. The chosen row_size will always be a multiple of this value.
    // Specifying 0 indicates no alignment requirements.
    int row_stride_align;

    // --- Deprecated options
    float filter_scale PL_DEPRECATED; // no effect, use `config.blur` instead
};

#define pl_filter_params(...) (&(struct pl_filter_params) { __VA_ARGS__ })

// Represents an initialized instance of a particular filter, with a
// precomputed LUT. The interpretation of the LUT depends on the type of the
// filter (polar or separable).
typedef const struct pl_filter_t {
    // Deep copy of the parameters, for convenience.
    struct pl_filter_params params;

    // Contains the true radius of the computed filter. This may be
    // smaller than the configured radius depending on the exact filter
    // parameters used. Mainly relevant for polar filters, since
    // it affects the value range of *weights.
    float radius;

    // Radius of the first zero crossing (main lobe size).
    float radius_zero;

    // The computed look-up table (LUT). For polar filters, this is interpreted
    // as a 1D array with dimensions [lut_entries] containing the raw filter
    // samples on the scale [0, radius]. For separable (non-polar) filters,
    // this is interpreted as a 2D array with dimensions
    // [lut_entries][row_stride]. The inner rows contain the `row_size` samples
    // to convolve with the corresponding input pixels. The outer coordinate is
    // used to very the fractional offset (phase). So for example, if the
    // sample position to reconstruct is directly aligned with the source
    // texels, you would use the values from weights[0]. If the sample position
    // to reconstruct is exactly half-way between two source texels (180° out
    // of phase), you would use the values from weights[lut_entries/2].
    const float *weights;

    // --- separable filters only (!params.config.polar)

    // The number of source texels to convolve over for each row. This value
    // will never exceed the given `max_row_size`. If the filter ends up
    // cut off because of this, the bool `insufficient` will be set to true.
    int row_size;
    bool insufficient;

    // The separation (in *weights) between each row of the filter. Always
    // a multiple of params.row_stride_align.
    int row_stride;

    // --- deprecated / removed fields
    float radius_cutoff PL_DEPRECATED; // identical to `radius`
} *pl_filter;

// Generate (compute) a filter instance based on a given filter configuration.
// The resulting pl_filter must be freed with `pl_filter_free` when no longer
// needed. Returns NULL if filter generation fails due to invalid parameters
// (i.e. missing a required parameter).
PL_API pl_filter pl_filter_generate(pl_log log, const struct pl_filter_params *params);
PL_API void pl_filter_free(pl_filter *filter);

PL_API_END

#endif // LIBPLACEBO_FILTER_KERNELS_H_