From 104bdde746c9ceccd9e9ab09b22ef228b8f7026e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 4 Oct 2019 11:54:29 +0200 Subject: [PATCH] kms: Predict state changes when processing update We can't just update the state of the connector and CRTC from KMS since it might contain too new updates, e.g. from a from a future hot plug. In order to not add ad-hoc hot plug detection everywhere, predict the state changes by looking inside the MetaKmsUpdate object, and let the hot-plug state changes happen after the actual hot-plug event. This fixes issues where connectors were discovered as disconnected while doing a mode-set, meaning assumptions about the connectedness of monitors elsewhere were broken until the hot plug event was processed. Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/782 https://gitlab.gnome.org/GNOME/mutter/merge_requests/826 --- .../native/meta-kms-connector-private.h | 3 + src/backends/native/meta-kms-connector.c | 30 ++++++++++ src/backends/native/meta-kms-crtc-private.h | 3 + src/backends/native/meta-kms-crtc.c | 57 +++++++++++++++++++ src/backends/native/meta-kms-device-private.h | 6 +- src/backends/native/meta-kms-device.c | 40 +++++++------ src/backends/native/meta-kms-impl-device.c | 16 ++++-- src/backends/native/meta-kms-impl-device.h | 6 +- src/backends/native/meta-kms-types.h | 6 -- src/backends/native/meta-kms.c | 49 +++++++--------- 10 files changed, 157 insertions(+), 59 deletions(-) diff --git a/src/backends/native/meta-kms-connector-private.h b/src/backends/native/meta-kms-connector-private.h index 427502a34..29901c487 100644 --- a/src/backends/native/meta-kms-connector-private.h +++ b/src/backends/native/meta-kms-connector-private.h @@ -25,6 +25,9 @@ void meta_kms_connector_update_state (MetaKmsConnector *connector, drmModeRes *drm_resources); +void meta_kms_connector_predict_state (MetaKmsConnector *connector, + MetaKmsUpdate *update); + MetaKmsConnector * meta_kms_connector_new (MetaKmsImplDevice *impl_device, drmModeConnector *drm_connector, drmModeRes *drm_resources); diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 1508d4fea..c018a5e62 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -24,6 +24,7 @@ #include +#include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-update-private.h" @@ -495,6 +496,35 @@ meta_kms_connector_update_state (MetaKmsConnector *connector, drmModeFreeConnector (drm_connector); } +void +meta_kms_connector_predict_state (MetaKmsConnector *connector, + MetaKmsUpdate *update) +{ + GList *mode_sets; + GList *l; + + if (!connector->current_state) + return; + + mode_sets = meta_kms_update_get_mode_sets (update); + for (l = mode_sets; l; l = l->next) + { + MetaKmsModeSet *mode_set = l->data; + MetaKmsCrtc *crtc; + + if (!g_list_find (mode_set->connectors, connector)) + continue; + + crtc = mode_set->crtc; + if (crtc) + connector->current_state->current_crtc_id = meta_kms_crtc_get_id (crtc); + else + connector->current_state->current_crtc_id = 0; + + break; + } +} + static void find_property_ids (MetaKmsConnector *connector, MetaKmsImplDevice *impl_device, diff --git a/src/backends/native/meta-kms-crtc-private.h b/src/backends/native/meta-kms-crtc-private.h index 41db399e6..f9a3a6e0a 100644 --- a/src/backends/native/meta-kms-crtc-private.h +++ b/src/backends/native/meta-kms-crtc-private.h @@ -30,4 +30,7 @@ MetaKmsCrtc * meta_kms_crtc_new (MetaKmsImplDevice *impl_device, void meta_kms_crtc_update_state (MetaKmsCrtc *crtc); +void meta_kms_crtc_predict_state (MetaKmsCrtc *crtc, + MetaKmsUpdate *update); + #endif /* META_KMS_CRTC_PRIVATE_H */ diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 2b0f5385a..3610df903 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -143,6 +143,63 @@ meta_kms_crtc_update_state (MetaKmsCrtc *crtc) drmModeFreeCrtc (drm_crtc); } +void +meta_kms_crtc_predict_state (MetaKmsCrtc *crtc, + MetaKmsUpdate *update) +{ + GList *mode_sets; + GList *crtc_gammas; + GList *l; + + mode_sets = meta_kms_update_get_mode_sets (update); + for (l = mode_sets; l; l = l->next) + { + MetaKmsModeSet *mode_set = l->data; + + if (mode_set->crtc != crtc) + continue; + + if (mode_set->drm_mode) + { + MetaKmsPlaneAssignment *plane_assignment; + + plane_assignment = + meta_kms_update_get_primary_plane_assignment (update, crtc); + + crtc->current_state.rect = + meta_fixed_16_rectangle_to_rectangle (plane_assignment->src_rect); + crtc->current_state.is_drm_mode_valid = TRUE; + crtc->current_state.drm_mode = *mode_set->drm_mode; + } + else + { + crtc->current_state.rect = (MetaRectangle) { 0 }; + crtc->current_state.is_drm_mode_valid = FALSE; + crtc->current_state.drm_mode = (drmModeModeInfo) { 0 }; + } + + break; + } + + crtc_gammas = meta_kms_update_get_crtc_gammas (update); + for (l = crtc_gammas; l; l = l->next) + { + MetaKmsCrtcGamma *gamma = l->data; + + if (gamma->crtc != crtc) + continue; + + crtc->current_state.gamma.size = gamma->size; + crtc->current_state.gamma.red = + g_memdup (gamma->red, gamma->size * sizeof (uint16_t)); + crtc->current_state.gamma.green = + g_memdup (gamma->green, gamma->size * sizeof (uint16_t)); + crtc->current_state.gamma.blue = + g_memdup (gamma->blue, gamma->size * sizeof (uint16_t)); + break; + } +} + MetaKmsCrtc * meta_kms_crtc_new (MetaKmsImplDevice *impl_device, drmModeCrtc *drm_crtc, diff --git a/src/backends/native/meta-kms-device-private.h b/src/backends/native/meta-kms-device-private.h index bcb3a6e74..876fb30fc 100644 --- a/src/backends/native/meta-kms-device-private.h +++ b/src/backends/native/meta-kms-device-private.h @@ -24,7 +24,9 @@ MetaKmsImplDevice * meta_kms_device_get_impl_device (MetaKmsDevice *device); -void meta_kms_device_update_states_in_impl (MetaKmsDevice *device, - MetaKmsUpdateStatesFlags flags); +void meta_kms_device_update_states_in_impl (MetaKmsDevice *device); + +void meta_kms_device_predict_states_in_impl (MetaKmsDevice *device, + MetaKmsUpdate *update); #endif /* META_KMS_DEVICE_PRIVATE_H */ diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index d137c63b9..8ed2de024 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -109,28 +109,34 @@ meta_kms_device_get_primary_plane_for (MetaKmsDevice *device, } void -meta_kms_device_update_states_in_impl (MetaKmsDevice *device, - MetaKmsUpdateStatesFlags flags) +meta_kms_device_update_states_in_impl (MetaKmsDevice *device) +{ + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + + meta_assert_in_kms_impl (device->kms); + meta_assert_is_waiting_for_kms_impl_task (device->kms); + + meta_kms_impl_device_update_states (impl_device); + + g_list_free (device->crtcs); + device->crtcs = meta_kms_impl_device_copy_crtcs (impl_device); + + g_list_free (device->connectors); + device->connectors = meta_kms_impl_device_copy_connectors (impl_device); + + g_list_free (device->planes); + device->planes = meta_kms_impl_device_copy_planes (impl_device); +} + +void +meta_kms_device_predict_states_in_impl (MetaKmsDevice *device, + MetaKmsUpdate *update) { MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); meta_assert_in_kms_impl (device->kms); - meta_kms_impl_device_update_states (impl_device, flags); - - if (flags & META_KMS_UPDATE_STATES_FLAG_HOTPLUG) - { - meta_assert_is_waiting_for_kms_impl_task (device->kms); - - g_list_free (device->crtcs); - device->crtcs = meta_kms_impl_device_copy_crtcs (impl_device); - - g_list_free (device->connectors); - device->connectors = meta_kms_impl_device_copy_connectors (impl_device); - - g_list_free (device->planes); - device->planes = meta_kms_impl_device_copy_planes (impl_device); - } + meta_kms_impl_device_predict_states (impl_device, update); } static gboolean diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index dde192b42..922aca103 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -319,8 +319,7 @@ init_planes (MetaKmsImplDevice *impl_device) } void -meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device, - MetaKmsUpdateStatesFlags flags) +meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device) { drmModeRes *drm_resources; @@ -328,8 +327,7 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device, drm_resources = drmModeGetResources (impl_device->fd); - if (flags & META_KMS_UPDATE_STATES_FLAG_HOTPLUG) - update_connectors (impl_device, drm_resources); + update_connectors (impl_device, drm_resources); g_list_foreach (impl_device->crtcs, (GFunc) meta_kms_crtc_update_state, NULL); @@ -338,6 +336,16 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device, drmModeFreeResources (drm_resources); } +void +meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device, + MetaKmsUpdate *update) +{ + g_list_foreach (impl_device->crtcs, (GFunc) meta_kms_crtc_predict_state, + update); + g_list_foreach (impl_device->connectors, (GFunc) meta_kms_connector_predict_state, + update); +} + MetaKmsImplDevice * meta_kms_impl_device_new (MetaKmsDevice *device, MetaKmsImpl *impl, diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index 1e971af8b..5bd0f5f98 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -53,8 +53,10 @@ int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device); int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device); -void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device, - MetaKmsUpdateStatesFlags flags); +void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device); + +void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device, + MetaKmsUpdate *update); int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device); diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index ed4a4cd9d..dd14a7be7 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -56,10 +56,4 @@ typedef enum _MetaKmsDeviceFlag META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1, } MetaKmsDeviceFlag; -typedef enum _MetaKmsUpdateStatesFlags -{ - META_KMS_UPDATE_STATES_FLAG_NONE = 0, - META_KMS_UPDATE_STATES_FLAG_HOTPLUG = 1 << 0, -} MetaKmsUpdateStatesFlags; - #endif /* META_KMS_IMPL_TYPES_H */ diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 39d1f3155..9485bb4e8 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -175,10 +175,6 @@ struct _MetaKms G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT) -static void -meta_kms_update_states_in_impl (MetaKms *kms, - MetaKmsUpdateStatesFlags flags); - MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms) { @@ -194,6 +190,17 @@ meta_kms_get_pending_update (MetaKms *kms) return kms->pending_update; } +static void +meta_kms_predict_states_in_impl (MetaKms *kms, + MetaKmsUpdate *update) +{ + meta_assert_in_kms_impl (kms); + + g_list_foreach (kms->devices, + (GFunc) meta_kms_device_predict_states_in_impl, + update); +} + static gboolean meta_kms_update_process_in_impl (MetaKmsImpl *impl, gpointer user_data, @@ -205,8 +212,7 @@ meta_kms_update_process_in_impl (MetaKmsImpl *impl, ret = meta_kms_impl_process_update (impl, update, error); if (meta_kms_update_has_mode_set (update)) - meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl), - META_KMS_UPDATE_STATES_FLAG_NONE); + meta_kms_predict_states_in_impl (meta_kms_impl_get_kms (impl), update); return ret; } @@ -461,22 +467,16 @@ meta_kms_is_waiting_for_impl_task (MetaKms *kms) } static void -meta_kms_update_states_in_impl (MetaKms *kms, - MetaKmsUpdateStatesFlags flags) +meta_kms_update_states_in_impl (MetaKms *kms) { - GList *l; - COGL_TRACE_BEGIN_SCOPED (MetaKmsUpdateStates, "KMS (update states)"); meta_assert_in_kms_impl (kms); - for (l = kms->devices; l; l = l->next) - { - MetaKmsDevice *device = l->data; - - meta_kms_device_update_states_in_impl (device, flags); - } + g_list_foreach (kms->devices, + (GFunc) meta_kms_device_update_states_in_impl, + NULL); } static gboolean @@ -485,22 +485,17 @@ update_states_in_impl (MetaKmsImpl *impl, GError **error) { MetaKms *kms = meta_kms_impl_get_kms (impl);; - MetaKmsUpdateStatesFlags flags = GPOINTER_TO_UINT (user_data); - meta_kms_update_states_in_impl (kms, flags); + meta_kms_update_states_in_impl (kms); return TRUE; } static gboolean -meta_kms_update_states_sync (MetaKms *kms, - MetaKmsUpdateStatesFlags flags, - GError **error) +meta_kms_update_states_sync (MetaKms *kms, + GError **error) { - return meta_kms_run_impl_task_sync (kms, - update_states_in_impl, - GUINT_TO_POINTER (flags), - error); + return meta_kms_run_impl_task_sync (kms, update_states_in_impl, NULL, error); } static void @@ -508,9 +503,7 @@ handle_hotplug_event (MetaKms *kms) { g_autoptr (GError) error = NULL; - if (!meta_kms_update_states_sync (kms, - META_KMS_UPDATE_STATES_FLAG_HOTPLUG, - &error)) + if (!meta_kms_update_states_sync (kms, &error)) g_warning ("Updating KMS state failed: %s", error->message); g_signal_emit (kms, signals[RESOURCES_CHANGED], 0);