diff options
Diffstat (limited to 'src/include/libplacebo/shaders/sampling.h')
-rw-r--r-- | src/include/libplacebo/shaders/sampling.h | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/include/libplacebo/shaders/sampling.h b/src/include/libplacebo/shaders/sampling.h new file mode 100644 index 0000000..5221e44 --- /dev/null +++ b/src/include/libplacebo/shaders/sampling.h @@ -0,0 +1,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_ |