gpu: Make color conversion extensible

Change the glsl convert_color function to proceed in stages:
- first unpremultiply
- then linearize
- then transform linearly
- then delinearize
- then premultiply
All the steps are only taken if needed.
This commit is contained in:
Matthias Clasen
2024-07-11 14:30:10 -04:00
parent 2d69f35e0e
commit 457fd68168

View File

@@ -24,24 +24,6 @@ color_unpremultiply (vec4 color)
return color.a > 0.0 ? color / vec4 (color.aaa, 1.0) : color;
}
float
srgb_eotf (float v)
{
if (v >= 0.04045)
return pow (((v + 0.055) / (1.0 + 0.055)), 2.4);
else
return v / 12.92;
}
float
srgb_oetf (float v)
{
if (v > 0.0031308)
return 1.055 * pow (v, 1.0 / 2.4) - 0.055;
else
return 12.92 * v;
}
vec4
alt_color_alpha (vec4 color,
float alpha)
@@ -62,82 +44,115 @@ output_color_alpha (vec4 color,
return vec4 (color.rgb, color.a * alpha);
}
vec4
alt_color_from_output (vec4 color)
float
srgb_eotf (float v)
{
if (OUTPUT_COLOR_SPACE == ALT_COLOR_SPACE)
{
if (OUTPUT_PREMULTIPLIED && !ALT_PREMULTIPLIED)
return color_unpremultiply (color);
else if (!OUTPUT_PREMULTIPLIED && ALT_PREMULTIPLIED)
return color_premultiply (color);
else
return color;
}
if (v >= 0.04045)
return pow (((v + 0.055) / (1.0 + 0.055)), 2.4);
else
return v / 12.92;
}
if (OUTPUT_PREMULTIPLIED)
float
srgb_oetf (float v)
{
if (v > 0.0031308)
return 1.055 * pow (v, 1.0 / 2.4) - 0.055;
else
return 12.92 * v;
}
vec3
apply_eotf (vec3 color,
uint cs)
{
switch (cs)
{
case GDK_COLOR_STATE_ID_SRGB:
return vec3 (srgb_eotf (color.r),
srgb_eotf (color.g),
srgb_eotf (color.b));
default:
return color;
}
}
vec3
apply_oetf (vec3 color,
uint cs)
{
switch (cs)
{
case GDK_COLOR_STATE_ID_SRGB:
return vec3 (srgb_oetf (color.r),
srgb_oetf (color.g),
srgb_oetf (color.b));
default:
return color;
}
}
vec3
convert_linear (vec3 color,
uint from,
uint to)
{
return color;
}
uint
linear_color_space (uint cs)
{
return GDK_COLOR_STATE_ID_SRGB_LINEAR;
}
vec4
convert_color (vec4 color,
uint from,
bool from_premul,
uint to,
bool to_premul)
{
if (from_premul && (!to_premul || from != to))
color = color_unpremultiply (color);
if (OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB &&
ALT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR)
if (from != to)
{
color = vec4 (srgb_eotf (color.r),
srgb_eotf (color.g),
srgb_eotf (color.b),
color.a);
}
else if (OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR &&
ALT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB)
{
color = vec4 (srgb_oetf (color.r),
srgb_oetf (color.g),
srgb_oetf (color.b),
color.a);
uint from_linear = linear_color_space (from);
uint to_linear = linear_color_space (to);
if (from_linear != from)
color.rgb = apply_eotf (color.rgb, from);
if (from_linear != to_linear)
color.rgb = convert_linear (color.rgb, from_linear, to_linear);
if (to_linear != to)
color.rgb = apply_oetf (color.rgb, to);
}
if (ALT_PREMULTIPLIED)
if (to_premul && (!from_premul || from != to))
color = color_premultiply (color);
return color;
}
vec4
alt_color_from_output (vec4 color)
{
return convert_color (color,
OUTPUT_COLOR_SPACE, OUTPUT_PREMULTIPLIED,
ALT_COLOR_SPACE, ALT_PREMULTIPLIED);
}
vec4
output_color_from_alt (vec4 color)
{
if (OUTPUT_COLOR_SPACE == ALT_COLOR_SPACE)
{
if (ALT_PREMULTIPLIED && !OUTPUT_PREMULTIPLIED)
return color_unpremultiply (color);
else if (!ALT_PREMULTIPLIED && OUTPUT_PREMULTIPLIED)
return color_premultiply (color);
else
return color;
}
if (ALT_PREMULTIPLIED)
color = color_unpremultiply (color);
if (ALT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB &&
OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR)
{
color = vec4 (srgb_eotf (color.r),
srgb_eotf (color.g),
srgb_eotf (color.b),
color.a);
}
else if (ALT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB_LINEAR &&
OUTPUT_COLOR_SPACE == GDK_COLOR_STATE_ID_SRGB)
{
color = vec4 (srgb_oetf (color.r),
srgb_oetf (color.g),
srgb_oetf (color.b),
color.a);
}
if (OUTPUT_PREMULTIPLIED)
color = color_premultiply (color);
return color;
return convert_color (color,
ALT_COLOR_SPACE, ALT_PREMULTIPLIED,
OUTPUT_COLOR_SPACE, OUTPUT_PREMULTIPLIED);
}
float