From 7917b083cb9f639edd6eb8cd6df462791e21c9b5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 24 Oct 2017 12:43:58 +0200 Subject: [PATCH] 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 | 38 ++++++++- src/backends/native/meta-renderer-native.c | 8 +- src/backends/x11/meta-output-xrandr.c | 34 ++++++++ .../x11/nested/meta-renderer-x11-nested.c | 8 +- 10 files changed, 169 insertions(+), 31 deletions(-) diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c index 2b21b1a79..d2faa0f26 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 9e55d122b..41d6b4bce 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 59494db5d..c05a076e1 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 cfd045956..20f25440b 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 faf4dd061..bc7977886 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 e65826fda..a63a1cd10 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 544eb9593..b15ffd974 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 -find_connector_properties (MetaGpuKms *gpu_kms, - MetaOutputKms *output_kms) +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, + 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 2e7878ae2..23d9fda26 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 48c8fbbb7..4fed6e5d9 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 d5ad77877..a0c26c9b5 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 *