summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/shaders/sampling.h
blob: 5221e44a9d09c10f8d21d0f63cc78135c856c623 (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
/*
 * 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_SHADERS_SAMPLING_H_
#define LIBPLACEBO_SHADERS_SAMPLING_H_

// Sampling operations. These shaders perform some form of sampling operation
// from a given pl_tex. In order to use these, the pl_shader *must* have been
// created using the same `gpu` as the originating `pl_tex`. Otherwise, this
// is undefined behavior. They require nothing (PL_SHADER_SIG_NONE) and return
// a color (PL_SHADER_SIG_COLOR).

#include <libplacebo/colorspace.h>
#include <libplacebo/filters.h>
#include <libplacebo/shaders.h>

PL_API_BEGIN

// Common parameters for sampling operations
struct pl_sample_src {
    // There are two mutually exclusive ways of providing the source to sample
    // from:
    //
    // 1. Provide the texture and sampled region directly. This generates
    // a shader with input signature `PL_SHADER_SIG_NONE`, which binds the
    // texture as a descriptor (and the coordinates as a vertex attribute)
    pl_tex tex;             // texture to sample
    pl_rect2df rect;        // sub-rect to sample from (optional)
    enum pl_tex_address_mode address_mode; // preferred texture address mode

    // 2. Have the shader take it as an argument. Doing this requires
    // specifying the missing metadata of the texture backing the sampler, so
    // that the shader generation can generate the correct code.
    int tex_w, tex_h;             // dimensions of the actual texture
    enum pl_fmt_type format;      // format of the sampler being accepted
    enum pl_sampler_type sampler; // type of the sampler being accepted
    enum pl_tex_sample_mode mode; // sample mode of the sampler being accepted
    float sampled_w, sampled_h;   // dimensions of the sampled region (optional)

    // Common metadata for both sampler input types:
    int components;   // number of components to sample (optional)
    uint8_t component_mask; // bitmask of components to sample (optional)
    int new_w, new_h; // dimensions of the resulting output (optional)
    float scale;      // factor to multiply into sampled signal (optional)

    // Note: `component_mask` and `components` are mutually exclusive, the
    // former is preferred if both are specified.
};

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

struct pl_deband_params {
    // The number of debanding steps to perform per sample. Each step reduces a
    // bit more banding, but takes time to compute. Note that the strength of
    // each step falls off very quickly, so high numbers (>4) are practically
    // useless. Defaults to 1.
    int iterations;

    // The debanding filter's cut-off threshold. Higher numbers increase the
    // debanding strength dramatically, but progressively diminish image
    // details. Defaults to 3.0.
    float threshold;

    // The debanding filter's initial radius. The radius increases linearly
    // for each iteration. A higher radius will find more gradients, but a
    // lower radius will smooth more aggressively. Defaults to 16.0.
    float radius;

    // Add some extra noise to the image. This significantly helps cover up
    // remaining quantization artifacts. Higher numbers add more noise.
    // Note: When debanding HDR sources, even a small amount of grain can
    // result in a very big change to the brightness level. It's recommended to
    // either scale this value down or disable it entirely for HDR.
    //
    // Defaults to 4.0, which is very mild.
    float grain;

    // 'Neutral' grain value for each channel being debanded (sorted in order
    // from low to high index). Grain application will be modulated to avoid
    // disturbing colors close to this value. Set this to a value corresponding
    // to black in the relevant colorspace.
    float grain_neutral[3];
};

#define PL_DEBAND_DEFAULTS  \
    .iterations = 1,        \
    .threshold  = 3.0,      \
    .radius     = 16.0,     \
    .grain      = 4.0,

#define pl_deband_params(...) (&(struct pl_deband_params) {PL_DEBAND_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_deband_params pl_deband_default_params;

// Debands a given texture and returns the sampled color in `vec4 color`. If
// `params` is left as NULL, it defaults to &pl_deband_default_params. Note
// that `tex->params.format` must have PL_FMT_CAP_LINEAR. When the given
// `pl_sample_src` implies scaling, this effectively performs bilinear
// sampling on the input (but not the output).
//
// Note: This can also be used as a pure grain function, by setting the number
// of iterations to 0.
PL_API void pl_shader_deband(pl_shader sh, const struct pl_sample_src *src,
                             const struct pl_deband_params *params);

// Performs direct / native texture sampling, using whatever texture filter is
// available (linear for linearly sampleable sources, nearest otherwise).
//
// Note: This is generally very low quality and should be avoided if possible,
// for both upscaling and downscaling.
PL_API bool pl_shader_sample_direct(pl_shader sh, const struct pl_sample_src *src);

// Performs hardware-accelerated nearest neighbour sampling. This is similar to
// `pl_shader_sample_direct`, but forces nearest neighbour interpolation.
PL_API bool pl_shader_sample_nearest(pl_shader sh, const struct pl_sample_src *src);

// Performs hardware-accelerated bilinear sampling. This is similar to
// `pl_shader_sample_direct`, but forces bilinear interpolation.
PL_API bool pl_shader_sample_bilinear(pl_shader sh, const struct pl_sample_src *src);

// Optimized versions of specific, strictly positive scaler kernels that take
// adantage of linear texture sampling to reduce the number of fetches needed
// by a factor of four. This family of functions performs radius-2 scaling
// with only four texture fetches, which is far more efficient than using
// the generalized 1D scaling method. Only works well for upscaling.
PL_API bool pl_shader_sample_bicubic(pl_shader sh, const struct pl_sample_src *src);
PL_API bool pl_shader_sample_hermite(pl_shader sh, const struct pl_sample_src *src);
PL_API bool pl_shader_sample_gaussian(pl_shader sh, const struct pl_sample_src *src);

// A sampler that is similar to nearest neighbour sampling, but tries to
// preserve pixel aspect ratios. This is mathematically equivalent to taking an
// idealized image with square pixels, sampling it at an infinite resolution,
// and then downscaling that to the desired resolution. (Hence it being called
// "oversample"). Good for pixel art.
//
// The threshold provides a cutoff threshold below which the contribution of
// pixels should be ignored, trading some amount of aspect ratio distortion for
// a slightly crisper image. A value of `threshold == 0.5` makes this filter
// equivalent to regular nearest neighbour sampling.
PL_API bool pl_shader_sample_oversample(pl_shader sh, const struct pl_sample_src *src,
                                        float threshold);

struct pl_sample_filter_params {
    // The filter to use for sampling.
    struct pl_filter_config filter;

    // 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: Ignored if `filter.antiring` is already set to something nonzero.
    float antiring;

    // Disable the use of compute shaders (e.g. if rendering to non-storable tex)
    bool no_compute;
    // Disable the use of filter widening / anti-aliasing (for downscaling)
    bool no_widening;

    // This shader object is used to store the LUT, and will be recreated
    // if necessary. To avoid thrashing the resource, users should avoid trying
    // to re-use the same LUT for different filter configurations or scaling
    // ratios. Must be set to a valid pointer, and the target NULL-initialized.
    pl_shader_obj *lut;

    // Deprecated / removed fields
    int lut_entries PL_DEPRECATED; // hard-coded as 256
    float cutoff PL_DEPRECATED; // hard-coded as 1e-3
};

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

// Performs polar sampling. This internally chooses between an optimized compute
// shader, and various fragment shaders, depending on the supported GLSL version
// and GPU features. Returns whether or not it was successful.
//
// Note: `params->filter.polar` must be true to use this function.
PL_API bool pl_shader_sample_polar(pl_shader sh, const struct pl_sample_src *src,
                                   const struct pl_sample_filter_params *params);

// Performs orthogonal (1D) sampling. Using this twice in a row (once vertical
// and once horizontal) effectively performs a 2D upscale. This is lower
// quality than polar sampling, but significantly faster, and therefore the
// recommended default. Returns whether or not it was successful.
//
// `src` must represent a scaling operation that only scales in one direction,
// i.e. either only X or only Y. The other direction must be left unscaled.
//
// Note: Due to internal limitations, this may currently only be used on 2D
// textures - even though the basic principle would work for 1D and 3D textures
// as well.
PL_API bool pl_shader_sample_ortho2(pl_shader sh, const struct pl_sample_src *src,
                                    const struct pl_sample_filter_params *params);

struct pl_distort_params {
    // An arbitrary 2x2 affine transformation to apply to the input image.
    // For simplicity, the input image is explicitly centered and scaled such
    // that the longer dimension is in [-1,1], before applying this.
    pl_transform2x2 transform;

    // If true, the texture is placed inside the center of the canvas without
    // scaling. If false, it is effectively stretched to the canvas size.
    bool unscaled;

    // If true, the transformation is automatically scaled down and shifted to
    // ensure that the resulting image fits inside the output canvas.
    bool constrain;

    // If true, use bicubic interpolation rather than faster bilinear
    // interpolation. Higher quality but slower.
    bool bicubic;

    // Specifies the texture address mode to use when sampling out of bounds.
    enum pl_tex_address_mode address_mode;

    // If set, all out-of-bounds accesses will instead be treated as
    // transparent, according to the given alpha mode. (Which should match the
    // alpha mode of the texture)
    //
    // Note: `address_mode` has no effect when this is specified.
    enum pl_alpha_mode alpha_mode;
};

#define PL_DISTORT_DEFAULTS \
    .transform.mat.m = {{ 1, 0 }, {0, 1}},

#define pl_distort_params(...) (&(struct pl_distort_params) {PL_DISTORT_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_distort_params pl_distort_default_params;

// Distorts the input image using a given set of transformation parameters.
// `out_w` and `out_h` determine the size of the effective canvas inside which
// the distorted result may be rendered. Areas outside of this canvas will
// be implicitly cut off.
PL_API void pl_shader_distort(pl_shader sh, pl_tex tex, int out_w, int out_h,
                              const struct pl_distort_params *params);

enum PL_DEPRECATED { // for `int pass`
    PL_SEP_VERT = 0,
    PL_SEP_HORIZ,
    PL_SEP_PASSES
};

PL_API_END

#endif // LIBPLACEBO_SHADERS_SAMPLING_H_