diff --git a/libweston/color-lcms/color-curve-segments.c b/libweston/color-lcms/color-curve-segments.c index 51aae583e..95e30f6ed 100644 --- a/libweston/color-lcms/color-curve-segments.c +++ b/libweston/color-lcms/color-curve-segments.c @@ -676,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); +} diff --git a/libweston/color-lcms/color-curve-segments.h b/libweston/color-lcms/color-curve-segments.h index adb20dab4..b761a3264 100644 --- a/libweston/color-lcms/color-curve-segments.h +++ b/libweston/color-lcms/color-curve-segments.h @@ -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) { diff --git a/libweston/color-lcms/color-transform.c b/libweston/color-lcms/color-transform.c index 6f4ba3b8c..d3c20c048 100644 --- a/libweston/color-lcms/color-transform.c +++ b/libweston/color-lcms/color-transform.c @@ -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