[mutter] kms: Add update test API



commit a14923e9937dae02a1b3fccb7229fb82a8c9093a
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Wed Dec 8 21:20:52 2021 +0100

    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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2146>

 src/backends/native/meta-kms-impl-device-atomic.c |  5 ++
 src/backends/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 7e14cff014..bcb41e8adb 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 4391ebaeca..5017d86bf0 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 c89622d09a..c375f7ead8 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 71e5b423fb..98fbdb67ad 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 0750278ae5..5f65e75d01 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 9eae80e3fa..e8a129e4b7 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]