mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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
This commit is contained in:
parent
aa56595b31
commit
6e3ecadb79
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user