1
0
Fork 0

clutter/frame-clock: Break a feedback loop between VRR and triple buffering

VRR calls `clutter_frame_clock_schedule_update_now` which would keep
the buffer queue full, which in turn prevented direct scanout mode.
Because OnscreenNative currently only supports direct scanout with
double buffering.

We now break that feedback loop by preventing triple buffering from
being scheduled when the frame clock mode becomes variable.

Long term this could also be solved by supporting triple buffering in
direct scanout mode. But whether or not that would be optimal given
the latency penalty remains to be seen.
This commit is contained in:
Daniel van Vugt 2024-04-24 18:21:01 +08:00
parent 8124914758
commit d4832ab578

View file

@ -881,6 +881,25 @@ clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
maybe_reschedule_update (frame_clock); maybe_reschedule_update (frame_clock);
} }
static gboolean
want_triple_buffering (ClutterFrameClock *frame_clock)
{
switch (triple_buffering_mode)
{
case TRIPLE_BUFFERING_MODE_NEVER:
return FALSE;
case TRIPLE_BUFFERING_MODE_AUTO:
return frame_clock->mode == CLUTTER_FRAME_CLOCK_MODE_FIXED &&
!(frame_clock->last_flip_hints &
CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED);
case TRIPLE_BUFFERING_MODE_ALWAYS:
return TRUE;
}
g_assert_not_reached ();
return FALSE;
}
void void
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
{ {
@ -903,12 +922,19 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
return; return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
next_update_time_us = g_get_monotonic_time (); next_update_time_us = g_get_monotonic_time ();
frame_clock->state = frame_clock->state =
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW; CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW;
break; break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
if (want_triple_buffering (frame_clock))
{
frame_clock->state =
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW;
break;
}
G_GNUC_FALLTHROUGH;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
frame_clock->pending_reschedule = TRUE; frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE; frame_clock->pending_reschedule_now = TRUE;
@ -947,8 +973,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
TripleBufferingMode current_mode = triple_buffering_mode; TripleBufferingMode current_mode = triple_buffering_mode;
if (current_mode == TRIPLE_BUFFERING_MODE_AUTO && if (current_mode == TRIPLE_BUFFERING_MODE_AUTO &&
(frame_clock->last_flip_hints & !want_triple_buffering (frame_clock))
CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED))
current_mode = TRIPLE_BUFFERING_MODE_NEVER; current_mode = TRIPLE_BUFFERING_MODE_NEVER;
if (frame_clock->inhibit_count > 0) if (frame_clock->inhibit_count > 0)