/*
* 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 .
*/
#ifndef LIBPLACEBO_SHADERS_DITHERING_H_
#define LIBPLACEBO_SHADERS_DITHERING_H_
// Dithering shaders
#include
#include
#include
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_