From 18c85c9ffb23186f5e1739d31df6ceaee906893e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 9 Jan 2018 21:29:26 +0100 Subject: [PATCH] backends: Compare gpu/crtc/output configurations before applying This spares us from visible flickering whenever an unchanged configuration is reapplied, eg. after lid open. The code in the X11 paths that did the same comparisons has been removed in favor of the generic checks. https://bugzilla.gnome.org/show_bug.cgi?id=791879 --- src/backends/meta-monitor-manager-private.h | 6 + src/backends/meta-monitor-manager.c | 152 ++++++++++++++++++ .../native/meta-monitor-manager-kms.c | 31 ++++ .../x11/meta-monitor-manager-xrandr.c | 142 +--------------- 4 files changed, 194 insertions(+), 137 deletions(-) diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 20bb6b679..dd9b25259 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -388,4 +388,10 @@ gboolean meta_monitor_has_aspect_as_size (MetaMonitor *monitor); char * meta_monitor_manager_get_vendor_name (MetaMonitorManager *manager, const char *vendor); +gboolean meta_monitor_manager_get_has_changed (MetaMonitorManager *manager, + MetaCrtcInfo **crtc_infos, + unsigned int n_crtc_infos, + MetaOutputInfo **output_infos, + unsigned int n_output_infos); + #endif /* META_MONITOR_MANAGER_PRIVATE_H */ diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 41036ca2a..4048249fe 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -483,6 +483,158 @@ meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager) META_MONITOR_MANAGER_GET_CLASS (manager)->ensure_initial_config (manager); } +static gboolean +is_crtc_assignment_changed (MetaCrtc *crtc, + MetaCrtcInfo **crtc_infos, + unsigned int n_crtc_infos) +{ + unsigned int i; + + for (i = 0; i < n_crtc_infos; i++) + { + MetaCrtcInfo *crtc_info = crtc_infos[i]; + unsigned int j; + + if (crtc_info->crtc != crtc) + continue; + + if (crtc->current_mode != crtc_info->mode) + return TRUE; + + if (crtc->rect.x != crtc_info->x) + return TRUE; + + if (crtc->rect.y != crtc_info->y) + return TRUE; + + if (crtc->transform != crtc_info->transform) + return TRUE; + + for (j = 0; j < crtc_info->outputs->len; j++) + { + MetaOutput *output = ((MetaOutput**) crtc_info->outputs->pdata)[j]; + MetaCrtc *assigned_crtc; + + assigned_crtc = meta_output_get_assigned_crtc (output); + if (assigned_crtc != crtc) + return TRUE; + } + + return FALSE; + } + + return crtc->current_mode != NULL; +} + +static gboolean +is_output_assignment_changed (MetaOutput *output, + MetaCrtcInfo **crtc_infos, + unsigned int n_crtc_infos, + MetaOutputInfo **output_infos, + unsigned int n_output_infos) +{ + MetaCrtc *assigned_crtc; + gboolean output_is_found = FALSE; + unsigned int i; + + for (i = 0; i < n_output_infos; i++) + { + MetaOutputInfo *output_info = output_infos[i]; + + if (output_info->output != output) + continue; + + if (output->is_primary != output_info->is_primary) + return TRUE; + + if (output->is_presentation != output_info->is_presentation) + return TRUE; + + if (output->is_underscanning != output_info->is_underscanning) + return TRUE; + + output_is_found = TRUE; + } + + assigned_crtc = meta_output_get_assigned_crtc (output); + + if (!output_is_found) + return assigned_crtc != NULL; + + for (i = 0; i < n_crtc_infos; i++) + { + MetaCrtcInfo *crtc_info = crtc_infos[i]; + unsigned int j; + + for (j = 0; j < crtc_info->outputs->len; j++) + { + MetaOutput *crtc_info_output = + ((MetaOutput**) crtc_info->outputs->pdata)[j]; + + if (crtc_info_output == output && + crtc_info->crtc == assigned_crtc) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +is_assignments_changed (MetaMonitorManager *manager, + MetaGpu *gpu, + MetaCrtcInfo **crtc_infos, + unsigned int n_crtc_infos, + MetaOutputInfo **output_infos, + unsigned int n_output_infos) +{ + GList *l; + + for (l = meta_gpu_get_crtcs (gpu); l; l = l->next) + { + MetaCrtc *crtc = l->data; + + if (is_crtc_assignment_changed (crtc, crtc_infos, n_crtc_infos)) + return TRUE; + } + + for (l = meta_gpu_get_outputs (gpu); l; l = l->next) + { + MetaOutput *output = l->data; + + if (is_output_assignment_changed (output, + crtc_infos, + n_crtc_infos, + output_infos, + n_output_infos)) + return TRUE; + } + + return FALSE; +} + +gboolean +meta_monitor_manager_get_has_changed (MetaMonitorManager *manager, + MetaCrtcInfo **crtc_infos, + unsigned int n_crtc_infos, + MetaOutputInfo **output_infos, + unsigned int n_output_infos) +{ + GList *gpus; + GList *l; + + gpus = meta_backend_get_gpus (manager->backend); + for (l = gpus; l; l = l->next) + { + if (is_assignments_changed (manager, l->data, + crtc_infos, n_crtc_infos, + output_infos, n_output_infos)) + return TRUE; + } + + return FALSE; +} + static gboolean meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager, MetaMonitorsConfig *config, diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index 26c2ddb61..a768b74f2 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -77,6 +77,8 @@ struct _MetaMonitorManagerKms guint hotplug_handler_id; guint removed_handler_id; + + guint logical_monitors_invalid : 1; }; struct _MetaMonitorManagerKmsClass @@ -322,6 +324,7 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager MetaMonitorsConfigMethod method, GError **error) { + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); GPtrArray *crtc_infos; GPtrArray *output_infos; @@ -345,6 +348,26 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager return TRUE; } + if (!meta_monitor_manager_get_has_changed (manager, + (MetaCrtcInfo **) crtc_infos->pdata, + crtc_infos->len, + (MetaOutputInfo **) output_infos->pdata, + output_infos->len)) + { + /* Rebuild logical monitors if invalid, i.e. after + * meta_monitor_manager_read_current_state(). + */ + if (manager_kms->logical_monitors_invalid) + { + meta_monitor_manager_rebuild (manager, config); + manager_kms->logical_monitors_invalid = FALSE; + } + + g_ptr_array_free (crtc_infos, TRUE); + g_ptr_array_free (output_infos, TRUE); + return TRUE; + } + apply_crtc_assignments (manager, (MetaCrtcInfo **) crtc_infos->pdata, crtc_infos->len, @@ -356,6 +379,7 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager update_screen_size (manager, config); meta_monitor_manager_rebuild (manager, config); + manager_kms->logical_monitors_invalid = FALSE; return TRUE; } @@ -474,6 +498,13 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, static void handle_hotplug_event (MetaMonitorManager *manager) { + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + + /* read_current_state() will rebuild monitors, leaving MetaLogicalMonitors + * with stale pointers to those. We will need to rebuild those even though + * the configuration might not have actually changed (eg. tty switch). + */ + manager_kms->logical_monitors_invalid = TRUE; meta_monitor_manager_read_current_state (manager); meta_monitor_manager_on_hotplug (manager); } diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 8fae335f0..6e9d142f5 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -240,103 +240,6 @@ xrandr_set_crtc_config (MetaMonitorManagerXrandr *manager_xrandr, return TRUE; } -static gboolean -is_crtc_assignment_changed (MetaCrtc *crtc, - MetaCrtcInfo **crtc_infos, - unsigned int n_crtc_infos) -{ - unsigned int i; - - for (i = 0; i < n_crtc_infos; i++) - { - MetaCrtcInfo *crtc_info = crtc_infos[i]; - unsigned int j; - - if (crtc_info->crtc != crtc) - continue; - - if (crtc->current_mode != crtc_info->mode) - return TRUE; - - if (crtc->rect.x != crtc_info->x) - return TRUE; - - if (crtc->rect.y != crtc_info->y) - return TRUE; - - if (crtc->transform != crtc_info->transform) - return TRUE; - - for (j = 0; j < crtc_info->outputs->len; j++) - { - MetaOutput *output = ((MetaOutput**) crtc_info->outputs->pdata)[j]; - MetaCrtc *assigned_crtc; - - assigned_crtc = meta_output_get_assigned_crtc (output); - if (assigned_crtc != crtc) - return TRUE; - } - - return FALSE; - } - - return crtc->current_mode != NULL; -} - -static gboolean -is_output_assignment_changed (MetaOutput *output, - MetaCrtcInfo **crtc_infos, - unsigned int n_crtc_infos, - MetaOutputInfo **output_infos, - unsigned int n_output_infos) -{ - MetaCrtc *assigned_crtc; - gboolean output_is_found = FALSE; - unsigned int i; - - for (i = 0; i < n_output_infos; i++) - { - MetaOutputInfo *output_info = output_infos[i]; - - if (output_info->output != output) - continue; - - if (output->is_primary != output_info->is_primary) - return TRUE; - - if (output->is_presentation != output_info->is_presentation) - return TRUE; - - if (output->is_underscanning != output_info->is_underscanning) - return TRUE; - - output_is_found = TRUE; - } - - assigned_crtc = meta_output_get_assigned_crtc (output); - - if (!output_is_found) - return assigned_crtc != NULL; - - for (i = 0; i < n_crtc_infos; i++) - { - MetaCrtcInfo *crtc_info = crtc_infos[i]; - unsigned int j; - - for (j = 0; j < crtc_info->outputs->len; j++) - { - MetaOutput *crtc_info_output = - ((MetaOutput**) crtc_info->outputs->pdata)[j]; - - if (crtc_info_output == output && - crtc_info->crtc == assigned_crtc) - return FALSE; - } - } - - return TRUE; -} - static MetaGpu * meta_monitor_manager_xrandr_get_gpu (MetaMonitorManagerXrandr *manager_xrandr) { @@ -346,41 +249,6 @@ meta_monitor_manager_xrandr_get_gpu (MetaMonitorManagerXrandr *manager_xrandr) return META_GPU (meta_backend_get_gpus (backend)->data); } -static gboolean -is_assignments_changed (MetaMonitorManager *manager, - MetaCrtcInfo **crtc_infos, - unsigned int n_crtc_infos, - MetaOutputInfo **output_infos, - unsigned int n_output_infos) -{ - MetaMonitorManagerXrandr *manager_xrandr = - META_MONITOR_MANAGER_XRANDR (manager); - MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr); - GList *l; - - for (l = meta_gpu_get_crtcs (gpu); l; l = l->next) - { - MetaCrtc *crtc = l->data; - - if (is_crtc_assignment_changed (crtc, crtc_infos, n_crtc_infos)) - return TRUE; - } - - for (l = meta_gpu_get_outputs (gpu); l; l = l->next) - { - MetaOutput *output = l->data; - - if (is_output_assignment_changed (output, - crtc_infos, - n_crtc_infos, - output_infos, - n_output_infos)) - return TRUE; - } - - return FALSE; -} - static void apply_crtc_assignments (MetaMonitorManager *manager, gboolean save_timestamp, @@ -651,11 +519,11 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *mana * must check that our new assignment actually changes anything, otherwise * just update the logical state. */ - if (is_assignments_changed (manager, - (MetaCrtcInfo **) crtc_infos->pdata, - crtc_infos->len, - (MetaOutputInfo **) output_infos->pdata, - output_infos->len)) + if (meta_monitor_manager_get_has_changed (manager, + (MetaCrtcInfo **) crtc_infos->pdata, + crtc_infos->len, + (MetaOutputInfo **) output_infos->pdata, + output_infos->len)) { apply_crtc_assignments (manager, TRUE,