From 648c780e91744bdea4cc1c5aa6ba9b3d3a2cb90b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 13 Jul 2024 14:08:53 -0400 Subject: [PATCH 1/6] gpu: Respect colorstate for offscreens We want to render in at least the minimum required depth of the used colorstate. --- gsk/gpu/gskgpunodeprocessor.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 42227a00c0..12668849e4 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -598,7 +598,8 @@ gsk_gpu_node_processor_create_offscreen (GskGpuFrame *frame, image = gsk_gpu_device_create_offscreen_image (gsk_gpu_frame_get_device (frame), FALSE, - gsk_render_node_get_preferred_depth (node), + gdk_memory_depth_merge (gdk_color_state_get_depth (ccs), + gsk_render_node_get_preferred_depth (node)), area.width, area.height); if (image == NULL) return NULL; @@ -1065,7 +1066,8 @@ gsk_gpu_node_processor_add_rounded_clip_node_with_mask (GskGpuNodeProcessor *sel mask_image = gsk_gpu_node_processor_init_draw (&other, self->frame, self->ccs, - gsk_render_node_get_preferred_depth (node), + gdk_memory_depth_merge (gdk_color_state_get_depth (self->ccs), + gsk_render_node_get_preferred_depth (node)), &self->scale, &clip_bounds); gsk_gpu_node_processor_sync_globals (&other, 0); @@ -2277,7 +2279,8 @@ gsk_gpu_node_processor_add_gradient_node (GskGpuNodeProcessor *self, image = gsk_gpu_node_processor_init_draw (&other, self->frame, self->ccs, - gsk_render_node_get_preferred_depth (node), + gdk_memory_depth_merge (gdk_color_state_get_depth (self->ccs), + gsk_render_node_get_preferred_depth (node)), &self->scale, &bounds); From 2d69f35e0e697a37fdf564e51513332602534117 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 13 Jul 2024 07:41:59 -0400 Subject: [PATCH 2/6] colorstate: More details in the docs Add links to srgb definitions and references. --- gdk/gdkcolorstate.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gdk/gdkcolorstate.c b/gdk/gdkcolorstate.c index f83963d30d..d6fa9cf9d9 100644 --- a/gdk/gdkcolorstate.c +++ b/gdk/gdkcolorstate.c @@ -82,6 +82,14 @@ void * * Returns the color state object representing the sRGB color space. * + * This color state uses the primaries defined by BT.709-6 and the transfer function + * defined by IEC 61966-2-1. + * + * It is equivalent to H.273 ColourPrimaries 1 with TransferCharacteristics 13 and MatrixCoefficients 0. + * + * See e.g. [the CSS Color Module](https://www.w3.org/TR/css-color-4/#predefined-sRGB) + * for details about this colorstate. + * * Returns: the color state object for sRGB * * Since: 4.16 @@ -97,6 +105,13 @@ gdk_color_state_get_srgb (void) * * Returns the color state object representing the linearized sRGB color space. * + * This color state uses the primaries defined by BT.709-6 and a linear transfer function. + * + * It is equivalent to H.273 ColourPrimaries 1 with TransferCharacteristics 8 and MatrixCoefficients 0. + * + * See e.g. [the CSS Color Module](https://www.w3.org/TR/css-color-4/#predefined-sRGB-linear) + * for details about this colorstate. + * * Returns: the color state object for linearized sRGB * * Since: 4.16 From 457fd6816845867a85e537e4f05e25babc4af95b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Jul 2024 14:30:10 -0400 Subject: [PATCH 3/6] 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. --- gsk/gpu/shaders/color.glsl | 173 ++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 79 deletions(-) diff --git a/gsk/gpu/shaders/color.glsl b/gsk/gpu/shaders/color.glsl index 91538b2419..577e970978 100644 --- a/gsk/gpu/shaders/color.glsl +++ b/gsk/gpu/shaders/color.glsl @@ -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 From 54e5cc296ff19f9ab1ca1ae92d078f3d14ce30c1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Jul 2024 19:43:38 -0400 Subject: [PATCH 4/6] colorstate: Add rec2100-pq and rec2100-linear These are wide-gamut, HDR colorstates that we will need for HDR support. --- gdk/gdkcolorstate.c | 189 +++++++++++++++++++++++++++++++++++-- gdk/gdkcolorstate.h | 6 ++ gdk/gdkcolorstateprivate.h | 8 +- gsk/gpu/shaders/color.glsl | 83 ++++++++++++++-- gsk/gpu/shaders/enums.glsl | 2 + 5 files changed, 271 insertions(+), 17 deletions(-) diff --git a/gdk/gdkcolorstate.c b/gdk/gdkcolorstate.c index d6fa9cf9d9..6b669921de 100644 --- a/gdk/gdkcolorstate.c +++ b/gdk/gdkcolorstate.c @@ -122,6 +122,52 @@ gdk_color_state_get_srgb_linear (void) return GDK_COLOR_STATE_SRGB_LINEAR; } +/** + * gdk_color_state_get_rec2100_pq: + * + * Returns the color state object representing the rec2100-pq color space. + * + * This color state uses the primaries defined by BT.2020-2 and BT.2100-0 and the transfer + * function defined by SMPTE ST 2084 and BT.2100-2. + * + * It is equivalent to H.273 ColourPrimaries code point 9 with TransferCharacteristics 16. + * + * See e.g. [the CSS HDR Module](https://drafts.csswg.org/css-color-hdr/#valdef-color-rec2100-pq) + * for details about this colorstate. + * + * Returns: the color state object for rec2100-pq + * + * Since: 4.16 + */ +GdkColorState * +gdk_color_state_get_rec2100_pq (void) +{ + return GDK_COLOR_STATE_REC2100_PQ; +} + +/** + * gdk_color_state_get_rec2100_linear: + * + * Returns the color state object representing the linear rec2100 color space. + * + * This color state uses the primaries defined by BT.2020-2 and BT.2100-0 and a linear + * transfer function. + * + * It is equivalent to H.273 ColourPrimaries code point 9 with TransferCharacteristics 8. + * + * See e.g. [the CSS HDR Module](https://drafts.csswg.org/css-color-hdr/#valdef-color-rec2100-linear) + * for details about this colorstate. + * + * Returns: the color state object for linearized rec2100 + * + * Since: 4.16 + */ +GdkColorState * +gdk_color_state_get_rec2100_linear (void) +{ + return GDK_COLOR_STATE_REC2100_LINEAR; +} + /** * gdk_color_state_equal: * @self: a `GdkColorState` @@ -186,17 +232,30 @@ gdk_default_color_state_get_convert_to (GdkColorState *color_state, /* }}} */ /* {{{ Conversion functions */ -#define COORDINATE_TRANSFORM(name, tf) \ +#define TRANSFORM(name, eotf, matrix, oetf) \ static void \ -name(GdkColorState *self, \ - float (*values)[4], \ - gsize n_values) \ +name (GdkColorState *self, \ + float (*values)[4], \ + gsize n_values) \ { \ for (gsize i = 0; i < n_values; i++) \ { \ - values[i][0] = tf (values[i][0]); \ - values[i][1] = tf (values[i][1]); \ - values[i][2] = tf (values[i][2]); \ + values[i][0] = eotf (values[i][0]); \ + values[i][1] = eotf (values[i][1]); \ + values[i][2] = eotf (values[i][2]); \ + if ((float **)matrix != IDENTITY) \ + { \ + float res[3]; \ + res[0] = matrix[0][0] * values[i][0] + matrix[0][1] * values[i][1] + matrix[0][2] * values[i][2]; \ + res[1] = matrix[1][0] * values[i][0] + matrix[1][1] * values[i][1] + matrix[1][2] * values[i][2]; \ + res[2] = matrix[2][0] * values[i][0] + matrix[2][1] * values[i][1] + matrix[2][2] * values[i][2]; \ + values[i][0] = res[0]; \ + values[i][1] = res[1]; \ + values[i][2] = res[2]; \ + } \ + values[i][0] = oetf (values[i][0]); \ + values[i][1] = oetf (values[i][1]); \ + values[i][2] = oetf (values[i][2]); \ } \ } @@ -218,8 +277,86 @@ srgb_eotf (float v) return v / 12.92f; } -COORDINATE_TRANSFORM(gdk_default_srgb_to_srgb_linear, srgb_eotf) -COORDINATE_TRANSFORM(gdk_default_srgb_linear_to_srgb, srgb_oetf) +static inline float +pq_eotf (float v) +{ + float ninv = (1 << 14) / 2610.0; + float minv = (1 << 5) / 2523.0; + float c1 = 3424.0 / (1 << 12); + float c2 = 2413.0 / (1 << 7); + float c3 = 2392.0 / (1 << 7); + + float x = powf (MAX ((powf (v, minv) - c1), 0) / (c2 - (c3 * (powf (v, minv)))), ninv); + + return x * 10000 / 203.0; +} + +static inline float +pq_oetf (float v) +{ + float x = v * 203.0 / 10000.0; + float n = 2610.0 / (1 << 14); + float m = 2523.0 / (1 << 5); + float c1 = 3424.0 / (1 << 12); + float c2 = 2413.0 / (1 << 7); + float c3 = 2392.0 / (1 << 7); + + return powf (((c1 + (c2 * powf (x, n))) / (1 + (c3 * powf (x, n)))), m); +} + +/* These matrices are derived by combining the standard abc_to_xyz onces: + * + * rec2020_to_srgb = srgb_to_xyz⁻¹ * rec2020_to_xyz + * srgb_to_rec2020 = rec2020_to_xyz⁻¹ * srgb_to_xyz + * + * These values were used here: + * + * static const float srgb_to_xyz[3][3] = { + * { 0.4125288, 0.3581642, 0.1774037 }, + * { 0.2127102, 0.7163284, 0.0709615 }, + * { 0.0193373, 0.1193881, 0.9343260 }, + * } + * + * static const float rec2020_to_xyz[3][3] = { + * { 0.6369615, 0.1448079, 0.1663273 }, + * { 0.2627016, 0.6788934, 0.0584050 }, + * { 0.0000000, 0.0281098, 1.0449416 }, + * }; + * + * See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * for how to derive the abc_to_xyz matrices from chromaticity coordinates. + */ + +static const float rec2020_to_srgb[3][3] = { + { 1.659944, -0.588220, -0.071724 }, + { -0.124350, 1.132559, -0.008210 }, + { -0.018466, -0.102459, 1.120924 }, +}; + +static const float srgb_to_rec2020[3][3] = { + { 0.627610, 0.329815, 0.042574 }, + { 0.069029, 0.919817, 0.011154 }, + { 0.016649, 0.089510, 0.893842 }, +}; + +#define IDENTITY ((float**)0) +#define NONE(x) x + +TRANSFORM(gdk_default_srgb_to_srgb_linear, srgb_eotf, IDENTITY, NONE); +TRANSFORM(gdk_default_srgb_linear_to_srgb, NONE, IDENTITY, srgb_oetf) +TRANSFORM(gdk_default_rec2100_pq_to_rec2100_linear, pq_eotf, IDENTITY, NONE) +TRANSFORM(gdk_default_rec2100_linear_to_rec2100_pq, NONE, IDENTITY, pq_oetf) +TRANSFORM(gdk_default_srgb_linear_to_rec2100_linear, NONE, srgb_to_rec2020, NONE) +TRANSFORM(gdk_default_rec2100_linear_to_srgb_linear, NONE, rec2020_to_srgb, NONE) +TRANSFORM(gdk_default_srgb_to_rec2100_linear, srgb_eotf, srgb_to_rec2020, NONE) +TRANSFORM(gdk_default_rec2100_pq_to_srgb_linear, pq_eotf, rec2020_to_srgb, NONE) +TRANSFORM(gdk_default_srgb_linear_to_rec2100_pq, NONE, srgb_to_rec2020, pq_oetf) +TRANSFORM(gdk_default_rec2100_linear_to_srgb, NONE, rec2020_to_srgb, srgb_oetf) +TRANSFORM(gdk_default_srgb_to_rec2100_pq, srgb_eotf, srgb_to_rec2020, pq_oetf) +TRANSFORM(gdk_default_rec2100_pq_to_srgb, pq_eotf, rec2020_to_srgb, srgb_oetf) + +#undef IDENTITY +#undef NONE /* }}} */ @@ -244,6 +381,8 @@ GdkDefaultColorState gdk_default_color_states[] = { .no_srgb = GDK_COLOR_STATE_SRGB_LINEAR, .convert_to = { [GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_srgb_to_srgb_linear, + [GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_to_rec2100_pq, + [GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_to_rec2100_linear, }, }, [GDK_COLOR_STATE_ID_SRGB_LINEAR] = { @@ -257,6 +396,38 @@ GdkDefaultColorState gdk_default_color_states[] = { .no_srgb = NULL, .convert_to = { [GDK_COLOR_STATE_ID_SRGB] = gdk_default_srgb_linear_to_srgb, + [GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_linear_to_rec2100_pq, + [GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_linear_to_rec2100_linear, + }, + }, + [GDK_COLOR_STATE_ID_REC2100_PQ] = { + .parent = { + .klass = &GDK_DEFAULT_COLOR_STATE_CLASS, + .ref_count = 0, + .depth = GDK_MEMORY_FLOAT16, + .rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR, + }, + .name = "rec2100-pq", + .no_srgb = NULL, + .convert_to = { + [GDK_COLOR_STATE_ID_SRGB] = gdk_default_rec2100_pq_to_srgb, + [GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_pq_to_srgb_linear, + [GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_rec2100_pq_to_rec2100_linear, + }, + }, + [GDK_COLOR_STATE_ID_REC2100_LINEAR] = { + .parent = { + .klass = &GDK_DEFAULT_COLOR_STATE_CLASS, + .ref_count = 0, + .depth = GDK_MEMORY_FLOAT16, + .rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR, + }, + .name = "rec2100-linear", + .no_srgb = NULL, + .convert_to = { + [GDK_COLOR_STATE_ID_SRGB] = gdk_default_rec2100_linear_to_srgb, + [GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_linear_to_srgb_linear, + [GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_rec2100_linear_to_rec2100_pq, }, }, }; diff --git a/gdk/gdkcolorstate.h b/gdk/gdkcolorstate.h index cfd51210ea..d76b8f574d 100644 --- a/gdk/gdkcolorstate.h +++ b/gdk/gdkcolorstate.h @@ -43,6 +43,12 @@ GdkColorState * gdk_color_state_get_srgb (void); GDK_AVAILABLE_IN_4_16 GdkColorState * gdk_color_state_get_srgb_linear (void); +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_color_state_get_rec2100_pq (void); + +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_color_state_get_rec2100_linear (void); + GDK_AVAILABLE_IN_4_16 gboolean gdk_color_state_equal (GdkColorState *self, GdkColorState *other); diff --git a/gdk/gdkcolorstateprivate.h b/gdk/gdkcolorstateprivate.h index 7afc55efbe..054cb0d665 100644 --- a/gdk/gdkcolorstateprivate.h +++ b/gdk/gdkcolorstateprivate.h @@ -10,6 +10,8 @@ typedef enum { GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_SRGB_LINEAR, + GDK_COLOR_STATE_ID_REC2100_PQ, + GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_N_IDS } GdkColorStateId; @@ -53,8 +55,10 @@ struct _GdkDefaultColorState extern GdkDefaultColorState gdk_default_color_states[GDK_COLOR_STATE_N_IDS]; -#define GDK_COLOR_STATE_SRGB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB]) -#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR]) +#define GDK_COLOR_STATE_SRGB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB]) +#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR]) +#define GDK_COLOR_STATE_REC2100_PQ ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_PQ]) +#define GDK_COLOR_STATE_REC2100_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_LINEAR]) #define GDK_IS_DEFAULT_COLOR_STATE(c) ((GdkDefaultColorState *) (c) >= &gdk_default_color_states[0] && \ (GdkDefaultColorState *) (c) < &gdk_default_color_states[GDK_COLOR_STATE_N_IDS]) diff --git a/gsk/gpu/shaders/color.glsl b/gsk/gpu/shaders/color.glsl index 577e970978..0d2991395c 100644 --- a/gsk/gpu/shaders/color.glsl +++ b/gsk/gpu/shaders/color.glsl @@ -62,6 +62,34 @@ srgb_oetf (float v) return 12.92 * v; } +float +pq_eotf (float v) +{ + const float ninv = 16384.0 / 2610.0; + const float minv = 32.0 / 2523.0; + const float c1 = 3424.0 / 4096.0; + const float c2 = 2413.0 / 128.0; + const float c3 = 2392.0 / 128.0; + + float x = pow (max ((pow (v, minv) - c1), 0.0) / (c2 - (c3 * (pow (v, minv)))), ninv); + + return x * 10000.0 / 203.0; +} + +float +pq_oetf (float v) +{ + const float n = 2610.0 / 16384.0; + const float m = 2523.0 / 32.0; + const float c1 = 3424.0 / 4096.0; + const float c2 = 2413.0 / 128.0; + const float c3 = 2392.0 / 128.0; + + float x = v * 203.0 / 10000.0; + + return pow (((c1 + (c2 * pow (x, n))) / (1.0 + (c3 * pow (x, n)))), m); +} + vec3 apply_eotf (vec3 color, uint cs) @@ -73,8 +101,17 @@ apply_eotf (vec3 color, srgb_eotf (color.g), srgb_eotf (color.b)); - default: - return color; + case GDK_COLOR_STATE_ID_REC2100_PQ: + return vec3 (pq_eotf (color.r), + pq_eotf (color.g), + pq_eotf (color.b)); + + case GDK_COLOR_STATE_ID_SRGB_LINEAR: + case GDK_COLOR_STATE_ID_REC2100_LINEAR: + return color; + + default: + return vec3(1.0, 0.0, 0.8); } } @@ -89,23 +126,57 @@ apply_oetf (vec3 color, srgb_oetf (color.g), srgb_oetf (color.b)); - default: - return color; + case GDK_COLOR_STATE_ID_REC2100_PQ: + return vec3 (pq_oetf (color.r), + pq_oetf (color.g), + pq_oetf (color.b)); + + case GDK_COLOR_STATE_ID_SRGB_LINEAR: + case GDK_COLOR_STATE_ID_REC2100_LINEAR: + return color; + + default: + return vec3(0.0, 1.0, 0.8); } } +/* Note that these matrices are transposed from the C version */ +const mat3 srgb_from_rec2020 = mat3( + 1.659944, -0.124350, -0.018466, + -0.588220, 1.132559, -0.102459, + -0.071724, -0.008210, 1.120924 +); + +const mat3 rec2020_from_srgb = mat3( + 0.627610, 0.069029, 0.016649, + 0.329815, 0.919817, 0.089510, + 0.042574, 0.011154, 0.893842 +); + vec3 convert_linear (vec3 color, uint from, uint to) { - return color; + if (to == GDK_COLOR_STATE_ID_REC2100_LINEAR && from == GDK_COLOR_STATE_ID_SRGB_LINEAR) + return rec2020_from_srgb * color; + else if (to == GDK_COLOR_STATE_ID_SRGB_LINEAR && from == GDK_COLOR_STATE_ID_REC2100_LINEAR) + return srgb_from_rec2020 * color; + else + return vec3(0.8, 1.0, 0.0); } uint linear_color_space (uint cs) { - return GDK_COLOR_STATE_ID_SRGB_LINEAR; + switch (cs) + { + case GDK_COLOR_STATE_ID_SRGB: return GDK_COLOR_STATE_ID_SRGB_LINEAR; + case GDK_COLOR_STATE_ID_SRGB_LINEAR: return GDK_COLOR_STATE_ID_SRGB_LINEAR; + case GDK_COLOR_STATE_ID_REC2100_PQ: return GDK_COLOR_STATE_ID_REC2100_LINEAR; + case GDK_COLOR_STATE_ID_REC2100_LINEAR: return GDK_COLOR_STATE_ID_REC2100_LINEAR; + default: return 0u; + }; } vec4 diff --git a/gsk/gpu/shaders/enums.glsl b/gsk/gpu/shaders/enums.glsl index 2823f4c930..e78db57f5d 100644 --- a/gsk/gpu/shaders/enums.glsl +++ b/gsk/gpu/shaders/enums.glsl @@ -54,6 +54,8 @@ #define GDK_COLOR_STATE_ID_SRGB 0u #define GDK_COLOR_STATE_ID_SRGB_LINEAR 1u +#define GDK_COLOR_STATE_ID_REC2100_PQ 2u +#define GDK_COLOR_STATE_ID_REC2100_LINEAR 3u #define TOP 0u #define RIGHT 1u From a2389b316951479fa990a786bd3c4e161d2a8627 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 13 Jul 2024 08:54:47 -0400 Subject: [PATCH 5/6] Cosmetics Shift debug flags around so we can put hdr next to linear. --- gdk/gdkdebugprivate.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/gdk/gdkdebugprivate.h b/gdk/gdkdebugprivate.h index dbbc22cdf4..d9017f2c0e 100644 --- a/gdk/gdkdebugprivate.h +++ b/gdk/gdkdebugprivate.h @@ -41,19 +41,19 @@ typedef enum { /* flags below are influencing behavior */ GDK_DEBUG_LINEAR = 1 << 13, - GDK_DEBUG_PORTALS = 1 << 14, - GDK_DEBUG_NO_PORTALS = 1 << 15, - GDK_DEBUG_GL_DISABLE = 1 << 16, - GDK_DEBUG_GL_NO_FRACTIONAL= 1 << 17, - GDK_DEBUG_FORCE_OFFLOAD = 1 << 18, - GDK_DEBUG_GL_DISABLE_GL = 1 << 19, - GDK_DEBUG_GL_DISABLE_GLES = 1 << 20, - GDK_DEBUG_GL_PREFER_GL = 1 << 21, - GDK_DEBUG_GL_DEBUG = 1 << 22, - GDK_DEBUG_GL_EGL = 1 << 23, - GDK_DEBUG_GL_GLX = 1 << 24, - GDK_DEBUG_GL_WGL = 1 << 25, - GDK_DEBUG_VULKAN_DISABLE = 1 << 26, + GDK_DEBUG_PORTALS = 1 << 15, + GDK_DEBUG_NO_PORTALS = 1 << 16, + GDK_DEBUG_GL_DISABLE = 1 << 17, + GDK_DEBUG_GL_NO_FRACTIONAL= 1 << 18, + GDK_DEBUG_FORCE_OFFLOAD = 1 << 19, + GDK_DEBUG_GL_DISABLE_GL = 1 << 20, + GDK_DEBUG_GL_DISABLE_GLES = 1 << 21, + GDK_DEBUG_GL_PREFER_GL = 1 << 22, + GDK_DEBUG_GL_DEBUG = 1 << 23, + GDK_DEBUG_GL_EGL = 1 << 24, + GDK_DEBUG_GL_GLX = 1 << 25, + GDK_DEBUG_GL_WGL = 1 << 26, + GDK_DEBUG_VULKAN_DISABLE = 1 << 27, GDK_DEBUG_DEFAULT_SETTINGS= 1 << 28, GDK_DEBUG_HIGH_DEPTH = 1 << 29, GDK_DEBUG_NO_VSYNC = 1 << 30, From 7aeab7a63fd9c613c2eb054c9a2d7b326571c224 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 13 Jul 2024 08:55:22 -0400 Subject: [PATCH 6/6] Add a debug flag for hdr rendering Set GDK_DEBUG=hdr to force the use of rec2100 as compositing colorstate. --- gdk/gdk.c | 1 + gdk/gdkcolorstateprivate.h | 3 +++ gdk/gdkdebugprivate.h | 1 + 3 files changed, 5 insertions(+) diff --git a/gdk/gdk.c b/gdk/gdk.c index c4073e27ec..a818ed95b9 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -121,6 +121,7 @@ static const GdkDebugKey gdk_debug_keys[] = { { "offload", GDK_DEBUG_OFFLOAD, "Information about subsurfaces and graphics offload" }, { "linear", GDK_DEBUG_LINEAR, "Enable linear rendering" }, + { "hdr", GDK_DEBUG_HDR, "Force HDR rendering" }, { "portals", GDK_DEBUG_PORTALS, "Force use of portals" }, { "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals" }, { "force-offload", GDK_DEBUG_FORCE_OFFLOAD, "Force graphics offload for all textures" }, diff --git a/gdk/gdkcolorstateprivate.h b/gdk/gdkcolorstateprivate.h index 054cb0d665..d5195b9a9a 100644 --- a/gdk/gdkcolorstateprivate.h +++ b/gdk/gdkcolorstateprivate.h @@ -70,6 +70,9 @@ GdkColorState * gdk_color_state_get_no_srgb_tf (GdkColorState static inline GdkColorState * gdk_color_state_get_rendering_color_state (GdkColorState *self) { + if (GDK_DEBUG_CHECK (HDR)) + self = GDK_COLOR_STATE_REC2100_PQ; + if (!GDK_DEBUG_CHECK (LINEAR)) return self; diff --git a/gdk/gdkdebugprivate.h b/gdk/gdkdebugprivate.h index d9017f2c0e..348bf11251 100644 --- a/gdk/gdkdebugprivate.h +++ b/gdk/gdkdebugprivate.h @@ -41,6 +41,7 @@ typedef enum { /* flags below are influencing behavior */ GDK_DEBUG_LINEAR = 1 << 13, + GDK_DEBUG_HDR = 1 << 14, GDK_DEBUG_PORTALS = 1 << 15, GDK_DEBUG_NO_PORTALS = 1 << 16, GDK_DEBUG_GL_DISABLE = 1 << 17,