render/color: add wlr_color_transform_pipeline

Useful to apply multiple transforms in sequence, e.g. sRGB inverse
EOTF followed by gamma LUTs.
This commit is contained in:
Simon Ser 2025-06-15 15:03:18 +02:00
parent 3d36ab9211
commit 0b58bddf13
3 changed files with 60 additions and 0 deletions

View file

@ -9,6 +9,7 @@ enum wlr_color_transform_type {
COLOR_TRANSFORM_INVERSE_EOTF, COLOR_TRANSFORM_INVERSE_EOTF,
COLOR_TRANSFORM_LCMS2, COLOR_TRANSFORM_LCMS2,
COLOR_TRANSFORM_LUT_3X1D, COLOR_TRANSFORM_LUT_3X1D,
COLOR_TRANSFORM_PIPELINE,
}; };
struct wlr_color_transform { struct wlr_color_transform {
@ -39,6 +40,13 @@ struct wlr_color_transform_lut_3x1d {
size_t dim; size_t dim;
}; };
struct wlr_color_transform_pipeline {
struct wlr_color_transform base;
struct wlr_color_transform **transforms;
size_t len;
};
void wlr_color_transform_init(struct wlr_color_transform *tr, void wlr_color_transform_init(struct wlr_color_transform *tr,
enum wlr_color_transform_type type); enum wlr_color_transform_type type);

View file

@ -141,6 +141,13 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim, struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
const uint16_t *r, const uint16_t *g, const uint16_t *b); const uint16_t *r, const uint16_t *g, const uint16_t *b);
/**
* Initialize a color transformation to apply a sequence of color transforms
* one after another.
*/
struct wlr_color_transform *wlr_color_transform_init_pipeline(
struct wlr_color_transform **transforms, size_t len);
/** /**
* Increase the reference count of the color transform by 1. * Increase the reference count of the color transform by 1.
*/ */

View file

@ -62,6 +62,33 @@ struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
return &tx->base; return &tx->base;
} }
struct wlr_color_transform *wlr_color_transform_init_pipeline(
struct wlr_color_transform **transforms, size_t len) {
assert(len > 0);
struct wlr_color_transform **copy = calloc(len, sizeof(copy[0]));
if (copy == NULL) {
return NULL;
}
struct wlr_color_transform_pipeline *tx = calloc(1, sizeof(*tx));
if (!tx) {
free(copy);
return NULL;
}
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_PIPELINE);
// TODO: flatten nested pipeline transforms
for (size_t i = 0; i < len; i++) {
copy[i] = wlr_color_transform_ref(transforms[i]);
}
tx->transforms = copy;
tx->len = len;
return &tx->base;
}
static void color_transform_destroy(struct wlr_color_transform *tr) { static void color_transform_destroy(struct wlr_color_transform *tr) {
switch (tr->type) { switch (tr->type) {
case COLOR_TRANSFORM_INVERSE_EOTF: case COLOR_TRANSFORM_INVERSE_EOTF:
@ -73,6 +100,14 @@ static void color_transform_destroy(struct wlr_color_transform *tr) {
struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr); struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
free(lut_3x1d->lut_3x1d); free(lut_3x1d->lut_3x1d);
break; break;
case COLOR_TRANSFORM_PIPELINE:;
struct wlr_color_transform_pipeline *pipeline =
wl_container_of(tr, pipeline, base);
for (size_t i = 0; i < pipeline->len; i++) {
wlr_color_transform_unref(pipeline->transforms[i]);
}
free(pipeline->transforms);
break;
} }
wlr_addon_set_finish(&tr->addons); wlr_addon_set_finish(&tr->addons);
free(tr); free(tr);
@ -203,6 +238,16 @@ void wlr_color_transform_eval(struct wlr_color_transform *tr,
case COLOR_TRANSFORM_LUT_3X1D: case COLOR_TRANSFORM_LUT_3X1D:
color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in); color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
break; break;
case COLOR_TRANSFORM_PIPELINE:;
struct wlr_color_transform_pipeline *pipeline =
wl_container_of(tr, pipeline, base);
float color[3];
memcpy(color, in, sizeof(color));
for (size_t i = 0; i < pipeline->len; i++) {
wlr_color_transform_eval(pipeline->transforms[i], color, color);
}
memcpy(out, color, sizeof(color));
break;
} }
} }