mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-05 20:28:03 +02:00
color: implement perceptual quantizer transfer function
This implements WESTON_TF_ST2084_PQ. Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
0af48f0415
commit
8762c3bab5
5 changed files with 176 additions and 16 deletions
|
|
@ -26,6 +26,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "color-properties.h"
|
||||
#include "color-operations.h"
|
||||
|
||||
#include "shared/helpers.h"
|
||||
|
|
@ -122,6 +123,63 @@ sample_powlin(float params[3][MAX_PARAMS_PARAM_CURVE], uint32_t ch,
|
|||
}
|
||||
}
|
||||
|
||||
static float
|
||||
perceptual_quantizer(float x)
|
||||
{
|
||||
float aux, c1, c2, c3, m1_inv, m2_inv;
|
||||
|
||||
m1_inv = 1.0 / 0.1593017578125;
|
||||
m2_inv = 1.0 / 78.84375;
|
||||
c1 = 0.8359375;
|
||||
c2 = 18.8515625;
|
||||
c3 = 18.6875;
|
||||
aux = pow(x, m2_inv);
|
||||
|
||||
/* Normalized result. We don't take into consideration the luminance
|
||||
* levels, as we don't receive the input as nits, but normalized in the
|
||||
* [0, 1] range. */
|
||||
return pow(MAX(aux - c1, 0.0) / (c2 - c3 * aux), m1_inv);
|
||||
}
|
||||
|
||||
static float
|
||||
perceptual_quantizer_inverse(float x)
|
||||
{
|
||||
float aux, c1, c2, c3, m1, m2;
|
||||
|
||||
m1 = 0.1593017578125;
|
||||
m2 = 78.84375;
|
||||
c1 = 0.8359375;
|
||||
c2 = 18.8515625;
|
||||
c3 = 18.6875;
|
||||
aux = pow(x, m1);
|
||||
|
||||
/* Normalized result. We don't take into consideration the luminance
|
||||
* levels, as we don't receive the input as nits, but normalized in the
|
||||
* [0, 1] range. */
|
||||
return pow((c1 + c2 * aux) / (1.0 + c3 * aux), m2);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_pq(enum weston_tf_direction tf_direction, uint32_t ch, uint32_t len,
|
||||
float *in, float *out)
|
||||
{
|
||||
unsigned int i;
|
||||
float x;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
/**
|
||||
* PQ and inverse PQ are always clamped, undefined for values
|
||||
* out of [0, 1] range.
|
||||
*/
|
||||
x = ensure_unorm(in[i]);
|
||||
|
||||
if (tf_direction == WESTON_FORWARD_TF)
|
||||
out[i] = perceptual_quantizer(x);
|
||||
else
|
||||
out[i] = perceptual_quantizer_inverse(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a color curve and a channel, sample an input.
|
||||
*
|
||||
|
|
@ -146,13 +204,23 @@ weston_color_curve_sample(struct weston_compositor *compositor,
|
|||
|
||||
switch(curve->type) {
|
||||
case WESTON_COLOR_CURVE_TYPE_ENUM:
|
||||
/* Lower the enum curve to a param curve and we'll handle that below. */
|
||||
ret = weston_color_curve_enum_get_parametric(compositor,
|
||||
&curve->u.enumerated,
|
||||
¶metric);
|
||||
if (!ret)
|
||||
return false;
|
||||
goto param;
|
||||
/**
|
||||
* If the TF of the enum curve is implemented, sample from that.
|
||||
* Otherwise, fallback to a parametric curve and we'll handle
|
||||
* that below.
|
||||
*/
|
||||
switch(curve->u.enumerated.tf->tf) {
|
||||
case WESTON_TF_ST2084_PQ:
|
||||
sample_pq(curve->u.enumerated.tf_direction, ch, len, in, out);
|
||||
return true;
|
||||
default:
|
||||
ret = weston_color_curve_enum_get_parametric(compositor,
|
||||
&curve->u.enumerated,
|
||||
¶metric);
|
||||
if (!ret)
|
||||
return false;
|
||||
goto param;
|
||||
}
|
||||
case WESTON_COLOR_CURVE_TYPE_PARAMETRIC:
|
||||
/* Parametric curve, let's copy it and we'll handle that below. */
|
||||
parametric = curve->u.parametric;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
#define SHADER_COLOR_CURVE_LUT_3x1D 1
|
||||
#define SHADER_COLOR_CURVE_LINPOW 2
|
||||
#define SHADER_COLOR_CURVE_POWLIN 3
|
||||
#define SHADER_COLOR_CURVE_PQ 4
|
||||
#define SHADER_COLOR_CURVE_PQ_INVERSE 5
|
||||
|
||||
/* enum gl_shader_color_mapping */
|
||||
#define SHADER_COLOR_MAPPING_IDENTITY 0
|
||||
|
|
@ -348,6 +350,62 @@ sample_powlin_vec3(float params[MAX_CURVESET_PARAMS], bool must_clamp,
|
|||
sample_powlin(params, must_clamp, color.b, 2));
|
||||
}
|
||||
|
||||
float
|
||||
perceptual_quantizer(float x)
|
||||
{
|
||||
float aux, c1, c2, c3, m1_inv, m2_inv;
|
||||
|
||||
m1_inv = 1.0 / 0.1593017578125;
|
||||
m2_inv = 1.0 / 78.84375;
|
||||
c1 = 0.8359375;
|
||||
c2 = 18.8515625;
|
||||
c3 = 18.6875;
|
||||
aux = pow(x, m2_inv);
|
||||
|
||||
/* Normalized result. We don't take into consideration the luminance
|
||||
* levels, as that's only useful when converting the optical values to
|
||||
* nits, but we return them in the [0, 1] range. */
|
||||
return pow(max(aux - c1, 0.0) / (c2 - c3 * aux), m1_inv);
|
||||
}
|
||||
|
||||
float
|
||||
perceptual_quantizer_inverse(float x)
|
||||
{
|
||||
float aux, c1, c2, c3, m1, m2;
|
||||
|
||||
m1 = 0.1593017578125;
|
||||
m2 = 78.84375;
|
||||
c1 = 0.8359375;
|
||||
c2 = 18.8515625;
|
||||
c3 = 18.6875;
|
||||
aux = pow(x, m1);
|
||||
|
||||
/* Normalized result. We don't take into consideration the luminance
|
||||
* levels, as we don't receive the input as nits, but normalized in the
|
||||
* [0, 1] range. */
|
||||
return pow((c1 + c2 * aux) / (1.0 + c3 * aux), m2);
|
||||
}
|
||||
|
||||
float
|
||||
sample_perceptual_quantizer(compile_const bool inverse, float x)
|
||||
{
|
||||
/* PQ and its inverse are only defined for input values in this range. */
|
||||
x = clamp(x, 0.0, 1.0);
|
||||
|
||||
if (inverse)
|
||||
return perceptual_quantizer_inverse(x);
|
||||
|
||||
return perceptual_quantizer(x);
|
||||
}
|
||||
|
||||
vec3
|
||||
sample_perceptual_quantizer_vec3(compile_const bool inverse, vec3 color)
|
||||
{
|
||||
return vec3(sample_perceptual_quantizer(inverse, color.r),
|
||||
sample_perceptual_quantizer(inverse, color.g),
|
||||
sample_perceptual_quantizer(inverse, color.b));
|
||||
}
|
||||
|
||||
vec3
|
||||
color_pre_curve(vec3 color)
|
||||
{
|
||||
|
|
@ -365,6 +423,12 @@ color_pre_curve(vec3 color)
|
|||
return sample_powlin_vec3(color_pre_curve_params,
|
||||
color_pre_curve_clamped_input,
|
||||
color);
|
||||
} else if (c_color_pre_curve == SHADER_COLOR_CURVE_PQ) {
|
||||
return sample_perceptual_quantizer_vec3(false, /* not inverse */
|
||||
color);
|
||||
} else if (c_color_pre_curve == SHADER_COLOR_CURVE_PQ_INVERSE) {
|
||||
return sample_perceptual_quantizer_vec3(true, /* inverse */
|
||||
color);
|
||||
} else {
|
||||
/* Never reached, bad c_color_pre_curve. */
|
||||
return vec3(1.0, 0.3, 1.0);
|
||||
|
|
@ -412,6 +476,12 @@ color_post_curve(vec3 color)
|
|||
return sample_powlin_vec3(color_post_curve_params,
|
||||
color_post_curve_clamped_input,
|
||||
color);
|
||||
} else if (c_color_post_curve == SHADER_COLOR_CURVE_PQ) {
|
||||
return sample_perceptual_quantizer_vec3(false, /* not inverse */
|
||||
color);
|
||||
} else if (c_color_post_curve == SHADER_COLOR_CURVE_PQ_INVERSE) {
|
||||
return sample_perceptual_quantizer_vec3(true, /* inverse */
|
||||
color);
|
||||
} else {
|
||||
/* Never reached, bad c_color_post_curve. */
|
||||
return vec3(1.0, 0.3, 1.0);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,8 @@ enum gl_shader_color_curve {
|
|||
SHADER_COLOR_CURVE_LUT_3x1D,
|
||||
SHADER_COLOR_CURVE_LINPOW,
|
||||
SHADER_COLOR_CURVE_POWLIN,
|
||||
SHADER_COLOR_CURVE_PQ,
|
||||
SHADER_COLOR_CURVE_PQ_INVERSE,
|
||||
};
|
||||
|
||||
/* Keep the following in sync with fragment.glsl. */
|
||||
|
|
@ -282,15 +284,15 @@ struct gl_shader_requirements
|
|||
bool tint:1;
|
||||
bool wireframe:1;
|
||||
|
||||
unsigned color_pre_curve:2; /* enum gl_shader_color_curve */
|
||||
unsigned color_pre_curve:3; /* enum gl_shader_color_curve */
|
||||
unsigned color_mapping:2; /* enum gl_shader_color_mapping */
|
||||
unsigned color_post_curve:2; /* enum gl_shader_color_curve */
|
||||
unsigned color_post_curve:3; /* enum gl_shader_color_curve */
|
||||
|
||||
/*
|
||||
* The total size of all bitfields plus pad_bits_ must fill up exactly
|
||||
* how many bytes the compiler allocates for them together.
|
||||
*/
|
||||
unsigned pad_bits_:18;
|
||||
unsigned pad_bits_:16;
|
||||
};
|
||||
static_assert(sizeof(struct gl_shader_requirements) ==
|
||||
4 /* total bitfield size in bytes */,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <libweston/libweston.h>
|
||||
#include "color.h"
|
||||
#include "color-properties.h"
|
||||
#include "gl-renderer.h"
|
||||
#include "gl-renderer-internal.h"
|
||||
|
||||
|
|
@ -77,6 +78,8 @@ gl_renderer_color_curve_fini(struct gl_renderer_color_curve *gl_curve)
|
|||
{
|
||||
switch (gl_curve->type) {
|
||||
case SHADER_COLOR_CURVE_IDENTITY:
|
||||
case SHADER_COLOR_CURVE_PQ:
|
||||
case SHADER_COLOR_CURVE_PQ_INVERSE:
|
||||
case SHADER_COLOR_CURVE_LINPOW:
|
||||
case SHADER_COLOR_CURVE_POWLIN:
|
||||
break;
|
||||
|
|
@ -175,12 +178,23 @@ gl_color_curve_enum(struct gl_renderer *gr,
|
|||
struct weston_color_curve_parametric parametric;
|
||||
bool ret;
|
||||
|
||||
/* Lower TF to a parametric curve. */
|
||||
ret = weston_color_curve_enum_get_parametric(gr->compositor,
|
||||
&curve->u.enumerated,
|
||||
¶metric);
|
||||
if (!ret)
|
||||
return false;
|
||||
/**
|
||||
* Handle enum curve (if TF is implemented) or fallback to a parametric
|
||||
* curve.
|
||||
*/
|
||||
switch(curve->u.enumerated.tf->tf) {
|
||||
case WESTON_TF_ST2084_PQ:
|
||||
gl_curve->type = (curve->u.enumerated.tf_direction == WESTON_FORWARD_TF) ?
|
||||
SHADER_COLOR_CURVE_PQ : SHADER_COLOR_CURVE_PQ_INVERSE;
|
||||
return true;
|
||||
default:
|
||||
ret = weston_color_curve_enum_get_parametric(gr->compositor,
|
||||
&curve->u.enumerated,
|
||||
¶metric);
|
||||
if (!ret)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle parametric curve that we got from TF. */
|
||||
|
||||
|
|
@ -387,6 +401,8 @@ gl_shader_config_set_color_transform(struct gl_renderer *gr,
|
|||
sconf->req.color_pre_curve = gl_xform->pre_curve.type;
|
||||
switch (gl_xform->pre_curve.type) {
|
||||
case SHADER_COLOR_CURVE_IDENTITY:
|
||||
case SHADER_COLOR_CURVE_PQ:
|
||||
case SHADER_COLOR_CURVE_PQ_INVERSE:
|
||||
break;
|
||||
case SHADER_COLOR_CURVE_LUT_3x1D:
|
||||
sconf->color_pre_curve.lut_3x1d.tex = gl_xform->pre_curve.u.lut_3x1d.tex;
|
||||
|
|
@ -406,6 +422,8 @@ gl_shader_config_set_color_transform(struct gl_renderer *gr,
|
|||
sconf->req.color_post_curve = gl_xform->post_curve.type;
|
||||
switch (gl_xform->post_curve.type) {
|
||||
case SHADER_COLOR_CURVE_IDENTITY:
|
||||
case SHADER_COLOR_CURVE_PQ:
|
||||
case SHADER_COLOR_CURVE_PQ_INVERSE:
|
||||
break;
|
||||
case SHADER_COLOR_CURVE_LUT_3x1D:
|
||||
sconf->color_post_curve.lut_3x1d.tex = gl_xform->post_curve.u.lut_3x1d.tex;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ gl_shader_color_curve_to_string(enum gl_shader_color_curve kind)
|
|||
CASERET(SHADER_COLOR_CURVE_LUT_3x1D)
|
||||
CASERET(SHADER_COLOR_CURVE_LINPOW)
|
||||
CASERET(SHADER_COLOR_CURVE_POWLIN)
|
||||
CASERET(SHADER_COLOR_CURVE_PQ)
|
||||
CASERET(SHADER_COLOR_CURVE_PQ_INVERSE)
|
||||
#undef CASERET
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue