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>
This commit is contained in:
parent
369596a82b
commit
996eb4b6ae
1 changed files with 129 additions and 27 deletions
|
@ -78,6 +78,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
|
||||||
|
@ -1654,6 +1661,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1762,6 +1771,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,
|
||||||
|
@ -1769,10 +1851,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));
|
||||||
|
|
||||||
|
@ -1793,43 +1880,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:
|
||||||
|
|
Loading…
Reference in a new issue