1
0
Fork 0

kms/impl-device: Track dispatch duration in crtc_frame_deadline_dispatch

And take it into account in meta_kms_crtc_get_deadline_evasion.

This uses the same fundamental approach as clutter frame clock scheduling:

Measure the deadline timer dispatch duration, keep track of the longest
duration, and set the timer to fire such that the longest measured
dispatch duration would result in it completing shortly before start of
vblank.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3612

v2:
* Move DEADLINE_EVASION_CONSTANT_US addition from
  meta_kms_crtc_determine_deadline to meta_kms_crtc_get_deadline_evasion.
* Calculate how long before start of vblank dispatch completed for
  debug output in crtc_frame_deadline_dispatch.
* Shorten over-long lines in crtc_frame_deadline_dispatch.
v3:
* Take VRR into account in crtc_frame_deadline_dispatch &
  meta_kms_crtc_update_shortterm_max_dispatch_duration. (Robert Mader)
v4:
* Check if deadline has already passed in meta_kms_crtc_determine_deadline,
  set the deadline for one refresh interval later if so.
* Fix indentation in crtc_frame_deadline_dispatch.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3934>
This commit is contained in:
Michel Dänzer 2024-08-08 16:36:05 +02:00 committed by Marge Bot
parent d7012d2ad3
commit bd8db38460
3 changed files with 120 additions and 19 deletions

View file

@ -28,8 +28,7 @@
#include "backends/native/meta-kms-update-private.h"
#include "backends/native/meta-kms-utils.h"
#define DEADLINE_EVASION_US 800
#define DEADLINE_EVASION_WITH_KMS_TOPIC_US 1000
#define DEADLINE_EVASION_CONSTANT_US 200
#define MINIMUM_REFRESH_RATE 30.f
@ -52,6 +51,10 @@ struct _MetaKmsCrtc
MetaKmsCrtcPropTable prop_table;
gboolean is_leased;
int64_t shortterm_max_dispatch_duration_us;
int64_t deadline_evasion_us;
int64_t deadline_evasion_update_time_us;
};
G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT)
@ -558,6 +561,33 @@ get_crtc_type_bitmask (MetaKmsCrtc *crtc)
}
}
static void
maybe_update_deadline_evasion (MetaKmsCrtc *crtc,
int64_t next_presentation_time_us)
{
/* Do not update long-term max if there has been no measurement */
if (!crtc->shortterm_max_dispatch_duration_us)
return;
if (next_presentation_time_us - crtc->deadline_evasion_update_time_us <
G_USEC_PER_SEC)
return;
if (crtc->deadline_evasion_us > crtc->shortterm_max_dispatch_duration_us)
{
/* Exponential drop-off toward the clamped short-term max */
crtc->deadline_evasion_us -=
(crtc->deadline_evasion_us - crtc->shortterm_max_dispatch_duration_us) / 2;
}
else
{
crtc->deadline_evasion_us = crtc->shortterm_max_dispatch_duration_us;
}
crtc->shortterm_max_dispatch_duration_us = 0;
crtc->deadline_evasion_update_time_us = next_presentation_time_us;
}
gboolean
meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
int64_t *out_next_deadline_us,
@ -605,14 +635,18 @@ meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
else
{
drmModeModeInfo *drm_mode;
int64_t refresh_interval_us;
int64_t vblank_duration_us;
int64_t deadline_evasion_us;
int64_t now_us;
drm_mode = &crtc->current_state.drm_mode;
refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC /
meta_calculate_drm_mode_refresh_rate (&crtc->current_state.drm_mode));
next_presentation_us =
(int64_t) (s2us (vblank.reply.tval_sec) + vblank.reply.tval_usec + 0.5 +
G_USEC_PER_SEC / meta_calculate_drm_mode_refresh_rate (drm_mode));
s2us (vblank.reply.tval_sec) + vblank.reply.tval_usec + refresh_interval_us;
/*
* 1
@ -626,10 +660,27 @@ meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
*/
deadline_evasion_us = meta_kms_crtc_get_deadline_evasion (crtc);
maybe_update_deadline_evasion (crtc, next_presentation_us);
vblank_duration_us = meta_calculate_drm_mode_vblank_duration_us (drm_mode);
next_deadline_us = next_presentation_us - (vblank_duration_us +
deadline_evasion_us);
now_us = g_get_monotonic_time ();
if (now_us > next_deadline_us)
{
if (meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
{
meta_topic (META_DEBUG_KMS_DEADLINE,
"Missed deadline by %3"G_GINT64_FORMAT "µs, "
"skipping by %"G_GINT64_FORMAT "µs",
now_us - next_deadline_us,
refresh_interval_us);
}
next_presentation_us += refresh_interval_us;
next_deadline_us += refresh_interval_us;
}
}
*out_next_presentation_us = next_presentation_us;
@ -638,11 +689,29 @@ meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
return TRUE;
}
void
meta_kms_crtc_update_shortterm_max_dispatch_duration (MetaKmsCrtc *crtc,
int64_t duration_us)
{
int64_t refresh_interval_us;
/* meta_kms_crtc_determine_deadline doesn't use deadline evasion with VRR */
if (crtc->current_state.vrr.enabled)
return;
if (duration_us <= crtc->shortterm_max_dispatch_duration_us)
return;
refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC /
meta_calculate_drm_mode_refresh_rate (&crtc->current_state.drm_mode));
crtc->shortterm_max_dispatch_duration_us = MIN (duration_us, refresh_interval_us);
}
int64_t
meta_kms_crtc_get_deadline_evasion (MetaKmsCrtc *crtc)
{
if (meta_is_topic_enabled (META_DEBUG_KMS))
return DEADLINE_EVASION_WITH_KMS_TOPIC_US;
else
return DEADLINE_EVASION_US;
return MAX (crtc->shortterm_max_dispatch_duration_us,
crtc->deadline_evasion_us) + DEADLINE_EVASION_CONSTANT_US;
}

