color: add get_color_profile_from_params() to color managers

Add function to color managers to create color profiles from parameters.
This will be used by the parametric color profile builder that we'll add
in the next commit.

WARNING: we still do not fully support creating color profiles from
parameters. This just creates a boilerplate color profile that we're
planning to extend later.

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
Leandro Ribeiro 2024-02-22 10:22:37 -03:00
parent 89a57c7b10
commit 93d086f068
6 changed files with 221 additions and 11 deletions

View File

@ -491,6 +491,7 @@ weston_color_manager_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmlcms_destroy_color_profile; cm->base.destroy_color_profile = cmlcms_destroy_color_profile;
cm->base.ref_stock_sRGB_color_profile = cmlcms_ref_stock_sRGB_color_profile; cm->base.ref_stock_sRGB_color_profile = cmlcms_ref_stock_sRGB_color_profile;
cm->base.get_color_profile_from_icc = cmlcms_get_color_profile_from_icc; cm->base.get_color_profile_from_icc = cmlcms_get_color_profile_from_icc;
cm->base.get_color_profile_from_params = cmlcms_get_color_profile_from_params;
cm->base.send_image_desc_info = cmlcms_send_image_desc_info; cm->base.send_image_desc_info = cmlcms_send_image_desc_info;
cm->base.destroy_color_transform = cmlcms_destroy_color_transform; cm->base.destroy_color_transform = cmlcms_destroy_color_transform;
cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform; cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform;

View File

@ -93,8 +93,17 @@ struct cmlcms_output_profile_extract {
struct lcmsProfilePtr vcgt; struct lcmsProfilePtr vcgt;
}; };
/**
* Profile type, based on what was used to create it.
*/
enum cmlcms_profile_type {
CMLCMS_PROFILE_TYPE_ICC = 0, /* created with ICC profile. */
CMLCMS_PROFILE_TYPE_PARAMS, /* created with color parameters. */
};
struct cmlcms_color_profile { struct cmlcms_color_profile {
struct weston_color_profile base; struct weston_color_profile base;
enum cmlcms_profile_type type;
/* struct weston_color_manager_lcms::color_profile_list */ /* struct weston_color_manager_lcms::color_profile_list */
struct wl_list link; struct wl_list link;
@ -102,9 +111,12 @@ struct cmlcms_color_profile {
struct lcmsProfilePtr profile; struct lcmsProfilePtr profile;
struct cmlcms_md5_sum md5sum; struct cmlcms_md5_sum md5sum;
/* Only for profiles created from an ICC file. */ /* Only for CMLCMS_PROFILE_TYPE_ICC */
struct ro_anonymous_file *prof_rofile; struct ro_anonymous_file *prof_rofile;
/* Only for CMLCMS_PROFILE_TYPE_PARAMS */
struct weston_color_profile_params *params;
/* Populated only when profile used as output profile */ /* Populated only when profile used as output profile */
struct cmlcms_output_profile_extract extract; struct cmlcms_output_profile_extract extract;
}; };
@ -153,6 +165,13 @@ cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm,
struct weston_color_profile **cprof_out, struct weston_color_profile **cprof_out,
char **errmsg); char **errmsg);
bool
cmlcms_get_color_profile_from_params(struct weston_color_manager *cm_base,
const struct weston_color_profile_params *params,
const char *name_part,
struct weston_color_profile **cprof_out,
char **errmsg);
bool bool
cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info,
struct weston_color_profile *cprof_base); struct weston_color_profile *cprof_base);

View File

