From a14923e9937dae02a1b3fccb7229fb82a8c9093a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 8 Dec 2021 21:20:52 +0100 Subject: [PATCH] kms: Add update test API This API can be used to construct a MetaKmsUpdate with plane assignments that in isolation will be tested against the current KMS state. How it is tested depends on the KMS implementation; in the simple / legacy KMS backend, the tests are identical to the current scanout requirements (dimension, stride, format, modifiers, all must match), and with atomic KMS, it uses the TEST_ONLY on a real constructed atomic mode setting commit. Part-of: --- .../native/meta-kms-impl-device-atomic.c | 5 ++ .../native/meta-kms-impl-device-simple.c | 89 ++++++++++++++++++- src/backends/native/meta-kms-update-private.h | 4 + src/backends/native/meta-kms-update.c | 11 +++ src/backends/native/meta-kms.c | 37 +++++++- src/backends/native/meta-kms.h | 4 + 6 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index 7e14cff01..bcb41e8ad 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -785,6 +785,8 @@ commit_flags_string (uint32_t commit_flags) commit_flag_strings[i++] = "ATOMIC_ALLOW_MODESET"; if (commit_flags & DRM_MODE_PAGE_FLIP_EVENT) commit_flag_strings[i++] = "PAGE_FLIP_EVENT"; + if (commit_flags & DRM_MODE_ATOMIC_TEST_ONLY) + commit_flag_strings[i++] = "TEST_ONLY"; commit_flags_string = g_strjoinv ("|", (char **) commit_flag_strings); strncpy (static_commit_flags_string, commit_flags_string, @@ -996,6 +998,9 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, if (meta_kms_update_get_page_flip_listeners (update)) commit_flags |= DRM_MODE_PAGE_FLIP_EVENT; + if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY) + commit_flags |= DRM_MODE_ATOMIC_TEST_ONLY; + commit: meta_topic (META_DEBUG_KMS, "[atomic] Committing update %" G_GUINT64_FORMAT ", flags: %s", diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index 4391ebaec..5017d86bf 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -41,6 +41,12 @@ typedef struct _CachedModeSet { GList *connectors; drmModeModeInfo *drm_mode; + + int width; + int height; + int stride; + uint32_t format; + uint64_t modifier; } CachedModeSet; struct _MetaKmsImplDeviceSimple @@ -259,14 +265,21 @@ process_connector_update (MetaKmsImplDevice *impl_device, static CachedModeSet * cached_mode_set_new (GList *connectors, - const drmModeModeInfo *drm_mode) + const drmModeModeInfo *drm_mode, + MetaDrmBuffer *buffer) { CachedModeSet *cached_mode_set; + cached_mode_set = g_new0 (CachedModeSet, 1); *cached_mode_set = (CachedModeSet) { .connectors = g_list_copy (connectors), .drm_mode = g_memdup2 (drm_mode, sizeof *drm_mode), + .width = meta_drm_buffer_get_width (buffer), + .height = meta_drm_buffer_get_height (buffer), + .stride = meta_drm_buffer_get_stride (buffer), + .format = meta_drm_buffer_get_format (buffer), + .modifier = meta_drm_buffer_get_modifier (buffer), }; return cached_mode_set; @@ -353,6 +366,7 @@ process_mode_set (MetaKmsImplDevice *impl_device, g_autofree uint32_t *connectors = NULL; int n_connectors; MetaKmsPlaneAssignment *plane_assignment; + MetaDrmBuffer *buffer; drmModeModeInfo *drm_mode; uint32_t x, y; uint32_t fb_id; @@ -363,7 +377,6 @@ process_mode_set (MetaKmsImplDevice *impl_device, if (mode_set->mode) { - MetaDrmBuffer *buffer; GList *l; drm_mode = g_alloca (sizeof *drm_mode); @@ -437,6 +450,7 @@ process_mode_set (MetaKmsImplDevice *impl_device, } else { + buffer = NULL; drm_mode = NULL; x = y = 0; n_connectors = 0; @@ -471,7 +485,8 @@ process_mode_set (MetaKmsImplDevice *impl_device, g_hash_table_replace (impl_device_simple->cached_mode_sets, crtc, cached_mode_set_new (mode_set->connectors, - drm_mode)); + drm_mode, + buffer)); } else { @@ -1397,6 +1412,71 @@ meta_kms_impl_device_simple_setup_drm_event_context (MetaKmsImplDevice *impl_dev drm_event_context->page_flip_handler = page_flip_handler; } +static MetaKmsFeedback * +perform_update_test (MetaKmsImplDevice *impl_device, + MetaKmsUpdate *update) +{ + MetaKmsImplDeviceSimple *impl_device_simple = + META_KMS_IMPL_DEVICE_SIMPLE (impl_device); + GList *failed_planes = NULL; + GList *l; + + for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next) + { + MetaKmsPlaneAssignment *plane_assignment = l->data; + MetaKmsPlane *plane = plane_assignment->plane; + MetaKmsCrtc *crtc = plane_assignment->crtc; + MetaDrmBuffer *buffer = plane_assignment->buffer; + CachedModeSet *cached_mode_set; + + if (!plane_assignment->crtc || + !plane_assignment->buffer) + continue; + + cached_mode_set = get_cached_mode_set (impl_device_simple, + plane_assignment->crtc); + if (!cached_mode_set) + { + MetaKmsPlaneFeedback *plane_feedback; + + plane_feedback = + meta_kms_plane_feedback_new_failed (plane, crtc, + "No existing mode set"); + failed_planes = g_list_append (failed_planes, plane_feedback); + continue; + } + + if (meta_drm_buffer_get_width (buffer) != cached_mode_set->width || + meta_drm_buffer_get_height (buffer) != cached_mode_set->height || + meta_drm_buffer_get_stride (buffer) != cached_mode_set->stride || + meta_drm_buffer_get_format (buffer) != cached_mode_set->format || + meta_drm_buffer_get_modifier (buffer) != cached_mode_set->modifier) + { + MetaKmsPlaneFeedback *plane_feedback; + + plane_feedback = + meta_kms_plane_feedback_new_failed (plane, crtc, + "Incompatible buffer"); + failed_planes = g_list_append (failed_planes, plane_feedback); + continue; + } + } + + if (failed_planes) + { + GError *error; + + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_FAILED, + "One or more buffers incompatible"); + return meta_kms_feedback_new_failed (failed_planes, error); + } + else + { + return meta_kms_feedback_new_passed (NULL); + } +} + static MetaKmsFeedback * meta_kms_impl_device_simple_process_update (MetaKmsImplDevice *impl_device, MetaKmsUpdate *update, @@ -1409,6 +1489,9 @@ meta_kms_impl_device_simple_process_update (MetaKmsImplDevice *impl_device, "[simple] Processing update %" G_GUINT64_FORMAT, meta_kms_update_get_sequence_number (update)); + if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY) + return perform_update_test (impl_device, update); + if (meta_kms_update_is_power_save (update)) { if (!process_power_save (impl_device, &error)) diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index c89622d09..c375f7ead 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -106,6 +106,10 @@ MetaKmsPlaneFeedback * meta_kms_plane_feedback_new_take_error (MetaKmsPlane *pla MetaKmsCrtc *crtc, GError *error); +MetaKmsPlaneFeedback * meta_kms_plane_feedback_new_failed (MetaKmsPlane *plane, + MetaKmsCrtc *crtc, + const char *error_message); + MetaKmsFeedback * meta_kms_feedback_new_passed (GList *failed_planes); MetaKmsFeedback * meta_kms_feedback_new_failed (GList *failed_planes, diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index 71e5b423f..98fbdb67a 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -72,6 +72,17 @@ meta_kms_plane_feedback_new_take_error (MetaKmsPlane *plane, return plane_feedback; } +MetaKmsPlaneFeedback * +meta_kms_plane_feedback_new_failed (MetaKmsPlane *plane, + MetaKmsCrtc *crtc, + const char *error_message) +{ + GError *error; + + error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, error_message); + return meta_kms_plane_feedback_new_take_error (plane, crtc, error); +} + MetaKmsFeedback * meta_kms_feedback_new_passed (GList *failed_planes) { diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 0750278ae..5f65e75d0 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -257,8 +257,13 @@ meta_kms_process_update_in_impl (MetaKmsImpl *impl, MetaKmsFeedback *feedback; feedback = meta_kms_impl_process_update (impl, data->update, data->flags); - meta_kms_device_predict_states_in_impl (meta_kms_update_get_device (update), - update); + + if (!(data->flags & META_KMS_UPDATE_FLAG_TEST_ONLY)) + { + MetaKmsDevice *device = meta_kms_update_get_device (update); + + meta_kms_device_predict_states_in_impl (device, update); + } return feedback; } @@ -329,6 +334,34 @@ meta_kms_post_pending_update_sync (MetaKms *kms, return feedback; } +static gpointer +meta_kms_test_update_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + MetaKmsUpdate *update = user_data; + MetaKmsUpdateFlag flags; + + flags = META_KMS_UPDATE_FLAG_TEST_ONLY; + return meta_kms_impl_process_update (impl, update, flags); +} + +MetaKmsFeedback * +meta_kms_post_test_update_sync (MetaKms *kms, + MetaKmsUpdate *update) +{ + g_assert (!meta_kms_update_get_page_flip_listeners (update)); + g_assert (!meta_kms_update_get_mode_sets (update)); + g_assert (!meta_kms_update_get_connector_updates (update)); + + meta_kms_update_lock (update); + + return meta_kms_run_impl_task_sync (kms, + meta_kms_test_update_in_impl, + update, + NULL); +} + static gpointer meta_kms_discard_pending_page_flips_in_impl (MetaKmsImpl *impl, gpointer user_data, diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index 9eae80e3f..e8a129e4b 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -35,6 +35,7 @@ typedef enum _MetaKmsUpdateFlag { META_KMS_UPDATE_FLAG_NONE = 0, META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR = 1 << 0, + META_KMS_UPDATE_FLAG_TEST_ONLY = 1 << 1, } MetaKmsUpdateFlag; #define META_TYPE_KMS (meta_kms_get_type ()) @@ -50,6 +51,9 @@ MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, MetaKmsDevice *device, MetaKmsUpdateFlag flags); +MetaKmsFeedback * meta_kms_post_test_update_sync (MetaKms *kms, + MetaKmsUpdate *update); + void meta_kms_discard_pending_page_flips (MetaKms *kms); void meta_kms_notify_modes_set (MetaKms *kms);