Skip to content
Commits on Source (10)
......@@ -34,6 +34,21 @@
#include "color-lcms.h"
#include "shared/helpers.h"
const char *
cmlcms_category_name(enum cmlcms_category cat)
{
static const char *const category_names[] = {
[CMLCMS_CATEGORY_INPUT_TO_BLEND] = "input-to-blend",
[CMLCMS_CATEGORY_BLEND_TO_OUTPUT] = "blend-to-output",
[CMLCMS_CATEGORY_INPUT_TO_OUTPUT] = "input-to-output",
};
if (cat < 0 || cat >= ARRAY_LENGTH(category_names))
return "[illegal category value]";
return category_names[cat] ?: "[undocumented category value]";
}
static cmsUInt32Number
cmlcms_get_render_intent(enum cmlcms_category cat,
struct weston_surface *surface,
......
......@@ -61,14 +61,14 @@ struct cmlcms_color_profile {
cmsHPROFILE profile;
struct cmlcms_md5_sum md5sum;
/**
* If the profile does support being an output profile and it is used as an
* output then this field represents a light linearizing transfer function
* and it can not be null. The field is null only if the profile is not
* usable as an output profile. The field is set when cmlcms_color_profile
* is created.
/** The curves to decode an electrical signal
*
* For ICC profiles, if the profile type is matrix-shaper, then eotf
* contains the TRC, otherwise eotf contains an approximated EOTF if the
* profile is used for output.
* The field may be populated on demand.
*/
cmsToneCurve *output_eotf[3];
cmsToneCurve *eotf[3];
/**
* If the profile does support being an output profile and it is used as an
......@@ -114,6 +114,9 @@ enum cmlcms_category {
CMLCMS_CATEGORY_INPUT_TO_OUTPUT,
};
const char *
cmlcms_category_name(enum cmlcms_category cat);
static inline struct cmlcms_color_profile *
get_cprof(struct weston_color_profile *cprof_base)
{
......@@ -147,15 +150,46 @@ struct cmlcms_color_transform {
struct cmlcms_color_transform_search_param search_key;
/*
* Cached data in case weston_color_transform needs them.
* Pre-curve and post-curve refer to the weston_color_transform
* pipeline elements and have no semantic meaning. They both are a
* result of optimizing an arbitrary LittleCMS pipeline, not
* e.g. EOTF or VCGT per se.
*/
cmsToneCurve *pre_curve[3];
cmsToneCurve *post_curve[3];
/**
* 3D LUT color mapping part of the transformation, if needed.
* For category CMLCMS_CATEGORY_INPUT_TO_OUTPUT it includes pre-curve and
* post-curve.
* For category CMLCMS_CATEGORY_INPUT_TO_BLEND it includes pre-curve.
* For category CMLCMS_CATEGORY_BLEND_TO_OUTPUT and when identity it is
* not used
* 3D LUT color mapping part of the transformation, if needed by the
* weston_color_transform. This is used as a fallback when an
* arbitrary LittleCMS pipeline cannot be translated into a more
* specific form.
*/
cmsHTRANSFORM cmap_3dlut;
/**
* Certain categories of transformations need their own LittleCMS
* contexts in order to use our LittleCMS plugin.
*/
cmsContext lcms_ctx;
/**
* The result of pipeline construction, optimization, and analysis.
*/
enum {
/** Error producing a pipeline */
CMLCMS_TRANSFORM_FAILED = 0,
/**
* Pipeline was optimized into weston_color_transform,
* 3D LUT not used.
*/
CMLCMS_TRANSFORM_OPTIMIZED,
/** The transformation uses 3D LUT. */
CMLCMS_TRANSFORM_3DLUT,
} status;
};
static inline struct cmlcms_color_transform *
......@@ -194,4 +228,8 @@ retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
unsigned int
cmlcms_reasonable_1D_points(void);
cmsToneCurve *
lcmsJoinToneCurve(cmsContext context_id, const cmsToneCurve *X,
const cmsToneCurve *Y, unsigned int resulting_points);
#endif /* WESTON_COLOR_LCMS_H */
......@@ -148,7 +148,7 @@ release:
* LCMS API cmsJoinToneCurve does y = Y^-1(X(t)),
* but want to have y = Y^(X(t))
*/
static cmsToneCurve *
cmsToneCurve *
lcmsJoinToneCurve(cmsContext context_id, const cmsToneCurve *X,
const cmsToneCurve *Y, unsigned int resulting_points)
{
......@@ -324,7 +324,7 @@ cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
{
wl_list_remove(&cprof->link);
cmsFreeToneCurveTriple(cprof->vcgt);
cmsFreeToneCurveTriple(cprof->output_eotf);
cmsFreeToneCurveTriple(cprof->eotf);
cmsFreeToneCurveTriple(cprof->output_inv_eotf_vcgt);
cmsCloseProfile(cprof->profile);
free(cprof->base.description);
......@@ -402,7 +402,7 @@ cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm)
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
cm->sRGB_profile->profile,
cm->sRGB_profile->output_eotf,
cm->sRGB_profile->eotf,
cm->sRGB_profile->output_inv_eotf_vcgt,
cm->sRGB_profile->vcgt,
cmlcms_reasonable_1D_points()))
......
This diff is collapsed.
......@@ -106,6 +106,9 @@ enum weston_color_mapping_type {
/** 3D-dimensional look-up table */
WESTON_COLOR_MAPPING_TYPE_3D_LUT,
/** matrix */
WESTON_COLOR_MAPPING_TYPE_MATRIX,
};
/**
......@@ -155,6 +158,13 @@ struct weston_color_mapping_3dlut {
unsigned optimal_len;
};
/**
* A 3x3 matrix and data is arranged as column major
*/
struct weston_color_mapping_matrix {
float matrix[9];
};
/**
* Color mapping function
*
......@@ -169,6 +179,7 @@ struct weston_color_mapping {
union {
/* identity: no parameters */
struct weston_color_mapping_3dlut lut3d;
struct weston_color_mapping_matrix mat;
} u;
};
......@@ -201,7 +212,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;
};
/**
......
......@@ -50,6 +50,7 @@
/* enum gl_shader_color_mapping */
#define SHADER_COLOR_MAPPING_IDENTITY 0
#define SHADER_COLOR_MAPPING_3DLUT 1
#define SHADER_COLOR_MAPPING_MATRIX 2
#if DEF_VARIANT == SHADER_VARIANT_EXTERNAL
#extension GL_OES_EGL_image_external : require
......@@ -76,10 +77,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,11 +126,14 @@ 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;
uniform HIGHPRECISION vec2 color_mapping_lut_scale_offset;
#endif
uniform HIGHPRECISION mat3 color_mapping_matrix;
vec4
sample_input_texture()
......@@ -242,10 +248,39 @@ color_mapping(vec3 color)
return color;
else if (c_color_mapping == SHADER_COLOR_MAPPING_3DLUT)
return sample_color_mapping_lut_3d(color);
else if (c_color_mapping == SHADER_COLOR_MAPPING_MATRIX)
return color_mapping_matrix * color.rgb;
else /* Never reached, bad c_color_mapping. */
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 +294,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;
}
......
......@@ -61,6 +61,7 @@ enum gl_shader_color_curve {
enum gl_shader_color_mapping {
SHADER_COLOR_MAPPING_IDENTITY = 0,
SHADER_COLOR_MAPPING_3DLUT,
SHADER_COLOR_MAPPING_MATRIX,
};
/** GL shader requirements key
......@@ -79,12 +80,13 @@ struct gl_shader_requirements
bool green_tint:1;
unsigned color_pre_curve:1; /* enum gl_shader_color_curve */
unsigned color_mapping:1; /* enum gl_shader_color_mapping */
unsigned color_mapping:2; /* 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_:22;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
......@@ -109,7 +111,10 @@ struct gl_shader_config {
GLuint tex;
GLfloat scale_offset[2];
} lut3d;
GLfloat matrix[9];
} color_mapping;
GLuint color_post_curve_lut_tex;
GLfloat color_post_curve_lut_scale_offset[2];
};
struct gl_renderer {
......
......@@ -30,6 +30,7 @@
#include <GLES2/gl2ext.h>
#include <assert.h>
#include <string.h>
#include <libweston/libweston.h>
#include "color.h"
......@@ -53,6 +54,7 @@ struct gl_renderer_color_mapping {
float scale;
float offset;
} lut3d;
struct weston_color_mapping_matrix mat;
};
} ;
......@@ -61,6 +63,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 +85,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 +145,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 +229,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;
......@@ -265,6 +275,25 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform)
case WESTON_COLOR_MAPPING_TYPE_3D_LUT:
ok = gl_3d_lut(gl_xform, xform);
break;
case WESTON_COLOR_MAPPING_TYPE_MATRIX:
gl_xform->mapping.type = SHADER_COLOR_MAPPING_MATRIX;
gl_xform->mapping.mat = xform->mapping.u.mat;
ok = true;
break;
}
if (!ok) {
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);
......@@ -290,6 +319,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:
......@@ -302,6 +336,11 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf,
assert(sconf->color_mapping.lut3d.scale_offset[1] > 0.0);
ret = true;
break;
case SHADER_COLOR_MAPPING_MATRIX:
assert(sconf->req.color_mapping == SHADER_COLOR_MAPPING_MATRIX);
ARRAY_COPY(sconf->color_mapping.matrix, gl_xform->mapping.mat.matrix);
ret = true;
break;
case SHADER_COLOR_MAPPING_IDENTITY:
ret = true;
break;
......
......@@ -66,7 +66,10 @@ struct gl_shader {
GLint tex_uniform;
GLint scale_offset_uniform;
} lut3d;
GLint matrix_uniform;
} 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;
};
......@@ -111,6 +114,7 @@ gl_shader_color_mapping_to_string(enum gl_shader_color_mapping kind)
#define CASERET(x) case x: return #x;
CASERET(SHADER_COLOR_MAPPING_IDENTITY)
CASERET(SHADER_COLOR_MAPPING_3DLUT)
CASERET(SHADER_COLOR_MAPPING_MATRIX)
#undef CASERET
}
......@@ -182,10 +186,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 +209,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,12 +298,24 @@ 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 =
glGetUniformLocation(shader->program, "color_mapping_lut_3d");
glGetUniformLocation(shader->program,
"color_mapping_lut_3d");
shader->color_mapping.lut3d.scale_offset_uniform =
glGetUniformLocation(shader->program,"color_mapping_lut_scale_offset");
glGetUniformLocation(shader->program,
"color_mapping_lut_scale_offset");
break;
case SHADER_COLOR_MAPPING_MATRIX:
shader->color_mapping.matrix_uniform =
glGetUniformLocation(shader->program,
"color_mapping_matrix");
break;
case SHADER_COLOR_MAPPING_IDENTITY:
break;
......@@ -410,6 +429,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,11 +580,32 @@ 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;
default:
assert(false);
case SHADER_COLOR_MAPPING_MATRIX:
assert(shader->color_mapping.matrix_uniform != -1);
glUniformMatrix3fv(shader->color_mapping.matrix_uniform,
1, GL_FALSE,
sconf->color_mapping.matrix);
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;
}
}
......
......@@ -530,7 +530,7 @@ process_pipeline_comparison(const struct buffer *src_buf,
*
* weston_plot_rgb_diff_stat('opaque_pixel_conversion-f05-dump.txt')
*/
dump = fopen_dump_file("dump");
dump = fopen_dump_file(arg->meta.name);
#endif
struct image_header ih_src = image_header_from(src_buf->image);
......@@ -693,7 +693,7 @@ check_blend_pattern(struct buffer *bg_buf,
*
* weston_plot_rgb_diff_stat('output_icc_alpha_blend-f01-dump.txt', 255, 8)
*/
dump = fopen_dump_file("dump");
dump = fopen_dump_file(arg->meta.name);
#endif
uint32_t *bg_row = get_middle_row(bg_buf);
......