mirror of
https://github.com/brl/mutter.git
synced 2025-06-13 16:59:30 +00:00
onscreen/native: Handle unexpected scanout failures async
We test direct client buffer scanout using a TEST_ONLY commit on atomic, and with various conditions in non-atomic, but if we end up failing to actually commit despite this, handle the fallout asynchronously. What this means is that we'll reschedule a new frame immediately. For this to work, the same scanout buffer needs to be avoided for the same CRTC. This is done by using the newly added signal on the CoglScanout object to let the MetaWaylandBuffer object mark the current buffer as non-working for the onsrceen that it failed on. This allows to re-try buffers on the same onscreen when new ones are attached. This queues a full damage, since we consumed the qeued redraw rect. The redraw rect wasn't lost - it was accumulated to make sure the whole primary plane was redrawed according to the damage region, whenever we would end up no longer doing direct scanout, but this accumulation only works when we're not intentionally stopping to scanout. For now, lets just damage the whole view, it's just an graceful fallback in response to an unexpected error anyway. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2854>
This commit is contained in:
@ -1046,17 +1046,14 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
|
||||
err:
|
||||
meta_topic (META_DEBUG_KMS, "[atomic] KMS update failed: %s", error->message);
|
||||
|
||||
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);
|
||||
}
|
||||
process_entries (impl_device,
|
||||
update,
|
||||
req,
|
||||
blob_ids,
|
||||
meta_kms_update_get_page_flip_listeners (update),
|
||||
error,
|
||||
discard_page_flip_listener,
|
||||
NULL);
|
||||
|
||||
if (req)
|
||||
drmModeAtomicFree (req);
|
||||
|
@ -1166,8 +1166,7 @@ maybe_dispatch_page_flips (MetaKmsImplDevice *impl_device,
|
||||
*failed_planes = g_list_prepend (*failed_planes, plane_feedback);
|
||||
}
|
||||
|
||||
if (!(flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR))
|
||||
meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
|
||||
meta_kms_page_flip_data_discard_in_impl (page_flip_data, *error);
|
||||
|
||||
goto err;
|
||||
}
|
||||
@ -1176,14 +1175,11 @@ maybe_dispatch_page_flips (MetaKmsImplDevice *impl_device,
|
||||
return TRUE;
|
||||
|
||||
err:
|
||||
if (!(flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR))
|
||||
for (l = page_flip_datas; l; l = l->next)
|
||||
{
|
||||
for (l = page_flip_datas; l; l = l->next)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data = l->data;
|
||||
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);
|
||||
|
||||
|
@ -79,8 +79,7 @@ typedef enum _MetaKmsResourceChanges
|
||||
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,
|
||||
META_KMS_UPDATE_FLAG_TEST_ONLY = 1 << 0,
|
||||
} MetaKmsUpdateFlag;
|
||||
|
||||
typedef enum _MetaKmsPlaneType MetaKmsPlaneType;
|
||||
|
@ -170,8 +170,6 @@ GList * meta_kms_update_get_mode_sets (MetaKmsUpdate *update);
|
||||
META_EXPORT_TEST
|
||||
GList * meta_kms_update_get_page_flip_listeners (MetaKmsUpdate *update);
|
||||
|
||||
void meta_kms_update_drop_defunct_page_flip_listeners (MetaKmsUpdate *update);
|
||||
|
||||
META_EXPORT_TEST
|
||||
GList * meta_kms_update_get_connector_updates (MetaKmsUpdate *update);
|
||||
|
||||
|
@ -462,28 +462,6 @@ 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_unref (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,
|
||||
|
@ -46,7 +46,6 @@ typedef enum _MetaKmsAssignPlaneFlag
|
||||
enum _MetaKmsPageFlipListenerFlag
|
||||
{
|
||||
META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE = 0,
|
||||
META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR = 1 << 0,
|
||||
};
|
||||
|
||||
struct _MetaKmsPageFlipListenerVtable
|
||||
|
@ -270,28 +270,7 @@ meta_kms_post_pending_update_sync (MetaKms *kms,
|
||||
|
||||
result_listeners = meta_kms_update_take_result_listeners (update);
|
||||
|
||||
if (feedback->error &&
|
||||
flags & META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
meta_kms_update_unlock (update);
|
||||
|
||||
for (l = feedback->failed_planes; l; l = l->next)
|
||||
{
|
||||
MetaKmsPlane *plane = l->data;
|
||||
|
||||
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
|
||||
{
|
||||
meta_kms_update_free (update);
|
||||
}
|
||||
meta_kms_update_free (update);
|
||||
|
||||
for (l = result_listeners; l; l = l->next)
|
||||
{
|
||||
|
@ -1266,6 +1266,40 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
|
||||
return result == META_KMS_FEEDBACK_PASSED;
|
||||
}
|
||||
|
||||
static void
|
||||
on_scanout_update_result (const MetaKmsFeedback *kms_feedback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (user_data);
|
||||
CoglOnscreen *onscreen = COGL_ONSCREEN (onscreen_native);
|
||||
const GError *error;
|
||||
CoglFrameInfo *frame_info;
|
||||
|
||||
error = meta_kms_feedback_get_error (kms_feedback);
|
||||
if (!error)
|
||||
return;
|
||||
|
||||
if (!g_error_matches (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_PERMISSION_DENIED))
|
||||
{
|
||||
ClutterStageView *view = CLUTTER_STAGE_VIEW (onscreen_native->view);
|
||||
|
||||
g_warning ("Direct scanout page flip failed: %s", error->message);
|
||||
|
||||
cogl_scanout_notify_failed (COGL_SCANOUT (onscreen_native->gbm.next_fb),
|
||||
onscreen);
|
||||
clutter_stage_view_add_redraw_clip (view, NULL);
|
||||
clutter_stage_view_schedule_update_now (view);
|
||||
}
|
||||
|
||||
frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
|
||||
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
|
||||
|
||||
meta_onscreen_native_notify_frame_complete (onscreen);
|
||||
meta_onscreen_native_clear_next_fb (onscreen);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout,
|
||||
@ -1293,9 +1327,7 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
||||
GError *fill_timings_error = NULL;
|
||||
MetaKmsCrtc *kms_crtc;
|
||||
MetaKmsDevice *kms_device;
|
||||
MetaKmsUpdateFlag flags;
|
||||
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
||||
const GError *feedback_error;
|
||||
MetaKmsUpdate *kms_update;
|
||||
|
||||
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
||||
if (power_save_mode != META_POWER_SAVE_ON)
|
||||
@ -1351,40 +1383,28 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
||||
}
|
||||
}
|
||||
|
||||
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
|
||||
kms_device = meta_kms_crtc_get_device (kms_crtc);
|
||||
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
|
||||
|
||||
meta_kms_update_add_result_listener (kms_update,
|
||||
on_scanout_update_result,
|
||||
onscreen_native);
|
||||
|
||||
meta_onscreen_native_flip_crtc (onscreen,
|
||||
onscreen_native->view,
|
||||
onscreen_native->crtc,
|
||||
META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR,
|
||||
META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
|
||||
kms_device = meta_kms_crtc_get_device (kms_crtc);
|
||||
|
||||
meta_topic (META_DEBUG_KMS,
|
||||
"Posting direct scanout update for CRTC %u (%s)",
|
||||
meta_kms_crtc_get_id (kms_crtc),
|
||||
meta_kms_device_get_path (kms_device));
|
||||
|
||||
flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR;
|
||||
kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
|
||||
switch (meta_kms_feedback_get_result (kms_feedback))
|
||||
{
|
||||
case META_KMS_FEEDBACK_PASSED:
|
||||
clutter_frame_set_result (frame,
|
||||
CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
|
||||
break;
|
||||
case META_KMS_FEEDBACK_FAILED:
|
||||
feedback_error = meta_kms_feedback_get_error (kms_feedback);
|
||||
|
||||
if (g_error_matches (feedback_error,
|
||||
G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
|
||||
break;
|
||||
|
||||
g_clear_object (&onscreen_native->gbm.next_fb);
|
||||
g_propagate_error (error, g_error_copy (feedback_error));
|
||||
return FALSE;
|
||||
}
|
||||
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
|
||||
meta_kms_post_pending_update_sync (kms, kms_device, META_KMS_UPDATE_FLAG_NONE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user