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>
This commit is contained in:
parent
4b0fd9ab76
commit
1d7920872d
12 changed files with 84 additions and 32 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue