mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 19:10:43 -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);
|
cairo_region_destroy (swap_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
|
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
|
||||||
ClutterStageView *view,
|
ClutterStageView *view,
|
||||||
CoglScanout *scanout)
|
CoglScanout *scanout,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
ClutterStageCoglPrivate *priv =
|
ClutterStageCoglPrivate *priv =
|
||||||
_clutter_stage_cogl_get_instance_private (stage_cogl);
|
_clutter_stage_cogl_get_instance_private (stage_cogl);
|
||||||
@ -660,14 +661,21 @@ clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
|
|||||||
CoglOnscreen *onscreen;
|
CoglOnscreen *onscreen;
|
||||||
CoglFrameInfo *frame_info;
|
CoglFrameInfo *frame_info;
|
||||||
|
|
||||||
g_return_if_fail (cogl_is_onscreen (framebuffer));
|
g_assert (cogl_is_onscreen (framebuffer));
|
||||||
|
|
||||||
onscreen = COGL_ONSCREEN (framebuffer);
|
onscreen = COGL_ONSCREEN (framebuffer);
|
||||||
|
|
||||||
frame_info = cogl_frame_info_new (priv->global_frame_counter);
|
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++;
|
priv->global_frame_counter++;
|
||||||
|
|
||||||
cogl_onscreen_direct_scanout (onscreen, scanout, frame_info);
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -679,8 +687,15 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
|||||||
|
|
||||||
scanout = clutter_stage_view_take_scanout (view);
|
scanout = clutter_stage_view_take_scanout (view);
|
||||||
if (scanout)
|
if (scanout)
|
||||||
clutter_stage_cogl_scanout_view (stage_cogl, view, scanout);
|
{
|
||||||
else
|
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);
|
clutter_stage_cogl_redraw_view_primary (stage_cogl, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,24 +406,30 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
|
|||||||
return winsys->onscreen_get_buffer_age (onscreen);
|
return winsys->onscreen_get_buffer_age (onscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
gboolean
|
||||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||||
CoglScanout *scanout,
|
CoglScanout *scanout,
|
||||||
CoglFrameInfo *info)
|
CoglFrameInfo *info,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
const CoglWinsysVtable *winsys;
|
const CoglWinsysVtable *winsys;
|
||||||
|
|
||||||
g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
|
g_warn_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 (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
|
||||||
|
|
||||||
info->frame_counter = onscreen->frame_counter;
|
info->frame_counter = onscreen->frame_counter;
|
||||||
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
||||||
|
|
||||||
winsys = _cogl_framebuffer_get_winsys (framebuffer);
|
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++;
|
onscreen->frame_counter++;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COGL_HAS_X11_SUPPORT
|
#ifdef COGL_HAS_X11_SUPPORT
|
||||||
|
@ -291,10 +291,11 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
|||||||
/**
|
/**
|
||||||
* cogl_onscreen_direct_scanout: (skip)
|
* cogl_onscreen_direct_scanout: (skip)
|
||||||
*/
|
*/
|
||||||
COGL_EXPORT void
|
COGL_EXPORT gboolean
|
||||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||||
CoglScanout *scanout,
|
CoglScanout *scanout,
|
||||||
CoglFrameInfo *info);
|
CoglFrameInfo *info,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_onscreen_swap_region:
|
* cogl_onscreen_swap_region:
|
||||||
|
@ -119,10 +119,11 @@ typedef struct _CoglWinsysVtable
|
|||||||
int n_rectangles,
|
int n_rectangles,
|
||||||
CoglFrameInfo *info);
|
CoglFrameInfo *info);
|
||||||
|
|
||||||
void
|
gboolean
|
||||||
(*onscreen_direct_scanout) (CoglOnscreen *onscreen,
|
(*onscreen_direct_scanout) (CoglOnscreen *onscreen,
|
||||||
CoglScanout *scanout,
|
CoglScanout *scanout,
|
||||||
CoglFrameInfo *info);
|
CoglFrameInfo *info,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
void
|
void
|
||||||
(*onscreen_set_visibility) (CoglOnscreen *onscreen,
|
(*onscreen_set_visibility) (CoglOnscreen *onscreen,
|
||||||
|
@ -206,12 +206,14 @@ meta_crtc_kms_set_mode (MetaCrtcKms *crtc_kms,
|
|||||||
void
|
void
|
||||||
meta_crtc_kms_page_flip (MetaCrtcKms *crtc_kms,
|
meta_crtc_kms_page_flip (MetaCrtcKms *crtc_kms,
|
||||||
const MetaKmsPageFlipFeedback *page_flip_feedback,
|
const MetaKmsPageFlipFeedback *page_flip_feedback,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
MetaKmsUpdate *kms_update)
|
MetaKmsUpdate *kms_update)
|
||||||
{
|
{
|
||||||
meta_kms_update_page_flip (kms_update,
|
meta_kms_update_page_flip (kms_update,
|
||||||
meta_crtc_kms_get_kms_crtc (crtc_kms),
|
meta_crtc_kms_get_kms_crtc (crtc_kms),
|
||||||
page_flip_feedback,
|
page_flip_feedback,
|
||||||
|
flags,
|
||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "backends/meta-crtc.h"
|
#include "backends/meta-crtc.h"
|
||||||
#include "backends/native/meta-gpu-kms.h"
|
#include "backends/native/meta-gpu-kms.h"
|
||||||
#include "backends/native/meta-kms-crtc.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 ())
|
#define META_TYPE_CRTC_KMS (meta_crtc_kms_get_type ())
|
||||||
G_DECLARE_FINAL_TYPE (MetaCrtcKms, meta_crtc_kms,
|
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,
|
void meta_crtc_kms_page_flip (MetaCrtcKms *crtc_kms,
|
||||||
const MetaKmsPageFlipFeedback *page_flip_feedback,
|
const MetaKmsPageFlipFeedback *page_flip_feedback,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
MetaKmsUpdate *kms_update);
|
MetaKmsUpdate *kms_update);
|
||||||
|
|
||||||
|
@ -988,6 +988,9 @@ err_planes_assigned:
|
|||||||
{
|
{
|
||||||
MetaKmsPageFlip *page_flip = l->data;
|
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);
|
discard_page_flip (impl, update, page_flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ typedef struct _MetaKmsPageFlip
|
|||||||
{
|
{
|
||||||
MetaKmsCrtc *crtc;
|
MetaKmsCrtc *crtc;
|
||||||
const MetaKmsPageFlipFeedback *feedback;
|
const MetaKmsPageFlipFeedback *feedback;
|
||||||
|
MetaKmsPageFlipFlag flags;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
MetaKmsCustomPageFlipFunc custom_page_flip_func;
|
MetaKmsCustomPageFlipFunc custom_page_flip_func;
|
||||||
gpointer custom_page_flip_user_data;
|
gpointer custom_page_flip_user_data;
|
||||||
|
@ -285,6 +285,7 @@ void
|
|||||||
meta_kms_update_page_flip (MetaKmsUpdate *update,
|
meta_kms_update_page_flip (MetaKmsUpdate *update,
|
||||||
MetaKmsCrtc *crtc,
|
MetaKmsCrtc *crtc,
|
||||||
const MetaKmsPageFlipFeedback *feedback,
|
const MetaKmsPageFlipFeedback *feedback,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
MetaKmsPageFlip *page_flip;
|
MetaKmsPageFlip *page_flip;
|
||||||
@ -295,6 +296,7 @@ meta_kms_update_page_flip (MetaKmsUpdate *update,
|
|||||||
*page_flip = (MetaKmsPageFlip) {
|
*page_flip = (MetaKmsPageFlip) {
|
||||||
.crtc = crtc,
|
.crtc = crtc,
|
||||||
.feedback = feedback,
|
.feedback = feedback,
|
||||||
|
.flags = flags,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ typedef enum _MetaKmsAssignPlaneFlag
|
|||||||
META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0,
|
META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0,
|
||||||
} MetaKmsAssignPlaneFlag;
|
} MetaKmsAssignPlaneFlag;
|
||||||
|
|
||||||
|
typedef enum _MetaKmsPageFlipFlag
|
||||||
|
{
|
||||||
|
META_KMS_PAGE_FLIP_FLAG_NONE = 0,
|
||||||
|
META_KMS_PAGE_FLIP_FLAG_NO_DISCARD_FEEDBACK = 1 << 0,
|
||||||
|
} MetaKmsPageFlipFlag;
|
||||||
|
|
||||||
struct _MetaKmsPageFlipFeedback
|
struct _MetaKmsPageFlipFeedback
|
||||||
{
|
{
|
||||||
void (* flipped) (MetaKmsCrtc *crtc,
|
void (* flipped) (MetaKmsCrtc *crtc,
|
||||||
@ -99,6 +105,7 @@ MetaKmsPlaneAssignment * meta_kms_update_unassign_plane (MetaKmsUpdate *update,
|
|||||||
void meta_kms_update_page_flip (MetaKmsUpdate *update,
|
void meta_kms_update_page_flip (MetaKmsUpdate *update,
|
||||||
MetaKmsCrtc *crtc,
|
MetaKmsCrtc *crtc,
|
||||||
const MetaKmsPageFlipFeedback *feedback,
|
const MetaKmsPageFlipFeedback *feedback,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
void meta_kms_update_custom_page_flip (MetaKmsUpdate *update,
|
void meta_kms_update_custom_page_flip (MetaKmsUpdate *update,
|
||||||
|
@ -1254,6 +1254,7 @@ static void
|
|||||||
meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
|
meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
|
||||||
MetaRendererView *view,
|
MetaRendererView *view,
|
||||||
MetaCrtc *crtc,
|
MetaCrtc *crtc,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
MetaKmsUpdate *kms_update)
|
MetaKmsUpdate *kms_update)
|
||||||
{
|
{
|
||||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||||
@ -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_assign_primary_plane (crtc_kms, fb_id, kms_update);
|
||||||
meta_crtc_kms_page_flip (crtc_kms,
|
meta_crtc_kms_page_flip (crtc_kms,
|
||||||
&page_flip_feedback,
|
&page_flip_feedback,
|
||||||
|
flags,
|
||||||
g_object_ref (view),
|
g_object_ref (view),
|
||||||
kms_update);
|
kms_update);
|
||||||
|
|
||||||
@ -1341,6 +1343,7 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen,
|
meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen,
|
||||||
|
MetaKmsPageFlipFlag flags,
|
||||||
MetaKmsUpdate *kms_update)
|
MetaKmsUpdate *kms_update)
|
||||||
{
|
{
|
||||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||||
@ -1359,6 +1362,7 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen,
|
|||||||
if (power_save_mode == META_POWER_SAVE_ON)
|
if (power_save_mode == META_POWER_SAVE_ON)
|
||||||
{
|
{
|
||||||
meta_onscreen_native_flip_crtc (onscreen, view, onscreen_native->crtc,
|
meta_onscreen_native_flip_crtc (onscreen, view, onscreen_native->crtc,
|
||||||
|
flags,
|
||||||
kms_update);
|
kms_update);
|
||||||
}
|
}
|
||||||
else
|
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);
|
update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
|
||||||
|
|
||||||
ensure_crtc_modes (onscreen, kms_update);
|
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
|
* 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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
||||||
CoglScanout *scanout,
|
CoglScanout *scanout,
|
||||||
CoglFrameInfo *frame_info)
|
CoglFrameInfo *frame_info,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||||
@ -2090,21 +2097,38 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
|||||||
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
||||||
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
||||||
MetaKmsUpdate *kms_update;
|
MetaKmsUpdate *kms_update;
|
||||||
|
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
||||||
|
|
||||||
kms_update = meta_kms_ensure_pending_update (kms);
|
kms_update = meta_kms_ensure_pending_update (kms);
|
||||||
|
|
||||||
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
||||||
render_gpu);
|
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_warn_if_fail (!onscreen_native->gbm.next_fb);
|
||||||
|
|
||||||
g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
|
g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
|
||||||
|
|
||||||
ensure_crtc_modes (onscreen, kms_update);
|
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
|
static gboolean
|
||||||
|
Loading…
Reference in New Issue
Block a user