[mutter] kms: Gracefully handle page flipping direct scanouts failing



commit 1d7920872d23946014afa67c753e7c512bf510d6
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Jul 1 19:45:03 2021 +0200

    kms: Gracefully handle page flipping direct scanouts failing
    
    When drmModePageFlip() or drmModeAtomicCommit() unexpectedly failed (e.g.
    ENOSPC, which has been seen in the wild), this failure was not handled
    very gracefully. The page flip listener for the scanout was left in the
    MetaKmsUpdate, meaning when the primary plane composition was later page
    flipped, two page flip listeners were added, one for the primary plane,
    and one for the scanout. This caused the 'page-flipped' event to be
    handled twice, the second time being fatal.
    
    Handle this by making 'no-discard' listener flag be somewhat reversed,
    and say 'drop-on-error', and then drop all 'drop-on-error' listeners
    when a MetaKmsUpdate failed to be processed.
    
    Also for a "preserve" flagged update, don't ever trigger "discard"
    callbacks just yet, as preserved updates are used again for the primary
    plane composition, in order to not miss e.g. CRTC gamma updates, or
    cursor plane updates, which were added separately.
    
    Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1809
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1910>

 src/backends/native/meta-kms-impl-device-atomic.c | 22 +++++++++++++---------
 src/backends/native/meta-kms-impl-device-simple.c | 19 +++++++++++++------
 src/backends/native/meta-kms-impl-device.c        |  5 +++--
 src/backends/native/meta-kms-impl-device.h        |  7 +++++--
 src/backends/native/meta-kms-impl.c               |  7 ++++---
 src/backends/native/meta-kms-impl.h               |  5 +++--
 src/backends/native/meta-kms-page-flip.c          |  3 ---
 src/backends/native/meta-kms-update-private.h     |  2 ++
 src/backends/native/meta-kms-update.c             | 22 ++++++++++++++++++++++
 src/backends/native/meta-kms-update.h             |  2 +-
 src/backends/native/meta-kms.c                    | 20 +++++++++++++++++---
 src/backends/native/meta-onscreen-native.c        |  2 +-
 12 files changed, 84 insertions(+), 32 deletions(-)