View file

@ -68,4 +68,7 @@ gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc);
gboolean meta_kms_crtc_is_leased (MetaKmsCrtc *crtc);
void meta_kms_crtc_update_shortterm_max_dispatch_duration (MetaKmsCrtc *crtc,
int64_t duration_us);
int64_t meta_kms_crtc_get_deadline_evasion (MetaKmsCrtc *crtc);

View file

@ -41,6 +41,7 @@
#include "backends/native/meta-kms-plane-private.h"
#include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.h"
#include "backends/native/meta-kms-utils.h"
#include "backends/native/meta-thread-private.h"
#include "meta-default-modes.h"
@ -1563,12 +1564,13 @@ crtc_frame_deadline_dispatch (MetaThreadImpl *thread_impl,
GError **error)
{
CrtcFrame *crtc_frame = user_data;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc_frame->crtc);
MetaKmsCrtc *crtc = crtc_frame->crtc;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
g_autoptr (MetaKmsFeedback) feedback = NULL;
uint64_t timer_value;
ssize_t ret;
int64_t dispatch_time_us = 0;
int64_t dispatch_time_us = 0, update_done_time_us, interval_us;
if (meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
dispatch_time_us = g_get_monotonic_time ();
@ -1594,21 +1596,48 @@ crtc_frame_deadline_dispatch (MetaThreadImpl *thread_impl,
g_steal_pointer (&crtc_frame->pending_update),
META_KMS_UPDATE_FLAG_NONE);
update_done_time_us = g_get_monotonic_time ();
/* Calculate how long after the planned start of deadline dispatch it finished */
interval_us = update_done_time_us - crtc_frame->deadline.expected_deadline_time_us;
if (meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
{
int64_t lateness_us, duration_us;
lateness_us = dispatch_time_us -
crtc_frame->deadline.expected_deadline_time_us;
duration_us = g_get_monotonic_time () - dispatch_time_us;
lateness_us = dispatch_time_us - crtc_frame->deadline.expected_deadline_time_us;
duration_us = update_done_time_us - dispatch_time_us;
if (meta_kms_crtc_get_current_state (crtc)->vrr.enabled)
{
meta_topic (META_DEBUG_KMS_DEADLINE,
"Deadline dispatch started %3"G_GINT64_FORMAT "µs %s and "
"VRR deadline dispatch started %3"G_GINT64_FORMAT "µs %s and "
"completed %3"G_GINT64_FORMAT "µs after that.",
ABS (lateness_us),
lateness_us >= 0 ? "late" : "early",
duration_us);
}
else
{
int64_t deadline_evasion_us, vblank_delta_us;
deadline_evasion_us = meta_kms_crtc_get_deadline_evasion (crtc);
vblank_delta_us = deadline_evasion_us - lateness_us - duration_us;
meta_topic (META_DEBUG_KMS_DEADLINE,
"Deadline evasion %3"G_GINT64_FORMAT "µs, "
"dispatch started %3"G_GINT64_FORMAT "µs %s and "
"completed %3"G_GINT64_FORMAT "µs after that, "
"%3"G_GINT64_FORMAT "µs %s start of vblank.",
deadline_evasion_us,
ABS (lateness_us),
lateness_us >= 0 ? "late" : "early",
duration_us,
ABS (vblank_delta_us),
vblank_delta_us >= 0 ? "before" : "after");
}
}
meta_kms_crtc_update_shortterm_max_dispatch_duration (crtc, interval_us);
if (meta_kms_feedback_did_pass (feedback))
crtc_frame->deadline.is_deadline_page_flip = TRUE;