@ -285,17 +285,28 @@ ensure_output_profile_extract(struct cmlcms_color_profile *cprof,
unsigned int num_points, unsigned int num_points,
const char **err_msg) const char **err_msg)
{ {
struct weston_compositor *compositor = cprof->base.cm->compositor;
bool ret; bool ret;
/* Everything already computed */ /* Everything already computed */
if (cprof->extract.eotf.p) if (cprof->extract.eotf.p)
return true; return true;
ret = ensure_output_profile_extract_icc(&cprof->extract, lcms_ctx, switch (cprof->type) {
cprof->profile, num_points, err_msg); case CMLCMS_PROFILE_TYPE_ICC:
ret = ensure_output_profile_extract_icc(&cprof->extract, lcms_ctx,
if (ret) cprof->profile, num_points,
weston_assert_ptr(cprof->base.cm->compositor, cprof->extract.eotf.p); err_msg);
if (ret)
weston_assert_ptr(compositor, cprof->extract.eotf.p);
break;
case CMLCMS_PROFILE_TYPE_PARAMS:
/* TODO: need to address this when we create param profiles. */
ret = false;
break;
default:
weston_assert_not_reached(compositor, "unknown profile type");
}
return ret; return ret;
} }
@ -337,6 +348,9 @@ cmlcms_find_color_profile_by_md5(const struct weston_color_manager_lcms *cm,
struct cmlcms_color_profile *cprof; struct cmlcms_color_profile *cprof;
wl_list_for_each(cprof, &cm->color_profile_list, link) { wl_list_for_each(cprof, &cm->color_profile_list, link) {
if (cprof->type != CMLCMS_PROFILE_TYPE_ICC)
continue;
if (memcmp(cprof->md5sum.bytes, if (memcmp(cprof->md5sum.bytes,
md5sum->bytes, sizeof(md5sum->bytes)) == 0) md5sum->bytes, sizeof(md5sum->bytes)) == 0)
return cprof; return cprof;
@ -345,11 +359,42 @@ cmlcms_find_color_profile_by_md5(const struct weston_color_manager_lcms *cm,
return NULL; return NULL;
} }
static struct cmlcms_color_profile *
cmlcms_find_color_profile_by_params(const struct weston_color_manager_lcms *cm,
const struct weston_color_profile_params *params)
{
struct cmlcms_color_profile *cprof;
/* Ensure no uninitialized data inside struct to make memcmp work. */
static_assert(sizeof(*params) ==
2 * sizeof(float) * 2 * 4 + /* primaries, target_primaries */
sizeof(params->primaries_info) +
sizeof(params->tf_info) +
sizeof(params->tf_params) +
sizeof(params->min_luminance) +
sizeof(params->max_luminance) +
sizeof(params->maxCLL) +
sizeof(params->maxFALL),
"struct weston_color_profile_params must not contain implicit padding");
wl_list_for_each(cprof, &cm->color_profile_list, link) {
if (cprof->type != CMLCMS_PROFILE_TYPE_PARAMS)
continue;
if (memcmp(cprof->params, params, sizeof(*params)) == 0)
return cprof;
}
return NULL;
}
char * char *
cmlcms_color_profile_print(const struct cmlcms_color_profile *cprof) cmlcms_color_profile_print(const struct cmlcms_color_profile *cprof)
{ {
char *str; char *str;
/* TODO: also print cprof->params for parametric profiles. */
str_printf(&str, " description: %s\n", cprof->base.description); str_printf(&str, " description: %s\n", cprof->base.description);
abort_oom_if_null(str); abort_oom_if_null(str);
@ -394,11 +439,25 @@ cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
cmsCloseProfile(cprof->extract.vcgt.p); cmsCloseProfile(cprof->extract.vcgt.p);
cmsCloseProfile(cprof->extract.inv_eotf.p); cmsCloseProfile(cprof->extract.inv_eotf.p);
cmsCloseProfile(cprof->extract.eotf.p); cmsCloseProfile(cprof->extract.eotf.p);
cmsCloseProfile(cprof->profile.p);
/* Only profiles created from ICC files have these. */ switch (cprof->type) {
if (cprof->prof_rofile) case CMLCMS_PROFILE_TYPE_ICC:
os_ro_anonymous_file_destroy(cprof->prof_rofile); cmsCloseProfile(cprof->profile.p);
/**
* TODO: drop this if when we convert the stock sRGB profile to
* a parametric one. When we do that, all ICC profiles will have
* their ro_anonymous_file, so we won't have to check.
*/
if (cprof->prof_rofile)
os_ro_anonymous_file_destroy(cprof->prof_rofile);
break;
case CMLCMS_PROFILE_TYPE_PARAMS:
free(cprof->params);
break;
default:
weston_assert_not_reached(cm->base.compositor,
"unknown profile type");
}
weston_log_scope_printf(cm->profiles_scope, "Destroyed color profile p%u. " \ weston_log_scope_printf(cm->profiles_scope, "Destroyed color profile p%u. " \
"Description: %s\n", cprof->base.id, cprof->base.description); "Description: %s\n", cprof->base.id, cprof->base.description);
@ -477,6 +536,8 @@ cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm)
if (!cm->sRGB_profile) if (!cm->sRGB_profile)
goto err_close; goto err_close;
cm->sRGB_profile->type = CMLCMS_PROFILE_TYPE_ICC;
if (!ensure_output_profile_extract(cm->sRGB_profile, cm->lcms_ctx, if (!ensure_output_profile_extract(cm->sRGB_profile, cm->lcms_ctx,
cmlcms_reasonable_1D_points(), &err_msg)) cmlcms_reasonable_1D_points(), &err_msg))
goto err_close; goto err_close;
@ -556,6 +617,8 @@ cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm_base,
if (!cprof) if (!cprof)
goto err_close; goto err_close;
cprof->type = CMLCMS_PROFILE_TYPE_ICC;
cprof->prof_rofile = os_ro_anonymous_file_create(icc_len, icc_data); cprof->prof_rofile = os_ro_anonymous_file_create(icc_len, icc_data);
if (!cprof->prof_rofile) if (!cprof->prof_rofile)
goto err_close; goto err_close;
@ -571,6 +634,62 @@ err_close:
return false; return false;
} }
bool
cmlcms_get_color_profile_from_params(struct weston_color_manager *cm_base,
const struct weston_color_profile_params *params,
const char *name_part,
struct weston_color_profile **cprof_out,
char **errmsg)
{
struct weston_color_manager_lcms *cm = to_cmlcms(cm_base);
struct cmlcms_color_profile *cprof;
char *desc;
char *str;
/* TODO: add a helper similar to cmlcms_color_profile_create() but for
* parametric color profiles. For now this just creates a cprof
* boilerplate, just to help us to imagine how things would work.
*
* The color profile that this function creates is invalid and we won't
* be able to do anything useful with that.
*/
cprof = cmlcms_find_color_profile_by_params(cm, params);
if (cprof) {
*cprof_out = weston_color_profile_ref(&cprof->base);
return true;
}
cprof = xzalloc(sizeof(*cprof));
cprof->type = CMLCMS_PROFILE_TYPE_PARAMS;
cprof->params = xzalloc(sizeof(*cprof->params));
memcpy(cprof->params, params, sizeof(*params));
str_printf(&desc, "Parametric (%s): %s, %s",
name_part,
params->primaries_info ? params->primaries_info->desc :
"custom primaries",
params->tf_info->desc);
weston_color_profile_init(&cprof->base, &cm->base);
cprof->base.description = desc;
wl_list_insert(&cm->color_profile_list, &cprof->link);
weston_log_scope_printf(cm->profiles_scope,
"New color profile: p%u. WARNING: this is a " \
"boilerplate color profile. We still do not fully " \
"support creating color profiles from params\n",
cprof->base.id);
str = cmlcms_color_profile_print(cprof);
weston_log_scope_printf(cm->profiles_scope, "%s", str);
free(str);
*cprof_out = &cprof->base;
return true;
}
bool bool
cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info,
struct weston_color_profile *cprof_base) struct weston_color_profile *cprof_base)
@ -583,7 +702,13 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info,
int32_t fd; int32_t fd;
uint32_t len; uint32_t len;
if (cprof->prof_rofile) { /**
* TODO: when we convert the stock sRGB profile to a parametric profile
* instead of an ICC one, we'll be able to change the if/else below to
* a switch/case.
*/
if (cprof->type == CMLCMS_PROFILE_TYPE_ICC && cprof != cm->sRGB_profile) {
/* ICC-based color profile, so just send the ICC file fd. If we /* ICC-based color profile, so just send the ICC file fd. If we
* get an error (negative fd), the helper will send the proper * get an error (negative fd), the helper will send the proper
* error to the client. */ * error to the client. */

View File

@ -1225,6 +1225,12 @@ xform_realize_chain(struct cmlcms_color_transform *xform)
struct lcmsProfilePtr extra = { NULL }; struct lcmsProfilePtr extra = { NULL };
cmsUInt32Number dwFlags; cmsUInt32Number dwFlags;
/* TODO: address this when we implement param color profiles.*/
if (output_profile->type == CMLCMS_PROFILE_TYPE_PARAMS ||
(xform->search_key.input_profile &&
xform->search_key.input_profile->type == CMLCMS_PROFILE_TYPE_PARAMS))
return false;
render_intent = xform->search_key.render_intent; render_intent = xform->search_key.render_intent;
/* /*

View File

@ -135,6 +135,17 @@ cmnoop_get_color_profile_from_icc(struct weston_color_manager *cm,
return false; return false;
} }
static bool
cmnoop_get_color_profile_from_params(struct weston_color_manager *cm,
const struct weston_color_profile_params *params,
const char *name_part,
struct weston_color_profile **cprof_out,
char **errmsg)
{
*errmsg = xstrdup("parametric profiles are unsupported.");
return false;
}
static void static void
cmnoop_destroy_color_transform(struct weston_color_transform *xform) cmnoop_destroy_color_transform(struct weston_color_transform *xform)
{ {
@ -256,6 +267,7 @@ weston_color_manager_noop_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmnoop_destroy_color_profile; cm->base.destroy_color_profile = cmnoop_destroy_color_profile;
cm->base.ref_stock_sRGB_color_profile = cmnoop_ref_stock_sRGB_color_profile; cm->base.ref_stock_sRGB_color_profile = cmnoop_ref_stock_sRGB_color_profile;
cm->base.get_color_profile_from_icc = cmnoop_get_color_profile_from_icc; cm->base.get_color_profile_from_icc = cmnoop_get_color_profile_from_icc;
cm->base.get_color_profile_from_params = cmnoop_get_color_profile_from_params;
cm->base.send_image_desc_info = NULL; cm->base.send_image_desc_info = NULL;
cm->base.destroy_color_transform = cmnoop_destroy_color_transform; cm->base.destroy_color_transform = cmnoop_destroy_color_transform;
cm->base.get_surface_color_transform = cmnoop_get_surface_color_transform; cm->base.get_surface_color_transform = cmnoop_get_surface_color_transform;

View File

@ -127,6 +127,30 @@ struct weston_color_profile {
uint32_t id; uint32_t id;
}; };
/** Parameters that define a parametric color profile */
struct weston_color_profile_params {
/* Primary color volume; always set. */
struct weston_color_gamut primaries;
/* Primary color volume by enumeration; optional, may be NULL. */
const struct weston_color_primaries_info *primaries_info;
/* Encoding transfer characteristic by enumeration; always set. */
const struct weston_color_tf_info *tf_info;
/* Transfer characteristic's parameters; depends on tf_info. */
float tf_params[10];
/* Target color volume; always set. */
struct weston_color_gamut target_primaries;
/* Luminance parameters cd/m²; negative when not set */
float min_luminance, max_luminance;
float maxCLL;
float maxFALL;
};
/** Type or formula for a curve */ /** Type or formula for a curve */
enum weston_color_curve_type { enum weston_color_curve_type {
/** Identity function, no-op */ /** Identity function, no-op */
@ -471,6 +495,29 @@ struct weston_color_manager {
struct weston_color_profile **cprof_out, struct weston_color_profile **cprof_out,
char **errmsg); char **errmsg);
/** Create a color profile from parameters
*
* \param cm The color manager.
* \param params The struct weston_color_profile_params with the params.
* \param name_part A string to be used in describing the profile.
* \param cprof_out On success, the created object is returned here.
* On failure, untouched.
* \param errmsg On success, untouched. On failure, a pointer to a
* string describing the error is stored here. The string must be
* free()'d.
* \return True on success, false on failure.
*
* This may return a new reference to an existing color profile if
* that profile is identical to the one that would be created, apart
* from name_part.
*/
bool
(*get_color_profile_from_params)(struct weston_color_manager *cm,
const struct weston_color_profile_params *params,
const char *name_part,
struct weston_color_profile **cprof_out,
char **errmsg);
/** Send image description to clients. /** Send image description to clients.
* *
* \param cm_image_desc_info The image description info object * \param cm_image_desc_info The image description info object