[gnome-flashback] monitor-manager: add support for the "max bpc" connector property



commit f8e94a9113d2c63ef8d8e90b6c9f4d9c8f53d82b
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sun Aug 21 16:40:41 2022 +0300

    monitor-manager: add support for the "max bpc" connector property
    
    Based on mutter commits:
    https://gitlab.gnome.org/GNOME/mutter/-/commit/e0e10c29d962ef902dba13b1115a1d2e4bf43f6e
    https://gitlab.gnome.org/GNOME/mutter/-/commit/6ff0d600c3d0fcc945489428b5b1a2d1aca68bfe
    https://gitlab.gnome.org/GNOME/mutter/-/commit/a907cef9050a4bc24dd8bf65f9a3121fa43f9a2d
    https://gitlab.gnome.org/GNOME/mutter/-/commit/4eef54f80ad2daa4fc8758ed0821de02b07c573f
    https://gitlab.gnome.org/GNOME/mutter/-/commit/99d84ae1cc8f027a35c32d266cef48758daaff6d
    https://gitlab.gnome.org/GNOME/mutter/-/commit/d39137c63189775c23e962ef73a4bf41e7c29ca7
    https://gitlab.gnome.org/GNOME/mutter/-/commit/03336788fb079cb8aa203e031f85d039a87832ce
    https://gitlab.gnome.org/GNOME/mutter/-/commit/db0f12135ebc0d1ff11556140f36851228ce41bc

 backends/gf-monitor-config-manager.c |   8 ++-
 backends/gf-monitor-config-private.h |   2 +
 backends/gf-monitor-config-store.c   |  51 ++++++++++++++
 backends/gf-monitor-config.c         |   2 +
 backends/gf-monitor-manager-xrandr.c |  12 ++++
 backends/gf-monitor-private.h        |   3 +
 backends/gf-monitor.c                |  11 +++
 backends/gf-output-info-private.h    |   3 +
 backends/gf-output-private.h         |   5 ++
 backends/gf-output-xrandr.c          | 125 ++++++++++++++++++++++++++++++++++-
 backends/gf-output.c                 |  22 ++++++
 11 files changed, 241 insertions(+), 3 deletions(-)
---
diff --git a/backends/gf-monitor-config-manager.c b/backends/gf-monitor-config-manager.c
index 706f241..07f8a4d 100644
--- a/backends/gf-monitor-config-manager.c
+++ b/backends/gf-monitor-config-manager.c
@@ -791,7 +791,9 @@ clone_monitor_config_list (GList *configs_in)
       *config_out = (GfMonitorConfig) {
         .monitor_spec = gf_monitor_spec_clone (config_in->monitor_spec),
         .mode_spec = g_memdup2 (config_in->mode_spec, sizeof (GfMonitorModeSpec)),
-        .enable_underscanning = config_in->enable_underscanning
+        .enable_underscanning = config_in->enable_underscanning,
+        .has_max_bpc = config_in->has_max_bpc,
+        .max_bpc = config_in->max_bpc
       };
 
       configs_out = g_list_append (configs_out, config_out);
@@ -1145,7 +1147,9 @@ assign_monitor_crtc (GfMonitor          *monitor,
     .output = output,
     .is_primary = assign_output_as_primary,
     .is_presentation = assign_output_as_presentation,
-    .is_underscanning = data->monitor_config->enable_underscanning
+    .is_underscanning = data->monitor_config->enable_underscanning,
+    .has_max_bpc = data->monitor_config->has_max_bpc,
+    .max_bpc = data->monitor_config->max_bpc
   };
 
   g_ptr_array_add (data->crtc_assignments, crtc_assignment);
diff --git a/backends/gf-monitor-config-private.h b/backends/gf-monitor-config-private.h
index 44bd61e..0d8e0db 100644
--- a/backends/gf-monitor-config-private.h
+++ b/backends/gf-monitor-config-private.h
@@ -31,6 +31,8 @@ typedef struct
   GfMonitorSpec     *monitor_spec;
   GfMonitorModeSpec *mode_spec;
   gboolean           enable_underscanning;
+  gboolean           has_max_bpc;
+  unsigned int       max_bpc;
 } GfMonitorConfig;
 
 GfMonitorConfig *gf_monitor_config_new    (GfMonitor        *monitor,
diff --git a/backends/gf-monitor-config-store.c b/backends/gf-monitor-config-store.c
index e377b67..2031f69 100644
--- a/backends/gf-monitor-config-store.c
+++ b/backends/gf-monitor-config-store.c
@@ -158,6 +158,7 @@ typedef enum
   STATE_MONITOR_MODE_RATE,
   STATE_MONITOR_MODE_FLAG,
   STATE_MONITOR_UNDERSCANNING,
+  STATE_MONITOR_MAXBPC,
   STATE_DISABLED,
   STATE_POLICY,
   STATE_STORES,
@@ -497,6 +498,10 @@ handle_start_element (GMarkupParseContext  *context,
             {
               parser->state = STATE_MONITOR_UNDERSCANNING;
             }
+          else if (g_str_equal (element_name, "maxbpc"))
+            {
+              parser->state = STATE_MONITOR_MAXBPC;
+            }
           else
             {
               g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
@@ -590,6 +595,13 @@ handle_start_element (GMarkupParseContext  *context,
           return;
         }
 
+      case STATE_MONITOR_MAXBPC:
+        {
+          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                       "Invalid element '%s' under maxbpc", element_name);
+          return;
+        }
+
       case STATE_DISABLED:
         {
           if (!g_str_equal (element_name, "monitorspec"))
@@ -791,6 +803,7 @@ finish_monitor_spec (ConfigParser *parser)
       case STATE_MONITOR_MODE_RATE:
       case STATE_MONITOR_MODE_FLAG:
       case STATE_MONITOR_UNDERSCANNING:
+      case STATE_MONITOR_MAXBPC:
       case STATE_POLICY:
       case STATE_STORES:
       case STATE_STORE:
@@ -899,6 +912,14 @@ handle_end_element (GMarkupParseContext  *context,
           return;
         }
 
+      case STATE_MONITOR_MAXBPC:
+        {
+          g_assert (g_str_equal (element_name, "maxbpc"));
+
+          parser->state = STATE_MONITOR;
+          return;
+        }
+
       case STATE_MONITOR:
         {
           GfLogicalMonitorConfig *logical_monitor_config;
@@ -1378,6 +1399,29 @@ handle_text (GMarkupParseContext  *context,
           return;
         }
 
+      case STATE_MONITOR_MAXBPC:
+        {
+          int signed_max_bpc;
+
+          if (read_int (text, text_len, &signed_max_bpc, error))
+            {
+              if (signed_max_bpc >= 0)
+                {
+                  parser->current_monitor_config->has_max_bpc = TRUE;
+                  parser->current_monitor_config->max_bpc = signed_max_bpc;
+                }
+              else
+                {
+                  g_set_error (error, G_MARKUP_ERROR,
+                               G_MARKUP_ERROR_INVALID_CONTENT,
+                               "Invalid negative maxbpc value '%s'",
+                               text);
+                }
+            }
+
+          return;
+        }
+
       case STATE_STORE:
         {
           GfConfigStore store;
@@ -1623,6 +1667,13 @@ append_monitors (GString *buffer,
       g_string_append (buffer, "        </mode>\n");
       if (monitor_config->enable_underscanning)
         g_string_append (buffer, "        <underscanning>yes</underscanning>\n");
+
+      if (monitor_config->has_max_bpc)
+        {
+          g_string_append_printf (buffer, "        <maxbpc>%u</maxbpc>\n",
+                                  monitor_config->max_bpc);
+        }
+
       g_string_append (buffer, "      </monitor>\n");
     }
 }
diff --git a/backends/gf-monitor-config.c b/backends/gf-monitor-config.c
index 3bbe1d4..a4c1a67 100644
--- a/backends/gf-monitor-config.c
+++ b/backends/gf-monitor-config.c
@@ -42,6 +42,8 @@ gf_monitor_config_new (GfMonitor     *monitor,
   config->mode_spec = g_memdup2 (mode_spec, sizeof (GfMonitorModeSpec));
   config->enable_underscanning = gf_monitor_is_underscanning (monitor);
 
+  config->has_max_bpc = gf_monitor_get_max_bpc (monitor, &config->max_bpc);
+
   return config;
 }
 
diff --git a/backends/gf-monitor-manager-xrandr.c b/backends/gf-monitor-manager-xrandr.c
index 9786852..cd9d3cb 100644
--- a/backends/gf-monitor-manager-xrandr.c
+++ b/backends/gf-monitor-manager-xrandr.c
@@ -141,6 +141,7 @@ is_output_assignment_changed (GfOutput            *output,
   for (i = 0; i < n_output_assignments; i++)
     {
       GfOutputAssignment *output_assignment;
+      unsigned int max_bpc;
 
       output_assignment = output_assignments[i];
 
@@ -156,6 +157,17 @@ is_output_assignment_changed (GfOutput            *output,
       if (gf_output_is_underscanning (output) != output_assignment->is_underscanning)
         return TRUE;
 
+      if (gf_output_get_max_bpc (output, &max_bpc))
+        {
+          if (!output_assignment->has_max_bpc ||
+              max_bpc != output_assignment->max_bpc)
+            return TRUE;
+        }
+      else if (output_assignment->has_max_bpc)
+        {
+          return TRUE;
+        }
+
       output_is_found = TRUE;
     }
 
diff --git a/backends/gf-monitor-private.h b/backends/gf-monitor-private.h
index ce6ea98..6c608dc 100644
--- a/backends/gf-monitor-private.h
+++ b/backends/gf-monitor-private.h
@@ -139,6 +139,9 @@ gboolean            gf_monitor_supports_underscanning     (GfMonitor
 
 gboolean            gf_monitor_is_underscanning           (GfMonitor                  *monitor);
 
+gboolean            gf_monitor_get_max_bpc                (GfMonitor                  *self,
+                                                           unsigned int               *max_bpc);
+
 gboolean            gf_monitor_is_laptop_panel            (GfMonitor                  *monitor);
 
 gboolean            gf_monitor_is_same_as                 (GfMonitor                  *monitor,
diff --git a/backends/gf-monitor.c b/backends/gf-monitor.c
index 7b1c374..e480467 100644
--- a/backends/gf-monitor.c
+++ b/backends/gf-monitor.c
@@ -781,6 +781,17 @@ gf_monitor_is_underscanning (GfMonitor *monitor)
   return gf_output_is_underscanning (output);
 }
 
+gboolean
+gf_monitor_get_max_bpc (GfMonitor    *self,
+                        unsigned int *max_bpc)
+{
+  GfOutput *output;
+
+  output = gf_monitor_get_main_output (self);
+
+  return gf_output_get_max_bpc (output, max_bpc);
+}
+
 gboolean
 gf_monitor_is_laptop_panel (GfMonitor *monitor)
 {
diff --git a/backends/gf-output-info-private.h b/backends/gf-output-info-private.h
index d37b19e..5f3788e 100644
--- a/backends/gf-output-info-private.h
+++ b/backends/gf-output-info-private.h
@@ -74,6 +74,9 @@ typedef struct
   gboolean             supports_underscanning;
   gboolean             supports_color_transform;
 
+  unsigned int         max_bpc_min;
+  unsigned int         max_bpc_max;
+
   /* 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 e59cdd4..278644f 100644
--- a/backends/gf-output-private.h
+++ b/backends/gf-output-private.h
@@ -45,6 +45,8 @@ typedef struct
   gboolean  is_primary;
   gboolean  is_presentation;
   gboolean  is_underscanning;
+  gboolean  has_max_bpc;
+  unsigned  int max_bpc;
 } GfOutputAssignment;
 
 #define GF_TYPE_OUTPUT (gf_output_get_type ())
@@ -92,6 +94,9 @@ gboolean            gf_output_is_presentation           (GfOutput
 
 gboolean            gf_output_is_underscanning          (GfOutput                 *self);
 
+gboolean            gf_output_get_max_bpc               (GfOutput                 *self,
+                                                         unsigned int             *max_bpc);
+
 void                gf_output_set_backlight             (GfOutput                 *self,
                                                          int                       backlight);
 
diff --git a/backends/gf-output-xrandr.c b/backends/gf-output-xrandr.c
index c9ebda6..55d25fb 100644
--- a/backends/gf-output-xrandr.c
+++ b/backends/gf-output-xrandr.c
@@ -154,6 +154,25 @@ output_set_underscanning_xrandr (GfOutput *output,
     }
 }
 
+static void
+output_set_max_bpc_xrandr (GfOutput     *output,
+                           unsigned int  max_bpc)
+{
+  Display *xdisplay;
+  Atom prop;
+  uint32_t value;
+
+  xdisplay = xdisplay_from_output (output);
+  prop = XInternAtom (xdisplay, "max bpc", False);
+  value = max_bpc;
+
+  xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                    (XID) gf_output_get_id (output),
+                                    prop, XCB_ATOM_INTEGER, 32,
+                                    XCB_PROP_MODE_REPLACE,
+                                    1, &value);
+}
+
 static guint8 *
 get_edid_property (Display  *xdisplay,
                    RROutput  output,
@@ -637,6 +656,52 @@ output_get_boolean_property (GfOutput    *output,
   return value;
 }
 
+static gboolean
+output_get_max_bpc_xrandr (GfOutput   *output,
+                           unsigned int *max_bpc)
+{
+  Display *xdisplay;
+  Atom atom;
+  Atom actual_type;
+  int actual_format;
+  unsigned long nitems;
+  unsigned long bytes_after;
+  unsigned char *buffer;
+
+  xdisplay = xdisplay_from_output (output);
+  atom = XInternAtom (xdisplay, "max bpc", False);
+  buffer = NULL;
+
+  XRRGetOutputProperty (xdisplay,
+                        (XID) gf_output_get_id (output),
+                        atom,
+                        0,
+                        G_MAXLONG,
+                        False,
+                        False,
+                        XCB_ATOM_INTEGER,
+                        &actual_type,
+                        &actual_format,
+                        &nitems,
+                        &bytes_after,
+                        &buffer);
+
+  if (actual_type != XCB_ATOM_INTEGER || actual_format != 32 || nitems < 1)
+    {
+      if (buffer != NULL)
+        XFree (buffer);
+
+      return FALSE;
+    }
+
+  if (max_bpc)
+    *max_bpc = *((uint32_t*) buffer);
+
+  XFree (buffer);
+
+  return TRUE;
+}
+
 static gboolean
 output_get_presentation_xrandr (GfOutput *output)
 {
@@ -724,6 +789,44 @@ output_get_supports_underscanning_xrandr (Display  *xdisplay,
   return supports_underscanning;
 }
 
+static gboolean
+output_get_max_bpc_range_xrandr (Display      *xdisplay,
+                                 RROutput      output_id,
+                                 unsigned int *min,
+                                 unsigned int *max)
+{
+  Atom atom;
+  XRRPropertyInfo *property_info;
+  long *values;
+
+  if (!output_get_property_exists (xdisplay, output_id, "max bpc"))
+    return FALSE;
+
+  atom = XInternAtom (xdisplay, "max bpc", False);
+  property_info = XRRQueryOutputProperty (xdisplay, (XID) output_id, atom);
+
+  if (property_info == NULL)
+    return FALSE;
+
+  if (property_info->num_values != 2)
+    {
+      XFree (property_info);
+      return FALSE;
+    }
+
+  values = (long *) property_info->values;
+
+  if (min)
+    *min = values[0];
+
+  if (max)
+    *max = values[1];
+
+  XFree (property_info);
+
+  return TRUE;
+}
+
 static gboolean
 output_get_supports_color_transform_xrandr (Display  *xdisplay,
                                             RROutput  output_id)
@@ -920,6 +1023,12 @@ gf_output_xrandr_new (GfGpuXrandr   *gpu_xrandr,
 
   output_info->supports_underscanning = output_get_supports_underscanning_xrandr (xdisplay,
                                                                                   output_id);
+
+  output_get_max_bpc_range_xrandr (xdisplay,
+                                   output_id,
+                                   &output_info->max_bpc_min,
+                                   &output_info->max_bpc_max);
+
   output_info->supports_color_transform = output_get_supports_color_transform_xrandr (xdisplay,
                                                                                       output_id);
 
@@ -935,6 +1044,7 @@ gf_output_xrandr_new (GfGpuXrandr   *gpu_xrandr,
   if (assigned_crtc)
     {
       GfOutputAssignment output_assignment;
+      gboolean has_max_bpc;
 
       output_assignment = (GfOutputAssignment) {
         .is_primary = (XID) gf_output_get_id (output) == primary_output,
@@ -942,6 +1052,9 @@ gf_output_xrandr_new (GfGpuXrandr   *gpu_xrandr,
         .is_underscanning = output_get_underscanning_xrandr (output),
       };
 
+      has_max_bpc = output_get_max_bpc_xrandr (output, &output_assignment.max_bpc);
+      output_assignment.has_max_bpc = has_max_bpc;
+
       gf_output_assign_crtc (output, assigned_crtc, &output_assignment);
     }
   else
@@ -983,9 +1096,12 @@ gf_output_xrandr_apply_mode (GfOutputXrandr *self)
 {
   GfOutput *output;
   Display *xdisplay;
+  const GfOutputInfo *output_info;
+  unsigned int max_bpc;
 
   output = GF_OUTPUT (self);
   xdisplay = xdisplay_from_output (output);
+  output_info = gf_output_get_info (output);
 
   if (gf_output_is_primary (output))
     {
@@ -995,11 +1111,18 @@ gf_output_xrandr_apply_mode (GfOutputXrandr *self)
 
   output_set_presentation_xrandr (output, gf_output_is_presentation (output));
 
-  if (gf_output_get_info (output)->supports_underscanning)
+  if (output_info->supports_underscanning)
     {
       output_set_underscanning_xrandr (output,
                                        gf_output_is_underscanning (output));
     }
+
+  if (gf_output_get_max_bpc (output, &max_bpc) &&
+      max_bpc >= output_info->max_bpc_min &&
+      max_bpc <= output_info->max_bpc_max)
+    {
+      output_set_max_bpc_xrandr (output, max_bpc);
+    }
 }
 
 void
diff --git a/backends/gf-output.c b/backends/gf-output.c
index ab7aed2..685ac0e 100644
--- a/backends/gf-output.c
+++ b/backends/gf-output.c
@@ -49,6 +49,9 @@ typedef struct
 
   gboolean      is_underscanning;
 
+  gboolean      has_max_bpc;
+  unsigned int  max_bpc;
+
   int           backlight;
 } GfOutputPrivate;
 
@@ -311,6 +314,11 @@ gf_output_assign_crtc (GfOutput                 *self,
   priv->is_primary = output_assignment->is_primary;
   priv->is_presentation = output_assignment->is_presentation;
   priv->is_underscanning = output_assignment->is_underscanning;
+
+  priv->has_max_bpc = output_assignment->has_max_bpc;
+
+  if (priv->has_max_bpc)
+    priv->max_bpc = output_assignment->max_bpc;
 }
 
 void
@@ -439,6 +447,20 @@ gf_output_is_underscanning (GfOutput *self)
   return priv->is_underscanning;
 }
 
+gboolean
+gf_output_get_max_bpc (GfOutput     *self,
+                       unsigned int *max_bpc)
+{
+  GfOutputPrivate *priv;
+
+  priv = gf_output_get_instance_private (self);
+
+  if (priv->has_max_bpc && max_bpc != NULL)
+    *max_bpc = priv->max_bpc;
+
+  return priv->has_max_bpc;
+}
+
 void
 gf_output_set_backlight (GfOutput *self,
                          int       backlight)


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