render: introduce bt.1886 transfer function

This commit is contained in:
llyyr 2025-10-04 14:48:42 +05:30
parent d8fb7adcf0
commit 6e1c8748ff
10 changed files with 52 additions and 0 deletions

View file

@ -188,6 +188,8 @@ static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
abort(); // unsupported abort(); // unsupported
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
abort(); // unsupported abort(); // unsupported
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
abort(); // unsupported
} }
abort(); // unreachable abort(); // unreachable
} }

View file

@ -154,6 +154,7 @@ enum wlr_vk_texture_transform {
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1, WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2, WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3, WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
}; };
enum wlr_vk_shader_source { 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_INVERSE_ST2084_PQ = 2,
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3, WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
}; };
struct wlr_vk_pipeline_key { struct wlr_vk_pipeline_key {
@ -202,6 +204,7 @@ struct wlr_vk_render_format_setup {
VkPipeline output_pipe_pq; VkPipeline output_pipe_pq;
VkPipeline output_pipe_lut3d; VkPipeline output_pipe_lut3d;
VkPipeline output_pipe_gamma22; VkPipeline output_pipe_gamma22;
VkPipeline output_pipe_bt1886;
struct wlr_vk_renderer *renderer; struct wlr_vk_renderer *renderer;
struct wl_list pipelines; // struct wlr_vk_pipeline.link struct wl_list pipelines; // struct wlr_vk_pipeline.link

View file

@ -29,6 +29,7 @@ enum wlr_color_transfer_function {
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1, WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2, WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3, WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
}; };
/** /**

View file

@ -202,6 +202,13 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f
.reference = 203, .reference = 203,
}; };
break; break;
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
*lum = (struct wlr_color_luminances){
.min = 0.01,
.max = 100,
.reference = 100,
};
break;
default: default:
*lum = (struct wlr_color_luminances){ *lum = (struct wlr_color_luminances){
.min = 0.2, .min = 0.2,

View file

@ -246,6 +246,9 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22; pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22;
break; 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; 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: case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22; tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22;
break; 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( struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(

View file

@ -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_pq, NULL);
vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL); vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL);
vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL); vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL);
vkDestroyPipeline(dev, setup->output_pipe_bt1886, NULL);
struct wlr_vk_pipeline *pipeline, *tmp_pipeline; struct wlr_vk_pipeline *pipeline, *tmp_pipeline;
wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) { 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)) { &setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) {
goto error; 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 { } else {
assert(format->vk_srgb); assert(format->vk_srgb);
VkAttachmentDescription attachment = { VkAttachmentDescription attachment = {

View file

@ -23,6 +23,7 @@ layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0;
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2 #define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
#define OUTPUT_TRANSFORM_LUT_3D 3 #define OUTPUT_TRANSFORM_LUT_3D 3
#define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4 #define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4
#define OUTPUT_TRANSFORM_INVERSE_BT1886 5
float linear_channel_to_srgb(float x) { float linear_channel_to_srgb(float x) {
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055); 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)); 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() { void main() {
vec4 in_color = subpassLoad(in_color).rgba; vec4 in_color = subpassLoad(in_color).rgba;
@ -74,6 +83,8 @@ void main() {
rgb = linear_color_to_srgb(rgb); rgb = linear_color_to_srgb(rgb);
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) { } else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) {
rgb = pow(rgb, vec3(1. / 2.2)); 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 // Back to pre-multiplied alpha

View file

@ -19,6 +19,7 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
#define TEXTURE_TRANSFORM_SRGB 1 #define TEXTURE_TRANSFORM_SRGB 1
#define TEXTURE_TRANSFORM_ST2084_PQ 2 #define TEXTURE_TRANSFORM_ST2084_PQ 2
#define TEXTURE_TRANSFORM_GAMMA22 3 #define TEXTURE_TRANSFORM_GAMMA22 3
#define TEXTURE_TRANSFORM_BT1886 4
float srgb_channel_to_linear(float x) { float srgb_channel_to_linear(float x) {
return mix(x / 12.92, return mix(x / 12.92,
@ -45,6 +46,14 @@ vec3 pq_color_to_linear(vec3 color) {
return pow(num / denom, vec3(inv_m1)); 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() { void main() {
vec4 in_color = textureLod(tex, uv, 0); vec4 in_color = textureLod(tex, uv, 0);
@ -63,6 +72,8 @@ void main() {
rgb = pq_color_to_linear(rgb); rgb = pq_color_to_linear(rgb);
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) { } else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) {
rgb = pow(rgb, vec3(2.2)); rgb = pow(rgb, vec3(2.2));
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
rgb = bt1886_color_to_linear(rgb);
} }
rgb *= data.luminance_multiplier; rgb *= data.luminance_multiplier;

View file

@ -41,6 +41,7 @@ static bool get_tf_preference(enum wlr_color_transfer_function tf) {
return 0; return 0;
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
return 1; return 1;
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
case WLR_COLOR_TRANSFER_FUNCTION_SRGB: case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR: case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
return -1; return -1;

View file

@ -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; return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22:
return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22; return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886:
return WLR_COLOR_TRANSFER_FUNCTION_BT1886;
default: default:
abort(); 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; return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22: case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
return WP_COLOR_MANAGER_V1_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(); abort();
} }