Add support for some of the yuv-related cicp tuples. Concretely, this adds bt601, bt709 and bt2020, both in their narrow and full-range variants.
488 lines
10 KiB
GLSL
488 lines
10 KiB
GLSL
#define GSK_N_TEXTURES 1
|
|
|
|
#include "common.glsl"
|
|
|
|
#define VARIATION_OPACITY (1u << 0)
|
|
#define VARIATION_STRAIGHT_ALPHA (1u << 1)
|
|
#define VARIATION_REVERSE (1u << 2)
|
|
|
|
#define HAS_VARIATION(var) ((GSK_VARIATION & var) == var)
|
|
|
|
PASS(0) vec2 _pos;
|
|
PASS_FLAT(1) Rect _rect;
|
|
PASS(2) vec2 _tex_coord;
|
|
PASS_FLAT(3) float _opacity;
|
|
PASS_FLAT(4) uint _transfer_function;
|
|
PASS_FLAT(5) mat3 _mat;
|
|
PASS_FLAT(8) mat3 _yuv;
|
|
PASS_FLAT(11) uint _range;
|
|
|
|
#ifdef GSK_VERTEX_SHADER
|
|
|
|
IN(0) vec4 in_rect;
|
|
IN(1) vec4 in_tex_rect;
|
|
IN(2) float in_opacity;
|
|
IN(3) uint in_color_primaries;
|
|
IN(4) uint in_transfer_function;
|
|
IN(5) uint in_matrix_coefficients;
|
|
IN(6) uint in_range;
|
|
|
|
|
|
const mat3 identity = mat3(
|
|
1.0, 0.0, 0.0,
|
|
0.0, 1.0, 0.0,
|
|
0.0, 0.0, 1.0
|
|
);
|
|
|
|
const mat3 srgb_to_xyz = mat3(
|
|
0.4124564, 0.2126729, 0.0193339,
|
|
0.3575761, 0.7151522, 0.1191920,
|
|
0.1804375, 0.0721750, 0.9503041
|
|
);
|
|
|
|
const mat3 xyz_to_srgb = mat3(
|
|
3.2404542, -0.9692660, 0.0556434,
|
|
-1.5371385, 1.8760108, -0.2040259,
|
|
-0.4985314, 0.0415560, 1.0572252
|
|
);
|
|
|
|
const mat3 rec2020_to_xyz = mat3(
|
|
0.6369580, 0.2627002, 0.0000000,
|
|
0.1446169, 0.6779981, 0.0280727,
|
|
0.1688810, 0.0593017, 1.0609851
|
|
);
|
|
|
|
const mat3 xyz_to_rec2020 = mat3(
|
|
1.7166512, -0.6666844, 0.0176399,
|
|
-0.3556708, 1.6164812, -0.0427706,
|
|
-0.2533663, 0.0157685, 0.9421031
|
|
);
|
|
|
|
const mat3 pal_to_xyz = mat3(
|
|
0.4305538, 0.2220043, 0.0201822,
|
|
0.3415498, 0.7066548, 0.1295534,
|
|
0.1783523, 0.0713409, 0.9393222
|
|
);
|
|
|
|
const mat3 xyz_to_pal = mat3(
|
|
3.0633611, -0.9692436, 0.0678610,
|
|
-1.3933902, 1.8759675, -0.2287993,
|
|
-0.4758237, 0.0415551, 1.0690896
|
|
);
|
|
|
|
const mat3 ntsc_to_xyz = mat3(
|
|
0.3935209, 0.2123764, 0.0187391,
|
|
0.3652581, 0.7010599, 0.1119339,
|
|
0.1916769, 0.0865638, 0.9583847
|
|
);
|
|
|
|
const mat3 xyz_to_ntsc = mat3(
|
|
3.5060033, -1.0690476, 0.0563066,
|
|
-1.7397907, 1.9777789, -0.1969757,
|
|
-0.5440583, 0.0351714, 1.0499523
|
|
);
|
|
|
|
const mat3 p3_to_xyz = mat3(
|
|
0.4865709, 0.2289746, 0.0000000,
|
|
0.2656677, 0.6917385, 0.0451134,
|
|
0.1982173, 0.0792869, 1.0439444
|
|
);
|
|
|
|
const mat3 xyz_to_p3 = mat3(
|
|
2.4934969, -0.8294890, 0.0358458,
|
|
-0.9313836, 1.7626641, -0.0761724,
|
|
-0.4027108, 0.0236247, 0.9568845
|
|
);
|
|
|
|
const mat3 rgb_to_bt601 = mat3(
|
|
0.299000, -0.168736, 0.500000,
|
|
0.587000, -0.331264, -0.418688,
|
|
0.114000, 0.500000, -0.081312
|
|
);
|
|
|
|
const mat3 bt601_to_rgb = mat3(
|
|
1.000000, 1.000000, 1.000000,
|
|
0.000000, -0.344136, 1.772000,
|
|
1.402000, -0.714136, 0.000000
|
|
);
|
|
|
|
const mat3 rgb_to_bt709 = mat3(
|
|
0.212600, -0.114572, 0.500000,
|
|
0.715200, -0.385428, -0.454153,
|
|
0.072200, 0.500000, -0.045847
|
|
);
|
|
|
|
const mat3 bt709_to_rgb = mat3(
|
|
1.000000, 1.000000, 1.000000,
|
|
0.000000, -0.187324, 1.855600,
|
|
1.574800, -0.468124, -0.000000
|
|
);
|
|
|
|
const mat3 rgb_to_bt2020 = mat3(
|
|
0.262700, -0.139630, 0.500000,
|
|
0.678000, -0.360370, -0.459786,
|
|
0.059300, 0.500000, -0.040214
|
|
);
|
|
|
|
const mat3 bt2020_to_rgb = mat3(
|
|
1.000000, 1.000000, 1.000000,
|
|
-0.000000, -0.164553, 1.881400,
|
|
1.474600, -0.571353, -0.000000
|
|
);
|
|
|
|
mat3
|
|
cicp_to_xyz (uint cp)
|
|
{
|
|
switch (cp)
|
|
{
|
|
case 1u: return srgb_to_xyz;
|
|
case 5u: return pal_to_xyz;
|
|
case 6u: return ntsc_to_xyz;
|
|
case 9u: return rec2020_to_xyz;
|
|
case 10u: return identity;
|
|
case 12u: return p3_to_xyz;
|
|
default: return identity;
|
|
}
|
|
}
|
|
|
|
mat3
|
|
cicp_from_xyz (uint cp)
|
|
{
|
|
switch (cp)
|
|
{
|
|
case 1u: return xyz_to_srgb;
|
|
case 5u: return xyz_to_pal;
|
|
case 6u: return xyz_to_ntsc;
|
|
case 9u: return xyz_to_rec2020;
|
|
case 10u: return identity;
|
|
case 12u: return xyz_to_p3;
|
|
default: return identity;
|
|
}
|
|
}
|
|
|
|
|
|
mat3
|
|
yuv_to_rgb (uint mc)
|
|
{
|
|
switch (mc)
|
|
{
|
|
case 0u: return identity;
|
|
case 1u: return bt709_to_rgb;
|
|
case 5u:
|
|
case 6u: return bt601_to_rgb;
|
|
case 9u: return bt2020_to_rgb;
|
|
}
|
|
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
|
|
}
|
|
|
|
mat3
|
|
rgb_to_yuv (uint mc)
|
|
{
|
|
switch (mc)
|
|
{
|
|
case 0u: return identity;
|
|
case 1u: return rgb_to_bt709;
|
|
case 5u:
|
|
case 6u: return rgb_to_bt601;
|
|
case 9u: return rgb_to_bt2020;
|
|
}
|
|
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
|
|
}
|
|
|
|
void
|
|
run (out vec2 pos)
|
|
{
|
|
Rect r = rect_from_gsk (in_rect);
|
|
|
|
pos = rect_get_position (r);
|
|
|
|
_pos = pos;
|
|
_rect = r;
|
|
_tex_coord = rect_get_coord (rect_from_gsk (in_tex_rect), pos);
|
|
_opacity = in_opacity;
|
|
_transfer_function = in_transfer_function;
|
|
_range = in_range;
|
|
|
|
if (HAS_VARIATION (VARIATION_REVERSE))
|
|
{
|
|
if (OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB ||
|
|
OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR)
|
|
_mat = cicp_from_xyz (in_color_primaries) * srgb_to_xyz;
|
|
else
|
|
_mat = cicp_from_xyz (in_color_primaries) * rec2020_to_xyz;
|
|
|
|
_yuv = rgb_to_yuv (in_matrix_coefficients);
|
|
}
|
|
else
|
|
{
|
|
if (OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB ||
|
|
OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR)
|
|
_mat = xyz_to_srgb * cicp_to_xyz (in_color_primaries);
|
|
else
|
|
_mat = xyz_to_rec2020 * cicp_to_xyz (in_color_primaries);
|
|
|
|
_yuv = yuv_to_rgb (in_matrix_coefficients);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef GSK_FRAGMENT_SHADER
|
|
|
|
|
|
float
|
|
bt709_eotf (float v)
|
|
{
|
|
if (v < 0.081)
|
|
return v / 4.5;
|
|
else
|
|
return pow ((v + 0.099) / 1.099, 1.0/0.45);
|
|
}
|
|
|
|
float
|
|
bt709_oetf (float v)
|
|
{
|
|
if (v < 0.081)
|
|
return v * 4.5;
|
|
else
|
|
return 1.099 * pow (v, 0.45) - 0.099;
|
|
}
|
|
|
|
float
|
|
gamma22_oetf (float v)
|
|
{
|
|
return pow (v, 1.0 / 2.2);
|
|
}
|
|
|
|
float
|
|
gamma22_eotf (float v)
|
|
{
|
|
return pow (v, 2.2);
|
|
}
|
|
|
|
float
|
|
gamma28_oetf (float v)
|
|
{
|
|
return pow (v, 1.0 / 2.8);
|
|
}
|
|
|
|
float
|
|
gamma28_eotf (float v)
|
|
{
|
|
return pow (v, 2.8);
|
|
}
|
|
|
|
float
|
|
hlg_eotf (float v)
|
|
{
|
|
const float a = 0.17883277;
|
|
const float b = 0.28466892;
|
|
const float c = 0.55991073;
|
|
|
|
if (v <= 0.5)
|
|
return (v * v) / 3.0;
|
|
else
|
|
return exp (((v - c) / a) + b) / 12.0;
|
|
}
|
|
|
|
float
|
|
hlg_oetf (float v)
|
|
{
|
|
const float a = 0.17883277;
|
|
const float b = 0.28466892;
|
|
const float c = 0.55991073;
|
|
|
|
if (v <= 1.0 / 12.0)
|
|
return sqrt (3.0 * v);
|
|
else
|
|
return a * log (12.0 * v - b) + c;
|
|
}
|
|
|
|
vec3
|
|
apply_cicp_eotf (vec3 color,
|
|
uint transfer_function)
|
|
{
|
|
switch (transfer_function)
|
|
{
|
|
case 1u:
|
|
case 6u:
|
|
case 14u:
|
|
case 15u:
|
|
return vec3 (bt709_eotf (color.r),
|
|
bt709_eotf (color.g),
|
|
bt709_eotf (color.b));
|
|
|
|
case 4u:
|
|
return vec3 (gamma22_eotf (color.r),
|
|
gamma22_eotf (color.g),
|
|
gamma22_eotf (color.b));
|
|
|
|
case 5u:
|
|
return vec3 (gamma28_eotf (color.r),
|
|
gamma28_eotf (color.g),
|
|
gamma28_eotf (color.b));
|
|
|
|
case 8u:
|
|
return color;
|
|
|
|
case 13u:
|
|
return vec3 (srgb_eotf (color.r),
|
|
srgb_eotf (color.g),
|
|
srgb_eotf (color.b));
|
|
|
|
case 16u:
|
|
return vec3 (pq_eotf (color.r),
|
|
pq_eotf (color.g),
|
|
pq_eotf (color.b));
|
|
|
|
case 18u:
|
|
return vec3 (hlg_eotf (color.r),
|
|
hlg_eotf (color.g),
|
|
hlg_eotf (color.b));
|
|
|
|
default:
|
|
return vec3 (1.0, 0.2, 0.8);
|
|
}
|
|
}
|
|
|
|
vec3
|
|
apply_cicp_oetf (vec3 color,
|
|
uint transfer_function)
|
|
{
|
|
switch (transfer_function)
|
|
{
|
|
case 1u:
|
|
case 6u:
|
|
case 14u:
|
|
case 15u:
|
|
return vec3 (bt709_oetf (color.r),
|
|
bt709_oetf (color.g),
|
|
bt709_oetf (color.b));
|
|
|
|
case 4u:
|
|
return vec3 (gamma22_oetf (color.r),
|
|
gamma22_oetf (color.g),
|
|
gamma22_oetf (color.b));
|
|
|
|
case 5u:
|
|
return vec3 (gamma28_oetf (color.r),
|
|
gamma28_oetf (color.g),
|
|
gamma28_oetf (color.b));
|
|
|
|
case 8u:
|
|
return color;
|
|
|
|
case 13u:
|
|
return vec3 (srgb_oetf (color.r),
|
|
srgb_oetf (color.g),
|
|
srgb_oetf (color.b));
|
|
|
|
case 16u:
|
|
return vec3 (pq_oetf (color.r),
|
|
pq_oetf (color.g),
|
|
pq_oetf (color.b));
|
|
|
|
case 18u:
|
|
return vec3 (hlg_oetf (color.r),
|
|
hlg_oetf (color.g),
|
|
hlg_oetf (color.b));
|
|
|
|
default:
|
|
return vec3 (1.0, 0.2, 0.8);
|
|
}
|
|
}
|
|
|
|
vec4
|
|
convert_color_from_cicp (vec4 color,
|
|
bool from_premul,
|
|
uint to,
|
|
bool to_premul)
|
|
{
|
|
if (from_premul)
|
|
color = color_unpremultiply (color);
|
|
|
|
if (_range == 0u)
|
|
{
|
|
color.r = (color.r - 16.0/255.0) * 255.0/219.0;
|
|
color.g = (color.g - 16.0/255.0) * 255.0/224.0;
|
|
color.b = (color.b - 16.0/255.0) * 255.0/224.0;
|
|
}
|
|
|
|
color.g -= 0.5;
|
|
color.b -= 0.5;
|
|
|
|
color.rgb = _yuv * color.rgb;
|
|
|
|
color.rgb = apply_cicp_eotf (color.rgb, _transfer_function);
|
|
color.rgb = _mat * color.rgb;
|
|
color.rgb = apply_oetf (color.rgb, to);
|
|
|
|
if (to_premul)
|
|
color = color_premultiply (color);
|
|
|
|
return color;
|
|
}
|
|
|
|
vec4
|
|
convert_color_to_cicp (vec4 color,
|
|
bool to_premul,
|
|
uint from,
|
|
bool from_premul)
|
|
{
|
|
if (from_premul)
|
|
color = color_unpremultiply (color);
|
|
|
|
color.rgb = apply_eotf (color.rgb, from);
|
|
color.rgb = _mat * color.rgb;
|
|
color.rgb = apply_cicp_oetf (color.rgb, _transfer_function);
|
|
|
|
color.rgb = _yuv * color.rgb;
|
|
|
|
color.g += 0.5;
|
|
color.b += 0.5;
|
|
|
|
if (_range == 0u)
|
|
{
|
|
color.r = color.r * 219.0/255.0 + 16.0/255.0;
|
|
color.g = color.g * 224.0/255.0 + 16.0/255.0;
|
|
color.b = color.b * 224.0/255.0 + 16.0/255.0;
|
|
}
|
|
|
|
if (to_premul)
|
|
color = color_premultiply (color);
|
|
|
|
return color;
|
|
}
|
|
|
|
void
|
|
run (out vec4 color,
|
|
out vec2 position)
|
|
{
|
|
vec4 pixel;
|
|
|
|
if (HAS_VARIATION (VARIATION_STRAIGHT_ALPHA))
|
|
pixel = gsk_texture_straight_alpha (GSK_TEXTURE0, _tex_coord);
|
|
else
|
|
pixel = texture (GSK_TEXTURE0, _tex_coord);
|
|
|
|
if (HAS_VARIATION (VARIATION_REVERSE))
|
|
pixel = convert_color_to_cicp (pixel,
|
|
ALT_PREMULTIPLIED,
|
|
OUTPUT_COLOR_SPACE, OUTPUT_PREMULTIPLIED);
|
|
else
|
|
pixel = convert_color_from_cicp (pixel,
|
|
ALT_PREMULTIPLIED,
|
|
OUTPUT_COLOR_SPACE, OUTPUT_PREMULTIPLIED);
|
|
|
|
float alpha = rect_coverage (_rect, _pos);
|
|
if (HAS_VARIATION (VARIATION_OPACITY))
|
|
alpha *= _opacity;
|
|
|
|
color = output_color_alpha (pixel, alpha);
|
|
|
|
position = _pos;
|
|
}
|
|
|
|
#endif
|