[gnome-flashback] monitor-manager: support the CTM RandR property



commit 55c01885e92e9887038ab82584e428b587b72169
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Aug 13 13:08:07 2022 +0300

    monitor-manager: support the CTM RandR property
    
    Based on mutter commits:
    https://gitlab.gnome.org/GNOME/mutter/-/commit/e88467f9d76bcacecf14
    https://gitlab.gnome.org/GNOME/mutter/-/commit/aa498dc27a47a527558f
    https://gitlab.gnome.org/GNOME/mutter/-/commit/cf8efb58274d9a81ec00

 backends/gf-monitor-manager-private.h       |  4 ++
 backends/gf-monitor-manager-types-private.h |  1 +
 backends/gf-monitor-manager-xrandr.c        |  9 ++++
 backends/gf-monitor-manager.c               | 69 +++++++++++++++++++++++++
 backends/gf-output-info-private.h           |  2 +
 backends/gf-output-private.h                |  6 +++
 backends/gf-output-xrandr-private.h         |  4 ++
 backends/gf-output-xrandr.c                 | 79 ++++++++++++++++++++++++++++-
 backends/org.gnome.Mutter.DisplayConfig.xml | 15 ++++++
 9 files changed, 188 insertions(+), 1 deletion(-)
---
diff --git a/backends/gf-monitor-manager-private.h b/backends/gf-monitor-manager-private.h
index fdcdde8..a05893e 100644
--- a/backends/gf-monitor-manager-private.h
+++ b/backends/gf-monitor-manager-private.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013 Red Hat Inc.
  * Copyright (C) 2017-2019 Alberts Muktupāvels
+ * 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 published by
@@ -140,6 +141,9 @@ typedef struct
                                                                  gint                        *max_height);
 
   GfLogicalMonitorLayoutMode   (* get_default_layout_mode)      (GfMonitorManager            *manager);
+
+  void                         (* set_output_ctm)               (GfOutput                    *output,
+                                                                 const GfOutputCtm           *ctm);
 } GfMonitorManagerClass;
 
 GType                       gf_monitor_manager_get_type                     (void);
diff --git a/backends/gf-monitor-manager-types-private.h b/backends/gf-monitor-manager-types-private.h
index 384a54c..15d7678 100644
--- a/backends/gf-monitor-manager-types-private.h
+++ b/backends/gf-monitor-manager-types-private.h
@@ -43,6 +43,7 @@ typedef struct _GfGpu GfGpu;
 
 typedef struct _GfCrtc GfCrtc;
 typedef struct _GfOutput GfOutput;
+typedef struct _GfOutputCtm GfOutputCtm;
 typedef struct _GfCrtcMode GfCrtcMode;
 
 G_END_DECLS
diff --git a/backends/gf-monitor-manager-xrandr.c b/backends/gf-monitor-manager-xrandr.c
index 178d48b..eece357 100644
--- a/backends/gf-monitor-manager-xrandr.c
+++ b/backends/gf-monitor-manager-xrandr.c
@@ -7,6 +7,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013 Red Hat Inc.
  * Copyright (C) 2017-2019 Alberts Muktupāvels
+ * 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 published by
@@ -1007,6 +1008,13 @@ gf_monitor_manager_xrandr_get_default_layout_mode (GfMonitorManager *manager)
   return GF_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 }
 
+static void
+gf_monitor_manager_xrandr_set_output_ctm (GfOutput          *output,
+                                          const GfOutputCtm *ctm)
+{
+  gf_output_xrandr_set_ctm (GF_OUTPUT_XRANDR (output), ctm);
+}
+
 static void
 gf_monitor_manager_xrandr_class_init (GfMonitorManagerXrandrClass *xrandr_class)
 {
@@ -1035,6 +1043,7 @@ gf_monitor_manager_xrandr_class_init (GfMonitorManagerXrandrClass *xrandr_class)
   manager_class->get_capabilities = gf_monitor_manager_xrandr_get_capabilities;
   manager_class->get_max_screen_size = gf_monitor_manager_xrandr_get_max_screen_size;
   manager_class->get_default_layout_mode = gf_monitor_manager_xrandr_get_default_layout_mode;
+  manager_class->set_output_ctm = gf_monitor_manager_xrandr_set_output_ctm;
 }
 
 static void
diff --git a/backends/gf-monitor-manager.c b/backends/gf-monitor-manager.c
index 1e3289e..4e9d63c 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -7,6 +7,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013 Red Hat Inc.
  * Copyright (C) 2017-2019 Alberts Muktupāvels
+ * 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 published by
@@ -1373,6 +1374,7 @@ gf_monitor_manager_handle_get_resources (GfDBusDisplayConfig   *skeleton,
       const char *connector_type_name;
       gboolean is_underscanning;
       gboolean supports_underscanning;
+      gboolean supports_color_transform;
 
       output = l->data;
       output_info = gf_output_get_info (output);
@@ -1420,6 +1422,7 @@ gf_monitor_manager_handle_get_resources (GfDBusDisplayConfig   *skeleton,
       is_underscanning = gf_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",
@@ -1448,6 +1451,8 @@ gf_monitor_manager_handle_get_resources (GfDBusDisplayConfig   *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);
 
@@ -2133,6 +2138,67 @@ gf_monitor_manager_handle_apply_monitors_config (GfDBusDisplayConfig   *skeleton
   return TRUE;
 }
 
+static gboolean
+gf_monitor_manager_handle_set_output_ctm (GfDBusDisplayConfig   *skeleton,
+                                          GDBusMethodInvocation *invocation,
+                                          guint                  serial,
+                                          guint                  output_id,
+                                          GVariant              *ctm_var,
+                                          GfMonitorManager      *self)
+{
+  GfMonitorManagerClass *manager_class;
+  GList *combined_outputs;
+  GfOutput *output;
+  GfOutputCtm ctm;
+  int i;
+
+  if (serial != self->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 (self, gf_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);
+    }
+
+  manager_class = GF_MONITOR_MANAGER_GET_CLASS (self);
+
+  if (manager_class->set_output_ctm != NULL)
+    manager_class->set_output_ctm (output, &ctm);
+
+  gf_dbus_display_config_complete_set_output_ctm (skeleton, invocation);
+
+  return TRUE;
+}
+
 static void
 monitor_manager_setup_dbus_config_handlers (GfMonitorManager *manager)
 {
@@ -2154,6 +2220,9 @@ monitor_manager_setup_dbus_config_handlers (GfMonitorManager *manager)
   g_signal_connect_object (manager->display_config, "handle-apply-monitors-config",
                            G_CALLBACK (gf_monitor_manager_handle_apply_monitors_config),
                            manager, 0);
+  g_signal_connect_object (manager->display_config, "handle-set-output-ctm",
+                           G_CALLBACK (gf_monitor_manager_handle_set_output_ctm),
+                           manager, 0);
 }
 
 static void
diff --git a/backends/gf-output-info-private.h b/backends/gf-output-info-private.h
index 29db275..d37b19e 100644
--- a/backends/gf-output-info-private.h
+++ b/backends/gf-output-info-private.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013 Red Hat Inc.
  * Copyright (C) 2017-2020 Alberts Muktupāvels
+ * 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 published by
@@ -71,6 +72,7 @@ typedef struct
   int                  backlight_max;
 
   gboolean             supports_underscanning;
+  gboolean             supports_color_transform;
 
   /* Get a new preferred mode on hotplug events, to handle
    * dynamic guest resizing
diff --git a/backends/gf-output-private.h b/backends/gf-output-private.h
index 1ac0d24..c7c45eb 100644
--- a/backends/gf-output-private.h
+++ b/backends/gf-output-private.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013 Red Hat Inc.
  * Copyright (C) 2017-2019 Alberts Muktupāvels
+ * 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 published by
@@ -33,6 +34,11 @@
 
 G_BEGIN_DECLS
 
+typedef struct _GfOutputCtm
+{
+  uint64_t matrix[9];
+} GfOutputCtm;
+
 typedef struct
 {
   GfOutput *output;
diff --git a/backends/gf-output-xrandr-private.h b/backends/gf-output-xrandr-private.h
index c8a7d32..49f9300 100644
--- a/backends/gf-output-xrandr-private.h
+++ b/backends/gf-output-xrandr-private.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2017 Red Hat
  * Copyright (C) 2019 Alberts Muktupāvels
+ * 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 published by
@@ -42,6 +43,9 @@ void           gf_output_xrandr_apply_mode       (GfOutputXrandr *self);
 void           gf_output_xrandr_change_backlight (GfOutputXrandr *self,
                                                   int             value);
 
+void           gf_output_xrandr_set_ctm          (GfOutputXrandr    *self,
+                                                  const GfOutputCtm *ctm);
+
 G_END_DECLS
 
 #endif
diff --git a/backends/gf-output-xrandr.c b/backends/gf-output-xrandr.c
index 230ec23..c9ebda6 100644
--- a/backends/gf-output-xrandr.c
+++ b/backends/gf-output-xrandr.c
@@ -7,6 +7,7 @@
  * Copyright (C) 2004-2006 Elijah Newren
  * Copyright (C) 2013-2017 Red Hat Inc.
  * Copyright (C) 2017-2019 Alberts Muktupāvels
+ * 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 published by
@@ -36,11 +37,29 @@
 
 struct _GfOutputXrandr
 {
-  GfOutput parent;
+  GfOutput    parent;
+
+  gboolean    ctm_initialized;
+  GfOutputCtm ctm;
 };
 
 G_DEFINE_TYPE (GfOutputXrandr, gf_output_xrandr, GF_TYPE_OUTPUT)
 
+static gboolean
+ctm_is_equal (const GfOutputCtm *ctm1,
+              const GfOutputCtm *ctm2)
+{
+  int i;
+
+  for (i = 0; i < 9; i++)
+    {
+      if (ctm1->matrix[i] != ctm2->matrix[i])
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
 static Display *
 xdisplay_from_gpu (GfGpu *gpu)
 {
@@ -705,6 +724,35 @@ 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;
+  unsigned char *buffer;
+
+  atom = XInternAtom (xdisplay, "CTM", False);
+  buffer = NULL;
+
+  XRRGetOutputProperty (xdisplay,
+                        (XID) output_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_INTEGER,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  XFree (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
 normalize_backlight (GfOutput *output,
                      gint      hw_value)
@@ -872,6 +920,9 @@ gf_output_xrandr_new (GfGpuXrandr   *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 (GF_TYPE_OUTPUT_XRANDR,
@@ -977,3 +1028,29 @@ gf_output_xrandr_change_backlight (GfOutputXrandr *self,
   /* We're not selecting for property notifies, so update the value immediately */
   gf_output_set_backlight (output, normalize_backlight (output, hw_value));
 }
+
+void
+gf_output_xrandr_set_ctm (GfOutputXrandr    *self,
+                          const GfOutputCtm *ctm)
+{
+  if (!self->ctm_initialized || !ctm_is_equal (ctm, &self->ctm))
+    {
+      GfOutput *output;
+      Display *xdisplay;
+      Atom ctm_atom;
+
+      output = GF_OUTPUT (self);
+
+      xdisplay = xdisplay_from_output (output);
+      ctm_atom = XInternAtom (xdisplay, "CTM", False);
+
+      xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                        (XID) gf_output_get_id (output),
+                                        ctm_atom, XCB_ATOM_INTEGER, 32,
+                                        XCB_PROP_MODE_REPLACE,
+                                        18, &ctm->matrix);
+
+      self->ctm_initialized = TRUE;
+      self->ctm = *ctm;
+    }
+}
diff --git a/backends/org.gnome.Mutter.DisplayConfig.xml b/backends/org.gnome.Mutter.DisplayConfig.xml
index d0afd23..33dcbd6 100644
--- a/backends/org.gnome.Mutter.DisplayConfig.xml
+++ b/backends/org.gnome.Mutter.DisplayConfig.xml
@@ -403,5 +403,20 @@
       <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]