mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-06 04:28:24 +02:00
Merge branch 'mr/parametric-srgb' into 'main'
Switch the default sRGB profile from ICC to parametric See merge request wayland/weston!1954
This commit is contained in:
commit
c427e4d258
12 changed files with 297 additions and 215 deletions
|
|
@ -2110,13 +2110,7 @@ wet_output_set_color_profile(struct weston_output *output,
|
|||
} else if (parent_winsys_profile) {
|
||||
cprof = weston_color_profile_ref(parent_winsys_profile);
|
||||
} else {
|
||||
/*
|
||||
* TODO: Once parametric color profiles are fully supported
|
||||
* and interoperable with ICC profiles, the default profile
|
||||
* would be created like this:
|
||||
* cprof = wet_create_output_color_profile(output, wc, "auto:");
|
||||
*/
|
||||
return 0;
|
||||
cprof = wet_create_output_color_profile(output, wc, "auto:");
|
||||
}
|
||||
|
||||
if (!cprof)
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ join_powerlaw_curvesets(cmsContext context_id,
|
|||
ret = cmsStageAllocToneCurves(context_id, ARRAY_LENGTH(arr), arr);
|
||||
abort_oom_if_null(ret);
|
||||
cmsFreeToneCurveTriple(arr);
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -573,6 +573,56 @@ curveset_print(cmsStage *stage, struct weston_log_scope *scope)
|
|||
}
|
||||
}
|
||||
|
||||
static const cmsCurveSegment *
|
||||
get_defining_curve_segment(cmsToneCurve *from, bool *clamped_input)
|
||||
{
|
||||
const cmsCurveSegment *seg0, *seg1, *seg2;
|
||||
|
||||
/* We handle curves with 1 or 3 segments. No more, no less. */
|
||||
seg0 = cmsGetToneCurveSegment(0, from);
|
||||
seg1 = cmsGetToneCurveSegment(1, from);
|
||||
seg2 = cmsGetToneCurveSegment(2, from);
|
||||
if (seg0 && !seg1) {
|
||||
/* Case 1: we have a single segment (seg0). */
|
||||
|
||||
/* If the domain is (-inf, inf), the curve is unbounded. */
|
||||
if (are_segment_breaks_equal(seg0->x0, -INFINITY) &&
|
||||
are_segment_breaks_equal(seg0->x1, INFINITY)) {
|
||||
*clamped_input = false;
|
||||
return seg0;
|
||||
}
|
||||
|
||||
/* If the domain is [0.0, 1.0], the curve is bounded. */
|
||||
if (are_segment_breaks_equal(seg0->x0, 0.0) &&
|
||||
are_segment_breaks_equal(seg0->x1, 1.0)) {
|
||||
*clamped_input = true;
|
||||
return seg0;
|
||||
}
|
||||
|
||||
/* We don't handle anything else. */
|
||||
return NULL;
|
||||
} else if (seg0 && seg1 && seg2) {
|
||||
/* Case 2: we have three segments. Clamped input.
|
||||
*
|
||||
* Ensure that the domain breaks are (-inf, 0.0],
|
||||
* (0.0, 1.0] and (1.0, inf].
|
||||
*/
|
||||
if (!are_segment_breaks_equal(seg0->x0, -INFINITY) ||
|
||||
!are_segment_breaks_equal(seg0->x1, 0.0) ||
|
||||
!are_segment_breaks_equal(seg1->x0, 0.0) ||
|
||||
!are_segment_breaks_equal(seg1->x1, 1.0) ||
|
||||
!are_segment_breaks_equal(seg2->x0, 1.0) ||
|
||||
!are_segment_breaks_equal(seg2->x1, INFINITY))
|
||||
return NULL;
|
||||
*clamped_input = true;
|
||||
return seg1;
|
||||
} else {
|
||||
/* Neither 1 or 3 segments. So we don't define the
|
||||
* curveset as parametric. */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
get_parametric_curveset_params(struct weston_compositor *compositor,
|
||||
_cmsStageToneCurvesData *trc_data,
|
||||
|
|
@ -580,7 +630,7 @@ get_parametric_curveset_params(struct weston_compositor *compositor,
|
|||
float curveset_params[3][MAX_PARAMS_LCMS_PARAM_CURVE],
|
||||
bool *clamped_input)
|
||||
{
|
||||
const cmsCurveSegment *seg, *seg0, *seg1, *seg2;
|
||||
const cmsCurveSegment *seg;
|
||||
cmsInt32Number curve_types[3];
|
||||
unsigned int i, j;
|
||||
|
||||
|
|
@ -596,44 +646,18 @@ get_parametric_curveset_params(struct weston_compositor *compositor,
|
|||
*clamped_input = false;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* We handle curves with 1 or 3 segments. No more, no less. */
|
||||
seg0 = cmsGetToneCurveSegment(0, trc_data->TheCurves[i]);
|
||||
seg1 = cmsGetToneCurveSegment(1, trc_data->TheCurves[i]);
|
||||
seg2 = cmsGetToneCurveSegment(2, trc_data->TheCurves[i]);
|
||||
bool clamp_this;
|
||||
|
||||
if (seg0 && !seg1) {
|
||||
/* Case 1: we have a single segment (seg0).
|
||||
*
|
||||
* Ensure that the domain is (-inf, inf) and that the
|
||||
* seg type is not 0 (the type of sampled segments).
|
||||
*/
|
||||
if (!are_segment_breaks_equal(seg0->x0, -INFINITY) ||
|
||||
!are_segment_breaks_equal(seg0->x1, INFINITY) ||
|
||||
seg0->Type == 0)
|
||||
return false;
|
||||
seg = seg0;
|
||||
} else if (seg0 && seg1 && seg2) {
|
||||
/* Case 2: we have three segments. Clamped input.
|
||||
*
|
||||
* Ensure that the domain breaks are (-inf, 0.0],
|
||||
* (0.0, 1.0] and (1.0, inf] and that the 2nd segment
|
||||
* type is not 0 (the type of sampled segments).
|
||||
*/
|
||||
if (!are_segment_breaks_equal(seg0->x0, -INFINITY) ||
|
||||
!are_segment_breaks_equal(seg0->x1, 0.0) ||
|
||||
!are_segment_breaks_equal(seg1->x0, 0.0) ||
|
||||
!are_segment_breaks_equal(seg1->x1, 1.0) ||
|
||||
!are_segment_breaks_equal(seg2->x0, 1.0) ||
|
||||
!are_segment_breaks_equal(seg2->x1, INFINITY) ||
|
||||
seg1->Type == 0)
|
||||
return false;
|
||||
seg = seg1;
|
||||
*clamped_input = true;
|
||||
} else {
|
||||
/* Neither 1 or 3 segments. So we don't define the
|
||||
* curveset as parametric. */
|
||||
seg = get_defining_curve_segment(trc_data->TheCurves[i], &clamp_this);
|
||||
if (!seg)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Reject tabulated (LUT) segments. */
|
||||
if (seg->Type == 0)
|
||||
return false;
|
||||
|
||||
if (clamp_this)
|
||||
*clamped_input = true;
|
||||
|
||||
/* Copy the type and params from the segment that matters. We
|
||||
* don't use memcpy because we need to cast each cmsFloat64Number
|
||||
|
|
@ -652,3 +676,58 @@ get_parametric_curveset_params(struct weston_compositor *compositor,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Create a matrix stage equivalent to the CurveSet stage.
|
||||
*
|
||||
* A tabulated curve segment with 2 samples is equivalent to a matrix
|
||||
* (scaling and offset), ignoring possible input clamping and allowing
|
||||
* extrapolation.
|
||||
*
|
||||
* \param context_id The matrix stage is created in this context.
|
||||
* \param stage An arbitrary stage, can be NULL.
|
||||
* \return A new matrix stage equivalent to the given (CurveSet) stage, or
|
||||
* NULL otherwise.
|
||||
*/
|
||||
cmsStage *
|
||||
lcms_matrix_stage_from_curve(cmsContext context_id, cmsStage *stage)
|
||||
{
|
||||
const _cmsStageToneCurvesData *data;
|
||||
cmsFloat64Number Matrix[3 * 3] = {}; /* row-major */
|
||||
cmsFloat64Number Offset[3];
|
||||
unsigned i;
|
||||
|
||||
if (!stage || cmsStageType(stage) != cmsSigCurveSetElemType)
|
||||
return NULL;
|
||||
|
||||
data = cmsStageData(stage);
|
||||
if (data->nCurves != 3)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
const cmsCurveSegment *seg;
|
||||
bool clamped_input;
|
||||
double y0, y1, k;
|
||||
|
||||
seg = get_defining_curve_segment(data->TheCurves[i], &clamped_input);
|
||||
if (!seg)
|
||||
return NULL;
|
||||
|
||||
/* Type 0 is tabulated. */
|
||||
if (seg->Type != 0)
|
||||
return NULL;
|
||||
|
||||
if (seg->nGridPoints != 2)
|
||||
return NULL;
|
||||
|
||||
y0 = seg->SampledPoints[0];
|
||||
y1 = seg->SampledPoints[1];
|
||||
|
||||
/* y = k * x + Offset */
|
||||
|
||||
k = (y1 - y0) / (seg->x1 - seg->x0);
|
||||
Offset[i] = y0 - k * seg->x0;
|
||||
Matrix[3 * i + i] = k;
|
||||
}
|
||||
|
||||
return cmsStageAllocMatrix(context_id, 3, 3, Matrix, Offset);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ get_parametric_curveset_params(struct weston_compositor *compositor,
|
|||
float curveset_params[3][MAX_PARAMS_LCMS_PARAM_CURVE],
|
||||
bool *clamped_input);
|
||||
|
||||
cmsStage *
|
||||
lcms_matrix_stage_from_curve(cmsContext context_id, cmsStage *stage);
|
||||
|
||||
void
|
||||
curveset_print(cmsStage *stage, struct weston_log_scope *scope);
|
||||
|
||||
|
|
@ -64,6 +67,12 @@ get_parametric_curveset_params(struct weston_compositor *compositor,
|
|||
return false;
|
||||
}
|
||||
|
||||
cmsStage *
|
||||
lcms_matrix_stage_from_curve(cmsContext ContextID, cmsStage *stage)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
curveset_print(cmsStage *stage, struct weston_log_scope *scope)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -429,19 +429,13 @@ cmlcms_init(struct weston_color_manager *cm_base)
|
|||
|
||||
cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger);
|
||||
|
||||
if (!cmlcms_create_stock_profile(cm)) {
|
||||
weston_log("color-lcms: error: cmlcms_create_stock_profile failed\n");
|
||||
goto out_err;
|
||||
}
|
||||
cm->sRGB_profile = cmlcms_create_stock_profile(cm);
|
||||
|
||||
weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion());
|
||||
|
||||
return true;
|
||||
|
||||
out_err:
|
||||
if (cm->lcms_ctx)
|
||||
cmsDeleteContext(cm->lcms_ctx);
|
||||
cm->lcms_ctx = NULL;
|
||||
|
||||
weston_log_scope_destroy(cm->transforms_scope);
|
||||
cm->transforms_scope = NULL;
|
||||
weston_log_scope_destroy(cm->optimizer_scope);
|
||||
|
|
@ -520,7 +514,6 @@ weston_color_manager_create(struct weston_compositor *compositor)
|
|||
cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform;
|
||||
cm->base.create_output_color_outcome = cmlcms_create_output_color_outcome;
|
||||
|
||||
/* We support all color features. */
|
||||
cm->base.supported_color_features = (1 << WESTON_COLOR_FEATURE_ICC) |
|
||||
(1 << WESTON_COLOR_FEATURE_PARAMETRIC) |
|
||||
(1 << WESTON_COLOR_FEATURE_SET_PRIMARIES) |
|
||||
|
|
@ -529,14 +522,12 @@ weston_color_manager_create(struct weston_compositor *compositor)
|
|||
(1 << WESTON_COLOR_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES) |
|
||||
(1 << WESTON_COLOR_FEATURE_EXTENDED_TARGET_VOLUME);
|
||||
|
||||
/* We support all rendering intents. */
|
||||
cm->base.supported_rendering_intents = (1 << WESTON_RENDER_INTENT_PERCEPTUAL) |
|
||||
(1 << WESTON_RENDER_INTENT_SATURATION) |
|
||||
/* (1 << WESTON_RENDER_INTENT_SATURATION) | */
|
||||
(1 << WESTON_RENDER_INTENT_ABSOLUTE) |
|
||||
(1 << WESTON_RENDER_INTENT_RELATIVE) |
|
||||
(1 << WESTON_RENDER_INTENT_RELATIVE_BPC);
|
||||
|
||||
/* We support all primaries named. */
|
||||
cm->base.supported_primaries_named = (1 << WESTON_PRIMARIES_CICP_SRGB) |
|
||||
(1 << WESTON_PRIMARIES_CICP_PAL_M) |
|
||||
(1 << WESTON_PRIMARIES_CICP_PAL) |
|
||||
|
|
@ -548,18 +539,10 @@ weston_color_manager_create(struct weston_compositor *compositor)
|
|||
(1 << WESTON_PRIMARIES_CICP_DISPLAY_P3) |
|
||||
(1 << WESTON_PRIMARIES_ADOBE_RGB);
|
||||
|
||||
/**
|
||||
* TODO: this is a lie just to make the color-management-parametric
|
||||
* tests to work. Without this the tests would be much more limited. We
|
||||
* actually need to implement such TF's. There's no problem doing that,
|
||||
* as parametric color profiles themselves are still unsupported.
|
||||
*/
|
||||
|
||||
/* We need to implement each tf, and we support only a few of them. */
|
||||
cm->base.supported_tf_named = (1 << WESTON_TF_GAMMA22) |
|
||||
(1 << WESTON_TF_GAMMA28) |
|
||||
(1 << WESTON_TF_SRGB) |
|
||||
(1 << WESTON_TF_ST2084_PQ);
|
||||
(1 << WESTON_TF_ST2084_PQ) |
|
||||
(1 << WESTON_TF_EXT_LINEAR);
|
||||
|
||||
wl_list_init(&cm->color_transform_list);
|
||||
wl_list_init(&cm->color_profile_list);
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ ref_cprof(struct cmlcms_color_profile *cprof);
|
|||
void
|
||||
unref_cprof(struct cmlcms_color_profile *cprof);
|
||||
|
||||
bool
|
||||
struct cmlcms_color_profile *
|
||||
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm);
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -558,57 +558,36 @@ make_icc_file_description(struct lcmsProfilePtr profile,
|
|||
* BT.709 primaries with gamma-2.2 transfer characteristic. This is the
|
||||
* expected sRGB display response.
|
||||
*/
|
||||
bool
|
||||
struct cmlcms_color_profile *
|
||||
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm)
|
||||
{
|
||||
static const cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
|
||||
static const cmsCIExyYTRIPLE bt709 = {
|
||||
{ 0.6400, 0.3300, 1.0 },
|
||||
{ 0.3000, 0.6000, 1.0 },
|
||||
{ 0.1500, 0.0600, 1.0 }
|
||||
};
|
||||
cmsToneCurve *gamma22[3];
|
||||
struct lcmsProfilePtr profile = { NULL };
|
||||
struct cmlcms_md5_sum md5sum;
|
||||
struct weston_compositor *compositor = cm->base.compositor;
|
||||
struct weston_color_profile_params p = {};
|
||||
struct cmlcms_color_profile *stock;
|
||||
char *desc = NULL;
|
||||
const char *err_msg = NULL;
|
||||
|
||||
gamma22[0] = gamma22[1] = gamma22[2] = cmsBuildGamma(cm->lcms_ctx, 2.2);
|
||||
if (gamma22[0])
|
||||
profile.p = cmsCreateRGBProfileTHR(cm->lcms_ctx, &D65, &bt709, gamma22);
|
||||
cmsFreeToneCurve(gamma22[0]);
|
||||
if (!profile.p) {
|
||||
weston_log("color-lcms: error: failed to create stock sRGB profile.\n");
|
||||
return false;
|
||||
}
|
||||
if (!cmsMD5computeID(profile.p)) {
|
||||
weston_log("Failed to compute MD5 for stock sRGB profile.\n");
|
||||
goto err_close;
|
||||
}
|
||||
p.primaries_info = weston_color_primaries_info_from(compositor,
|
||||
WESTON_PRIMARIES_CICP_SRGB);
|
||||
p.primaries = p.primaries_info->color_gamut;
|
||||
p.tf.info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22);
|
||||
p.reference_white_luminance = 80.0;
|
||||
p.min_luminance = 0.2;
|
||||
p.max_luminance = 80.0;
|
||||
p.target_primaries = p.primaries;
|
||||
p.target_min_luminance = p.min_luminance;
|
||||
p.target_max_luminance = p.max_luminance;
|
||||
p.maxCLL = -1.0f;
|
||||
p.maxFALL = -1.0f;
|
||||
|
||||
cmsGetHeaderProfileID(profile.p, md5sum.bytes);
|
||||
desc = make_icc_file_description(profile, &md5sum, "sRGB stock");
|
||||
if (!desc)
|
||||
goto err_close;
|
||||
str_printf(&desc, "default sRGB: %s primaries, %s transfer function",
|
||||
p.primaries_info->desc, p.tf.info->desc);
|
||||
abort_oom_if_null(desc);
|
||||
|
||||
cm->sRGB_profile = cmlcms_color_profile_alloc(cm, CMLCMS_PROFILE_TYPE_ICC, desc);
|
||||
cm->sRGB_profile->icc.profile = profile;
|
||||
cm->sRGB_profile->icc.md5sum = md5sum;
|
||||
stock = cmlcms_color_profile_alloc(cm, CMLCMS_PROFILE_TYPE_PARAMS, desc);
|
||||
*stock->params = p;
|
||||
cmlcms_color_profile_register(stock);
|
||||
|
||||
if (!ensure_output_profile_extract(cm->sRGB_profile, cm->lcms_ctx,
|
||||
cmlcms_reasonable_1D_points(), &err_msg))
|
||||
goto err_close;
|
||||
|
||||
cmlcms_color_profile_register(cm->sRGB_profile);
|
||||
|
||||
return true;
|
||||
|
||||
err_close:
|
||||
if (err_msg)
|
||||
weston_log("%s\n", err_msg);
|
||||
|
||||
cmlcms_color_profile_destroy(cm->sRGB_profile);
|
||||
return false;
|
||||
return stock;
|
||||
}
|
||||
|
||||
struct weston_color_profile *
|
||||
|
|
@ -719,84 +698,47 @@ cmlcms_get_color_profile_from_params(struct weston_color_manager *cm_base,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
cmlcms_send_icc_info(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct cmlcms_color_profile *cprof)
|
||||
{
|
||||
int32_t fd;
|
||||
uint32_t len;
|
||||
|
||||
/* ICC-based color profile, so just send the ICC file fd. If we
|
||||
* get an error (negative fd), the helper will send the proper
|
||||
* error to the client. */
|
||||
fd = os_ro_anonymous_file_get_fd(cprof->icc.prof_rofile,
|
||||
RO_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
if (fd < 0) {
|
||||
weston_cm_send_icc_file(cm_image_desc_info, -1, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = os_ro_anonymous_file_size(cprof->icc.prof_rofile);
|
||||
weston_assert_u32_gt(cprof->base.cm->compositor, len, 0);
|
||||
|
||||
weston_cm_send_icc_file(cm_image_desc_info, fd, len);
|
||||
|
||||
os_ro_anonymous_file_put_fd(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info,
|
||||
struct weston_color_profile *cprof_base)
|
||||
{
|
||||
struct weston_color_manager_lcms *cm = to_cmlcms(cprof_base->cm);
|
||||
struct weston_compositor *compositor = cm->base.compositor;
|
||||
struct cmlcms_color_profile *cprof = to_cmlcms_cprof(cprof_base);
|
||||
const struct weston_color_primaries_info *primaries_info;
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
int32_t fd;
|
||||
uint32_t len;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* get an error (negative fd), the helper will send the proper
|
||||
* error to the client. */
|
||||
fd = os_ro_anonymous_file_get_fd(cprof->icc.prof_rofile,
|
||||
RO_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
if (fd < 0) {
|
||||
weston_cm_send_icc_file(cm_image_desc_info, -1, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = os_ro_anonymous_file_size(cprof->icc.prof_rofile);
|
||||
weston_assert_u32_gt(compositor, len, 0);
|
||||
|
||||
weston_cm_send_icc_file(cm_image_desc_info, fd, len);
|
||||
|
||||
os_ro_anonymous_file_put_fd(fd);
|
||||
} else {
|
||||
/* TODO: we still don't support parametric color profiles that
|
||||
* are not the stock one. This should change when we start
|
||||
* advertising parametric image description support in our
|
||||
* color-management protocol implementation. */
|
||||
if (cprof != cm->sRGB_profile)
|
||||
weston_assert_not_reached(compositor, "we don't support parametric " \
|
||||
"cprof's that are not the stock sRGB one");
|
||||
|
||||
/* Stock sRGB color profile. TODO: when we add support for
|
||||
* parametric color profiles, the stock sRGB will be crafted
|
||||
* using parameters, instead of cmsCreate_sRGBProfileTHR()
|
||||
* (which we currently use). So we'll get the parameters
|
||||
* directly from it, instead of hardcoding as we are doing here.
|
||||
* We don't get the parameters from the stock sRGB color profile
|
||||
* because it is not trivial to retrieve that from LittleCMS. */
|
||||
|
||||
/* Send the H.273 ColourPrimaries code point that matches the
|
||||
* Rec709 primaries and the D65 white point. */
|
||||
primaries_info = weston_color_primaries_info_from(compositor,
|
||||
WESTON_PRIMARIES_CICP_SRGB);
|
||||
weston_cm_send_primaries_named(cm_image_desc_info, primaries_info);
|
||||
|
||||
/* These are the Rec709 primaries and D65 white point. */
|
||||
weston_cm_send_primaries(cm_image_desc_info,
|
||||
&primaries_info->color_gamut);
|
||||
|
||||
/* Target primaries, equal to the primary primaries. */
|
||||
weston_cm_send_target_primaries(cm_image_desc_info,
|
||||
&primaries_info->color_gamut);
|
||||
|
||||
/* sRGB transfer function. */
|
||||
tf_info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22);
|
||||
weston_cm_send_tf_named(cm_image_desc_info, tf_info);
|
||||
|
||||
/* Primary luminance, default values from the protocol. */
|
||||
weston_cm_send_luminances(cm_image_desc_info, 0.2, 80.0, 80.0);
|
||||
|
||||
/* Target luminance, min/max equals primary luminance min/max. */
|
||||
weston_cm_send_target_luminances(cm_image_desc_info, 0.2, 80.0);
|
||||
switch (cprof->type) {
|
||||
case CMLCMS_PROFILE_TYPE_ICC:
|
||||
return cmlcms_send_icc_info(cm_image_desc_info, cprof);
|
||||
case CMLCMS_PROFILE_TYPE_PARAMS:
|
||||
weston_cm_send_parametric_info(cm_image_desc_info, cprof->params);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct weston_color_profile *
|
||||
|
|
|
|||
|
|
@ -387,6 +387,30 @@ merge_curvesets(cmsPipeline **lut, cmsContext context_id)
|
|||
return modified;
|
||||
}
|
||||
|
||||
static void
|
||||
linear_curvesets_to_matrices(cmsPipeline **lut, cmsContext context_id)
|
||||
{
|
||||
cmsPipeline *pipe;
|
||||
cmsStage *elem;
|
||||
cmsStage *matrix;
|
||||
|
||||
pipe = cmsPipelineAlloc(context_id, 3, 3);
|
||||
abort_oom_if_null(pipe);
|
||||
|
||||
elem = cmsPipelineGetPtrToFirstStage(*lut);
|
||||
for (; elem; elem = cmsStageNext(elem)) {
|
||||
matrix = lcms_matrix_stage_from_curve(context_id, elem);
|
||||
if (matrix) {
|
||||
cmsPipelineInsertStage(pipe, cmsAT_END, matrix);
|
||||
} else {
|
||||
cmsPipelineInsertStage(pipe, cmsAT_END, cmsStageDup(elem));
|
||||
}
|
||||
}
|
||||
|
||||
cmsPipelineFree(*lut);
|
||||
*lut = pipe;
|
||||
}
|
||||
|
||||
static const struct weston_color_tf_info *
|
||||
lcms_curve_matches_any_tf(struct weston_compositor *compositor,
|
||||
uint32_t lcms_curve_type, bool clamped_input,
|
||||
|
|
@ -1013,6 +1037,8 @@ lcms_optimize_pipeline(cmsPipeline **lut, cmsContext context_id)
|
|||
{
|
||||
bool cont_opt;
|
||||
|
||||
linear_curvesets_to_matrices(lut, context_id);
|
||||
|
||||
/**
|
||||
* This optimization loop will delete identity stages. Deleting
|
||||
* identity matrix stages is harmless, but deleting identity
|
||||
|
|
|
|||
|
|
@ -209,15 +209,34 @@ weston_cm_send_target_primaries(struct cm_image_desc_info *cm_image_desc_info,
|
|||
* This is a helper function that should be used by the color plugin
|
||||
* that owns the color profile and has information about it.
|
||||
*
|
||||
* \param cm_image_desc_info The image description info object
|
||||
* \param tf_info The tf_info object
|
||||
* \param cm_image_desc_info The image description info object.
|
||||
* \param tf The color transfer function to send.
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_cm_send_tf_named(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_tf_info *tf_info)
|
||||
weston_cm_send_tf(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_tf *tf)
|
||||
{
|
||||
wp_image_description_info_v1_send_tf_named(cm_image_desc_info->owner,
|
||||
tf_info->protocol_tf);
|
||||
switch (tf->info->tf) {
|
||||
case WESTON_TF_BT1886:
|
||||
case WESTON_TF_GAMMA22:
|
||||
case WESTON_TF_GAMMA28:
|
||||
case WESTON_TF_SRGB:
|
||||
case WESTON_TF_EXT_SRGB:
|
||||
case WESTON_TF_ST240:
|
||||
case WESTON_TF_ST428:
|
||||
case WESTON_TF_ST2084_PQ:
|
||||
case WESTON_TF_EXT_LINEAR:
|
||||
case WESTON_TF_LOG_100:
|
||||
case WESTON_TF_LOG_316:
|
||||
case WESTON_TF_XVYCC:
|
||||
case WESTON_TF_HLG:
|
||||
wp_image_description_info_v1_send_tf_named(cm_image_desc_info->owner,
|
||||
tf->info->protocol_tf);
|
||||
break;
|
||||
case WESTON_TF_POWER:
|
||||
wp_image_description_info_v1_send_tf_power(cm_image_desc_info->owner,
|
||||
tf->params[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -261,6 +280,37 @@ weston_cm_send_target_luminances(struct cm_image_desc_info *cm_image_desc_info,
|
|||
max_lum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send complete parametric image description information to the client.
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_cm_send_parametric_info(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_profile_params *par)
|
||||
{
|
||||
if (par->primaries_info)
|
||||
weston_cm_send_primaries_named(cm_image_desc_info, par->primaries_info);
|
||||
weston_cm_send_primaries(cm_image_desc_info, &par->primaries);
|
||||
weston_cm_send_target_primaries(cm_image_desc_info, &par->target_primaries);
|
||||
|
||||
weston_cm_send_tf(cm_image_desc_info, &par->tf);
|
||||
|
||||
weston_cm_send_luminances(cm_image_desc_info, par->min_luminance,
|
||||
par->max_luminance, par->reference_white_luminance);
|
||||
weston_cm_send_target_luminances(cm_image_desc_info,
|
||||
par->target_min_luminance,
|
||||
par->target_max_luminance);
|
||||
|
||||
if (par->maxCLL > 0.0f) {
|
||||
wp_image_description_info_v1_send_target_max_cll(cm_image_desc_info->owner,
|
||||
par->maxCLL);
|
||||
}
|
||||
|
||||
if (par->maxFALL > 0.0f) {
|
||||
wp_image_description_info_v1_send_target_max_fall(cm_image_desc_info->owner,
|
||||
par->maxFALL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an image description info object.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ weston_cm_send_target_primaries(struct cm_image_desc_info *cm_image_desc_info,
|
|||
const struct weston_color_gamut *color_gamut);
|
||||
|
||||
void
|
||||
weston_cm_send_tf_named(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_tf_info *tf_info);
|
||||
weston_cm_send_tf(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_tf *tf);
|
||||
|
||||
void
|
||||
weston_cm_send_luminances(struct cm_image_desc_info *cm_image_desc_info,
|
||||
|
|
@ -67,4 +67,8 @@ void
|
|||
weston_cm_send_target_luminances(struct cm_image_desc_info *cm_image_desc_info,
|
||||
float min_lum, float max_lum);
|
||||
|
||||
void
|
||||
weston_cm_send_parametric_info(struct cm_image_desc_info *cm_image_desc_info,
|
||||
const struct weston_color_profile_params *par);
|
||||
|
||||
#endif /* WESTON_COLOR_MANAGEMENT_H */
|
||||
|
|
|
|||
|
|
@ -583,11 +583,6 @@ on DRM, headless, wayland, and x11 backends, and for remoting and pipewire
|
|||
outputs.
|
||||
.TP 7
|
||||
.BI "color-profile=" name
|
||||
|
||||
.B NOTE:
|
||||
This feature is not fully implemented yet, and therefore it is not expected to
|
||||
work.
|
||||
|
||||
Color profiles describe how the display is assumed to behave. Knowing the
|
||||
display color behavior, Weston can adapt window contents to produce the
|
||||
presumed appearance. The option
|
||||
|
|
@ -605,7 +600,7 @@ section by referring to it by its
|
|||
value. Alternatively this key can use one of the special profile names that
|
||||
contain a colon (:).
|
||||
|
||||
The default, once implemented, will be
|
||||
The default is
|
||||
.BR "color-profile=auto:" .
|
||||
|
||||
The following special names are accepted:
|
||||
|
|
|
|||
|
|
@ -95,10 +95,10 @@ static const struct test_case test_cases[] = {
|
|||
/******** Successful cases *******/
|
||||
|
||||
{
|
||||
/* sRGB primaries with sRGB TF; succeeds. */
|
||||
/* sRGB primaries with gamma22; succeeds. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -112,10 +112,10 @@ static const struct test_case test_cases[] = {
|
|||
.error_point = ERROR_POINT_NONE,
|
||||
},
|
||||
{
|
||||
/* Custom primaries with sRGB TF; succeeds. */
|
||||
/* Custom primaries with gamma22; succeeds. */
|
||||
.primaries_named = NOT_SET,
|
||||
.primaries = &color_gamut_sRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -129,10 +129,10 @@ static const struct test_case test_cases[] = {
|
|||
.error_point = ERROR_POINT_NONE,
|
||||
},
|
||||
{
|
||||
/* sRGB primaries, sRGB TF and valid luminance values; succeeds. */
|
||||
/* sRGB primaries, gamma22 and valid luminance values; succeeds. */
|
||||
.primaries_named = NOT_SET,
|
||||
.primaries = &color_gamut_sRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = 0.5,
|
||||
.primaries_max_lum = 2000,
|
||||
|
|
@ -163,10 +163,10 @@ static const struct test_case test_cases[] = {
|
|||
.error_point = ERROR_POINT_NONE,
|
||||
},
|
||||
{
|
||||
/* sRGB primaries, sRGB TF and valid target primaries; succeeds. */
|
||||
/* sRGB primaries, gamma22 and valid target primaries; succeeds. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -309,7 +309,7 @@ static const struct test_case test_cases[] = {
|
|||
* protocol error. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -327,7 +327,7 @@ static const struct test_case test_cases[] = {
|
|||
* protocol error. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -381,7 +381,7 @@ static const struct test_case test_cases[] = {
|
|||
* defined range); graceful failure. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -399,7 +399,7 @@ static const struct test_case test_cases[] = {
|
|||
* graceful failure. */
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
.primaries = NULL,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.tf_power = NOT_SET,
|
||||
.primaries_min_lum = NOT_SET,
|
||||
.primaries_max_lum = NOT_SET,
|
||||
|
|
@ -433,7 +433,7 @@ color_manager_get(struct client *client)
|
|||
test_assert_u32_eq(cm->supported_rendering_intents,
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) |
|
||||
/* (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | */
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC));
|
||||
|
||||
|
|
@ -455,7 +455,7 @@ color_manager_get(struct client *client)
|
|||
test_assert_u32_eq(cm->supported_tf,
|
||||
(1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22) |
|
||||
(1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28) |
|
||||
(1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB) |
|
||||
(1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR) |
|
||||
(1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ));
|
||||
|
||||
test_assert_true(cm->init_done);
|
||||
|
|
@ -736,10 +736,10 @@ TEST(set_tf_named_twice)
|
|||
|
||||
image_desc_creator_param = color_manager_create_param(cm);
|
||||
wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param,
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
||||
client_roundtrip(client); /* make sure connection is still valid */
|
||||
wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param,
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
||||
expect_protocol_error(client, &wp_image_description_creator_params_v1_interface,
|
||||
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET);
|
||||
wp_image_description_creator_params_v1_destroy(image_desc_creator_param);
|
||||
|
|
@ -763,7 +763,7 @@ TEST(set_tf_power_then_tf_named)
|
|||
2.4 * 10000);
|
||||
client_roundtrip(client); /* make sure connection is still valid */
|
||||
wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param,
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
||||
expect_protocol_error(client, &wp_image_description_creator_params_v1_interface,
|
||||
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET);
|
||||
wp_image_description_creator_params_v1_destroy(image_desc_creator_param);
|
||||
|
|
@ -784,7 +784,7 @@ TEST(set_tf_named_then_tf_power)
|
|||
|
||||
image_desc_creator_param = color_manager_create_param(cm);
|
||||
wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param,
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
||||
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
||||
client_roundtrip(client); /* make sure connection is still valid */
|
||||
wp_image_description_creator_params_v1_set_tf_power(image_desc_creator_param,
|
||||
2.4 * 10000);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ color_manager_get(struct client *client)
|
|||
test_assert_u32_eq(cm->supported_rendering_intents,
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) |
|
||||
/* (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | */
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE) |
|
||||
(1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue