[mutter] backends/native: Fall back to compositing if direct scanout failed



commit 6e3ecadb79b46e366777541834899105808e8215
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Sep 10 17:41:06 2020 +0200

    backends/native: Fall back to compositing if direct scanout failed
    
    Even when a direct client buffer has a compatible format, stride and
    modifier for direct scanout, drmModePageFlip() may still fail sometimes.
    
    From testing, it has been observed that it may seemingly randomly fail
    with ENOSPC, where all subsequent attempts later on the same CRTC
    failing with EBUSY.
    
    Handle this by falling back to flipping after having composited a full
    frame again.
    
    Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1410

 clutter/clutter/cogl/clutter-stage-cogl.c     | 33 +++++++++++-----
 cogl/cogl/cogl-onscreen.c                     | 20 ++++++----
 cogl/cogl/cogl-onscreen.h                     |  9 +++--
 cogl/cogl/winsys/cogl-winsys-private.h        |  9 +++--
 src/backends/native/meta-crtc-kms.c           |  2 +
 src/backends/native/meta-crtc-kms.h           |  2 +
 src/backends/native/meta-kms-impl-simple.c    |  3 ++
 src/backends/native/meta-kms-update-private.h |  1 +
 src/backends/native/meta-kms-update.c         |  2 +
 src/backends/native/meta-kms-update.h         |  7 ++++
 src/backends/native/meta-renderer-native.c    | 54 +++++++++++++++++++--------
 11 files changed, 103 insertions(+), 39 deletions(-)
---
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 9baccbd0e8..b682662003 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -649,10 +649,11 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
   cairo_region_destroy (swap_region);
 }
 
-static void
-clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
-                                 ClutterStageView *view,
-                                 CoglScanout      *scanout)
+static gboolean
+clutter_stage_cogl_scanout_view (ClutterStageCogl  *stage_cogl,
+                                 ClutterStageView  *view,
+                                 CoglScanout       *scanout,
+                                 GError           **error)
 {
   ClutterStageCoglPrivate *priv =
     _clutter_stage_cogl_get_instance_private (stage_cogl);
@@ -660,14 +661,21 @@ clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
   CoglOnscreen *onscreen;
   CoglFrameInfo *frame_info;
 
-  g_return_if_fail (cogl_is_onscreen (framebuffer));
+  g_assert (cogl_is_onscreen (framebuffer));
 
   onscreen = COGL_ONSCREEN (framebuffer);
 
   frame_info = cogl_frame_info_new (priv->global_frame_counter);
+
+  if (!cogl_onscreen_direct_scanout (onscreen, scanout, frame_info, error))
+    {
+      cogl_object_unref (frame_info);
+      return FALSE;
+    }
+
   priv->global_frame_counter++;
 
-  cogl_onscreen_direct_scanout (onscreen, scanout, frame_info);
+  return TRUE;
 }
 
 static void
@@ -679,9 +687,16 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
 
   scanout = clutter_stage_view_take_scanout (view);
   if (scanout)
-    clutter_stage_cogl_scanout_view (stage_cogl, view, scanout);
-  else
-    clutter_stage_cogl_redraw_view_primary (stage_cogl, view);
+    {
+      g_autoptr (GError) error = NULL;
+
+      if (clutter_stage_cogl_scanout_view (stage_cogl, view, scanout, &error))
+        return;
+
+      g_warning ("Failed to scan out client buffer: %s", error->message);
+    }
+
+  clutter_stage_cogl_redraw_view_primary (stage_cogl, view);
 }
 
 static void
diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c
index a3c1514a5e..4f3f48fbe1 100644
--- a/cogl/cogl/cogl-onscreen.c
+++ b/cogl/cogl/cogl-onscreen.c
@@ -406,24 +406,30 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
   return winsys->onscreen_get_buffer_age (onscreen);
 }
 
-void
-cogl_onscreen_direct_scanout (CoglOnscreen  *onscreen,
-                              CoglScanout   *scanout,
-                              CoglFrameInfo *info)
+gboolean
+cogl_onscreen_direct_scanout (CoglOnscreen   *onscreen,
+                              CoglScanout    *scanout,
+                              CoglFrameInfo  *info,
+                              GError        **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   const CoglWinsysVtable *winsys;
 
-  g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
-  g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
+  g_warn_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
+  g_warn_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
 
   info->frame_counter = onscreen->frame_counter;
   g_queue_push_tail (&onscreen->pending_frame_infos, info);
 
   winsys = _cogl_framebuffer_get_winsys (framebuffer);
-  winsys->onscreen_direct_scanout (onscreen, scanout, info);
+  if (!winsys->onscreen_direct_scanout (onscreen, scanout, info, error))
+    {
+      g_queue_pop_tail (&onscreen->pending_frame_infos);
+      return FALSE;
+    }
 
   onscreen->frame_counter++;
+  return TRUE;
 }
 
 #ifdef COGL_HAS_X11_SUPPORT
diff --git a/cogl/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h
index b0cd99fce2..824672f5ef 100644
--- a/cogl/cogl/cogl-onscreen.h
+++ b/cogl/cogl/cogl-onscreen.h
@@ -291,10 +291,11 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
 /**
  * cogl_onscreen_direct_scanout: (skip)
  */
