[mutter] monitor-manager: Take drm-connector panel-orientation property into account



commit 7917b083cb9f639edd6eb8cd6df462791e21c9b5
Author: Hans de Goede <hdegoede redhat com>
Date:   Tue Oct 24 12:43:58 2017 +0200

    monitor-manager: Take drm-connector panel-orientation property into account
    
    Some x86 clamshell design devices use portrait tablet LCD panels while
    they should use a landscape panel, resoluting in a 90 degree rotated
    picture.
    
    Newer kernels detect this and rotate the fb console in software to
    compensate. These kernels also export their knowledge of the LCD panel
    orientation vs the casing in a "panel orientation" drm_connector property.
    
    This commit adds support to mutter for reading the "panel orientation"
    and transparently (from a mutter consumer's pov) fixing this by applying
    a (hidden) rotation transform to compensate for the panel orientation.
    
    Related: https://bugs.freedesktop.org/show_bug.cgi?id=94894
    
    https://bugzilla.gnome.org/show_bug.cgi?id=782294

 src/backends/meta-logical-monitor.c                |    3 +-
 src/backends/meta-monitor-config-manager.c         |    9 +-
 src/backends/meta-monitor-manager-private.h        |    7 ++
 src/backends/meta-monitor.c                        |   82 +++++++++++++++----
 src/backends/meta-monitor.h                        |   10 +++
 src/backends/meta-output.h                         |    1 +
 src/backends/native/meta-output-kms.c              |   36 ++++++++-
 src/backends/native/meta-renderer-native.c         |    8 ++-
 src/backends/x11/meta-output-xrandr.c              |   34 ++++++++
 src/backends/x11/nested/meta-renderer-x11-nested.c |    8 ++-
 10 files changed, 168 insertions(+), 30 deletions(-)
---
diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c
index 2b21b1a..d2faa0f 100644
--- a/src/backends/meta-logical-monitor.c
+++ b/src/backends/meta-logical-monitor.c
@@ -103,7 +103,8 @@ derive_monitor_transform (MetaMonitor *monitor)
 
   main_output = meta_monitor_get_main_output (monitor);
 
-  return main_output->crtc->transform;
+  return meta_monitor_crtc_to_logical_transform (monitor,
+                                                 main_output->crtc->transform);
 }
 
 MetaLogicalMonitor *
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index 9e55d12..41d6b4b 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -152,11 +152,10 @@ assign_monitor_crtc (MetaMonitor         *monitor,
     }
 
   transform = data->logical_monitor_config->transform;
-  if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
-                                                 crtc,
-                                                 transform))
-    crtc_transform = transform;
-  else
+  crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
+  if (!meta_monitor_manager_is_transform_handled (data->monitor_manager,
+                                                  crtc,
+                                                  crtc_transform))
     crtc_transform = META_MONITOR_TRANSFORM_NORMAL;
 
   meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 59494db..c05a076 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -384,4 +384,11 @@ meta_monitor_transform_is_rotated (MetaMonitorTransform transform)
   return (transform % 2);
 }
 
+/* Returns true if transform involves flipping */
+static inline gboolean
+meta_monitor_transform_is_flipped (MetaMonitorTransform transform)
+{
+  return (transform >= META_MONITOR_TRANSFORM_FLIPPED);
+}
+
 #endif /* META_MONITOR_MANAGER_PRIVATE_H */
diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
index cfd0459..20f2544 100644
--- a/src/backends/meta-monitor.c
+++ b/src/backends/meta-monitor.c
@@ -354,6 +354,37 @@ meta_monitor_get_connector_type (MetaMonitor *monitor)
   return output->connector_type;
 }
 
+MetaMonitorTransform
+meta_monitor_logical_to_crtc_transform (MetaMonitor          *monitor,
+                                        MetaMonitorTransform  transform)
+{
+  MetaOutput *output = meta_monitor_get_main_output (monitor);
+  MetaMonitorTransform new_transform;
+
+  new_transform = (transform + output->panel_orientation_transform) %
+                  META_MONITOR_TRANSFORM_FLIPPED;
+  if (meta_monitor_transform_is_flipped (transform))
+    new_transform += META_MONITOR_TRANSFORM_FLIPPED;
+
+  return new_transform;
+}
+
+MetaMonitorTransform
+meta_monitor_crtc_to_logical_transform (MetaMonitor          *monitor,
+                                        MetaMonitorTransform  transform)
+{
+  MetaOutput *output = meta_monitor_get_main_output (monitor);
+  MetaMonitorTransform new_transform;
+
+  new_transform = (transform + META_MONITOR_TRANSFORM_FLIPPED -
+                   output->panel_orientation_transform) %
+                  META_MONITOR_TRANSFORM_FLIPPED;
+  if (meta_monitor_transform_is_flipped (transform))
+    new_transform += META_MONITOR_TRANSFORM_FLIPPED;
+
+  return new_transform;
+}
+
 static void
 meta_monitor_finalize (GObject *object)
 {
@@ -423,6 +454,29 @@ meta_monitor_add_mode (MetaMonitor     *monitor,
   return TRUE;
 }
 
+static MetaMonitorModeSpec
+meta_monitor_create_spec (MetaMonitor  *monitor,
+                          int           width,
+                          int           height,
+                          MetaCrtcMode *crtc_mode)
+{
+  MetaOutput *output = meta_monitor_get_main_output (monitor);
+
+  if (meta_monitor_transform_is_rotated (output->panel_orientation_transform))
+    {
+      int temp = width;
+      width = height;
+      height = temp;
+    }
+
+  return (MetaMonitorModeSpec) {
+    .width = width,
+    .height = height,
+    .refresh_rate = crtc_mode->refresh_rate,
+    .flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS
+  };
+}
+
 static void
 meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
 {
@@ -443,12 +497,10 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
       gboolean replace;
 
       mode = g_new0 (MetaMonitorMode, 1);
-      mode->spec = (MetaMonitorModeSpec) {
-        .width = crtc_mode->width,
-        .height = crtc_mode->height,
-        .refresh_rate = crtc_mode->refresh_rate,
-        .flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS
-      },
+      mode->spec = meta_monitor_create_spec (monitor,
+                                             crtc_mode->width,
+                                             crtc_mode->height,
+                                             crtc_mode);
       mode->id = generate_mode_id (&mode->spec);
       mode->crtc_modes = g_new (MetaMonitorCrtcMode, 1);
       mode->crtc_modes[0] = (MetaMonitorCrtcMode) {
@@ -780,12 +832,8 @@ create_tiled_monitor_mode (MetaMonitorTiled *monitor_tiled,
   mode->is_tiled = TRUE;
   meta_monitor_tiled_calculate_tiled_size (monitor, &width, &height);
 
-  mode->parent.spec = (MetaMonitorModeSpec) {
-    .width = width,
-    .height = height,
-    .refresh_rate = reference_crtc_mode->refresh_rate,
-    .flags = reference_crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS
-  };
+  mode->parent.spec =
+    meta_monitor_create_spec (monitor, width, height, reference_crtc_mode);
   mode->parent.id = generate_mode_id (&mode->parent.spec);
 
   mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode,
@@ -895,12 +943,10 @@ create_untiled_monitor_mode (MetaMonitorTiled *monitor_tiled,
   mode = g_new0 (MetaMonitorModeTiled, 1);
 
   mode->is_tiled = FALSE;
-  mode->parent.spec = (MetaMonitorModeSpec) {
-    .width = crtc_mode->width,
-    .height = crtc_mode->height,
-    .refresh_rate = crtc_mode->refresh_rate,
-    .flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS
-  };
+  mode->parent.spec = meta_monitor_create_spec (monitor,
+                                                crtc_mode->width,
+                                                crtc_mode->height,
+                                                crtc_mode);
   mode->parent.id = generate_mode_id (&mode->parent.spec);
   mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode,
                                     g_list_length (monitor_priv->outputs));
diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h
index faf4dd0..bc79778 100644
--- a/src/backends/meta-monitor.h
+++ b/src/backends/meta-monitor.h
@@ -145,6 +145,16 @@ const char * meta_monitor_get_serial (MetaMonitor *monitor);
 
 MetaConnectorType meta_monitor_get_connector_type (MetaMonitor *monitor);
 
+/* This function returns the transform corrected for the panel orientation */
+MetaMonitorTransform meta_monitor_logical_to_crtc_transform (MetaMonitor          *monitor,
+                                                             MetaMonitorTransform  transform);
+/*
+ * This function converts a transform corrected for the panel orientation
+ * to its logical (user-visible) transform.
+ */
+MetaMonitorTransform meta_monitor_crtc_to_logical_transform (MetaMonitor          *monitor,
+                                                             MetaMonitorTransform  transform);
+
 uint32_t meta_monitor_tiled_get_tile_group_id (MetaMonitorTiled *monitor_tiled);
 
 gboolean meta_monitor_get_suggested_position (MetaMonitor *monitor,
diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h
index e65826f..a63a1cd 100644
--- a/src/backends/meta-output.h
+++ b/src/backends/meta-output.h
@@ -78,6 +78,7 @@ struct _MetaOutput
   CoglSubpixelOrder subpixel_order;
 
   MetaConnectorType connector_type;
+  MetaMonitorTransform panel_orientation_transform;
 
   MetaCrtcMode *preferred_mode;
   MetaCrtcMode **modes;
diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c
index 544eb95..b15ffd9 100644
--- a/src/backends/native/meta-output-kms.c
+++ b/src/backends/native/meta-output-kms.c
@@ -229,9 +229,37 @@ meta_output_kms_read_edid (MetaOutput *output)
 }
 
 static void
+handle_panel_orientation (MetaOutput        *output,
+                          drmModePropertyPtr prop,
+                          int                orientation)
+{
+  const char *name = prop->enums[orientation].name;
+
+  if (strcmp (name, "Upside Down") == 0)
+    {
+      output->panel_orientation_transform = META_MONITOR_TRANSFORM_180;
+    }
+  else if (strcmp (name, "Left Side Up") == 0)
+    {
+      /* Left side up, rotate 90 degrees counter clockwise to correct */
+      output->panel_orientation_transform = META_MONITOR_TRANSFORM_90;
+    }
+  else if (strcmp (name, "Right Side Up") == 0)
+    {
+      /* Right side up, rotate 270 degrees counter clockwise to correct */
+      output->panel_orientation_transform = META_MONITOR_TRANSFORM_270;
+    }
+  else
+    {
+      output->panel_orientation_transform = META_MONITOR_TRANSFORM_NORMAL;
+    }
+}
+
+static void
 find_connector_properties (MetaGpuKms    *gpu_kms,
-                           MetaOutputKms *output_kms)
+                           MetaOutput    *output)
 {
+  MetaOutputKms *output_kms = output->driver_private;
   drmModeConnector *connector = output_kms->connector;
   int fd;
   int i;
@@ -268,6 +296,10 @@ find_connector_properties (MetaGpuKms    *gpu_kms,
         output_kms->hotplug_mode_update = connector->prop_values[i];
       else if (strcmp (prop->name, "scaling mode") == 0)
         output_kms->has_scaling = TRUE;
+      else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
+               strcmp (prop->name, "panel orientation") == 0)
+        handle_panel_orientation (output, prop,
+                                  output_kms->connector->prop_values[i]);
 
       drmModeFreeProperty (prop);
     }
@@ -469,7 +501,7 @@ meta_create_kms_output (MetaGpuKms       *gpu_kms,
     }
 
   output_kms->connector = connector;
-  find_connector_properties (gpu_kms, output_kms);
+  find_connector_properties (gpu_kms, output);
 
   init_output_modes (output, gpu_kms);
 
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 2e7878a..23d9fda 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -2342,8 +2342,12 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
 {
   MetaMonitor *main_monitor;
   MetaOutput *main_output;
+  MetaMonitorTransform crtc_transform;
   main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
   main_output = meta_monitor_get_main_output (main_monitor);
+  crtc_transform =
+    meta_monitor_logical_to_crtc_transform (main_monitor,
+                                            logical_monitor->transform);
 
   /*
    * Pick any monitor and output and check; all CRTCs of a logical monitor will
@@ -2352,10 +2356,10 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
 
   if (meta_monitor_manager_is_transform_handled (monitor_manager,
                                                  main_output->crtc,
-                                                 logical_monitor->transform))
+                                                 crtc_transform))
     return META_MONITOR_TRANSFORM_NORMAL;
   else
-    return logical_monitor->transform;
+    return crtc_transform;
 }
 
 static MetaRendererView *
diff --git a/src/backends/x11/meta-output-xrandr.c b/src/backends/x11/meta-output-xrandr.c
index 48c8fbb..4fed6e5 100644
--- a/src/backends/x11/meta-output-xrandr.c
+++ b/src/backends/x11/meta-output-xrandr.c
@@ -604,6 +604,38 @@ output_get_connector_type (MetaOutput *output)
   return META_CONNECTOR_TYPE_Unknown;
 }
 
+static gint
+output_get_panel_orientation_transform (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  unsigned long nitems, bytes_after;
+  Atom atom, actual_type;
+  int actual_format;
+  g_autofree unsigned char *buffer = NULL;
+  g_autofree char *str = NULL;
+
+  atom = XInternAtom (xdisplay, "panel orientation", False);
+  XRRGetOutputProperty (xdisplay, (XID)output->winsys_id, atom,
+                        0, G_MAXLONG, False, False, XA_ATOM,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
+    return META_MONITOR_TRANSFORM_NORMAL;
+
+  str = XGetAtomName (xdisplay, *(Atom *)buffer);
+  if (strcmp (str, "Upside Down") == 0)
+    return META_MONITOR_TRANSFORM_180;
+
+  if (strcmp (str, "Left Side Up") == 0)
+    return META_MONITOR_TRANSFORM_90;
+
+  if (strcmp (str, "Right Side Up") == 0)
+    return META_MONITOR_TRANSFORM_270;
+
+  return META_MONITOR_TRANSFORM_NORMAL;
+}
+
 static void
 output_get_tile_info (MetaOutput *output)
 {
@@ -744,6 +776,8 @@ meta_create_xrandr_output (MetaGpuXrandr *gpu_xrandr,
   output->suggested_x = output_get_suggested_x (output);
   output->suggested_y = output_get_suggested_y (output);
   output->connector_type = output_get_connector_type (output);
+  output->panel_orientation_transform =
+    output_get_panel_orientation_transform (output);
 
   output_get_tile_info (output);
   output_get_modes (output, xrandr_output);
diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c 
b/src/backends/x11/nested/meta-renderer-x11-nested.c
index d5ad778..a0c26c9 100644
--- a/src/backends/x11/nested/meta-renderer-x11-nested.c
+++ b/src/backends/x11/nested/meta-renderer-x11-nested.c
@@ -50,8 +50,12 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
 {
   MetaMonitor *main_monitor;
   MetaOutput *main_output;
+  MetaMonitorTransform crtc_transform;
   main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
   main_output = meta_monitor_get_main_output (main_monitor);
+  crtc_transform =
+    meta_monitor_logical_to_crtc_transform (main_monitor,
+                                            logical_monitor->transform);
 
   /*
    * Pick any monitor and output and check; all CRTCs of a logical monitor will
@@ -60,10 +64,10 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
 
   if (meta_monitor_manager_is_transform_handled (monitor_manager,
                                                  main_output->crtc,
-                                                 logical_monitor->transform))
+                                                 crtc_transform))
     return META_MONITOR_TRANSFORM_NORMAL;
   else
-    return logical_monitor->transform;
+    return crtc_transform;
 }
 
 static MetaRendererView *


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