From c9fd7dfb3c19b4c57d5542d4e1b1f64c40beaa56 Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <pekka.paalanen@collabora.com>
Date: Tue, 8 Jun 2021 14:17:44 +0300
Subject: [PATCH] libweston: add weston_output::color_profile

Add API to set an output's color profile. This new function can also be
called while the output is enabled. This allows changing the output
color profile even at runtime if desired.

color-noop has no way of creating weston_color_profile objects, so it
just asserts that no color profile is set.

color-lcms does not yet implement taking the output color profile into
account, so for now it just fails everything if a profile is set.

weston_surface_color_transform_fini() was previously used only prior to
freeing the struct, but now it is used also to just clear the struct,
hence it needs to reset the fields.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
---
 include/libweston/libweston.h     |  5 +++
 libweston/color-lcms/color-lcms.c | 17 +++++++++
 libweston/color-noop.c            |  8 ++--
 libweston/color.c                 |  2 +
 libweston/compositor.c            | 61 +++++++++++++++++++++++++++++++
 5 files changed, 89 insertions(+), 4 deletions(-)

diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
index 6f053877bb..d68f535a14 100644
--- a/include/libweston/libweston.h
+++ b/include/libweston/libweston.h
@@ -374,6 +374,7 @@ struct weston_output {
 	bool enabled; /**< is in the output_list, not pending list */
 	int scale;
 
+	struct weston_color_profile *color_profile;
 	struct weston_color_transform *from_sRGB_to_output;
 	struct weston_color_transform *from_sRGB_to_blend;
 	struct weston_color_transform *from_blend_to_output;
@@ -2082,6 +2083,10 @@ void
 weston_output_set_transform(struct weston_output *output,
 			    uint32_t transform);
 
+bool
+weston_output_set_color_profile(struct weston_output *output,
+				struct weston_color_profile *cprof);
+
 void
 weston_output_init(struct weston_output *output,
 		   struct weston_compositor *compositor,
diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c
index 16e9981269..18340a3931 100644
--- a/libweston/color-lcms/color-lcms.c
+++ b/libweston/color-lcms/color-lcms.c
@@ -57,6 +57,10 @@ cmlcms_get_surface_color_transform(struct weston_color_manager *cm_base,
 	};
 	struct cmlcms_color_transform *xform;
 
+	/* TODO: use output color profile */
+	if (output->color_profile)
+		return false;
+
 	xform = cmlcms_color_transform_get(cm, &param);
 	if (!xform)
 		return false;
@@ -82,6 +86,10 @@ cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
 	};
 	struct cmlcms_color_transform *xform;
 
+	/* TODO: use output color profile */
+	if (output->color_profile)
+		return false;
+
 	xform = cmlcms_color_transform_get(cm, &param);
 	if (!xform)
 		return false;
@@ -96,6 +104,11 @@ cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
 					  struct weston_color_transform **xform_out)
 {
 	/* Assumes output color space is sRGB SDR */
+
+	/* TODO: use output color profile */
+	if (output->color_profile)
+		return false;
+
 	/* Identity transform */
 	*xform_out = NULL;
 
@@ -114,6 +127,10 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
 	};
 	struct cmlcms_color_transform *xform;
 
+	/* TODO: use output color profile */
+	if (output->color_profile)
+		return false;
+
 	xform = cmlcms_color_transform_get(cm, &param);
 	if (!xform)
 		return false;
