compositor-drm: support hdr10 metadata protocol

Upstream-Status: Inappropriate [i.MX-specific]

Signed-off-by: Haihua Hu <jared.hu@nxp.com>
diff --git a/Makefile.am b/Makefile.am
index f298fd2..f01282a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -171,7 +171,9 @@
 	protocol/weston-touch-calibration-protocol.c			\
 	protocol/weston-touch-calibration-server-protocol.h		\
 	protocol/alpha-compositing-unstable-v1-protocol.c		\
-	protocol/alpha-compositing-unstable-v1-server-protocol.h
+	protocol/alpha-compositing-unstable-v1-server-protocol.h\
+	protocol/hdr10-metadata-unstable-v1-protocol.c			\
+	protocol/hdr10-metadata-unstable-v1-server-protocol.h
 
 BUILT_SOURCES += $(nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES)
 
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 0648796..bbdc80a 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -74,6 +74,7 @@
 #include "presentation-time-server-protocol.h"
 #include "linux-dmabuf.h"
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "hdr10-metadata-unstable-v1-server-protocol.h"
 
 #ifndef DRM_CLIENT_CAP_ASPECT_RATIO
 #define DRM_CLIENT_CAP_ASPECT_RATIO	4
@@ -192,6 +193,7 @@
 	WDRM_CONNECTOR_EDID = 0,
 	WDRM_CONNECTOR_DPMS,
 	WDRM_CONNECTOR_CRTC_ID,
+	WDRM_CONNECTOR_HDR10_METADATA,
 	WDRM_CONNECTOR__COUNT
 };
 
@@ -226,6 +228,7 @@
 		.num_enum_values = WDRM_DPMS_STATE__COUNT,
 	},
 	[WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
+	[WDRM_CONNECTOR_HDR10_METADATA] = { .name = "HDR_SOURCE_METADATA", },
 };
 
 /**
@@ -278,6 +281,9 @@
 	struct wl_listener session_listener;
 	uint32_t gbm_format;
 
+	/* hdr10 metadata blob id */
+	unsigned int hdr_blob_id;
+
 	/* we need these parameters in order to not fail drmModeAddFB2()
 	 * due to out of bounds dimensions, and then mistakenly set
 	 * sprites_are_broken:
@@ -2581,6 +2587,15 @@
 			ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
 						  output->crtc_id);
 		}
+
+		if (backend->hdr_blob_id > 0) {
+			wl_list_for_each(head, &output->base.head_list, base.output_link) {
+				/* checking if the output driver this head */
+				if (head->base.output == &output->base)
+					connector_add_prop(req, head, WDRM_CONNECTOR_HDR10_METADATA,
+							backend->hdr_blob_id);
+			}
+		}
 	} else {
 		ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
 		ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
@@ -2779,6 +2794,10 @@
 	assert(wl_list_empty(&pending_state->output_list));
 
 out:
+	if (b->hdr_blob_id > 0) {
+		drmModeDestroyPropertyBlob (b->drm.fd, b->hdr_blob_id);
+		b->hdr_blob_id = 0;
+	}
 	drmModeAtomicFree(req);
 	drm_pending_state_free(pending_state);
 	return ret;
@@ -7112,6 +7131,96 @@
 	drm_output_set_seat,
 };
 
+static void
+hdr10_metadata_destroy(struct wl_client *client,
+			  struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+hdr10_metadata_set_metadata(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t eotf,
+				 uint32_t type,
+			     uint32_t display_primaries_red,
+			     uint32_t display_primaries_green,
+			     uint32_t display_primaries_blue,
+			     uint32_t white_point,
+			     uint32_t mastering_display_luminance,
+			     uint32_t max_cll,
+				 uint32_t max_fall)
+{
+	struct weston_compositor *compositor = wl_resource_get_user_data(resource);
+	struct drm_backend *b = to_drm_backend(compositor);
+	struct hdr_static_metadata hdr_metadata;
+
+	hdr_metadata.eotf = eotf & 0xffff;
+	hdr_metadata.type = type & 0xffff;
+	hdr_metadata.display_primaries_x[0] = (display_primaries_red >> 16) & 0xffff;
+	hdr_metadata.display_primaries_y[0] = display_primaries_red & 0xffff;
+	hdr_metadata.display_primaries_x[1] = (display_primaries_green >> 16) & 0xffff;
+	hdr_metadata.display_primaries_y[1] = display_primaries_green & 0xffff;
+	hdr_metadata.display_primaries_x[2] = (display_primaries_blue >> 16) & 0xffff;
+	hdr_metadata.display_primaries_y[2] = display_primaries_blue & 0xffff;
+	hdr_metadata.white_point_x = (white_point >> 16) & 0xffff;
+	hdr_metadata.white_point_y = white_point & 0xffff;
+	hdr_metadata.max_mastering_display_luminance =
+				(mastering_display_luminance >> 16) & 0xffff;
+	hdr_metadata.min_mastering_display_luminance =
+				mastering_display_luminance & 0xffff;
+	hdr_metadata.max_cll = max_cll & 0xffff;
+	hdr_metadata.max_fall = max_fall & 0xffff;
+
+	drmModeCreatePropertyBlob(b->drm.fd, &hdr_metadata, sizeof(hdr_metadata), &b->hdr_blob_id);
+}
+
+static const struct zwp_hdr10_metadata_v1_interface hdr10_metadata_interface = {
+	hdr10_metadata_destroy,
+	hdr10_metadata_set_metadata,
+};
+
+static void
+bind_hdr10_metadata(struct wl_client *client,
+		       void *data, uint32_t version, uint32_t id)
+{
+	struct wl_resource *resource;
+	struct weston_compositor *compositor = data;
+
+	resource = wl_resource_create(client, &zwp_hdr10_metadata_v1_interface,
+				      version, id);
+	if (resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &hdr10_metadata_interface,
+				       compositor, NULL);
+}
+
+static bool
+drm_backend_is_hdr_supported(struct weston_compositor *compositor)
+{
+	struct drm_output *output;
+	struct drm_head *head;
+
+	wl_list_for_each(output, &compositor->output_list, base.link) {
+		wl_list_for_each(head, &output->base.head_list, base.output_link) {
+			if (head->props_conn[WDRM_CONNECTOR_HDR10_METADATA].prop_id > 0)
+				return true;
+		}
+	}
+
+	wl_list_for_each(output, &compositor->pending_output_list, base.link) {
+		wl_list_for_each(head, &output->base.head_list, base.output_link) {
+			if (head->props_conn[WDRM_CONNECTOR_HDR10_METADATA].prop_id > 0)
+				return true;
+		}
+	}
+
+	return true;
+}
+
 static struct drm_backend *
 drm_backend_create(struct weston_compositor *compositor,
 		   struct weston_drm_backend_config *config)
@@ -7282,6 +7391,15 @@
 				   "support failed.\n");
 	}
 
+	if (drm_backend_is_hdr_supported(compositor)) {
+		if (!wl_global_create(compositor->wl_display, &zwp_hdr10_metadata_v1_interface, 1,
+				      compositor, bind_hdr10_metadata)) {
+			weston_log("Error: initializing hdr10 support failed\n");
+		}
+	} else {
+		weston_log("info: HDR is not support\n");
+	}
+
 	ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
 					 &api, sizeof(api));