From c2d9ae21425ae968f4491a73ea024df1338c52cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Poisot?= Date: Sun, 17 Aug 2025 15:51:26 +0000 Subject: [PATCH] render: introduce Gamma 2.2 color transform --- backend/drm/atomic.c | 2 ++ include/render/vulkan.h | 3 +++ include/wlr/render/color.h | 1 + render/vulkan/pass.c | 9 ++++++++- render/vulkan/renderer.c | 6 ++++++ render/vulkan/shaders/output.frag | 3 +++ render/vulkan/shaders/texture.frag | 3 +++ types/scene/surface.c | 1 + types/wlr_color_management_v1.c | 4 ++++ 9 files changed, 31 insertions(+), 1 deletion(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 33ce6f42d..7b4b4636a 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -186,6 +186,8 @@ static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) { return 2; case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR: abort(); // unsupported + case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: + abort(); // unsupported } abort(); // unreachable } diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 33d158dee..498661070 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -153,6 +153,7 @@ enum wlr_vk_texture_transform { WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0, WLR_VK_TEXTURE_TRANSFORM_SRGB = 1, WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2, + WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3, }; enum wlr_vk_shader_source { @@ -167,6 +168,7 @@ enum wlr_vk_output_transform { WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2, WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3, + WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4, }; struct wlr_vk_pipeline_key { @@ -199,6 +201,7 @@ struct wlr_vk_render_format_setup { VkPipeline output_pipe_srgb; VkPipeline output_pipe_pq; VkPipeline output_pipe_lut3d; + VkPipeline output_pipe_gamma22; struct wlr_vk_renderer *renderer; struct wl_list pipelines; // struct wlr_vk_pipeline.link diff --git a/include/wlr/render/color.h b/include/wlr/render/color.h index e2397b75a..7d5b26857 100644 --- a/include/wlr/render/color.h +++ b/include/wlr/render/color.h @@ -28,6 +28,7 @@ enum wlr_color_transfer_function { WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0, WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1, WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2, + WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3, }; /** diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 4cbb3c26c..5555f1197 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -246,6 +246,9 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: pipeline = render_buffer->two_pass.render_setup->output_pipe_pq; break; + case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: + pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22; + break; } struct wlr_color_luminances srgb_lum, dst_lum; @@ -796,6 +799,9 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ; break; + case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: + tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22; + break; } struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline( @@ -840,7 +846,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, } float luminance_multiplier = 1; - if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB) { + if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB + && tf != WLR_COLOR_TRANSFER_FUNCTION_GAMMA22) { struct wlr_color_luminances src_lum, srgb_lum; wlr_color_transfer_function_get_default_luminance(tf, &src_lum); wlr_color_transfer_function_get_default_luminance( diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index a1a1bf6da..ba14bc2ba 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -175,6 +175,7 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer, vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL); vkDestroyPipeline(dev, setup->output_pipe_pq, NULL); vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL); + vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL); struct wlr_vk_pipeline *pipeline, *tmp_pipeline; wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) { @@ -2345,6 +2346,11 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( &setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) { goto error; } + if (!init_blend_to_output_pipeline( + renderer, setup->render_pass, renderer->output_pipe_layout, + &setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) { + goto error; + } } else { assert(format->vk_srgb); VkAttachmentDescription attachment = { diff --git a/render/vulkan/shaders/output.frag b/render/vulkan/shaders/output.frag index 3d5ac4089..9785fd225 100644 --- a/render/vulkan/shaders/output.frag +++ b/render/vulkan/shaders/output.frag @@ -22,6 +22,7 @@ layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0; #define OUTPUT_TRANSFORM_INVERSE_SRGB 1 #define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2 #define OUTPUT_TRANSFORM_LUT_3D 3 +#define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4 float linear_channel_to_srgb(float x) { return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055); @@ -71,6 +72,8 @@ void main() { } else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) { // Produce sRGB encoded values rgb = linear_color_to_srgb(rgb); + } else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) { + rgb = pow(rgb, vec3(1. / 2.2)); } // Back to pre-multiplied alpha diff --git a/render/vulkan/shaders/texture.frag b/render/vulkan/shaders/texture.frag index 2a7e2c517..bb73681f5 100644 --- a/render/vulkan/shaders/texture.frag +++ b/render/vulkan/shaders/texture.frag @@ -18,6 +18,7 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0; #define TEXTURE_TRANSFORM_IDENTITY 0 #define TEXTURE_TRANSFORM_SRGB 1 #define TEXTURE_TRANSFORM_ST2084_PQ 2 +#define TEXTURE_TRANSFORM_GAMMA22 3 float srgb_channel_to_linear(float x) { return mix(x / 12.92, @@ -60,6 +61,8 @@ void main() { rgb = srgb_color_to_linear(rgb); } else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) { rgb = pq_color_to_linear(rgb); + } else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) { + rgb = pow(rgb, vec3(2.2)); } rgb *= data.luminance_multiplier; diff --git a/types/scene/surface.c b/types/scene/surface.c index c798abfb3..aebc00ea2 100644 --- a/types/scene/surface.c +++ b/types/scene/surface.c @@ -42,6 +42,7 @@ static bool get_tf_preference(enum wlr_color_transfer_function tf) { case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: return 1; case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR: + case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: return -1; } abort(); // unreachable diff --git a/types/wlr_color_management_v1.c b/types/wlr_color_management_v1.c index 4524015fd..54c0a44af 100644 --- a/types/wlr_color_management_v1.c +++ b/types/wlr_color_management_v1.c @@ -993,6 +993,8 @@ wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_ return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ; case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR: return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR; + case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: + return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22; default: abort(); } @@ -1007,6 +1009,8 @@ wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ; case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR; + case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: + return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; } abort(); }