mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-13 08:22:16 -04:00
render/vulkan: don't assume a default EOTF
All color-management decisions, including the use of a linear space for blending, are now moved up to wlr_scene
This commit is contained in:
parent
03d3041fba
commit
bf8b6a7127
3 changed files with 68 additions and 50 deletions
|
|
@ -31,9 +31,7 @@ struct wlr_render_timer;
|
|||
struct wlr_buffer_pass_options {
|
||||
/* Timer to measure the duration of the render pass */
|
||||
struct wlr_render_timer *timer;
|
||||
/* Color transform to apply to the output of the render pass.
|
||||
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
|
||||
* sRGB monitors) */
|
||||
/* Color transform to apply to the output of the render pass */
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
/* Signal a timeline synchronization point when the render pass completes.
|
||||
|
|
|
|||
|
|
@ -56,14 +56,6 @@ static void convert_pixman_box_to_vk_rect(const pixman_box32_t *box, VkRect2D *r
|
|||
};
|
||||
}
|
||||
|
||||
static float color_to_linear(float non_linear) {
|
||||
return pow(non_linear, 2.2);
|
||||
}
|
||||
|
||||
static float color_to_linear_premult(float non_linear, float alpha) {
|
||||
return (alpha == 0) ? 0 : color_to_linear(non_linear / alpha) * alpha;
|
||||
}
|
||||
|
||||
static void encode_proj_matrix(const float mat3[9], float mat4[4][4]) {
|
||||
float result[4][4] = {
|
||||
{ mat3[0], mat3[1], 0, mat3[2] },
|
||||
|
|
@ -138,7 +130,7 @@ static bool unwrap_output_color_transform(struct wlr_color_transform *transform,
|
|||
float matrix[static 9], enum wlr_color_transfer_function *tf) {
|
||||
if (transform == NULL) {
|
||||
wlr_matrix_identity(matrix);
|
||||
*tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
*tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
return true;
|
||||
}
|
||||
struct wlr_color_transform_inverse_eotf *eotf;
|
||||
|
|
@ -179,7 +171,7 @@ static bool unwrap_texture_color_transform(struct wlr_color_transform *transform
|
|||
float matrix[static 9], enum wlr_color_transfer_function *tf) {
|
||||
if (transform == NULL) {
|
||||
wlr_matrix_identity(matrix);
|
||||
*tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
*tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
return true;
|
||||
}
|
||||
struct wlr_color_transform_eotf *eotf;
|
||||
|
|
@ -256,7 +248,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
encode_proj_matrix(final_matrix, vert_pcr_data.mat4);
|
||||
|
||||
float matrix[9];
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
bool need_lut = false;
|
||||
size_t dim = 1;
|
||||
struct wlr_vk_color_transform *transform = NULL;
|
||||
|
|
@ -688,16 +680,11 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
|
|||
struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
|
||||
VkCommandBuffer cb = pass->command_buffer->vk;
|
||||
|
||||
// Input color values are given in sRGB space, shader expects
|
||||
// them in linear space. The shader does all computation in linear
|
||||
// space and expects in inputs in linear space since it outputs
|
||||
// colors in linear space as well (and vulkan then automatically
|
||||
// does the conversion for out sRGB render targets).
|
||||
float linear_color[] = {
|
||||
color_to_linear_premult(options->color.r, options->color.a),
|
||||
color_to_linear_premult(options->color.g, options->color.a),
|
||||
color_to_linear_premult(options->color.b, options->color.a),
|
||||
options->color.a, // no conversion for alpha
|
||||
options->color.r,
|
||||
options->color.g,
|
||||
options->color.b,
|
||||
options->color.a,
|
||||
};
|
||||
|
||||
pixman_region32_t clip;
|
||||
|
|
@ -834,7 +821,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
float color_matrix[9];
|
||||
if (!unwrap_texture_color_transform(options->color_transform, color_matrix, &tf))
|
||||
{
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
wlr_matrix_identity(color_matrix);
|
||||
}
|
||||
|
||||
|
|
@ -1218,7 +1205,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
}
|
||||
} else {
|
||||
// This is the default when unspecified
|
||||
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
}
|
||||
|
||||
bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
|
|
|
|||
|
|
@ -320,6 +320,8 @@ struct render_data {
|
|||
|
||||
struct wlr_render_pass *render_pass;
|
||||
pixman_region32_t damage;
|
||||
|
||||
struct wlr_color_transform *default_color_transform;
|
||||
};
|
||||
|
||||
static void logical_to_buffer_coords(pixman_region32_t *region, const struct render_data *data,
|
||||
|
|
@ -1469,6 +1471,28 @@ cleanup_transforms:
|
|||
return combined;
|
||||
}
|
||||
|
||||
static struct wlr_render_color scene_color_transform_premultiplied(
|
||||
struct wlr_color_transform *transform, float r, float g, float b, float a) {
|
||||
float transform_in[] = {
|
||||
(a == 0) ? 0 : r / a,
|
||||
(a == 0) ? 0 : g / a,
|
||||
(a == 0) ? 0 : b / a,
|
||||
};
|
||||
float transform_out[] = {0, 0, 0};
|
||||
if (transform != NULL) {
|
||||
wlr_color_transform_eval(transform, transform_out, transform_in);
|
||||
} else {
|
||||
memcpy(transform_out, transform_in, sizeof(transform_in));
|
||||
}
|
||||
struct wlr_render_color res = {
|
||||
.r = transform_out[0] * a,
|
||||
.g = transform_out[1] * a,
|
||||
.b = transform_out[2] * a,
|
||||
.a = a,
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
static void scene_entry_render(struct render_list_entry *entry, const struct render_data *data) {
|
||||
struct wlr_scene_node *node = entry->node;
|
||||
|
||||
|
|
@ -1508,12 +1532,11 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
|
||||
wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
|
||||
.box = dst_box,
|
||||
.color = {
|
||||
.r = scene_rect->color[0],
|
||||
.g = scene_rect->color[1],
|
||||
.b = scene_rect->color[2],
|
||||
.a = scene_rect->color[3],
|
||||
},
|
||||
.color = scene_color_transform_premultiplied(data->default_color_transform,
|
||||
scene_rect->color[0],
|
||||
scene_rect->color[1],
|
||||
scene_rect->color[2],
|
||||
scene_rect->color[3]),
|
||||
.clip = &render_region,
|
||||
});
|
||||
break;
|
||||
|
|
@ -1524,13 +1547,12 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
// Render the buffer as a rect, this is likely to be more efficient
|
||||
wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
|
||||
.box = dst_box,
|
||||
.color = {
|
||||
.r = (float)scene_buffer->single_pixel_buffer_color[0] / (float)UINT32_MAX,
|
||||
.g = (float)scene_buffer->single_pixel_buffer_color[1] / (float)UINT32_MAX,
|
||||
.b = (float)scene_buffer->single_pixel_buffer_color[2] / (float)UINT32_MAX,
|
||||
.a = (float)scene_buffer->single_pixel_buffer_color[3] /
|
||||
(float)UINT32_MAX * scene_buffer->opacity,
|
||||
},
|
||||
.color = scene_color_transform_premultiplied(data->default_color_transform,
|
||||
(float)scene_buffer->single_pixel_buffer_color[0] / (float)UINT32_MAX,
|
||||
(float)scene_buffer->single_pixel_buffer_color[1] / (float)UINT32_MAX,
|
||||
(float)scene_buffer->single_pixel_buffer_color[2] / (float)UINT32_MAX,
|
||||
(float)scene_buffer->single_pixel_buffer_color[3] /
|
||||
(float)UINT32_MAX * scene_buffer->opacity),
|
||||
.clip = &render_region,
|
||||
});
|
||||
break;
|
||||
|
|
@ -1587,7 +1609,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
if (entry->highlight_transparent_region) {
|
||||
wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
|
||||
.box = dst_box,
|
||||
.color = { .r = 0, .g = 0.3, .b = 0, .a = 0.3 },
|
||||
.color = scene_color_transform_premultiplied(data->default_color_transform,
|
||||
0, 0.3, 0, 0.3),
|
||||
.clip = &opaque,
|
||||
});
|
||||
}
|
||||
|
|
@ -2523,17 +2546,23 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
timer->pre_render_duration = timespec_to_nsec(&duration);
|
||||
}
|
||||
|
||||
if ((render_gamma_lut
|
||||
&& scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform)
|
||||
|| scene_output->prev_supplied_color_transform != options->color_transform
|
||||
|| (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION)) {
|
||||
const struct wlr_output_image_description *output_description =
|
||||
output_pending_image_description(output, state);
|
||||
if (!scene_output_combine_color_transforms(scene_output, options->color_transform,
|
||||
output_description, render_gamma_lut)) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
return false;
|
||||
if (output->renderer->features.output_color_transform) {
|
||||
if ((render_gamma_lut
|
||||
&& scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform)
|
||||
|| scene_output->prev_supplied_color_transform != options->color_transform
|
||||
|| (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION)
|
||||
|| scene_output->combined_color_transform == NULL) {
|
||||
const struct wlr_output_image_description *output_description =
|
||||
output_pending_image_description(output, state);
|
||||
if (!scene_output_combine_color_transforms(scene_output, options->color_transform,
|
||||
output_description, render_gamma_lut)) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
render_data.default_color_transform = wlr_color_transform_init_eotf_to_linear(
|
||||
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22);
|
||||
}
|
||||
|
||||
scene_output->in_point++;
|
||||
|
|
@ -2546,6 +2575,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
});
|
||||
if (render_pass == NULL) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
wlr_color_transform_unref(render_data.default_color_transform);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2630,7 +2660,8 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
|
||||
wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = buffer->width, .height = buffer->height },
|
||||
.color = { .r = alpha * 0.5, .g = 0, .b = 0, .a = alpha * 0.5 },
|
||||
.color = scene_color_transform_premultiplied(render_data.default_color_transform,
|
||||
alpha * 0.5, 0, 0, alpha * 0.5),
|
||||
.clip = &damage->region,
|
||||
});
|
||||
}
|
||||
|
|
@ -2641,6 +2672,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
|
||||
if (!wlr_render_pass_submit(render_pass)) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
wlr_color_transform_unref(render_data.default_color_transform);
|
||||
|
||||
// if we failed to render the buffer, it will have undefined contents
|
||||
// Trash the damage ring
|
||||
|
|
@ -2650,6 +2682,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
|
||||
wlr_output_state_set_buffer(state, buffer);
|
||||
wlr_buffer_unlock(buffer);
|
||||
wlr_color_transform_unref(render_data.default_color_transform);
|
||||
|
||||
if (scene_output->in_timeline != NULL) {
|
||||
wlr_output_state_set_wait_timeline(state, scene_output->in_timeline,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue