clutter/frame-clock: Add a state for when scheduled "now"

The new CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW state is almost
identical to CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, with one important
difference being that it avoids updates from being repeatedly
rescheduled "now" when multiple calls to
clutter_frame_clock_schedule_update_now() are done before the source
is actually dispatched.

Such repeated calls to schedule an update "now" may actually postpone
the dispatch if the CPU is very busy and the source dispatch is
delayed, defeating the purpose of scheduling a frame "now".

It also allows rescheduling "now" when the frame clock is uninhibited
after being inhibited while an update was scheduled "now". This may
be important in cases where the frame clock is inhibited for very
short periods in which it would otherwise lose the state of being
scheduled "now".

Scenarios such as this would become more common with the introduction
of variable refresh rate since it makes scheduling "now" a commonplace
occurrence.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3561>
This commit is contained in:
Dor Askayo 2024-02-04 00:54:45 +02:00
parent f72dbc8046
commit 82cdf90a71
2 changed files with 17 additions and 5 deletions

View File

@ -55,6 +55,7 @@ typedef enum _ClutterFrameClockState
CLUTTER_FRAME_CLOCK_STATE_INIT, CLUTTER_FRAME_CLOCK_STATE_INIT,
CLUTTER_FRAME_CLOCK_STATE_IDLE, CLUTTER_FRAME_CLOCK_STATE_IDLE,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW,
CLUTTER_FRAME_CLOCK_STATE_DISPATCHING, CLUTTER_FRAME_CLOCK_STATE_DISPATCHING,
CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED, CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED,
} ClutterFrameClockState; } ClutterFrameClockState;
@ -390,6 +391,7 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
case CLUTTER_FRAME_CLOCK_STATE_INIT: case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE: case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
g_warn_if_reached (); g_warn_if_reached ();
break; break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
@ -411,6 +413,7 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
case CLUTTER_FRAME_CLOCK_STATE_INIT: case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE: case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
g_warn_if_reached (); g_warn_if_reached ();
break; break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
@ -620,6 +623,11 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
frame_clock->pending_reschedule = TRUE; frame_clock->pending_reschedule = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
break; break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
break; break;
@ -659,6 +667,8 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
next_update_time_us = g_get_monotonic_time (); next_update_time_us = g_get_monotonic_time ();
break; break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->pending_reschedule = TRUE; frame_clock->pending_reschedule = TRUE;
@ -670,7 +680,7 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
frame_clock->next_update_time_us = next_update_time_us; frame_clock->next_update_time_us = next_update_time_us;
g_source_set_ready_time (frame_clock->source, next_update_time_us); g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
frame_clock->is_next_presentation_time_valid = FALSE; frame_clock->is_next_presentation_time_valid = FALSE;
frame_clock->has_next_frame_deadline = FALSE; frame_clock->has_next_frame_deadline = FALSE;
} }
@ -702,6 +712,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
(frame_clock->next_frame_deadline_us != 0); (frame_clock->next_frame_deadline_us != 0);
break; break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
return; return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
@ -808,6 +819,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
break; break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE: case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
break; break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
switch (result) switch (result)

View File

@ -4,11 +4,11 @@
```mermaid ```mermaid
stateDiagram stateDiagram
Init --> Scheduled : schedule update() -> now Init --> Scheduled/ScheduledNow : schedule update() -> now
Idle --> Scheduled : schedule update() -> given presentation time Idle --> Scheduled/ScheduledNow : schedule update() -> given presentation time
Scheduled --> Dispatching : target time hit Scheduled/ScheduledNow --> Dispatching : target time hit
Dispatching --> PendingPresented : queued page flip Dispatching --> PendingPresented : queued page flip
Dispatching --> Idle : no queued page flip Dispatching --> Idle : no queued page flip
PendingPresented --> Scheduled : page flipped, if recent schedule update PendingPresented --> Scheduled/ScheduledNow : page flipped, if recent schedule update
PendingPresented --> Idle : page flipped PendingPresented --> Idle : page flipped
``` ```