1
0
Fork 0

kms/impl-device: Add/remove deadline timer as required

On a hybrid machine with i915 primary and nvidia-drm (470) secondary,
`meta_render_device_egl_stream_initable_init` calls
`meta_kms_inhibit_kernel_thread` to change from the default 'kernel'
thread type to 'user'. And soon after that it would
`meta_render_device_egl_stream_finalize` because I'm not actually
using that GPU, and calls `meta_kms_uninhibit_kernel_thread`.

So during startup Mutter would default to a realtime kernel thread,
switch to a user thread (which doesn't support realtime), and then
switch back to a realtime kernel thread.

In the middle of all that, while the thread type was 'user' and
realtime disabled, something was invoking `ensure_crtc_frame` which
created a `CrtcFrame` without a deadline timer. Soon after that the
thread type changed back to 'kernel' with deadline timers expected, but
our existing `CrtcFrame` has no deadline timer associated with it. And
so it would never fire, causing the cursor to freeze whenever the primary
plane isn't changing. And the problem was permanent, not just the first
frame because each `CrtcFrame` gets repeatedly reused (maybe shouldn't
be called a "Frame"?).

Now we adapt to switching between kernel and user thread types by adding
and removing the deadline timer as required.

Close: https://gitlab.gnome.org/GNOME/mutter/-/issues/3464
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3950>
This commit is contained in:
Daniel van Vugt 2024-08-14 15:50:48 +08:00
parent 82fa9e676a
commit c436e7cb17

View file

@ -1664,18 +1664,22 @@ ensure_crtc_frame (MetaKmsImplDevice *impl_device,
MetaKmsImpl *impl = meta_kms_impl_device_get_impl (impl_device);
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
CrtcFrame *crtc_frame;
gboolean want_deadline_timer, have_deadline_timer;
crtc_frame = get_crtc_frame (impl_device, latch_crtc);
if (crtc_frame)
return crtc_frame;
if (!crtc_frame)
{
crtc_frame = g_new0 (CrtcFrame, 1);
crtc_frame->impl_device = impl_device;
crtc_frame->crtc = latch_crtc;
crtc_frame->deadline.timer_fd = -1;
crtc_frame->await_flush = TRUE;
g_hash_table_insert (priv->crtc_frames, latch_crtc, crtc_frame);
}
crtc_frame = g_new0 (CrtcFrame, 1);
crtc_frame->impl_device = impl_device;
crtc_frame->crtc = latch_crtc;
crtc_frame->deadline.timer_fd = -1;
crtc_frame->await_flush = TRUE;
if (is_using_deadline_timer (impl_device))
want_deadline_timer = is_using_deadline_timer (impl_device);
have_deadline_timer = crtc_frame->deadline.timer_fd >= 0;
if (want_deadline_timer && !have_deadline_timer)
{
int timer_fd;
GSource *source;
@ -1700,8 +1704,11 @@ ensure_crtc_frame (MetaKmsImplDevice *impl_device,
g_source_unref (source);
}
g_hash_table_insert (priv->crtc_frames, latch_crtc, crtc_frame);
else if (!want_deadline_timer && have_deadline_timer)
{
g_clear_fd (&crtc_frame->deadline.timer_fd, NULL);
g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy);
}
return crtc_frame;
}