mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-09 04:48:04 +02:00
color-lcms: optimize linear TRCs
The icc<->parametric color transformation code uses "optical ICC profiles" as part of the ICC pipeline. These profiles use a linear TRC to encode the black point. When such TRC survives all optimizations, it will cause the 3D LUT fallback path to be taken. Detect such curve sets on the ICC pipeline optimizer, and convert them to matrix stages. The matrix stages will then be optimized as usual, often eliminating the stage completely. The results can be seen in color-icc-output test after the stock sRGB profile has been changed into a parametric one, causing all cases in the test to hit the parametric-to-icc path. Some tests fail when they suddenly start using the 3D LUT path which causes the errors to rise. This patch fixes those (future) cases, and the errors remain the same as before changing the stock profile. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
parent
0e474b763f
commit
54b60ad51a
3 changed files with 90 additions and 0 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue