diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 7b4b4636a..41773d4f5 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -188,6 +188,8 @@ static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) { abort(); // unsupported case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: abort(); // unsupported + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: + abort(); // unsupported } abort(); // unreachable } diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 498661070..5358b01c1 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -154,6 +154,7 @@ enum wlr_vk_texture_transform { WLR_VK_TEXTURE_TRANSFORM_SRGB = 1, WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2, WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3, + WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4, }; enum wlr_vk_shader_source { @@ -169,6 +170,7 @@ enum wlr_vk_output_transform { WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2, WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4, + WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5, }; struct wlr_vk_pipeline_key { @@ -202,6 +204,7 @@ struct wlr_vk_render_format_setup { VkPipeline output_pipe_pq; VkPipeline output_pipe_lut3d; VkPipeline output_pipe_gamma22; + VkPipeline output_pipe_bt1886; 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 7d5b26857..d906e3425 100644 --- a/include/wlr/render/color.h +++ b/include/wlr/render/color.h @@ -29,6 +29,7 @@ enum wlr_color_transfer_function { WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1, WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2, WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3, + WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4, }; /** diff --git a/render/color.c b/render/color.c index ae9309dd1..da2f938f8 100644 --- a/render/color.c +++ b/render/color.c @@ -202,6 +202,13 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f .reference = 203, }; break; + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: + *lum = (struct wlr_color_luminances){ + .min = 0.01, + .max = 100, + .reference = 100, + }; + break; default: *lum = (struct wlr_color_luminances){ .min = 0.2, diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 4cce62eb5..9e212aacc 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_GAMMA22: pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22; break; + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: + pipeline = render_buffer->two_pass.render_setup->output_pipe_bt1886; + break; } struct wlr_color_luminances srgb_lum, dst_lum; @@ -799,6 +802,9 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22; break; + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: + tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886; + break; } struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline( diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index ba14bc2ba..3f880ca6c 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -176,6 +176,7 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer, vkDestroyPipeline(dev, setup->output_pipe_pq, NULL); vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL); vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL); + vkDestroyPipeline(dev, setup->output_pipe_bt1886, NULL); struct wlr_vk_pipeline *pipeline, *tmp_pipeline; wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) { @@ -2351,6 +2352,11 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( &setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) { goto error; } + if (!init_blend_to_output_pipeline( + renderer, setup->render_pass, renderer->output_pipe_layout, + &setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) { + goto error; + } } else { assert(format->vk_srgb); VkAttachmentDescription attachment = { diff --git a/render/vulkan/shaders/output.frag b/render/vulkan/shaders/output.frag index 9785fd225..b9cfcaaa2 100644 --- a/render/vulkan/shaders/output.frag +++ b/render/vulkan/shaders/output.frag @@ -23,6 +23,7 @@ layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0; #define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2 #define OUTPUT_TRANSFORM_LUT_3D 3 #define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4 +#define OUTPUT_TRANSFORM_INVERSE_BT1886 5 float linear_channel_to_srgb(float x) { return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055); @@ -47,6 +48,14 @@ vec3 linear_color_to_pq(vec3 color) { return pow((vec3(c1) + c2 * pow_n) / (vec3(1) + c3 * pow_n), vec3(m)); } +vec3 linear_color_to_bt1886(vec3 color) { + float lb = pow(0.0001, 1.0 / 2.4); + float lw = pow(1.0, 1.0 / 2.4); + float a = pow(lw - lb, 2.4); + float b = lb / (lw - lb); + return pow(color / a, vec3(1.0 / 2.4)) - vec3(b); +} + void main() { vec4 in_color = subpassLoad(in_color).rgba; @@ -74,6 +83,8 @@ void main() { rgb = linear_color_to_srgb(rgb); } else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) { rgb = pow(rgb, vec3(1. / 2.2)); + } else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_BT1886) { + rgb = linear_color_to_bt1886(rgb); } // Back to pre-multiplied alpha diff --git a/render/vulkan/shaders/texture.frag b/render/vulkan/shaders/texture.frag index bb73681f5..b7b78b19a 100644 --- a/render/vulkan/shaders/texture.frag +++ b/render/vulkan/shaders/texture.frag @@ -19,6 +19,7 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0; #define TEXTURE_TRANSFORM_SRGB 1 #define TEXTURE_TRANSFORM_ST2084_PQ 2 #define TEXTURE_TRANSFORM_GAMMA22 3 +#define TEXTURE_TRANSFORM_BT1886 4 float srgb_channel_to_linear(float x) { return mix(x / 12.92, @@ -45,6 +46,14 @@ vec3 pq_color_to_linear(vec3 color) { return pow(num / denom, vec3(inv_m1)); } +vec3 bt1886_color_to_linear(vec3 color) { + float lb = pow(0.0001, 1.0 / 2.4); + float lw = pow(1.0, 1.0 / 2.4); + float a = pow(lw - lb, 2.4); + float b = lb / (lw - lb); + return a * pow(color + vec3(b), vec3(2.4)); +} + void main() { vec4 in_color = textureLod(tex, uv, 0); @@ -63,6 +72,8 @@ void main() { rgb = pq_color_to_linear(rgb); } else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) { rgb = pow(rgb, vec3(2.2)); + } else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) { + rgb = bt1886_color_to_linear(rgb); } rgb *= data.luminance_multiplier; diff --git a/types/scene/surface.c b/types/scene/surface.c index 593537163..68a445b98 100644 --- a/types/scene/surface.c +++ b/types/scene/surface.c @@ -41,6 +41,7 @@ static bool get_tf_preference(enum wlr_color_transfer_function tf) { return 0; case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: return 1; + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: case WLR_COLOR_TRANSFER_FUNCTION_SRGB: case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR: return -1; diff --git a/types/wlr_color_management_v1.c b/types/wlr_color_management_v1.c index 80c357539..c69a69c81 100644 --- a/types/wlr_color_management_v1.c +++ b/types/wlr_color_management_v1.c @@ -995,6 +995,8 @@ wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_ return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR; case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22; + case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886: + return WLR_COLOR_TRANSFER_FUNCTION_BT1886; default: abort(); } @@ -1011,6 +1013,8 @@ wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR; case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; + case WLR_COLOR_TRANSFER_FUNCTION_BT1886: + return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886; } abort(); }