diff options
Diffstat (limited to 'src/include/libplacebo/shaders/dithering.h')
-rw-r--r-- | src/include/libplacebo/shaders/dithering.h | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/include/libplacebo/shaders/dithering.h b/src/include/libplacebo/shaders/dithering.h new file mode 100644 index 0000000..9146c81 --- /dev/null +++ b/src/include/libplacebo/shaders/dithering.h @@ -0,0 +1,140 @@ +/* + * 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_DITHERING_H_ +#define LIBPLACEBO_SHADERS_DITHERING_H_ + +// Dithering shaders + +#include <libplacebo/colorspace.h> +#include <libplacebo/dither.h> +#include <libplacebo/shaders.h> + +PL_API_BEGIN + +enum pl_dither_method { + // Dither with blue noise. Very high quality, but requires the use of a + // LUT. Warning: Computing a blue noise texture with a large size can be + // very slow, however this only needs to be performed once. Even so, using + // this with a `lut_size` greater than 6 is generally ill-advised. This is + // the preferred/default dither method. + PL_DITHER_BLUE_NOISE, + + // Dither with an ordered (bayer) dither matrix, using a LUT. Low quality, + // and since this also uses a LUT, there's generally no advantage to picking + // this instead of `PL_DITHER_BLUE_NOISE`. It's mainly there for testing. + PL_DITHER_ORDERED_LUT, + + // The same as `PL_DITHER_ORDERED_LUT`, but uses fixed function math instead + // of a LUT. This is faster, but only supports a fixed dither matrix size + // of 16x16 (equal to a `lut_size` of 4). + PL_DITHER_ORDERED_FIXED, + + // Dither with white noise. This does not require a LUT and is fairly cheap + // to compute. Unlike the other modes it doesn't show any repeating + // patterns either spatially or temporally, but the downside is that this + // is visually fairly jarring due to the presence of low frequencies in the + // noise spectrum. + PL_DITHER_WHITE_NOISE, + + PL_DITHER_METHOD_COUNT, +}; + +struct pl_dither_params { + // The source of the dither noise to use. + enum pl_dither_method method; + + // For the dither methods which require the use of a LUT, this controls + // the size of the LUT (base 2). If left as NULL, this defaults to 6, which + // is equivalent to a 64x64 dither matrix. Must not be larger than 8. + int lut_size; + + // Enables temporal dithering. This reduces the persistence of dithering + // artifacts by perturbing the dithering matrix per frame. + // Warning: This can cause nasty aliasing artifacts on some LCD screens. + bool temporal; + + // Gamma function to use for dither gamma correction. This will only have + // an effect when dithering to low bit depths (<= 4). + enum pl_color_transfer transfer; +}; + +#define PL_DITHER_DEFAULTS \ + .method = PL_DITHER_BLUE_NOISE, \ + .lut_size = 6, \ + /* temporal dithering commonly flickers on LCDs */ \ + .temporal = false, + +#define pl_dither_params(...) (&(struct pl_dither_params) { PL_DITHER_DEFAULTS __VA_ARGS__ }) +PL_API extern const struct pl_dither_params pl_dither_default_params; + +// Dither the colors to a lower depth, given in bits. This can be used on input +// colors of any precision. Basically, this rounds the colors to only linear +// multiples of the stated bit depth. The average intensity of the result +// will not change (i.e., the dither noise is balanced in both directions). +// If `params` is NULL, it defaults to &pl_dither_default_params. +// +// For the dither methods which require the use of a LUT, `dither_state` must +// be set to a valid pointer. To avoid thrashing the resource, users should +// avoid trying to re-use the same LUT for different dither configurations. If +// passed as NULL, libplacebo will automatically fall back to dither algorithms +// that don't require the use of a LUT. +// +// Warning: This dithering algorithm is not gamma-invariant; so using it for +// very low bit depths (below 4 or so) will noticeably increase the brightness +// of the resulting image. When doing low bit depth dithering for aesthetic +// purposes, it's recommended that the user explicitly (de)linearize the colors +// before and after this algorithm. +PL_API void pl_shader_dither(pl_shader sh, int new_depth, + pl_shader_obj *dither_state, + const struct pl_dither_params *params); + +struct pl_error_diffusion_params { + // Both the input and output texture must be provided up-front, with the + // same size. The output texture must be storable, and the input texture + // must be sampleable. + pl_tex input_tex; + pl_tex output_tex; + + // Depth to dither to. Required. + int new_depth; + + // Error diffusion kernel to use. Optional. If unspecified, defaults to + // `&pl_error_diffusion_sierra_lite`. + const struct pl_error_diffusion_kernel *kernel; +}; + +#define pl_error_diffusion_params(...) (&(struct pl_error_diffusion_params) { __VA_ARGS__ }) + +// Computes the shared memory requirements for a given error diffusion kernel. +// This can be used to test up-front whether or not error diffusion would be +// supported or not, before having to initialize textures. +PL_API size_t pl_error_diffusion_shmem_req(const struct pl_error_diffusion_kernel *kernel, + int height); + +// Apply an error diffusion dithering kernel. This is a much more expensive and +// heavy dithering method, and is not generally recommended for realtime usage +// where performance is critical. +// +// Requires compute shader support. Returns false if dithering fail e.g. as a +// result of shader memory limits being exceeded. The resulting shader must be +// dispatched with a work group count of exactly 1. +PL_API bool pl_shader_error_diffusion(pl_shader sh, const struct pl_error_diffusion_params *params); + +PL_API_END + +#endif // LIBPLACEBO_SHADERS_DITHERING_H_ |