-COGL_EXPORT void
-cogl_onscreen_direct_scanout (CoglOnscreen  *onscreen,
-                              CoglScanout   *scanout,
-                              CoglFrameInfo *info);
+COGL_EXPORT gboolean
+cogl_onscreen_direct_scanout (CoglOnscreen   *onscreen,
+                              CoglScanout    *scanout,
+                              CoglFrameInfo  *info,
+                              GError        **error);
 
 /**
  * cogl_onscreen_swap_region:
diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h
index b9dbff5240..2cf88f39b2 100644
--- a/cogl/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-private.h
@@ -119,10 +119,11 @@ typedef struct _CoglWinsysVtable
                                         int n_rectangles,
                                         CoglFrameInfo *info);
 
-  void
-  (*onscreen_direct_scanout) (CoglOnscreen  *onscreen,
-                              CoglScanout   *scanout,
-                              CoglFrameInfo *info);
+  gboolean
+  (*onscreen_direct_scanout) (CoglOnscreen   *onscreen,
+                              CoglScanout    *scanout,
+                              CoglFrameInfo  *info,
+                              GError        **error);
 
   void
   (*onscreen_set_visibility) (CoglOnscreen *onscreen,
diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c
index 9501fc8392..385e828ccf 100644
--- a/src/backends/native/meta-crtc-kms.c
+++ b/src/backends/native/meta-crtc-kms.c
@@ -206,12 +206,14 @@ meta_crtc_kms_set_mode (MetaCrtcKms   *crtc_kms,
 void
 meta_crtc_kms_page_flip (MetaCrtcKms                   *crtc_kms,
                          const MetaKmsPageFlipFeedback *page_flip_feedback,
+                         MetaKmsPageFlipFlag            flags,
                          gpointer                       user_data,
                          MetaKmsUpdate                 *kms_update)
 {
   meta_kms_update_page_flip (kms_update,
                              meta_crtc_kms_get_kms_crtc (crtc_kms),
                              page_flip_feedback,
+                             flags,
                              user_data);
 }
 
diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h
index 9ca80c438e..3e3e1a6e84 100644
--- a/src/backends/native/meta-crtc-kms.h
+++ b/src/backends/native/meta-crtc-kms.h
@@ -30,6 +30,7 @@
 #include "backends/meta-crtc.h"
 #include "backends/native/meta-gpu-kms.h"
 #include "backends/native/meta-kms-crtc.h"
+#include "backends/native/meta-kms-update.h"
 
 #define META_TYPE_CRTC_KMS (meta_crtc_kms_get_type ())
 G_DECLARE_FINAL_TYPE (MetaCrtcKms, meta_crtc_kms,
@@ -56,6 +57,7 @@ void meta_crtc_kms_set_mode (MetaCrtcKms   *crtc_kms,
 
 void meta_crtc_kms_page_flip (MetaCrtcKms                   *crtc_kms,
                               const MetaKmsPageFlipFeedback *page_flip_feedback,
+                              MetaKmsPageFlipFlag            flags,
                               gpointer                       user_data,
                               MetaKmsUpdate                 *kms_update);
 
diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c
index 5aa7adc08e..1afc89f747 100644
--- a/src/backends/native/meta-kms-impl-simple.c
+++ b/src/backends/native/meta-kms-impl-simple.c
@@ -988,6 +988,9 @@ err_planes_assigned:
     {
       MetaKmsPageFlip *page_flip = l->data;
 
+      if (page_flip->flags & META_KMS_PAGE_FLIP_FLAG_NO_DISCARD_FEEDBACK)
+        continue;
+
       discard_page_flip (impl, update, page_flip);
     }
 
diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h
index 4d4d4a2767..df886b8dd9 100644
--- a/src/backends/native/meta-kms-update-private.h
+++ b/src/backends/native/meta-kms-update-private.h
@@ -87,6 +87,7 @@ typedef struct _MetaKmsPageFlip
 {
   MetaKmsCrtc *crtc;
   const MetaKmsPageFlipFeedback *feedback;
+  MetaKmsPageFlipFlag flags;
   gpointer user_data;
   MetaKmsCustomPageFlipFunc custom_page_flip_func;
   gpointer custom_page_flip_user_data;
diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c
index d1092b43fc..94dd23e2c4 100644
--- a/src/backends/native/meta-kms-update.c
+++ b/src/backends/native/meta-kms-update.c
@@ -285,6 +285,7 @@ void
 meta_kms_update_page_flip (MetaKmsUpdate                 *update,
                            MetaKmsCrtc                   *crtc,
                            const MetaKmsPageFlipFeedback *feedback,
+                           MetaKmsPageFlipFlag            flags,
                            gpointer                       user_data)
 {
   MetaKmsPageFlip *page_flip;
@@ -295,6 +296,7 @@ meta_kms_update_page_flip (MetaKmsUpdate                 *update,
   *page_flip = (MetaKmsPageFlip) {
     .crtc = crtc,
     .feedback = feedback,
+    .flags = flags,
     .user_data = user_data,
   };
 
diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h
index 1727c1974a..0684ad1810 100644
--- a/src/backends/native/meta-kms-update.h
+++ b/src/backends/native/meta-kms-update.h
@@ -41,6 +41,12 @@ typedef enum _MetaKmsAssignPlaneFlag
   META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0,
 } MetaKmsAssignPlaneFlag;
 
+typedef enum _MetaKmsPageFlipFlag
+{
+  META_KMS_PAGE_FLIP_FLAG_NONE = 0,
+  META_KMS_PAGE_FLIP_FLAG_NO_DISCARD_FEEDBACK = 1 << 0,
+} MetaKmsPageFlipFlag;
+
 struct _MetaKmsPageFlipFeedback
 {
   void (* flipped) (MetaKmsCrtc  *crtc,
@@ -99,6 +105,7 @@ MetaKmsPlaneAssignment * meta_kms_update_unassign_plane (MetaKmsUpdate *update,
 void meta_kms_update_page_flip (MetaKmsUpdate                 *update,
                                 MetaKmsCrtc                   *crtc,
                                 const MetaKmsPageFlipFeedback *feedback,
+                                MetaKmsPageFlipFlag            flags,
                                 gpointer                       user_data);
 
 void meta_kms_update_custom_page_flip (MetaKmsUpdate                 *update,
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index cf29fc9b5b..b183cbf0e5 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -1251,10 +1251,11 @@ queue_dummy_power_save_page_flip (CoglOnscreen *onscreen)
 }
 
 static void
-meta_onscreen_native_flip_crtc (CoglOnscreen     *onscreen,
-                                MetaRendererView *view,
-                                MetaCrtc         *crtc,
-                                MetaKmsUpdate    *kms_update)
+meta_onscreen_native_flip_crtc (CoglOnscreen        *onscreen,
+                                MetaRendererView    *view,
+                                MetaCrtc            *crtc,
+                                MetaKmsPageFlipFlag  flags,
+                                MetaKmsUpdate       *kms_update)
 {
   CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
@@ -1288,6 +1289,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen     *onscreen,
       meta_crtc_kms_assign_primary_plane (crtc_kms, fb_id, kms_update);
       meta_crtc_kms_page_flip (crtc_kms,
                                &page_flip_feedback,
+                               flags,
                                g_object_ref (view),
                                kms_update);
 
@@ -1340,8 +1342,9 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen              *onscreen,
 }
 
 static void
-meta_onscreen_native_flip_crtcs (CoglOnscreen  *onscreen,
-                                 MetaKmsUpdate *kms_update)
+meta_onscreen_native_flip_crtcs (CoglOnscreen        *onscreen,
+                                 MetaKmsPageFlipFlag  flags,
+                                 MetaKmsUpdate       *kms_update)
 {
   CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
@@ -1359,6 +1362,7 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen  *onscreen,
   if (power_save_mode == META_POWER_SAVE_ON)
     {
       meta_onscreen_native_flip_crtc (onscreen, view, onscreen_native->crtc,
+                                      flags,
                                       kms_update);
     }
   else
@@ -1925,7 +1929,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen  *onscreen,
   update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
 
   ensure_crtc_modes (onscreen, kms_update);
-  meta_onscreen_native_flip_crtcs (onscreen, kms_update);
+  meta_onscreen_native_flip_crtcs (onscreen,
+                                   META_KMS_PAGE_FLIP_FLAG_NONE,
+                                   kms_update);
 
   /*
    * If we changed EGL context, cogl will have the wrong idea about what is
@@ -2072,10 +2078,11 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
   return TRUE;
 }
 
-static void
-meta_onscreen_native_direct_scanout (CoglOnscreen  *onscreen,
-                                     CoglScanout   *scanout,
-                                     CoglFrameInfo *frame_info)
+static gboolean
+meta_onscreen_native_direct_scanout (CoglOnscreen   *onscreen,
+                                     CoglScanout    *scanout,
+                                     CoglFrameInfo  *frame_info,
+                                     GError        **error)
 {
   CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
@@ -2090,21 +2097,38 @@ meta_onscreen_native_direct_scanout (CoglOnscreen  *onscreen,
   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
   MetaKms *kms = meta_backend_native_get_kms (backend_native);
   MetaKmsUpdate *kms_update;
+  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
 
   kms_update = meta_kms_ensure_pending_update (kms);
 
   renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
                                                          render_gpu);
 
-  g_return_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
-
+  g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
   g_warn_if_fail (!onscreen_native->gbm.next_fb);
+
   g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
 
   ensure_crtc_modes (onscreen, kms_update);
-  meta_onscreen_native_flip_crtcs (onscreen, kms_update);
+  meta_onscreen_native_flip_crtcs (onscreen,
+                                   META_KMS_PAGE_FLIP_FLAG_NO_DISCARD_FEEDBACK,
+                                   kms_update);
 
-  meta_kms_post_pending_update_sync (kms);
+  kms_feedback = meta_kms_post_pending_update_sync (kms);
+  if (meta_kms_feedback_get_result (kms_feedback) != META_KMS_FEEDBACK_PASSED)
+    {
+      const GError *feedback_error = meta_kms_feedback_get_error (kms_feedback);
+
+      if (g_error_matches (feedback_error,
+                           G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
+        return TRUE;
+
+      g_clear_object (&onscreen_native->gbm.next_fb);
+      g_propagate_error (error, g_error_copy (feedback_error));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 static gboolean


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