summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/gamut_mapping.h
blob: a92a73bd745605579e6778175ec2d80c83f9b671 (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
/*
 * 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_GAMUT_MAPPING_H_
#define LIBPLACEBO_GAMUT_MAPPING_H_

#include <libplacebo/common.h>
#include <libplacebo/colorspace.h>

PL_API_BEGIN

struct pl_gamut_map_params;
struct pl_gamut_map_function {
    const char *name;        // Identifier
    const char *description; // Friendly / longer name

    // The gamut-mapping function itself. Iterates over all values in `lut`,
    // and adapts them as needed.
    void (*map)(float *lut, const struct pl_gamut_map_params *params);

    // Returns true if `map` supports both stretching and contracting the
    // gamut. In this case, `map` is always executed, even if the output gamut
    // is larger than the input gamut.
    bool bidirectional;

    // Private data. Unused by libplacebo, but may be accessed by `map`.
    void *priv;
};

struct pl_gamut_map_constants {
    // (Relative) chromaticity protection zone for perceptual mapping [0,1]
    float perceptual_deadzone;

    // Strength of the perceptual saturation mapping component [0,1]
    float perceptual_strength;

    // I vs C curve gamma to use for colorimetric clipping [0,10]
    float colorimetric_gamma;

    // Knee point to use for softclipping methods (perceptual, softclip) [0,1]
    float softclip_knee;

    // Desaturation strength (for softclip only) [0,1]
    float softclip_desat;
};

#define PL_GAMUT_MAP_CONSTANTS    \
    .colorimetric_gamma  = 1.80f, \
    .softclip_knee       = 0.70f, \
    .softclip_desat      = 0.35f, \
    .perceptual_deadzone = 0.30f, \
    .perceptual_strength = 0.80f,

struct pl_gamut_map_params {
    // If `function` is NULL, defaults to `pl_gamut_map_clip`.
    const struct pl_gamut_map_function *function;

    // The desired input/output primaries. This affects the subjective color
    // volume in which the desired mapping shall take place.
    struct pl_raw_primaries input_gamut;
    struct pl_raw_primaries output_gamut;

    // Minimum/maximum luminance (PQ) of the target display. Note that the same
    // value applies to both the input and output, since it's assumed that tone
    // mapping has already happened by this stage. This effectively defines the
    // legal gamut boundary in RGB space.
    //
    // This also defines the I channel value range, for `pl_gamut_map_generate`
    float min_luma;
    float max_luma;

    // Common constants, should be initialized to PL_GAMUT_MAP_CONSTANTS if
    // not intending to override them further.
    struct pl_gamut_map_constants constants;

    // -- LUT generation options (for `pl_gamut_map_generate` only)

    // The size of the resulting LUT, per channel.
    //
    // Note: For quality, it's generally best to increase h > I > C
    int lut_size_I;
    int lut_size_C;
    int lut_size_h;

    // The stride (in number of floats) between elements in the resulting LUT.
    int lut_stride;

    // -- Removed parameters
    float chroma_margin PL_DEPRECATED; // non-functional
};

#define pl_gamut_map_params(...) (&(struct pl_gamut_map_params) {   \
    .constants = { PL_GAMUT_MAP_CONSTANTS },                        \
    __VA_ARGS__                                                     \
})

// Note: Only does pointer equality testing on `function`
PL_API bool pl_gamut_map_params_equal(const struct pl_gamut_map_params *a,
                                      const struct pl_gamut_map_params *b);

// Returns true if the given gamut mapping configuration effectively represents
// a no-op configuration. Gamut mapping can be skipped in this case.
PL_API bool pl_gamut_map_params_noop(const struct pl_gamut_map_params *params);

// Generate a gamut-mapping LUT for a given configuration. LUT samples are
// stored as IPTPQc4 values, but the LUT itself is indexed by IChPQc4,spanning
// the effective range [min_luma, max_luma] × [0, 0.5] × [-pi,pi].
//
// This ordering is designed to keep frequently co-occurring values close in
// memory, while permitting simple wrapping of the 'h' component.
PL_API void pl_gamut_map_generate(float *out, const struct pl_gamut_map_params *params);

// Samples a gamut mapping function for a single IPTPQc4 value. The input
// values are updated in-place.
PL_API void pl_gamut_map_sample(float x[3], const struct pl_gamut_map_params *params);

// Performs no gamut-mapping, just hard clips out-of-range colors per-channel.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_clip;

// Performs a perceptually balanced (saturation) gamut mapping, using a soft
// knee function to preserve in-gamut colors, followed by a final softclip
// operation. This works bidirectionally, meaning it can both compress and
// expand the gamut. Behaves similar to a blend of `saturation` and `softclip`.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_perceptual;

// Performs a perceptually balanced gamut mapping using a soft knee function to
// roll-off clipped regions, and a hue shifting function to preserve saturation.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_softclip;

// Performs relative colorimetric clipping, while maintaining an exponential
// relationship between brightness and chromaticity.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_relative;

// Performs simple RGB->RGB saturation mapping. The input R/G/B channels are
// mapped directly onto the output R/G/B channels. Will never clip, but will
// distort all hues and/or result in a faded look.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_saturation;

// Performs absolute colorimetric clipping. Like pl_gamut_map_relative, but
// does not adapt the white point.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_absolute;

// Performs constant-luminance colorimetric clipping, desaturing colors
// towards white until they're in-range.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_desaturate;

// Uniformly darkens the input slightly to prevent clipping on blown-out
// highlights, then clamps colorimetrically to the input gamut boundary,
// biased slightly to preserve chromaticity over luminance.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_darken;

// Performs no gamut mapping, but simply highlights out-of-gamut pixels.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_highlight;

// Linearly/uniformly desaturates the image in order to bring the entire
// image into the target gamut.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_linear;

// A list of built-in gamut mapping functions, terminated by NULL
PL_API extern const struct pl_gamut_map_function * const pl_gamut_map_functions[];
PL_API extern const int pl_num_gamut_map_functions; // excluding trailing NULL

// Find the gamut mapping function with the given name, or NULL on failure.
PL_API const struct pl_gamut_map_function *pl_find_gamut_map_function(const char *name);

PL_API_END

#endif // LIBPLACEBO_GAMUT_MAPPING_H_