---
diff --git a/src/backends/native/meta-kms-impl-device-atomic.c 
b/src/backends/native/meta-kms-impl-device-atomic.c
index d1f2e7b82f..4115b9b05d 100644
--- a/src/backends/native/meta-kms-impl-device-atomic.c
+++ b/src/backends/native/meta-kms-impl-device-atomic.c
@@ -849,7 +849,8 @@ process_power_save (MetaKmsImplDevice *impl_device,
 
 static MetaKmsFeedback *
 meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
-                                            MetaKmsUpdate     *update)
+                                            MetaKmsUpdate     *update,
+                                            MetaKmsUpdateFlag  flags)
 {
   GError *error = NULL;
   GList *failed_planes = NULL;
@@ -973,14 +974,17 @@ commit:
 err:
   meta_topic (META_DEBUG_KMS, "[atomic] KMS update failed: %s", error->message);
 
-  process_entries (impl_device,
-                   update,
-                   req,
-                   blob_ids,
-                   meta_kms_update_get_page_flip_listeners (update),
-                   error,
-                   discard_page_flip_listener,
-                   NULL);
+  if (!(flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR))
+    {
+      process_entries (impl_device,
+                       update,
+                       req,
+                       blob_ids,
+                       meta_kms_update_get_page_flip_listeners (update),
+                       error,
+                       discard_page_flip_listener,
+                       NULL);
+    }
 
   release_blob_ids (impl_device, blob_ids);
 
diff --git a/src/backends/native/meta-kms-impl-device-simple.c 
b/src/backends/native/meta-kms-impl-device-simple.c
index 1519962b8e..4f9fe78845 100644
--- a/src/backends/native/meta-kms-impl-device-simple.c
+++ b/src/backends/native/meta-kms-impl-device-simple.c
@@ -1085,6 +1085,7 @@ static gboolean
 maybe_dispatch_page_flips (MetaKmsImplDevice  *impl_device,
                            MetaKmsUpdate      *update,
                            GList             **failed_planes,
+                           MetaKmsUpdateFlag   flags,
                            GError            **error)
 {
   g_autoptr (GList) page_flip_datas = NULL;
@@ -1122,7 +1123,8 @@ maybe_dispatch_page_flips (MetaKmsImplDevice  *impl_device,
               *failed_planes = g_list_prepend (*failed_planes, plane_feedback);
             }
 
-          meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
+          if (!(flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR))
+            meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
 
           goto err;
         }
@@ -1131,11 +1133,14 @@ maybe_dispatch_page_flips (MetaKmsImplDevice  *impl_device,
   return TRUE;
 
 err:
-  for (l = page_flip_datas; l; l = l->next)
+  if (!(flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR))
     {
-      MetaKmsPageFlipData *page_flip_data = l->data;
+      for (l = page_flip_datas; l; l = l->next)
+        {
+          MetaKmsPageFlipData *page_flip_data = l->data;
 
-      meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
+          meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
+        }
     }
   g_list_free (page_flip_datas);
 
@@ -1375,7 +1380,8 @@ meta_kms_impl_device_simple_setup_drm_event_context (MetaKmsImplDevice *impl_dev
 
 static MetaKmsFeedback *
 meta_kms_impl_device_simple_process_update (MetaKmsImplDevice *impl_device,
-                                            MetaKmsUpdate     *update)
+                                            MetaKmsUpdate     *update,
+                                            MetaKmsUpdateFlag  flags)
 {
   GError *error = NULL;
   GList *failed_planes = NULL;
@@ -1415,7 +1421,8 @@ meta_kms_impl_device_simple_process_update (MetaKmsImplDevice *impl_device,
   if (!process_plane_assignments (impl_device, update, &failed_planes, &error))
     goto err;
 
-  if (!maybe_dispatch_page_flips (impl_device, update, &failed_planes, &error))
+  if (!maybe_dispatch_page_flips (impl_device, update, &failed_planes, flags,
+                                  &error))
     goto err;
 
 out:
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index 9dc631b577..75920fe6b5 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -651,11 +651,12 @@ meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device)
 
 MetaKmsFeedback *
 meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
-                                     MetaKmsUpdate     *update)
+                                     MetaKmsUpdate     *update,
+                                     MetaKmsUpdateFlag  flags)
 {
   MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
 
-  return klass->process_update (impl_device, update);
+  return klass->process_update (impl_device, update, flags);
 }
 
 void
diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h
index 6e8ec23787..913ba992f7 100644
--- a/src/backends/native/meta-kms-impl-device.h
+++ b/src/backends/native/meta-kms-impl-device.h
@@ -29,6 +29,7 @@
 #include "backends/native/meta-kms-page-flip-private.h"
 #include "backends/native/meta-kms-types.h"
 #include "backends/native/meta-kms-update.h"
+#include "backends/native/meta-kms.h"
 
 typedef struct _MetaKmsDeviceCaps
 {
@@ -64,7 +65,8 @@ struct _MetaKmsImplDeviceClass
   void (* setup_drm_event_context) (MetaKmsImplDevice *impl_device,
                                     drmEventContext   *drm_event_context);
   MetaKmsFeedback * (* process_update) (MetaKmsImplDevice *impl_device,
-                                        MetaKmsUpdate     *update);
+                                        MetaKmsUpdate     *update,
+                                        MetaKmsUpdateFlag  flags);
   void (* handle_page_flip_callback) (MetaKmsImplDevice   *impl_device,
                                       MetaKmsPageFlipData *page_flip_data);
   void (* discard_pending_page_flips) (MetaKmsImplDevice *impl_device);
@@ -132,7 +134,8 @@ void meta_kms_impl_device_reload_prop_values (MetaKmsImplDevice *impl_device,
                                               ...);
 
 MetaKmsFeedback * meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
-                                                       MetaKmsUpdate     *update);
+                                                       MetaKmsUpdate     *update,
+                                                       MetaKmsUpdateFlag  flags);
 
 void meta_kms_impl_device_handle_page_flip_callback (MetaKmsImplDevice   *impl_device,
                                                      MetaKmsPageFlipData *page_flip_data);
