mirror of
https://github.com/brl/mutter.git
synced 2025-02-16 13:24:09 +00:00
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
This commit is contained in:
parent
2a990cc140
commit
104bdde746
@ -25,6 +25,9 @@
|
|||||||
void meta_kms_connector_update_state (MetaKmsConnector *connector,
|
void meta_kms_connector_update_state (MetaKmsConnector *connector,
|
||||||
drmModeRes *drm_resources);
|
drmModeRes *drm_resources);
|
||||||
|
|
||||||
|
void meta_kms_connector_predict_state (MetaKmsConnector *connector,
|
||||||
|
MetaKmsUpdate *update);
|
||||||
|
|
||||||
MetaKmsConnector * meta_kms_connector_new (MetaKmsImplDevice *impl_device,
|
MetaKmsConnector * meta_kms_connector_new (MetaKmsImplDevice *impl_device,
|
||||||
drmModeConnector *drm_connector,
|
drmModeConnector *drm_connector,
|
||||||
drmModeRes *drm_resources);
|
drmModeRes *drm_resources);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "backends/native/meta-kms-crtc.h"
|
||||||
#include "backends/native/meta-kms-device-private.h"
|
#include "backends/native/meta-kms-device-private.h"
|
||||||
#include "backends/native/meta-kms-impl-device.h"
|
#include "backends/native/meta-kms-impl-device.h"
|
||||||
#include "backends/native/meta-kms-update-private.h"
|
#include "backends/native/meta-kms-update-private.h"
|
||||||
@ -495,6 +496,35 @@ meta_kms_connector_update_state (MetaKmsConnector *connector,
|
|||||||
drmModeFreeConnector (drm_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
|
static void
|
||||||
find_property_ids (MetaKmsConnector *connector,
|
find_property_ids (MetaKmsConnector *connector,
|
||||||
MetaKmsImplDevice *impl_device,
|
MetaKmsImplDevice *impl_device,
|
||||||
|
@ -30,4 +30,7 @@ MetaKmsCrtc * meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
|
|||||||
|
|
||||||
void meta_kms_crtc_update_state (MetaKmsCrtc *crtc);
|
void meta_kms_crtc_update_state (MetaKmsCrtc *crtc);
|
||||||
|
|
||||||
|
void meta_kms_crtc_predict_state (MetaKmsCrtc *crtc,
|
||||||
|
MetaKmsUpdate *update);
|
||||||
|
|
||||||
#endif /* META_KMS_CRTC_PRIVATE_H */
|
#endif /* META_KMS_CRTC_PRIVATE_H */
|
||||||
|
@ -143,6 +143,63 @@ meta_kms_crtc_update_state (MetaKmsCrtc *crtc)
|
|||||||
drmModeFreeCrtc (drm_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 *
|
MetaKmsCrtc *
|
||||||
meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
|
meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
|
||||||
drmModeCrtc *drm_crtc,
|
drmModeCrtc *drm_crtc,
|
||||||
|
@ -24,7 +24,9 @@
|
|||||||
|
|
||||||
MetaKmsImplDevice * meta_kms_device_get_impl_device (MetaKmsDevice *device);
|
MetaKmsImplDevice * meta_kms_device_get_impl_device (MetaKmsDevice *device);
|
||||||
|
|
||||||
void meta_kms_device_update_states_in_impl (MetaKmsDevice *device,
|
void meta_kms_device_update_states_in_impl (MetaKmsDevice *device);
|
||||||
MetaKmsUpdateStatesFlags flags);
|
|
||||||
|
void meta_kms_device_predict_states_in_impl (MetaKmsDevice *device,
|
||||||
|
MetaKmsUpdate *update);
|
||||||
|
|
||||||
#endif /* META_KMS_DEVICE_PRIVATE_H */
|
#endif /* META_KMS_DEVICE_PRIVATE_H */
|
||||||
|
@ -109,28 +109,34 @@ meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_kms_device_update_states_in_impl (MetaKmsDevice *device,
|
meta_kms_device_update_states_in_impl (MetaKmsDevice *device)
|
||||||
MetaKmsUpdateStatesFlags flags)
|
{
|
||||||
|
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);
|
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
|
||||||
|
|
||||||
meta_assert_in_kms_impl (device->kms);
|
meta_assert_in_kms_impl (device->kms);
|
||||||
|
|
||||||
meta_kms_impl_device_update_states (impl_device, flags);
|
meta_kms_impl_device_predict_states (impl_device, update);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -319,8 +319,7 @@ init_planes (MetaKmsImplDevice *impl_device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device,
|
meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
|
||||||
MetaKmsUpdateStatesFlags flags)
|
|
||||||
{
|
{
|
||||||
drmModeRes *drm_resources;
|
drmModeRes *drm_resources;
|
||||||
|
|
||||||
@ -328,8 +327,7 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device,
|
|||||||
|
|
||||||
drm_resources = drmModeGetResources (impl_device->fd);
|
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,
|
g_list_foreach (impl_device->crtcs, (GFunc) meta_kms_crtc_update_state,
|
||||||
NULL);
|
NULL);
|
||||||
@ -338,6 +336,16 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device,
|
|||||||
drmModeFreeResources (drm_resources);
|
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 *
|
MetaKmsImplDevice *
|
||||||
meta_kms_impl_device_new (MetaKmsDevice *device,
|
meta_kms_impl_device_new (MetaKmsDevice *device,
|
||||||
MetaKmsImpl *impl,
|
MetaKmsImpl *impl,
|
||||||
|
@ -53,8 +53,10 @@ int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device);
|
|||||||
|
|
||||||
int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device);
|
int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device);
|
||||||
|
|
||||||
void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device,
|
void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device);
|
||||||
MetaKmsUpdateStatesFlags flags);
|
|
||||||
|
void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device,
|
||||||
|
MetaKmsUpdate *update);
|
||||||
|
|
||||||
int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device);
|
int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device);
|
||||||
|
|
||||||
|
@ -56,10 +56,4 @@ typedef enum _MetaKmsDeviceFlag
|
|||||||
META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1,
|
META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1,
|
||||||
} MetaKmsDeviceFlag;
|
} 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 */
|
#endif /* META_KMS_IMPL_TYPES_H */
|
||||||
|
@ -175,10 +175,6 @@ struct _MetaKms
|
|||||||
|
|
||||||
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
|
||||||
|
|
||||||
static void
|
|
||||||
meta_kms_update_states_in_impl (MetaKms *kms,
|
|
||||||
MetaKmsUpdateStatesFlags flags);
|
|
||||||
|
|
||||||
MetaKmsUpdate *
|
MetaKmsUpdate *
|
||||||
meta_kms_ensure_pending_update (MetaKms *kms)
|
meta_kms_ensure_pending_update (MetaKms *kms)
|
||||||
{
|
{
|
||||||
@ -194,6 +190,17 @@ meta_kms_get_pending_update (MetaKms *kms)
|
|||||||
return kms->pending_update;
|
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
|
static gboolean
|
||||||
meta_kms_update_process_in_impl (MetaKmsImpl *impl,
|
meta_kms_update_process_in_impl (MetaKmsImpl *impl,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
@ -205,8 +212,7 @@ meta_kms_update_process_in_impl (MetaKmsImpl *impl,
|
|||||||
ret = meta_kms_impl_process_update (impl, update, error);
|
ret = meta_kms_impl_process_update (impl, update, error);
|
||||||
|
|
||||||
if (meta_kms_update_has_mode_set (update))
|
if (meta_kms_update_has_mode_set (update))
|
||||||
meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl),
|
meta_kms_predict_states_in_impl (meta_kms_impl_get_kms (impl), update);
|
||||||
META_KMS_UPDATE_STATES_FLAG_NONE);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -461,22 +467,16 @@ meta_kms_is_waiting_for_impl_task (MetaKms *kms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_kms_update_states_in_impl (MetaKms *kms,
|
meta_kms_update_states_in_impl (MetaKms *kms)
|
||||||
MetaKmsUpdateStatesFlags flags)
|
|
||||||
{
|
{
|
||||||
GList *l;
|
|
||||||
|
|
||||||
COGL_TRACE_BEGIN_SCOPED (MetaKmsUpdateStates,
|
COGL_TRACE_BEGIN_SCOPED (MetaKmsUpdateStates,
|
||||||
"KMS (update states)");
|
"KMS (update states)");
|
||||||
|
|
||||||
meta_assert_in_kms_impl (kms);
|
meta_assert_in_kms_impl (kms);
|
||||||
|
|
||||||
for (l = kms->devices; l; l = l->next)
|
g_list_foreach (kms->devices,
|
||||||
{
|
(GFunc) meta_kms_device_update_states_in_impl,
|
||||||
MetaKmsDevice *device = l->data;
|
NULL);
|
||||||
|
|
||||||
meta_kms_device_update_states_in_impl (device, flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -485,22 +485,17 @@ update_states_in_impl (MetaKmsImpl *impl,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
MetaKms *kms = meta_kms_impl_get_kms (impl);;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_kms_update_states_sync (MetaKms *kms,
|
meta_kms_update_states_sync (MetaKms *kms,
|
||||||
MetaKmsUpdateStatesFlags flags,
|
GError **error)
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
return meta_kms_run_impl_task_sync (kms,
|
return meta_kms_run_impl_task_sync (kms, update_states_in_impl, NULL, error);
|
||||||
update_states_in_impl,
|
|
||||||
GUINT_TO_POINTER (flags),
|
|
||||||
error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -508,9 +503,7 @@ handle_hotplug_event (MetaKms *kms)
|
|||||||
{
|
{
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
if (!meta_kms_update_states_sync (kms,
|
if (!meta_kms_update_states_sync (kms, &error))
|
||||||
META_KMS_UPDATE_STATES_FLAG_HOTPLUG,
|
|
||||||
&error))
|
|
||||||
g_warning ("Updating KMS state failed: %s", error->message);
|
g_warning ("Updating KMS state failed: %s", error->message);
|
||||||
|
|
||||||
g_signal_emit (kms, signals[RESOURCES_CHANGED], 0);
|
g_signal_emit (kms, signals[RESOURCES_CHANGED], 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user