[mutter] x11: Support the CTM (color transform matrix) RandR property



commit e88467f9d76bcacecf14f250e678196da497daf6
Author: Aaron Plattner <aplattner nvidia com>
Date:   Tue Feb 4 16:41:34 2020 -0800

    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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1048>

 src/backends/meta-monitor-manager-private.h    | 16 ++++++
 src/backends/meta-monitor-manager.c            | 67 ++++++++++++++++++++++++++
 src/backends/meta-output.h                     |  2 +
 src/backends/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 eaad2c4ce7..e6cffab1f9 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 dbf799975f..756c0e64cb 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 4f2d193376..c54d4206b3 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 03e6175f50..a2f8931625 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 3d55d5fc95..62ad086235 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 e253e522a6..ec5104f30f 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 044244e492..7522652dc0 100644
--- a/src/org.gnome.Mutter.DisplayConfig.xml
+++ b/src/org.gnome.Mutter.DisplayConfig.xml
@@ -455,5 +455,19 @@
       <arg name="logical_monitors" direction="in" type="a(iiduba(ssa{sv}))" />
       <arg name="properties" direction="in" type="a{sv}" />
     </method>
+
+    <!--
+        SetOutputCTM:
+        @serial: configuration serial
+        @output: API id of the output
+        @ctm: 3x3 matrix in fixed-point sign-magnitude S31.32
+
+        Changes the color transform matrix of @output
+    -->
+    <method name="SetOutputCTM">
+      <arg name="serial" direction="in" type="u" />
+      <arg name="output" direction="in" type="u" />
+      <arg name="ctm" direction="in" type="(ttttttttt)" />
+    </method>
   </interface>
 </node>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]