From e88467f9d76bcacecf14f250e678196da497daf6 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Tue, 4 Feb 2020 16:41:34 -0800 Subject: [PATCH] x11: Support the CTM (color transform matrix) RandR property When supported, this property allows the window system to apply a 3x3 color correction matrix in order to transform colors from the window system's native color space to the measured color space of a display device. Query for this property and set the 'supports-color-transform' property in the GetResource reply. Add support for the SetOutputCTM DBus method and plumb that through to the server's CTM property. Part-of: --- src/backends/meta-monitor-manager-private.h | 16 +++++ src/backends/meta-monitor-manager.c | 67 +++++++++++++++++++ src/backends/meta-output.h | 2 + .../x11/meta-monitor-manager-xrandr.c | 9 +++ src/backends/x11/meta-output-xrandr.c | 44 ++++++++++++ src/backends/x11/meta-output-xrandr.h | 4 ++ src/org.gnome.Mutter.DisplayConfig.xml | 14 ++++ 7 files changed, 156 insertions(+) diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index eaad2c4ce..e6cffab1f 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -5,6 +5,7 @@ * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * Copyright (C) 2013 Red Hat Inc. + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -92,6 +93,17 @@ struct _MetaOutputAssignment gboolean is_underscanning; }; +/* + * MetaOutputCtm: + * + * A 3x3 color transform matrix in the fixed-point S31.32 sign-magnitude format + * used by DRM. + */ +typedef struct _MetaOutputCtm +{ + uint64_t matrix[9]; +} MetaOutputCtm; + #define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ()) #define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager)) #define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) @@ -179,6 +191,7 @@ struct _MetaMonitorManager * @get_capabilities: vfunc for meta_monitor_manager_get_capabilities(). * @get_max_screen_size: vfunc for meta_monitor_manager_get_max_screen_size(). * @get_default_layout_mode: vfunc for meta_monitor_manager_get_default_layout_mode(). + * @set_output_ctm: vfunc for meta_monitor_manager_output_set_ctm() * * The base class for a #MetaMonitorManager. */ @@ -245,6 +258,9 @@ struct _MetaMonitorManagerClass int *); MetaLogicalMonitorLayoutMode (*get_default_layout_mode) (MetaMonitorManager *); + + void (*set_output_ctm) (MetaOutput *, + const MetaOutputCtm *); }; META_EXPORT_TEST diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index dbf799975..756c0e64c 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -8,6 +8,7 @@ * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * Copyright (C) 2013 Red Hat Inc. + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -1190,6 +1191,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, const char * connector_type_name; gboolean is_underscanning; gboolean supports_underscanning; + gboolean supports_color_transform; g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au")); for (j = 0; j < output_info->n_possible_crtcs; j++) @@ -1230,6 +1232,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, is_underscanning = meta_output_is_underscanning (output); connector_type_name = get_connector_type_name (output_info->connector_type); supports_underscanning = output_info->supports_underscanning; + supports_color_transform = output_info->supports_color_transform; g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&properties, "{sv}", "vendor", @@ -1258,6 +1261,8 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, g_variant_new_boolean (is_underscanning)); g_variant_builder_add (&properties, "{sv}", "supports-underscanning", g_variant_new_boolean (supports_underscanning)); + g_variant_builder_add (&properties, "{sv}", "supports-color-transform", + g_variant_new_boolean (supports_color_transform)); edid = manager_class->read_edid (manager, output); if (edid) @@ -2423,6 +2428,65 @@ meta_monitor_manager_handle_set_crtc_gamma (MetaDBusDisplayConfig *skeleton, return TRUE; } +static gboolean +meta_monitor_manager_handle_set_output_ctm (MetaDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint output_id, + GVariant *ctm_var, + MetaMonitorManager *manager) +{ + MetaMonitorManagerClass *klass; + GList *combined_outputs; + MetaOutput *output; + MetaOutputCtm ctm; + int i; + + if (serial != manager->serial) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "The requested configuration is based on stale information"); + return TRUE; + } + + combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs); + + if (output_id >= g_list_length (combined_outputs)) + { + g_list_free (combined_outputs); + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Invalid output id"); + return TRUE; + } + + output = g_list_nth_data (combined_outputs, output_id); + g_list_free (combined_outputs); + + if (g_variant_n_children (ctm_var) != 9) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Unexpected color transform matrix variant length"); + return TRUE; + } + + for (i = 0; i < 9; i++) + { + GVariant *tmp = g_variant_get_child_value (ctm_var, i); + ctm.matrix[i] = g_variant_get_uint64 (tmp); + g_variant_unref (tmp); + } + + klass = META_MONITOR_MANAGER_GET_CLASS (manager); + if (klass->set_output_ctm) + klass->set_output_ctm (output, &ctm); + meta_dbus_display_config_complete_set_output_ctm (skeleton, invocation); + + return TRUE; +} + static void monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager) { @@ -2444,6 +2508,9 @@ monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager) g_signal_connect_object (manager->display_config, "handle-apply-monitors-config", G_CALLBACK (meta_monitor_manager_handle_apply_monitors_config), manager, 0); + g_signal_connect_object (manager->display_config, "handle-set-output-ctm", + G_CALLBACK (meta_monitor_manager_handle_set_output_ctm), + manager, 0); } static void diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index 4f2d19337..c54d4206b 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2017 Red Hat + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -89,6 +90,7 @@ typedef struct _MetaOutputInfo int backlight_max; gboolean supports_underscanning; + gboolean supports_color_transform; /* * Get a new preferred mode on hotplug events, to handle dynamic guest diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 03e6175f5..a2f893162 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -8,6 +8,7 @@ * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * Copyright (C) 2013 Red Hat Inc. + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -1001,6 +1002,13 @@ meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; } +static void +meta_monitor_manager_xrandr_set_output_ctm (MetaOutput *output, + const MetaOutputCtm *ctm) +{ + meta_output_xrandr_set_ctm (META_OUTPUT_XRANDR (output), ctm); +} + static void meta_monitor_manager_xrandr_constructed (GObject *object) { @@ -1086,6 +1094,7 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) manager_class->get_capabilities = meta_monitor_manager_xrandr_get_capabilities; manager_class->get_max_screen_size = meta_monitor_manager_xrandr_get_max_screen_size; manager_class->get_default_layout_mode = meta_monitor_manager_xrandr_get_default_layout_mode; + manager_class->set_output_ctm = meta_monitor_manager_xrandr_set_output_ctm; quark_meta_monitor_xrandr_data = g_quark_from_static_string ("-meta-monitor-xrandr-data"); diff --git a/src/backends/x11/meta-output-xrandr.c b/src/backends/x11/meta-output-xrandr.c index 3d55d5fc9..62ad08623 100644 --- a/src/backends/x11/meta-output-xrandr.c +++ b/src/backends/x11/meta-output-xrandr.c @@ -14,6 +14,7 @@ * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * Copyright (C) 2013-2017 Red Hat Inc. + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -197,6 +198,21 @@ meta_output_xrandr_change_backlight (MetaOutputXrandr *output_xrandr, meta_output_set_backlight (output, normalize_backlight (output, hw_value)); } +void +meta_output_xrandr_set_ctm (MetaOutputXrandr *output_xrandr, + const MetaOutputCtm *ctm) +{ + MetaOutput *output = META_OUTPUT (output_xrandr); + Display *xdisplay = xdisplay_from_output (output); + Atom atom = XInternAtom (xdisplay, "CTM", False); + + xcb_randr_change_output_property (XGetXCBConnection (xdisplay), + (XID) meta_output_get_id (output), + atom, XCB_ATOM_INTEGER, 32, + XCB_PROP_MODE_REPLACE, + 18, &ctm->matrix); +} + static gboolean output_get_integer_property (Display *xdisplay, RROutput output_id, @@ -351,6 +367,32 @@ output_get_supports_underscanning_xrandr (Display *xdisplay, return supports_underscanning; } +static gboolean +output_get_supports_color_transform_xrandr (Display *xdisplay, + RROutput output_id) +{ + Atom atom, actual_type; + int actual_format; + unsigned long nitems, bytes_after; + g_autofree unsigned char *buffer = NULL; + + atom = XInternAtom (xdisplay, "CTM", False); + XRRGetOutputProperty (xdisplay, + (XID) output_id, + atom, + 0, G_MAXLONG, False, False, XA_INTEGER, + &actual_type, &actual_format, + &nitems, &bytes_after, &buffer); + + /* + * X's CTM property is 9 64-bit integers represented as an array of 18 32-bit + * integers. + */ + return (actual_type == XA_INTEGER && + actual_format == 32 && + nitems == 18); +} + static int output_get_backlight_xrandr (MetaOutput *output) { @@ -868,6 +910,8 @@ meta_output_xrandr_new (MetaGpuXrandr *gpu_xrandr, output_info->supports_underscanning = output_get_supports_underscanning_xrandr (xdisplay, output_id); + output_info->supports_color_transform = + output_get_supports_color_transform_xrandr (xdisplay, output_id); output_info_init_backlight_limits_xrandr (output_info, xdisplay, output_id); output = g_object_new (META_TYPE_OUTPUT_XRANDR, diff --git a/src/backends/x11/meta-output-xrandr.h b/src/backends/x11/meta-output-xrandr.h index e253e522a..ec5104f30 100644 --- a/src/backends/x11/meta-output-xrandr.h +++ b/src/backends/x11/meta-output-xrandr.h @@ -2,6 +2,7 @@ /* * Copyright (C) 2017 Red Hat + * Copyright (C) 2020 NVIDIA CORPORATION * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,6 +39,9 @@ void meta_output_xrandr_apply_mode (MetaOutputXrandr *output_xrandr); void meta_output_xrandr_change_backlight (MetaOutputXrandr *output_xrandr, int value); +void meta_output_xrandr_set_ctm (MetaOutputXrandr *output_xrandr, + const MetaOutputCtm *ctm); + GBytes * meta_output_xrandr_read_edid (MetaOutput *output_xrandr); MetaOutputXrandr * meta_output_xrandr_new (MetaGpuXrandr *gpu_xrandr, diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml index 044244e49..7522652dc 100644 --- a/src/org.gnome.Mutter.DisplayConfig.xml +++ b/src/org.gnome.Mutter.DisplayConfig.xml @@ -455,5 +455,19 @@ + + + + + + +