From 0129d102669bf793d19efc4a5e3744056360e812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 8 Aug 2024 16:36:05 +0200 Subject: [PATCH] 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. Part-of: Signed-off-by: Mingi Sung (cherry picked from commit 88e7f353) --- src/backends/native/meta-kms-crtc.c | 57 +++++++++++++++++++--- src/backends/native/meta-kms-crtc.h | 3 ++ src/backends/native/meta-kms-impl-device.c | 29 ++++++++--- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 4dfafb19a..cad9f88ce 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -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 @@ -50,6 +49,10 @@ struct _MetaKmsCrtc MetaKmsCrtcState current_state; MetaKmsCrtcPropTable prop_table; + + 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) @@ -543,6 +546,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, @@ -611,6 +641,7 @@ 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 + @@ -623,11 +654,25 @@ 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; + + 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; } diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h index d9682fce3..b293f8e7c 100644 --- a/src/backends/native/meta-kms-crtc.h +++ b/src/backends/native/meta-kms-crtc.h @@ -66,4 +66,7 @@ int meta_kms_crtc_get_idx (MetaKmsCrtc *crtc); META_EXPORT_TEST gboolean meta_kms_crtc_is_active (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); diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 31e9af451..6ce62cd69 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -39,6 +39,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" @@ -1392,12 +1393,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 (); @@ -1423,22 +1425,35 @@ 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; + int64_t deadline_evasion_us, lateness_us, duration_us, vblank_delta_us; + deadline_evasion_us = meta_kms_crtc_get_deadline_evasion (crtc); lateness_us = dispatch_time_us - crtc_frame->deadline.expected_deadline_time_us; - duration_us = g_get_monotonic_time () - dispatch_time_us; + duration_us = update_done_time_us - dispatch_time_us; + vblank_delta_us = deadline_evasion_us - lateness_us - duration_us; meta_topic (META_DEBUG_KMS_DEADLINE, - "Deadline dispatch started %3"G_GINT64_FORMAT "µs %s and " - "completed %3"G_GINT64_FORMAT "µs after that.", + "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); + 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; disarm_crtc_frame_deadline_timer (crtc_frame);