diff --git a/src/backends/native/meta-kms-impl.c b/src/backends/native/meta-kms-impl.c
index 036a0d783d..3a186209c6 100644
--- a/src/backends/native/meta-kms-impl.c
+++ b/src/backends/native/meta-kms-impl.c
@@ -78,8 +78,9 @@ meta_kms_impl_remove_impl_device (MetaKmsImpl       *impl,
 }
 
 MetaKmsFeedback *
-meta_kms_impl_process_update (MetaKmsImpl   *impl,
-                              MetaKmsUpdate *update)
+meta_kms_impl_process_update (MetaKmsImpl       *impl,
+                              MetaKmsUpdate     *update,
+                              MetaKmsUpdateFlag  flags)
 {
   MetaKmsImplPrivate *priv = meta_kms_impl_get_instance_private (impl);
   MetaKmsDevice *device;
@@ -90,7 +91,7 @@ meta_kms_impl_process_update (MetaKmsImpl   *impl,
   device = meta_kms_update_get_device (update);
   impl_device = meta_kms_device_get_impl_device (device);
 
-  return meta_kms_impl_device_process_update (impl_device, update);
+  return meta_kms_impl_device_process_update (impl_device, update, flags);
 }
 
 void
diff --git a/src/backends/native/meta-kms-impl.h b/src/backends/native/meta-kms-impl.h
index 723a21cd2e..00cf5538d0 100644
--- a/src/backends/native/meta-kms-impl.h
+++ b/src/backends/native/meta-kms-impl.h
@@ -31,8 +31,9 @@ G_DECLARE_FINAL_TYPE (MetaKmsImpl, meta_kms_impl,
 
 MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl);
 
-MetaKmsFeedback * meta_kms_impl_process_update (MetaKmsImpl   *impl,
-                                                MetaKmsUpdate *update);
+MetaKmsFeedback * meta_kms_impl_process_update (MetaKmsImpl       *impl,
+                                                MetaKmsUpdate     *update,
+                                                MetaKmsUpdateFlag  flags);
 
 void meta_kms_impl_add_impl_device (MetaKmsImpl       *impl,
                                     MetaKmsImplDevice *impl_device);
diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c
index 130fba06c9..817f4e7c8d 100644
--- a/src/backends/native/meta-kms-page-flip.c
+++ b/src/backends/native/meta-kms-page-flip.c
@@ -255,9 +255,6 @@ meta_kms_page_flip_data_discard (MetaKms  *kms,
     {
       MetaKmsPageFlipClosure *closure = l->data;
 
-      if (closure->flags & META_KMS_PAGE_FLIP_LISTENER_FLAG_NO_DISCARD)
-        continue;
-
       closure->vtable->discarded (page_flip_data->crtc,
                                   closure->user_data,
                                   page_flip_data->error);
diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h
index 1954c7a782..22491ece2d 100644
--- a/src/backends/native/meta-kms-update-private.h
+++ b/src/backends/native/meta-kms-update-private.h
@@ -126,6 +126,8 @@ GList * meta_kms_update_get_mode_sets (MetaKmsUpdate *update);
 
 GList * meta_kms_update_get_page_flip_listeners (MetaKmsUpdate *update);
 
+void meta_kms_update_drop_defunct_page_flip_listeners (MetaKmsUpdate *update);
+
 GList * meta_kms_update_get_connector_updates (MetaKmsUpdate *update);
 
 GList * meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update);
diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c
index 06d6d75155..be6eaefcc2 100644
--- a/src/backends/native/meta-kms-update.c
+++ b/src/backends/native/meta-kms-update.c
@@ -417,6 +417,28 @@ meta_kms_update_add_page_flip_listener (MetaKmsUpdate                       *upd
                                                 listener);
 }
 
+void
+meta_kms_update_drop_defunct_page_flip_listeners (MetaKmsUpdate *update)
+{
+  GList *l;
+
+  l = update->page_flip_listeners;
+  while (l)
+    {
+      MetaKmsPageFlipListener *listener = l->data;
+      GList *l_next = l->next;
+
+      if (listener->flags & META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR)
+        {
+          meta_kms_page_flip_listener_free (listener);
+          update->page_flip_listeners =
+            g_list_delete_link (update->page_flip_listeners, l);
+        }
+
+      l = l_next;
+    }
+}
+
 void
 meta_kms_update_set_custom_page_flip (MetaKmsUpdate             *update,
                                       MetaKmsCustomPageFlipFunc  func,
diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h
index 98fb8088f7..0c7707bbc4 100644
--- a/src/backends/native/meta-kms-update.h
+++ b/src/backends/native/meta-kms-update.h
@@ -46,7 +46,7 @@ typedef enum _MetaKmsAssignPlaneFlag
 enum _MetaKmsPageFlipListenerFlag
 {
   META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE = 0,
-  META_KMS_PAGE_FLIP_LISTENER_FLAG_NO_DISCARD = 1 << 0,
+  META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR = 1 << 0,
 };
 
 struct _MetaKmsPageFlipListenerVtable
diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c
index 57bb88e5f7..edb6f29eec 100644
--- a/src/backends/native/meta-kms.c
+++ b/src/backends/native/meta-kms.c
@@ -239,15 +239,22 @@ meta_kms_take_pending_update (MetaKms       *kms,
   return NULL;
 }
 
+typedef struct
+{
+  MetaKmsUpdate *update;
+  MetaKmsUpdateFlag flags;
+} PostUpdateData;
+
 static gpointer
 meta_kms_process_update_in_impl (MetaKmsImpl  *impl,
                                  gpointer      user_data,
                                  GError      **error)
 {
+  PostUpdateData *data = user_data;
+  MetaKmsUpdate *update = data->update;
   MetaKmsFeedback *feedback;
-  MetaKmsUpdate *update = user_data;
 
-  feedback = meta_kms_impl_process_update (impl, update);
+  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);
 
@@ -260,6 +267,7 @@ meta_kms_post_pending_update_sync (MetaKms           *kms,
                                    MetaKmsUpdateFlag  flags)
 {
   MetaKmsUpdate *update;
+  PostUpdateData data;
   MetaKmsFeedback *feedback;
   GList *result_listeners;
   GList *l;
@@ -273,9 +281,13 @@ meta_kms_post_pending_update_sync (MetaKms           *kms,
 
   meta_kms_update_lock (update);
 
+  data = (PostUpdateData) {
+    .update = update,
+    .flags = flags,
+  };
   feedback = meta_kms_run_impl_task_sync (kms,
                                           meta_kms_process_update_in_impl,
-                                          update,
+                                          &data,
                                           NULL);
 
   result_listeners = meta_kms_update_take_result_listeners (update);
@@ -294,6 +306,8 @@ meta_kms_post_pending_update_sync (MetaKms           *kms,
           meta_kms_update_drop_plane_assignment (update, plane);
         }
 
+      meta_kms_update_drop_defunct_page_flip_listeners (update);
+
       meta_kms_add_pending_update (kms, update);
     }
   else
diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
index da75b03ec4..02cd5da2e8 100644
--- a/src/backends/native/meta-onscreen-native.c
+++ b/src/backends/native/meta-onscreen-native.c
@@ -1259,7 +1259,7 @@ meta_onscreen_native_direct_scanout (CoglOnscreen   *onscreen,
   meta_onscreen_native_flip_crtc (onscreen,
                                   onscreen_native->view,
                                   onscreen_native->crtc,
-                                  META_KMS_PAGE_FLIP_LISTENER_FLAG_NO_DISCARD);
+                                  META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR);
 
   kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
   kms_device = meta_kms_crtc_get_device (kms_crtc);


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