1
0
Fork 0

kms/impl-device: Handle sync_fd in meta_kms_impl_device_handle_update

If the KMS thread is using the deadline timer, and a valid sync_file
descriptor is passed in:

1. The update is deferred, and the deadline timer is left armed, until
   the sync_fd signals (becomes readable).
2. Implicit synchronization is disabled for the KMS update.

This means cursor updates should no longer miss a display refresh
cycle due to mutter's compositing GPU work finishing too late.

v2:
* Use g_autoptr for GSource in meta_kms_impl_device_handle_update.
  (Sebastian Wick)
v3:
* Use meta_kms_update_get_sync_fd, don't track sync_fd in
  CrtcFrame::submitted_update. (Jonas Ådahl)
v4:
* Clean up CrtcFrame::submitted_update members in crtc_frame_free.
v5:
* Coding style cleanup in meta_kms_impl_device_handle_update.
  (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
This commit is contained in:
Michel Dänzer 2024-08-21 15:32:26 +02:00 committed by Mingi Sung
parent 168839e317
commit a9a221933e
Signed by: sungmg
GPG key ID: 41BAFD6FFD8036C5

View file

@ -76,6 +76,13 @@ typedef struct _CrtcDeadline
int64_t expected_presentation_time_us; int64_t expected_presentation_time_us;
gboolean has_expected_presentation_time; gboolean has_expected_presentation_time;
} deadline; } deadline;
struct {
MetaKmsUpdate *kms_update;
MetaKmsUpdateFlag flags;
MetaKmsCrtc *latch_crtc;
GSource *source;
} submitted_update;
} CrtcFrame; } CrtcFrame;
typedef enum _MetaDeadlineTimerState typedef enum _MetaDeadlineTimerState
@ -1469,6 +1476,8 @@ crtc_frame_free (CrtcFrame *crtc_frame)
g_clear_fd (&crtc_frame->deadline.timer_fd, NULL); g_clear_fd (&crtc_frame->deadline.timer_fd, NULL);
g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy); g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy);
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free); g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
g_clear_pointer (&crtc_frame->submitted_update.kms_update, meta_kms_update_free);
g_clear_pointer (&crtc_frame->submitted_update.source, g_source_destroy);
g_free (crtc_frame); g_free (crtc_frame);
} }
@ -1577,6 +1586,79 @@ queue_update (MetaKmsImplDevice *impl_device,
} }
} }
static gpointer
meta_kms_impl_device_update_ready (MetaThreadImpl *impl,
gpointer user_data,
GError **error)
{
CrtcFrame *crtc_frame = user_data;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc_frame->crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
MetaKmsUpdate *update;
MetaKmsCrtc *latch_crtc;
MetaKmsFeedback *feedback;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
g_clear_pointer (&crtc_frame->submitted_update.source, g_source_destroy);
update = g_steal_pointer (&crtc_frame->submitted_update.kms_update);
meta_kms_update_realize (update, impl_device);
latch_crtc = g_steal_pointer (&crtc_frame->submitted_update.latch_crtc);
if (crtc_frame->pending_page_flip &&
!meta_kms_update_get_mode_sets (update))
{
g_assert (latch_crtc);
meta_topic (META_DEBUG_KMS,
"Queuing update on CRTC %u (%s): pending page flip",
meta_kms_crtc_get_id (latch_crtc),
priv->path);
queue_update (impl_device, crtc_frame, update);
return GINT_TO_POINTER (TRUE);
}
if (crtc_frame->pending_update)
{
meta_kms_update_merge_from (crtc_frame->pending_update, update);
meta_kms_update_free (update);
update = g_steal_pointer (&crtc_frame->pending_update);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
meta_kms_device_handle_flush (priv->device, latch_crtc);
feedback = do_process (impl_device, latch_crtc, update, crtc_frame->submitted_update.flags);
if (meta_kms_feedback_did_pass (feedback) &&
crtc_frame->deadline.armed)
disarm_crtc_frame_deadline_timer (crtc_frame);
meta_kms_feedback_unref (feedback);
return GINT_TO_POINTER (TRUE);
}
static gboolean
is_fd_readable (int fd)
{
GPollFD poll_fd;
poll_fd.fd = fd;
poll_fd.events = G_IO_IN;
poll_fd.revents = 0;
if (!g_poll (&poll_fd, 1, 0))
return FALSE;
return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0;
}
void void
meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device, meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update, MetaKmsUpdate *update,
@ -1584,10 +1666,15 @@ meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
{ {
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
MetaKmsCrtc *latch_crtc; MetaKmsCrtc *latch_crtc;
CrtcFrame *crtc_frame; CrtcFrame *crtc_frame;
MetaKmsFeedback *feedback; MetaKmsFeedback *feedback;
g_autoptr (GSource) source = NULL;
g_autofree char *name = NULL;
int sync_fd = -1;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl)); meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
@ -1608,43 +1695,58 @@ meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
if (!ensure_device_file (impl_device, &error)) if (!ensure_device_file (impl_device, &error))
goto err; goto err;
meta_kms_update_realize (update, impl_device);
crtc_frame = ensure_crtc_frame (impl_device, latch_crtc); crtc_frame = ensure_crtc_frame (impl_device, latch_crtc);
crtc_frame->await_flush = FALSE; if (crtc_frame->submitted_update.kms_update)
if (crtc_frame->pending_page_flip &&
!meta_kms_update_get_mode_sets (update))
{ {
g_assert (latch_crtc); g_set_error (&error, G_IO_ERROR, G_IO_ERROR_PENDING,
"Previously-submitted update wasn't ready yet");
goto err;
}
meta_topic (META_DEBUG_KMS, crtc_frame->await_flush = FALSE;
"Queuing update on CRTC %u (%s): pending page flip", crtc_frame->submitted_update.kms_update = update;
meta_kms_crtc_get_id (latch_crtc), crtc_frame->submitted_update.flags = flags;
priv->path); crtc_frame->submitted_update.latch_crtc = latch_crtc;
queue_update (impl_device, crtc_frame, update); if (is_using_deadline_timer (impl_device))
sync_fd = meta_kms_update_get_sync_fd (update);
if (sync_fd >= 0)
{
GList *l;
for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next)
{
MetaKmsPlaneAssignment *assignment = l->data;
assignment->flags |= META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC;
}
}
if (sync_fd < 0 ||
is_fd_readable (sync_fd))
{
meta_kms_impl_device_update_ready (thread_impl,
crtc_frame,
NULL);
return; return;
} }
if (crtc_frame->pending_update) source = meta_thread_impl_register_fd (thread_impl,
{ sync_fd,
meta_kms_update_merge_from (crtc_frame->pending_update, update); meta_kms_impl_device_update_ready,
meta_kms_update_free (update); crtc_frame);
update = g_steal_pointer (&crtc_frame->pending_update);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
meta_kms_device_handle_flush (priv->device, latch_crtc); name = g_strdup_printf ("[mutter] KMS update sync_fd (crtc: %u, %s)",
meta_kms_crtc_get_id (latch_crtc),
priv->path);
g_source_set_name (source, name);
g_source_set_priority (source, G_PRIORITY_HIGH + 1);
g_source_set_can_recurse (source, FALSE);
g_source_set_ready_time (source, -1);
feedback = do_process (impl_device, latch_crtc, update, flags); crtc_frame->submitted_update.source = source;
if (meta_kms_feedback_did_pass (feedback) &&
crtc_frame->deadline.armed)
disarm_crtc_frame_deadline_timer (crtc_frame);
meta_kms_feedback_unref (feedback);
return; return;
err: err: