diff --git a/libweston/color-properties.c b/libweston/color-properties.c index 812a6984a..4df20fcd8 100644 --- a/libweston/color-properties.c +++ b/libweston/color-properties.c @@ -255,24 +255,62 @@ static const struct weston_color_primaries_info color_primaries_info_table[] = { }, }; +#define POWER_LAW_PARAMS(g) { g, 1.0, 0.0, 1.0, 0.0 } +#define SRGB_PIECE_WISE_PARAMS { 2.4, 1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045 } +#define INVERSE_SRGB_PIECE_WISE_PARAMS { 1.0f / 2.4f, 1.055, -0.055, 12.92, 0.0031308 } + +#define POWER_LAW(g, clamp) { \ + .type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW, \ + .clamped_input = (clamp), \ + .params = { POWER_LAW_PARAMS(g), POWER_LAW_PARAMS(g), \ + POWER_LAW_PARAMS(g), } \ +} + +#define SRGB_PIECE_WISE(clamp) { \ + .type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW, \ + .clamped_input = (clamp), \ + .params = { SRGB_PIECE_WISE_PARAMS, SRGB_PIECE_WISE_PARAMS, \ + SRGB_PIECE_WISE_PARAMS, } \ +} + +#define INVERSE_SRGB_PIECE_WISE(clamp) { \ + .type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_POWLIN, \ + .clamped_input = (clamp), \ + .params = { INVERSE_SRGB_PIECE_WISE_PARAMS, INVERSE_SRGB_PIECE_WISE_PARAMS, \ + INVERSE_SRGB_PIECE_WISE_PARAMS, } \ +} + static const struct weston_color_tf_info color_tf_info_table[] = { { .tf = WESTON_TF_BT1886, .desc = "BT.1886 transfer function", .protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886, .count_parameters = 0, + /** + * NOTE: This is the BT.1886 special case of L_B = 0 and + * L_W = 1. + */ + .curve_params_valid = true, + .curve = POWER_LAW(2.4, true), + .inverse_curve = POWER_LAW(1.0f / 2.4f, true), }, { .tf = WESTON_TF_GAMMA22, .desc = "Assumed display gamma 2.2 transfer function", .protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .count_parameters = 0, + .curve_params_valid = true, + .curve = POWER_LAW(2.2, true), + .inverse_curve = POWER_LAW(1.0f / 2.2f, true), }, { .tf = WESTON_TF_GAMMA28, .desc = "Assumed display gamma 2.8 transfer function", .protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28, .count_parameters = 0, + .curve_params_valid = true, + .curve = POWER_LAW(2.8, true), + .inverse_curve = POWER_LAW(1.0f / 2.8f, true), }, { .tf = WESTON_TF_EXT_LINEAR, @@ -285,12 +323,18 @@ static const struct weston_color_tf_info color_tf_info_table[] = { .desc = "sRGB piece-wise transfer function", .protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, .count_parameters = 0, + .curve_params_valid = true, + .curve = SRGB_PIECE_WISE(true), + .inverse_curve = INVERSE_SRGB_PIECE_WISE(true), }, { .tf = WESTON_TF_EXT_SRGB, .desc = "Extended sRGB piece-wise transfer function", .protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB, .count_parameters = 0, + .curve_params_valid = true, + .curve = SRGB_PIECE_WISE(false), + .inverse_curve = INVERSE_SRGB_PIECE_WISE(false), }, { .tf = WESTON_TF_ST240, diff --git a/libweston/color-properties.h b/libweston/color-properties.h index d9671652a..896c3f236 100644 --- a/libweston/color-properties.h +++ b/libweston/color-properties.h @@ -29,6 +29,7 @@ #include #include +#include "color.h" #include struct weston_compositor; @@ -113,6 +114,13 @@ struct weston_color_tf_info { * certain known functions that clients can define passing arbitrary * parameters. */ bool count_parameters; + + /** Are curve and inverse_curve valid? */ + bool curve_params_valid; + + /** Parametric curves to which we can map the tf and its inverse. */ + struct weston_color_curve_parametric curve; + struct weston_color_curve_parametric inverse_curve; }; const struct weston_color_feature_info * diff --git a/libweston/color.c b/libweston/color.c index ff0f9e3e9..8de53e9cd 100644 --- a/libweston/color.c +++ b/libweston/color.c @@ -44,6 +44,7 @@ #include "shared/string-helpers.h" #include "shared/helpers.h" #include "shared/xalloc.h" +#include "shared/weston-assert.h" /** * Increase reference count of the color profile object @@ -188,6 +189,54 @@ weston_color_profile_params_to_str(struct weston_color_profile_params *params, return str; } +/** + * Given an enumerated color curve, returns an equivalent parametric curve. + * + * \param compositor The compositor instance. + * \param curve The enumerated color curve. + * \param out Where this stores the parametric curve. + * \return True on success, false otherwise. + */ +WL_EXPORT bool +weston_color_curve_enum_get_parametric(struct weston_compositor *compositor, + const struct weston_color_curve_enum *curve, + struct weston_color_curve_parametric *out) +{ + unsigned int i; + + memset(out, 0, sizeof(*out)); + + /* This one is special, the only parametric TF we currently have. */ + if (curve->tf->tf == WESTON_TF_POWER) { + out->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW; + out->clamped_input = false; + for (i = 0; i < 3; i++) { + float exp = curve->params[i][0]; + /* LINPOW with such params matches pure power-law */ + out->params[i][0] = (curve->tf_direction == WESTON_FORWARD_TF) ? + exp : 1.0f / exp; /* g */ + out->params[i][1] = 1.0; /* a */ + out->params[i][2] = 0.0; /* b */ + out->params[i][3] = 1.0; /* c */ + out->params[i][4] = 0.0; /* d */ + } + return true; + } + + /* No other TF's have params. */ + weston_assert_uint32_eq(compositor, curve->tf->count_parameters, 0); + + if (!curve->tf->curve_params_valid) + return false; + + if (curve->tf_direction == WESTON_FORWARD_TF) + *out = curve->tf->curve; + else + *out = curve->tf->inverse_curve; + + return true; +} + /** * Increase reference count of the color transform object * @@ -266,6 +315,8 @@ curve_type_to_str(enum weston_color_curve_type curve_type) return "identity"; case WESTON_COLOR_CURVE_TYPE_LUT_3x1D: return "3x1D LUT"; + case WESTON_COLOR_CURVE_TYPE_ENUM: + return "enumerated"; case WESTON_COLOR_CURVE_TYPE_PARAMETRIC: return "parametric"; } @@ -313,6 +364,10 @@ weston_color_transform_string(const struct weston_color_transform *xform) fprintf(fp, "%spre %s", sep, curve_type_to_str(pre_type)); if (pre_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D) fprintf(fp, " [%u]", xform->pre_curve.u.lut_3x1d.optimal_len); + else if (pre_type == WESTON_COLOR_CURVE_TYPE_ENUM) + fprintf(fp, " [%s%s]", + (xform->pre_curve.u.enumerated.tf_direction == WESTON_INVERSE_TF) ? "inverse " : "", + xform->pre_curve.u.enumerated.tf->desc); else if (pre_type == WESTON_COLOR_CURVE_TYPE_PARAMETRIC) fprintf(fp, " [%s]", param_curve_type_to_str(xform->pre_curve.u.parametric.type)); @@ -330,6 +385,10 @@ weston_color_transform_string(const struct weston_color_transform *xform) fprintf(fp, "%spost %s", sep, curve_type_to_str(post_type)); if (post_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D) fprintf(fp, " [%u]", xform->post_curve.u.lut_3x1d.optimal_len); + else if (post_type == WESTON_COLOR_CURVE_TYPE_ENUM) + fprintf(fp, " [%s%s]", + (xform->post_curve.u.enumerated.tf_direction == WESTON_INVERSE_TF) ? "inverse " : "", + xform->post_curve.u.enumerated.tf->desc); else if (post_type == WESTON_COLOR_CURVE_TYPE_PARAMETRIC) fprintf(fp, " [%s]", param_curve_type_to_str(xform->post_curve.u.parametric.type)); diff --git a/libweston/color.h b/libweston/color.h index 7c42f096b..bf0123289 100644 --- a/libweston/color.h +++ b/libweston/color.h @@ -225,6 +225,9 @@ enum weston_color_curve_type { /** Three-channel, one-dimensional look-up table */ WESTON_COLOR_CURVE_TYPE_LUT_3x1D, + /** Enumerated color curve */ + WESTON_COLOR_CURVE_TYPE_ENUM, + /** Parametric color curve */ WESTON_COLOR_CURVE_TYPE_PARAMETRIC, }; @@ -255,6 +258,24 @@ struct weston_color_curve_lut_3x1d { unsigned optimal_len; }; +/** Direct or inverse of a tf. */ +enum weston_tf_direction { + WESTON_FORWARD_TF, + WESTON_INVERSE_TF, +}; + +/** Enumerated color curve */ +struct weston_color_curve_enum { + const struct weston_color_tf_info *tf; + + /* Determines if the direct or inverse of the tf should be used. */ + enum weston_tf_direction tf_direction; + + /* Some tf are parametric, and we keep the params here. They may be + * different for each color channel, and channels are in RGB order. */ + float params[3][MAX_PARAMS_TF]; +}; + /** Parametric color curve parameters */ struct weston_color_curve_parametric { enum weston_color_curve_parametric_type type; @@ -286,6 +307,7 @@ struct weston_color_curve { union { /* identity: no parameters */ struct weston_color_curve_lut_3x1d lut_3x1d; + struct weston_color_curve_enum enumerated; struct weston_color_curve_parametric parametric; } u; }; @@ -620,6 +642,11 @@ char * weston_color_profile_params_to_str(struct weston_color_profile_params *params, const char *ident); +bool +weston_color_curve_enum_get_parametric(struct weston_compositor *compositor, + const struct weston_color_curve_enum *curve, + struct weston_color_curve_parametric *out); + struct weston_color_transform * weston_color_transform_ref(struct weston_color_transform *xform); diff --git a/libweston/renderer-gl/gl-shader-config-color-transformation.c b/libweston/renderer-gl/gl-shader-config-color-transformation.c index ac89b8ae1..191150ef4 100644 --- a/libweston/renderer-gl/gl-shader-config-color-transformation.c +++ b/libweston/renderer-gl/gl-shader-config-color-transformation.c @@ -167,6 +167,38 @@ gl_color_curve_parametric(struct gl_renderer *gr, weston_assert_not_reached(gr->compositor, "unknown parametric color curve"); } +static bool +gl_color_curve_enum(struct gl_renderer *gr, + struct gl_renderer_color_curve *gl_curve, + const struct weston_color_curve *curve) +{ + struct weston_color_curve_parametric parametric; + bool ret; + + /* Lower TF to a parametric curve. */ + ret = weston_color_curve_enum_get_parametric(gr->compositor, + &curve->u.enumerated, + ¶metric); + if (!ret) + return false; + + /* Handle parametric curve that we got from TF. */ + + ARRAY_COPY(gl_curve->u.parametric.params, parametric.params); + gl_curve->u.parametric.clamped_input = parametric.clamped_input; + + switch(parametric.type) { + case WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW: + gl_curve->type = SHADER_COLOR_CURVE_LINPOW; + return true; + case WESTON_COLOR_CURVE_PARAMETRIC_TYPE_POWLIN: + gl_curve->type = SHADER_COLOR_CURVE_POWLIN; + return true; + } + + weston_assert_not_reached(gr->compositor, "unknown parametric color curve"); +} + static bool gl_color_curve_lut_3x1d(struct gl_renderer *gr, struct gl_renderer_color_curve *gl_curve, @@ -285,6 +317,10 @@ gl_renderer_color_transform_from(struct gl_renderer *gr, ok = gl_color_curve_parametric(gr, &gl_xform->pre_curve, &xform->pre_curve); break; + case WESTON_COLOR_CURVE_TYPE_ENUM: + ok = gl_color_curve_enum(gr, &gl_xform->pre_curve, + &xform->pre_curve); + break; } if (!ok) { gl_renderer_color_transform_destroy(gl_xform); @@ -323,6 +359,10 @@ gl_renderer_color_transform_from(struct gl_renderer *gr, ok = gl_color_curve_parametric(gr, &gl_xform->post_curve, &xform->post_curve); break; + case WESTON_COLOR_CURVE_TYPE_ENUM: + ok = gl_color_curve_enum(gr, &gl_xform->post_curve, + &xform->post_curve); + break; } if (!ok) { gl_renderer_color_transform_destroy(gl_xform);