mirror of
https://github.com/brl/mutter.git
synced 2024-12-22 19:12:04 +00:00
clutter/frame-clock: Handle immediate present feedback
In certain scenarios, the frame clock needs to handle present feedback long before the assumed presentation time happens. To avoid scheduling the next frame to soon, avoid scheduling one if we were presented half a frame interval within the last expected presentation time. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
This commit is contained in:
parent
96a108ed4e
commit
e743b36cfc
@ -72,6 +72,9 @@ struct _ClutterFrameClock
|
||||
ClutterFrameClockState state;
|
||||
int64_t last_presentation_time_us;
|
||||
|
||||
gboolean is_next_presentation_time_valid;
|
||||
int64_t next_presentation_time_us;
|
||||
|
||||
gboolean pending_reschedule;
|
||||
};
|
||||
|
||||
@ -120,7 +123,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
||||
|
||||
static void
|
||||
calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
||||
int64_t *out_next_update_time_us)
|
||||
int64_t *out_next_update_time_us,
|
||||
int64_t *out_next_presentation_time_us)
|
||||
{
|
||||
int64_t last_presentation_time_us;
|
||||
int64_t now_us;
|
||||
@ -128,6 +132,8 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
||||
int64_t refresh_interval_us;
|
||||
int64_t min_render_time_allowed_us;
|
||||
int64_t max_render_time_allowed_us;
|
||||
int64_t last_next_presentation_time_us;
|
||||
int64_t time_since_last_next_presentation_time_us;
|
||||
int64_t next_presentation_time_us;
|
||||
int64_t next_update_time_us;
|
||||
|
||||
@ -159,12 +165,24 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
||||
next_presentation_time_us = logical_clock_phase_us + hw_clock_offset_us;
|
||||
}
|
||||
|
||||
/* Skip one interval if we got an early presented event. */
|
||||
last_next_presentation_time_us = frame_clock->next_presentation_time_us;
|
||||
time_since_last_next_presentation_time_us =
|
||||
next_presentation_time_us - last_next_presentation_time_us;
|
||||
if (frame_clock->is_next_presentation_time_valid &&
|
||||
time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
|
||||
{
|
||||
next_presentation_time_us =
|
||||
frame_clock->next_presentation_time_us + refresh_interval_us;
|
||||
}
|
||||
|
||||
while (next_presentation_time_us < now_us + min_render_time_allowed_us)
|
||||
next_presentation_time_us += refresh_interval_us;
|
||||
|
||||
next_update_time_us = next_presentation_time_us - max_render_time_allowed_us;
|
||||
|
||||
*out_next_update_time_us = next_update_time_us;
|
||||
*out_next_presentation_time_us = next_presentation_time_us;
|
||||
}
|
||||
|
||||
void
|
||||
@ -178,7 +196,10 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
|
||||
next_update_time_us = g_get_monotonic_time ();
|
||||
break;
|
||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||
calculate_next_update_time_us (frame_clock, &next_update_time_us);
|
||||
calculate_next_update_time_us (frame_clock,
|
||||
&next_update_time_us,
|
||||
&frame_clock->next_presentation_time_us);
|
||||
frame_clock->is_next_presentation_time_valid = TRUE;
|
||||
break;
|
||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||
return;
|
||||
|
@ -158,6 +158,78 @@ frame_clock_schedule_update (void)
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
schedule_update_idle (gpointer user_data)
|
||||
{
|
||||
ClutterFrameClock *frame_clock = user_data;
|
||||
|
||||
clutter_frame_clock_schedule_update (frame_clock);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static ClutterFrameResult
|
||||
immediate_frame_clock_frame (ClutterFrameClock *frame_clock,
|
||||
int64_t frame_count,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *main_loop = user_data;
|
||||
|
||||
g_assert_cmpint (frame_count, ==, expected_frame_count);
|
||||
|
||||
expected_frame_count++;
|
||||
|
||||
if (test_frame_count == 0)
|
||||
{
|
||||
g_main_loop_quit (main_loop);
|
||||
return CLUTTER_FRAME_RESULT_IDLE;
|
||||
}
|
||||
|
||||
test_frame_count--;
|
||||
|
||||
clutter_frame_clock_notify_presented (frame_clock, g_get_monotonic_time ());
|
||||
g_idle_add (schedule_update_idle, frame_clock);
|
||||
|
||||
return CLUTTER_FRAME_RESULT_PENDING_PRESENTED;
|
||||
}
|
||||
|
||||
static const ClutterFrameListenerIface immediate_frame_listener_iface = {
|
||||
.frame = immediate_frame_clock_frame,
|
||||
};
|
||||
|
||||
static void
|
||||
frame_clock_immediate_present (void)
|
||||
{
|
||||
GMainLoop *main_loop;
|
||||
ClutterFrameClock *frame_clock;
|
||||
int64_t before_us;
|
||||
int64_t after_us;
|
||||
|
||||
test_frame_count = 10;
|
||||
expected_frame_count = 0;
|
||||
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
frame_clock = clutter_frame_clock_new (refresh_rate,
|
||||
&immediate_frame_listener_iface,
|
||||
main_loop);
|
||||
|
||||
before_us = g_get_monotonic_time ();
|
||||
|
||||
clutter_frame_clock_schedule_update (frame_clock);
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
after_us = g_get_monotonic_time ();
|
||||
|
||||
/* The initial frame will only be delayed by 2 ms, so we are checking one
|
||||
* less.
|
||||
*/
|
||||
g_assert_cmpint (after_us - before_us, >, 9 * refresh_interval_us);
|
||||
|
||||
g_main_loop_unref (main_loop);
|
||||
g_object_unref (frame_clock);
|
||||
}
|
||||
|
||||
CLUTTER_TEST_SUITE (
|
||||
CLUTTER_TEST_UNIT ("/frame-clock/schedule-update", frame_clock_schedule_update)
|
||||
CLUTTER_TEST_UNIT ("/frame-clock/immediate-present", frame_clock_immediate_present)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user