gl-renderer: add post-curve set to identity

Add post-curve support in color.h.
Pre-curve and post-curve describe color pipeline components
in a single GL shader invocation.The GL shader is supposed
to match struct weston_color_transform exactly.
We have the following color pipeline:
shader A -> blending -> shader B -> KMS. Both A and B shaders
using the same source file :fragment.glsl.
Each shader has pre and post curve.

The typical color pipeline with 3DLUT:
Shader A: pre-curve identity->3DLUT->blending->post-curve identity
Shader B: pre-curve->3DLUT identity->post-curve identity->KMS

The typical color pipeline with matrix (in next commits):
Shader A: pre-curve->matrix->blending->post-curve identity
Shader B: pre-curve->matrix identity->post-curve identity->KMS
The pre-curve plays role of EOTF (shader A) or INV_EOTF
(shader B) becouse we are stiching the shaders.

We assume that someone in the future may use both pre-curve
and post-curve, for example, when it is not possible to combine
these curves into 3DLUT and we will do mapping elements based on
their location in ICC profile.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
This commit is contained in:
Vitaly Prosyak 2022-06-24 10:48:38 -04:00 committed by Pekka Paalanen
parent 118ee6674b
commit 96f0fc3974
5 changed files with 95 additions and 4 deletions

View File

@ -201,7 +201,7 @@ struct weston_color_transform {
struct weston_color_mapping mapping;
/** Step 4: color curve after color mapping */
/* struct weston_color_curve post_curve; */
struct weston_color_curve post_curve;
};
/**

View File

@ -76,10 +76,12 @@ compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT;
compile_const bool c_green_tint = DEF_GREEN_TINT;
compile_const int c_color_pre_curve = DEF_COLOR_PRE_CURVE;
compile_const int c_color_mapping = DEF_COLOR_MAPPING;
compile_const int c_color_post_curve = DEF_COLOR_POST_CURVE;
compile_const bool c_need_color_pipeline =
c_color_pre_curve != SHADER_COLOR_CURVE_IDENTITY ||
c_color_mapping != SHADER_COLOR_MAPPING_IDENTITY;
c_color_mapping != SHADER_COLOR_MAPPING_IDENTITY ||
c_color_post_curve != SHADER_COLOR_CURVE_IDENTITY;
vec4
yuva2rgba(vec4 yuva)
@ -123,6 +125,8 @@ uniform float view_alpha;
uniform vec4 unicolor;
uniform HIGHPRECISION sampler2D color_pre_curve_lut_2d;
uniform HIGHPRECISION vec2 color_pre_curve_lut_scale_offset;
uniform HIGHPRECISION sampler2D color_post_curve_lut_2d;
uniform HIGHPRECISION vec2 color_post_curve_lut_scale_offset;
#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT
uniform HIGHPRECISION sampler3D color_mapping_lut_3d;
@ -246,6 +250,33 @@ color_mapping(vec3 color)
return vec3(1.0, 0.3, 1.0);
}
float
sample_color_post_curve_lut_2d(float x, compile_const int row)
{
float tx = lut_texcoord(x, color_post_curve_lut_scale_offset);
return texture2D(color_post_curve_lut_2d,
vec2(tx, (float(row) + 0.5) / 4.0)).x;
}
vec3
color_post_curve(vec3 color)
{
vec3 ret;
if (c_color_post_curve == SHADER_COLOR_CURVE_IDENTITY) {
return color;
} else if (c_color_post_curve == SHADER_COLOR_CURVE_LUT_3x1D) {
ret.r = sample_color_post_curve_lut_2d(color.r, 0);
ret.g = sample_color_post_curve_lut_2d(color.g, 1);
ret.b = sample_color_post_curve_lut_2d(color.b, 2);
return ret;
} else {
/* Never reached, bad c_color_post_curve. */
return vec3(1.0, 0.3, 1.0);
}
}
vec4
color_pipeline(vec4 color)
{
@ -259,6 +290,7 @@ color_pipeline(vec4 color)
color.rgb = color_pre_curve(color.rgb);
color.rgb = color_mapping(color.rgb);
color.rgb = color_post_curve(color.rgb);
return color;
}

View File

@ -80,11 +80,12 @@ struct gl_shader_requirements
unsigned color_pre_curve:1; /* enum gl_shader_color_curve */
unsigned color_mapping:1; /* enum gl_shader_color_mapping */
unsigned color_post_curve:1; /* enum gl_shader_color_curve */
/*
* The total size of all bitfields plus pad_bits_ must fill up exactly
* how many bytes the compiler allocates for them together.
*/
unsigned pad_bits_:24;
unsigned pad_bits_:23;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
@ -110,6 +111,8 @@ struct gl_shader_config {
GLfloat scale_offset[2];
} lut3d;
} color_mapping;
GLuint color_post_curve_lut_tex;
GLfloat color_post_curve_lut_scale_offset[2];
};
struct gl_renderer {

View File

@ -61,6 +61,7 @@ struct gl_renderer_color_transform {
struct wl_listener destroy_listener;
struct gl_renderer_color_curve pre_curve;
struct gl_renderer_color_mapping mapping;
struct gl_renderer_color_curve post_curve;
};
static void
@ -82,6 +83,7 @@ static void
gl_renderer_color_transform_destroy(struct gl_renderer_color_transform *gl_xform)
{
gl_renderer_color_curve_fini(&gl_xform->pre_curve);
gl_renderer_color_curve_fini(&gl_xform->post_curve);
gl_renderer_color_mapping_fini(&gl_xform->mapping);
wl_list_remove(&gl_xform->destroy_listener.link);
free(gl_xform);
@ -141,6 +143,8 @@ gl_color_curve_lut_3x1d(struct gl_renderer_color_curve *gl_curve,
/*
* Four rows, see fragment.glsl sample_color_pre_curve_lut_2d().
* The fourth row is unused in fragment.glsl color_pre_curve().
* Four rows, see fragment.glsl sample_color_post_curve_lut_2d().
* The fourth row is unused in fragment.glsl color_post_curve().
*/
lut = calloc(lut_len * nr_rows, sizeof *lut);
if (!lut)
@ -223,6 +227,10 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform)
.pre_curve.scale = 0.0f,
.pre_curve.offset = 0.0f,
.mapping.type = SHADER_COLOR_MAPPING_IDENTITY,
.post_curve.type = SHADER_COLOR_CURVE_IDENTITY,
.post_curve.tex = 0,
.post_curve.scale = 0.0f,
.post_curve.offset = 0.0f,
};
struct gl_renderer_color_transform *gl_xform;
bool ok = false;
@ -270,6 +278,20 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform)
gl_renderer_color_transform_destroy(gl_xform);
return NULL;
}
switch (xform->post_curve.type) {
case WESTON_COLOR_CURVE_TYPE_IDENTITY:
gl_xform->post_curve = no_op_gl_xform.post_curve;
ok = true;
break;
case WESTON_COLOR_CURVE_TYPE_LUT_3x1D:
ok = gl_color_curve_lut_3x1d(&gl_xform->post_curve,
&xform->post_curve, xform);
break;
}
if (!ok) {
gl_renderer_color_transform_destroy(gl_xform);
return NULL;
}
return gl_xform;
}
@ -290,6 +312,11 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf,
sconf->color_pre_curve_lut_scale_offset[0] = gl_xform->pre_curve.scale;
sconf->color_pre_curve_lut_scale_offset[1] = gl_xform->pre_curve.offset;
sconf->req.color_post_curve = gl_xform->post_curve.type;
sconf->color_post_curve_lut_tex = gl_xform->post_curve.tex;
sconf->color_post_curve_lut_scale_offset[0] = gl_xform->post_curve.scale;
sconf->color_post_curve_lut_scale_offset[1] = gl_xform->post_curve.offset;
sconf->req.color_mapping = gl_xform->mapping.type;
switch (gl_xform->mapping.type) {
case SHADER_COLOR_MAPPING_3DLUT:

View File

@ -67,6 +67,8 @@ struct gl_shader {
GLint scale_offset_uniform;
} lut3d;
} color_mapping;
GLint color_post_curve_lut_2d_uniform;
GLint color_post_curve_lut_scale_offset_uniform;
struct wl_list link; /* gl_renderer::shader_list */
struct timespec last_used;
};
@ -182,10 +184,11 @@ create_shader_description_string(const struct gl_shader_requirements *req)
int size;
char *str;
size = asprintf(&str, "%s %s %s %cinput_is_premult %cgreen",
size = asprintf(&str, "%s %s %s %s %cinput_is_premult %cgreen",
gl_shader_texture_variant_to_string(req->variant),
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
gl_shader_color_curve_to_string(req->color_post_curve),
req->input_is_premult ? '+' : '-',
req->green_tint ? '+' : '-');
if (size < 0)
@ -204,11 +207,13 @@ create_shader_config_string(const struct gl_shader_requirements *req)
"#define DEF_INPUT_IS_PREMULT %s\n"
"#define DEF_COLOR_PRE_CURVE %s\n"
"#define DEF_COLOR_MAPPING %s\n"
"#define DEF_COLOR_POST_CURVE %s\n"
"#define DEF_VARIANT %s\n",
req->green_tint ? "true" : "false",
req->input_is_premult ? "true" : "false",
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
gl_shader_color_curve_to_string(req->color_post_curve),
gl_shader_texture_variant_to_string(req->variant));
if (size < 0)
return NULL;
@ -291,6 +296,11 @@ gl_shader_create(struct gl_renderer *gr,
shader->color_pre_curve_lut_scale_offset_uniform =
glGetUniformLocation(shader->program, "color_pre_curve_lut_scale_offset");
shader->color_post_curve_lut_2d_uniform =
glGetUniformLocation(shader->program, "color_post_curve_lut_2d");
shader->color_post_curve_lut_scale_offset_uniform =
glGetUniformLocation(shader->program, "color_post_curve_lut_scale_offset");
switch(requirements->color_mapping) {
case SHADER_COLOR_MAPPING_3DLUT:
shader->color_mapping.lut3d.tex_uniform =
@ -410,6 +420,7 @@ gl_renderer_create_fallback_shader(struct gl_renderer *gr)
.input_is_premult = true,
.color_pre_curve = SHADER_COLOR_CURVE_IDENTITY,
.color_mapping = SHADER_COLOR_MAPPING_IDENTITY,
.color_post_curve = SHADER_COLOR_CURVE_IDENTITY,
};
struct gl_shader *shader;
@ -560,6 +571,7 @@ gl_shader_load_config(struct gl_shader *shader,
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_3D, sconf->color_mapping.lut3d.tex);
glUniform1i(shader->color_mapping.lut3d.tex_uniform, i);
i++;
glUniform2fv(shader->color_mapping.lut3d.scale_offset_uniform,
1, sconf->color_mapping.lut3d.scale_offset);
break;
@ -567,6 +579,23 @@ gl_shader_load_config(struct gl_shader *shader,
assert(false);
break;
}
switch (sconf->req.color_post_curve) {
case SHADER_COLOR_CURVE_IDENTITY:
assert(sconf->color_post_curve_lut_tex == 0);
break;
case SHADER_COLOR_CURVE_LUT_3x1D:
assert(sconf->color_post_curve_lut_tex != 0);
assert(shader->color_post_curve_lut_2d_uniform != -1);
assert(shader->color_post_curve_lut_scale_offset_uniform != -1);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, sconf->color_post_curve_lut_tex);
glUniform1i(shader->color_post_curve_lut_2d_uniform, i);
i++;
glUniform2fv(shader->color_post_curve_lut_scale_offset_uniform,
1, sconf->color_post_curve_lut_scale_offset);
break;
}
}
bool