diff --git a/libweston/color-noop.c b/libweston/color-noop.c
index 557797dcec..30a0762b2b 100644
--- a/libweston/color-noop.c
+++ b/libweston/color-noop.c
@@ -73,7 +73,7 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
 				   struct weston_surface_color_transform *surf_xform)
 {
 	/* TODO: Assert surface has no colorspace set */
-	/* TODO: Assert output has no colorspace set */
+	assert(output->color_profile == NULL);
 
 	/* Identity transform */
 	surf_xform->transform = NULL;
@@ -87,7 +87,7 @@ cmnoop_get_output_color_transform(struct weston_color_manager *cm_base,
 				  struct weston_output *output,
 				  struct weston_color_transform **xform_out)
 {
-	/* TODO: Assert output has no colorspace set */
+	assert(output->color_profile == NULL);
 
 	/* Identity transform */
 	*xform_out = NULL;
@@ -100,7 +100,7 @@ cmnoop_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
 					  struct weston_output *output,
 					  struct weston_color_transform **xform_out)
 {
-	/* TODO: Assert output has no colorspace set */
+	assert(output->color_profile == NULL);
 
 	/* Identity transform */
 	*xform_out = NULL;
@@ -113,7 +113,7 @@ cmnoop_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
 					 struct weston_output *output,
 					 struct weston_color_transform **xform_out)
 {
-	/* TODO: Assert output has no colorspace set */
+	assert(output->color_profile == NULL);
 
 	/* Identity transform */
 	*xform_out = NULL;
diff --git a/libweston/color.c b/libweston/color.c
index 90f332c5de..405e0965cd 100644
--- a/libweston/color.c
+++ b/libweston/color.c
@@ -181,6 +181,8 @@ void
 weston_surface_color_transform_fini(struct weston_surface_color_transform *surf_xform)
 {
 	weston_color_transform_unref(surf_xform->transform);
+	surf_xform->transform = NULL;
+	surf_xform->identity_pipeline = false;
 }
 
 /**
diff --git a/libweston/compositor.c b/libweston/compositor.c
index 11bb820c8b..5e0f9165b7 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -6310,6 +6310,9 @@ weston_output_set_color_transforms(struct weston_output *output)
 	output->from_sRGB_to_output = sRGB_to_output;
 	output->from_sRGB_to_blend = sRGB_to_blend;
 
+	weston_log("Output '%s' using color profile: %s\n", output->name,
+		   weston_color_profile_get_description(output->color_profile));
+
 	return true;
 }
 
@@ -6497,6 +6500,62 @@ weston_output_set_transform(struct weston_output *output,
 	}
 }
 
+/** Set output's color profile
+ *
+ * \param output The output to change.
+ * \param cprof The color profile to set. Can be NULL for default sRGB profile.
+ * \return True on success, or false on failure.
+ *
+ * The color profile must have WESTON_COLOR_PROFILE_KIND_OUTPUT bit,
+ * or it must be NULL.
+ *
+ * Calling this function changes the color profile of the output. This causes
+ * all existing weston_color_transform objects related to this output via
+ * paint nodes to be unreferenced and later re-created on demand.
+ *
+ * This function may not be called from within weston_output_repaint().
+ *
+ * On failure, nothing is changed.
+ *
+ * \ingroup output
+ */
+WL_EXPORT bool
+weston_output_set_color_profile(struct weston_output *output,
+				struct weston_color_profile *cprof)
+{
+	struct weston_color_profile *old;
+	struct weston_paint_node *pnode;
+
+	if (cprof && (cprof->usage & WESTON_COLOR_PROFILE_KIND_OUTPUT) == 0) {
+		weston_log("Error setting color profile '%s' for output '%s': not an output profile\n",
+			   weston_color_profile_get_description(cprof),
+			   output->name);
+		return false;
+	}
+
+	old = output->color_profile;
+	output->color_profile = weston_color_profile_ref(cprof);
+
+	if (output->enabled) {
+		if (!weston_output_set_color_transforms(output)) {
+			/* Failed, roll back */
+			weston_color_profile_unref(output->color_profile);
+			output->color_profile = old;
+			return false;
+		}
+
+		/* Remove outdated cached color transformations */
+		wl_list_for_each(pnode, &output->paint_node_list, output_link) {
+			weston_surface_color_transform_fini(&pnode->surf_xform);
+			pnode->surf_xform_valid = false;
+		}
+	}
+
+	weston_color_profile_unref(old);
+
+	return true;
+}
+
 /** Initializes a weston_output object with enough data so
  ** an output can be configured.
  *
@@ -6852,6 +6911,8 @@ weston_output_release(struct weston_output *output)
 	if (output->enabled)
 		weston_compositor_remove_output(output);
 
+	weston_color_profile_unref(output->color_profile);
+
 	pixman_region32_fini(&output->region);
 	wl_list_remove(&output->link);
 
-- 
GitLab