mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-15 14:33:01 -04:00
Merge branch 'render' into 'master'
render: general color_transform for wlr_render_pass_add_texture() See merge request wlroots/wlroots!5260
This commit is contained in:
commit
ed3c145f94
12 changed files with 544 additions and 151 deletions
|
|
@ -29,6 +29,17 @@ void wlr_color_transform_init(struct wlr_color_transform *tr, enum wlr_color_tra
|
|||
wlr_addon_set_init(&tr->addons);
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_eotf_to_linear(
|
||||
enum wlr_color_transfer_function tf) {
|
||||
struct wlr_color_transform_eotf *tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_EOTF);
|
||||
tx->tf = tf;
|
||||
return &tx->base;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf) {
|
||||
struct wlr_color_transform_inverse_eotf *tx = calloc(1, sizeof(*tx));
|
||||
|
|
@ -103,6 +114,7 @@ static void color_transform_destroy(struct wlr_color_transform *tr) {
|
|||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
case COLOR_TRANSFORM_MATRIX:
|
||||
case COLOR_TRANSFORM_EOTF:
|
||||
break;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
color_transform_lcms2_finish(color_transform_lcms2_from_base(tr));
|
||||
|
|
@ -140,6 +152,13 @@ void wlr_color_transform_unref(struct wlr_color_transform *tr) {
|
|||
}
|
||||
}
|
||||
|
||||
struct wlr_color_transform_eotf *wlr_color_transform_eotf_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_EOTF);
|
||||
struct wlr_color_transform_eotf *eotf = wl_container_of(tr, eotf, base);
|
||||
return eotf;
|
||||
}
|
||||
|
||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_INVERSE_EOTF);
|
||||
|
|
@ -154,6 +173,14 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
|||
return lut_3x1d;
|
||||
}
|
||||
|
||||
static float srgb_eval_eotf(float x) {
|
||||
if (x <= 0.04045) {
|
||||
return x / 12.92;
|
||||
} else {
|
||||
return powf((x + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
}
|
||||
|
||||
static float srgb_eval_inverse_eotf(float x) {
|
||||
// See https://www.w3.org/Graphics/Color/srgb
|
||||
if (x <= 0.0031308) {
|
||||
|
|
@ -163,6 +190,21 @@ static float srgb_eval_inverse_eotf(float x) {
|
|||
}
|
||||
}
|
||||
|
||||
static float st2084_pq_eval_eotf(float x) {
|
||||
float c1 = 0.8359375;
|
||||
float c2 = 18.8515625;
|
||||
float c3 = 18.6875;
|
||||
float inv_m2 = 1.0 / 78.84375;
|
||||
float inv_m1 = 1.0 / 0.1593017578125;
|
||||
float pow_m2 = powf(x, inv_m2);
|
||||
float num = pow_m2 - c1;
|
||||
if (num < 0) {
|
||||
num = 0;
|
||||
}
|
||||
float denom = c2 - c3 * pow_m2;
|
||||
return powf(num / denom, inv_m1);
|
||||
}
|
||||
|
||||
static float st2084_pq_eval_inverse_eotf(float x) {
|
||||
// H.273 TransferCharacteristics code point 16
|
||||
float c1 = 0.8359375;
|
||||
|
|
@ -180,6 +222,14 @@ static float st2084_pq_eval_inverse_eotf(float x) {
|
|||
return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
|
||||
}
|
||||
|
||||
static float bt1886_eval_eotf(float x) {
|
||||
float lb = powf(0.0001, 1.0 / 2.4);
|
||||
float lw = powf(1.0, 1.0 / 2.4);
|
||||
float a = powf(lw - lb, 2.4);
|
||||
float b = lb / (lw - lb);
|
||||
return a * powf(x + b, 2.4);
|
||||
}
|
||||
|
||||
static float bt1886_eval_inverse_eotf(float x) {
|
||||
float lb = powf(0.0001, 1.0 / 2.4);
|
||||
float lw = powf(1.0, 1.0 / 2.4);
|
||||
|
|
@ -188,6 +238,22 @@ static float bt1886_eval_inverse_eotf(float x) {
|
|||
return powf(x / a, 1.0 / 2.4) - b;
|
||||
}
|
||||
|
||||
static float transfer_function_eval_eotf(enum wlr_color_transfer_function tf, float x) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
return srgb_eval_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return st2084_pq_eval_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return x;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return powf(x, 2.2);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
return bt1886_eval_eotf(x);
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static float transfer_function_eval_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf, float x) {
|
||||
switch (tf) {
|
||||
|
|
@ -205,6 +271,14 @@ static float transfer_function_eval_inverse_eotf(
|
|||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void color_transform_eotf_eval(
|
||||
struct wlr_color_transform_eotf *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
out[i] = transfer_function_eval_eotf(tr->tf, in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void color_transform_inverse_eotf_eval(
|
||||
struct wlr_color_transform_inverse_eotf *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
|
|
@ -265,6 +339,9 @@ void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
|||
}
|
||||
memcpy(out, color, sizeof(color));
|
||||
break;
|
||||
case COLOR_TRANSFORM_EOTF:
|
||||
color_transform_eotf_eval(wlr_color_transform_eotf_from_base(tr), out, in);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,14 +47,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] },
|
||||
|
|
@ -125,11 +117,11 @@ static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool unwrap_color_transform(struct wlr_color_transform *transform,
|
||||
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;
|
||||
|
|
@ -159,6 +151,48 @@ static bool unwrap_color_transform(struct wlr_color_transform *transform,
|
|||
*tf = eotf->tf;
|
||||
return true;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
case COLOR_TRANSFORM_EOTF:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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_EXT_LINEAR;
|
||||
return true;
|
||||
}
|
||||
struct wlr_color_transform_eotf *eotf;
|
||||
struct wlr_color_transform_matrix *as_matrix;
|
||||
struct wlr_color_transform_pipeline *pipeline;
|
||||
switch (transform->type) {
|
||||
case COLOR_TRANSFORM_EOTF:
|
||||
eotf = wlr_color_transform_eotf_from_base(transform);
|
||||
wlr_matrix_identity(matrix);
|
||||
*tf = eotf->tf;
|
||||
return true;
|
||||
case COLOR_TRANSFORM_MATRIX:
|
||||
as_matrix = wl_container_of(transform, as_matrix, base);
|
||||
memcpy(matrix, as_matrix->matrix, sizeof(float[9]));
|
||||
*tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
return true;
|
||||
case COLOR_TRANSFORM_PIPELINE:
|
||||
pipeline = wl_container_of(transform, pipeline, base);
|
||||
if (pipeline->len != 2
|
||||
|| pipeline->transforms[0]->type != COLOR_TRANSFORM_EOTF
|
||||
|| pipeline->transforms[1]->type != COLOR_TRANSFORM_MATRIX) {
|
||||
return false;
|
||||
}
|
||||
eotf = wlr_color_transform_eotf_from_base(pipeline->transforms[0]);
|
||||
*tf = eotf->tf;
|
||||
as_matrix = wl_container_of(pipeline->transforms[1], as_matrix, base);
|
||||
memcpy(matrix, as_matrix->matrix, sizeof(float[9]));
|
||||
return true;
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -207,7 +241,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;
|
||||
|
|
@ -217,7 +251,12 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
need_lut = transform->lut_3d.dim > 0;
|
||||
dim = need_lut ? transform->lut_3d.dim : 1;
|
||||
memcpy(matrix, transform->color_matrix, sizeof(matrix));
|
||||
tf = transform->inverse_eotf;
|
||||
tf = transform->eotf;
|
||||
}
|
||||
if (need_lut) {
|
||||
if (!vulkan_command_buffer_ref_color_transform(render_cb, pass->color_transform)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (pass->color_transform == NULL || need_lut) {
|
||||
wlr_matrix_identity(matrix);
|
||||
|
|
@ -263,7 +302,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
if (need_lut) {
|
||||
lut_ds = transform->lut_3d.ds;
|
||||
} else {
|
||||
lut_ds = renderer->output_ds_lut3d_dummy;
|
||||
lut_ds = renderer->ds_lut3d_dummy;
|
||||
}
|
||||
VkDescriptorSet ds[] = {
|
||||
render_buffer->two_pass.blend_descriptor_set, // set 0
|
||||
|
|
@ -642,16 +681,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,
|
||||
};
|
||||
|
||||
struct wlr_box box;
|
||||
|
|
@ -752,6 +786,9 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
|
|||
pixman_region32_fini(&clip);
|
||||
}
|
||||
|
||||
static struct wlr_vk_color_transform *vk_color_transform_create(
|
||||
struct wlr_vk_renderer *renderer, struct wlr_color_transform *transform, bool output);
|
||||
|
||||
static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
||||
const struct wlr_render_texture_options *options) {
|
||||
struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
|
||||
|
|
@ -822,34 +859,64 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
};
|
||||
encode_proj_matrix(matrix, vert_pcr_data.mat4);
|
||||
|
||||
enum wlr_color_transfer_function tf = options->transfer_function;
|
||||
if (tf == 0) {
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
float color_matrix[9];
|
||||
bool need_lut = false;
|
||||
size_t dim = 1;
|
||||
struct wlr_vk_color_transform *transform = NULL;
|
||||
if (options->color_transform != NULL) {
|
||||
transform = get_color_transform(options->color_transform, renderer);
|
||||
if (transform == NULL) {
|
||||
transform = vk_color_transform_create(renderer, options->color_transform, false);
|
||||
if (transform == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create color transform");
|
||||
pass->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
need_lut = transform->lut_3d.dim > 0;
|
||||
dim = need_lut ? transform->lut_3d.dim : 1;
|
||||
memcpy(color_matrix, transform->color_matrix, sizeof(color_matrix));
|
||||
tf = transform->eotf;
|
||||
}
|
||||
if (need_lut) {
|
||||
if (!vulkan_command_buffer_ref_color_transform(pass->command_buffer,
|
||||
options->color_transform)) {
|
||||
pass->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (options->color_transform == NULL || need_lut) {
|
||||
wlr_matrix_identity(color_matrix);
|
||||
}
|
||||
|
||||
bool srgb_image_view = false;
|
||||
enum wlr_vk_texture_transform tex_transform = 0;
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
if (texture->using_mutable_srgb) {
|
||||
if (need_lut) {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_LUT_3D;
|
||||
} else {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
if (texture->using_mutable_srgb) {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
|
||||
srgb_image_view = true;
|
||||
} else {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB;
|
||||
}
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
|
||||
srgb_image_view = true;
|
||||
} else {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB;
|
||||
break;
|
||||
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;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
|
||||
break;
|
||||
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;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886;
|
||||
break;
|
||||
}
|
||||
|
||||
enum wlr_color_encoding color_encoding = options->color_encoding;
|
||||
|
|
@ -893,32 +960,28 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
return;
|
||||
}
|
||||
|
||||
float color_matrix[9];
|
||||
if (options->primaries != NULL) {
|
||||
struct wlr_color_primaries srgb;
|
||||
wlr_color_primaries_from_named(&srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
|
||||
|
||||
wlr_color_primaries_transform_absolute_colorimetric(options->primaries,
|
||||
&srgb, color_matrix);
|
||||
} else {
|
||||
wlr_matrix_identity(color_matrix);
|
||||
}
|
||||
|
||||
float luminance_multiplier = 1;
|
||||
if (options->luminance_multiplier != NULL) {
|
||||
luminance_multiplier = *options->luminance_multiplier;
|
||||
}
|
||||
|
||||
struct wlr_vk_frag_texture_pcr_data frag_pcr_data = {
|
||||
.alpha = alpha,
|
||||
.luminance_multiplier = luminance_multiplier,
|
||||
.lut_3d_offset = 0.5f / dim,
|
||||
.lut_3d_scale = (float)(dim - 1) / dim,
|
||||
};
|
||||
encode_color_matrix(color_matrix, frag_pcr_data.matrix);
|
||||
|
||||
bind_pipeline(pass, pipe->vk);
|
||||
|
||||
VkDescriptorSet lut_ds;
|
||||
if (need_lut) {
|
||||
lut_ds = transform->lut_3d.ds;
|
||||
} else {
|
||||
lut_ds = renderer->ds_lut3d_dummy;
|
||||
}
|
||||
VkDescriptorSet ds[] = {
|
||||
view->ds, // set 0
|
||||
lut_ds, // set 1
|
||||
};
|
||||
size_t ds_len = sizeof(ds) / sizeof(ds[0]);
|
||||
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipe->layout->vk, 0, 1, &view->ds, 0, NULL);
|
||||
pipe->layout->vk, 0, ds_len, ds, 0, NULL);
|
||||
|
||||
vkCmdPushConstants(cb, pipe->layout->vk,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
|
||||
|
|
@ -1145,7 +1208,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
|
||||
*ds_pool = vulkan_alloc_texture_ds(renderer,
|
||||
renderer->output_ds_lut3d_layout, ds);
|
||||
renderer->ds_lut3d_layout, ds);
|
||||
if (!*ds_pool) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate descriptor");
|
||||
goto fail_imageview;
|
||||
|
|
@ -1176,15 +1239,22 @@ fail_image:
|
|||
}
|
||||
|
||||
static struct wlr_vk_color_transform *vk_color_transform_create(
|
||||
struct wlr_vk_renderer *renderer, struct wlr_color_transform *transform) {
|
||||
struct wlr_vk_renderer *renderer, struct wlr_color_transform *transform,
|
||||
bool output) {
|
||||
struct wlr_vk_color_transform *vk_transform =
|
||||
calloc(1, sizeof(*vk_transform));
|
||||
if (!vk_transform) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool need_lut = !unwrap_color_transform(transform, vk_transform->color_matrix,
|
||||
&vk_transform->inverse_eotf);
|
||||
bool need_lut;
|
||||
if (output) {
|
||||
need_lut = !unwrap_output_color_transform(transform, vk_transform->color_matrix,
|
||||
&vk_transform->eotf);
|
||||
} else {
|
||||
need_lut = !unwrap_texture_color_transform(transform, vk_transform->color_matrix,
|
||||
&vk_transform->eotf);
|
||||
}
|
||||
|
||||
if (need_lut) {
|
||||
vk_transform->lut_3d.dim = 33;
|
||||
|
|
@ -1227,7 +1297,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;
|
||||
|
|
@ -1248,7 +1318,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
if (options != NULL && options->color_transform != NULL &&
|
||||
!get_color_transform(options->color_transform, renderer)) {
|
||||
/* Try to create a new color transform */
|
||||
if (!vk_color_transform_create(renderer, options->color_transform)) {
|
||||
if (!vk_color_transform_create(renderer, options->color_transform, true)) {
|
||||
wlr_log(WLR_ERROR, "Failed to create color transform");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -603,10 +603,11 @@ static void release_command_buffer_resources(struct wlr_vk_command_buffer *cb,
|
|||
wlr_texture_destroy(&texture->wlr_texture);
|
||||
}
|
||||
|
||||
if (cb->color_transform) {
|
||||
wlr_color_transform_unref(cb->color_transform);
|
||||
cb->color_transform = NULL;
|
||||
struct wlr_color_transform **transform;
|
||||
wl_array_for_each(transform, &cb->color_transforms) {
|
||||
wlr_color_transform_unref(*transform);
|
||||
}
|
||||
cb->color_transforms.size = 0;
|
||||
}
|
||||
|
||||
static struct wlr_vk_command_buffer *get_command_buffer(
|
||||
|
|
@ -710,6 +711,16 @@ void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb) {
|
|||
}
|
||||
}
|
||||
|
||||
bool vulkan_command_buffer_ref_color_transform(struct wlr_vk_command_buffer *cb,
|
||||
struct wlr_color_transform *color_transform) {
|
||||
struct wlr_color_transform **ref = wl_array_add(&cb->color_transforms, sizeof(*ref));
|
||||
if (ref == NULL) {
|
||||
return false;
|
||||
}
|
||||
*ref = wlr_color_transform_ref(color_transform);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void finish_render_buffer_out(struct wlr_vk_render_buffer_out *out,
|
||||
VkDevice dev) {
|
||||
vkDestroyFramebuffer(dev, out->framebuffer, NULL);
|
||||
|
|
@ -1303,9 +1314,9 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
|
|||
vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL);
|
||||
vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_srgb_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_lut3d_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(dev->dev, renderer->ds_lut3d_layout, NULL);
|
||||
vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL);
|
||||
vkDestroySampler(dev->dev, renderer->output_sampler_lut3d, NULL);
|
||||
vkDestroySampler(dev->dev, renderer->sampler_lut3d, NULL);
|
||||
|
||||
if (renderer->read_pixels_cache.initialized) {
|
||||
vkFreeMemory(dev->dev, renderer->read_pixels_cache.dst_img_memory, NULL);
|
||||
|
|
@ -1724,10 +1735,15 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
|||
},
|
||||
};
|
||||
|
||||
VkDescriptorSetLayout out_ds_layouts[] = {
|
||||
*out_ds_layout,
|
||||
renderer->ds_lut3d_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pl_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = out_ds_layout,
|
||||
.setLayoutCount = sizeof(out_ds_layouts) / sizeof(out_ds_layouts[0]),
|
||||
.pSetLayouts = out_ds_layouts,
|
||||
.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
|
||||
.pPushConstantRanges = pc_ranges,
|
||||
};
|
||||
|
|
@ -1778,7 +1794,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
};
|
||||
|
||||
res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL,
|
||||
&renderer->output_sampler_lut3d);
|
||||
&renderer->sampler_lut3d);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateSampler", res);
|
||||
return false;
|
||||
|
|
@ -1789,7 +1805,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = &renderer->output_sampler_lut3d,
|
||||
.pImmutableSamplers = &renderer->sampler_lut3d,
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo ds_lut3d_info = {
|
||||
|
|
@ -1799,7 +1815,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
};
|
||||
|
||||
res = vkCreateDescriptorSetLayout(dev, &ds_lut3d_info, NULL,
|
||||
&renderer->output_ds_lut3d_layout);
|
||||
&renderer->ds_lut3d_layout);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateDescriptorSetLayout", res);
|
||||
return false;
|
||||
|
|
@ -1821,7 +1837,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
|
||||
VkDescriptorSetLayout out_ds_layouts[] = {
|
||||
renderer->output_ds_srgb_layout,
|
||||
renderer->output_ds_lut3d_layout,
|
||||
renderer->ds_lut3d_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pl_info = {
|
||||
|
|
@ -2362,9 +2378,9 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) {
|
|||
return false;
|
||||
}
|
||||
|
||||
renderer->output_ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer,
|
||||
renderer->output_ds_lut3d_layout, &renderer->output_ds_lut3d_dummy);
|
||||
if (!renderer->output_ds_lut3d_dummy_pool) {
|
||||
renderer->ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer,
|
||||
renderer->ds_lut3d_layout, &renderer->ds_lut3d_dummy);
|
||||
if (!renderer->ds_lut3d_dummy_pool) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate descriptor");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2376,7 +2392,7 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) {
|
|||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.dstSet = renderer->output_ds_lut3d_dummy,
|
||||
.dstSet = renderer->ds_lut3d_dummy,
|
||||
.pImageInfo = &ds_img_info,
|
||||
};
|
||||
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
layout(set = 0, binding = 0) uniform sampler2D tex;
|
||||
|
||||
layout(set = 1, binding = 0) uniform sampler3D lut_3d;
|
||||
|
||||
layout(location = 0) in vec2 uv;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
|
|
@ -9,7 +11,8 @@ layout(location = 0) out vec4 out_color;
|
|||
layout(push_constant, row_major) uniform UBO {
|
||||
layout(offset = 80) mat4 matrix;
|
||||
float alpha;
|
||||
float luminance_multiplier;
|
||||
float lut_3d_offset;
|
||||
float lut_3d_scale;
|
||||
} data;
|
||||
|
||||
layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
||||
|
|
@ -20,6 +23,7 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
|||
#define TEXTURE_TRANSFORM_ST2084_PQ 2
|
||||
#define TEXTURE_TRANSFORM_GAMMA22 3
|
||||
#define TEXTURE_TRANSFORM_BT1886 4
|
||||
#define TEXTURE_TRANSFORM_LUT_3D 5
|
||||
|
||||
float srgb_channel_to_linear(float x) {
|
||||
return mix(x / 12.92,
|
||||
|
|
@ -80,10 +84,12 @@ void main() {
|
|||
rgb = pow(rgb, vec3(2.2));
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
|
||||
rgb = bt1886_color_to_linear(rgb);
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_LUT_3D) {
|
||||
// Apply 3D LUT
|
||||
vec3 pos = data.lut_3d_offset + rgb * data.lut_3d_scale;
|
||||
rgb = texture(lut_3d, pos).rgb;
|
||||
}
|
||||
|
||||
rgb *= data.luminance_multiplier;
|
||||
|
||||
rgb = mat3(data.matrix) * rgb;
|
||||
|
||||
// Back to pre-multiplied alpha
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue