From 430a8f2768db5192623cceb3c688ce0dae4c1089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 29 Sep 2023 18:39:01 +0200 Subject: [PATCH 1/3] kms/crtc: Handle OUT_FENCE_PTR atomic property --- src/backends/native/meta-kms-crtc-private.h | 1 + src/backends/native/meta-kms-crtc.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/backends/native/meta-kms-crtc-private.h b/src/backends/native/meta-kms-crtc-private.h index 27cb0c08d6e..62c447e9612 100644 --- a/src/backends/native/meta-kms-crtc-private.h +++ b/src/backends/native/meta-kms-crtc-private.h @@ -28,6 +28,7 @@ typedef enum _MetaKmsCrtcProp META_KMS_CRTC_PROP_ACTIVE, META_KMS_CRTC_PROP_GAMMA_LUT, META_KMS_CRTC_PROP_GAMMA_LUT_SIZE, + META_KMS_CRTC_PROP_OUT_FENCE_PTR, META_KMS_CRTC_N_PROPS } MetaKmsCrtcProp; diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index d89b1259895..87839e7637f 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -427,6 +427,11 @@ init_properties (MetaKmsCrtc *crtc, .name = "GAMMA_LUT_SIZE", .type = DRM_MODE_PROP_RANGE, }, + [META_KMS_CRTC_PROP_OUT_FENCE_PTR] = + { + .name = "OUT_FENCE_PTR", + .type = DRM_MODE_PROP_RANGE, + }, } }; } -- GitLab From 36327e2b5615d5829cab518f815341f58918f030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 2 Oct 2023 17:55:42 +0200 Subject: [PATCH 2/3] kms/impl-device/atomic: Use MetaKmsUpdate in impl_device_atomic_disable Instead of essentially duplicating an open-coded version of it. v2: * Use meta_kms_impl_device_get_device v3: * Use meta_kms_device_post_update, with one update per enabled CRTC. This handles the case where there is a pending page flip for the CRTC. --- .../native/meta-kms-impl-device-atomic.c | 108 ++++-------------- 1 file changed, 20 insertions(+), 88 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index 2ca70326fa6..abcb3b08178 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -856,9 +856,9 @@ commit_flags_string (uint32_t commit_flags) } static gboolean -disable_connectors (MetaKmsImplDevice *impl_device, - drmModeAtomicReq *req, - GError **error) +disable_planes_and_connectors (MetaKmsImplDevice *impl_device, + drmModeAtomicReq *req, + GError **error) { GList *l; @@ -874,16 +874,6 @@ disable_connectors (MetaKmsImplDevice *impl_device, return FALSE; } - return TRUE; -} - -static gboolean -disable_planes (MetaKmsImplDevice *impl_device, - drmModeAtomicReq *req, - GError **error) -{ - GList *l; - for (l = meta_kms_impl_device_peek_planes (impl_device); l; l = l->next) { MetaKmsPlane *plane = l->data; @@ -906,48 +896,6 @@ disable_planes (MetaKmsImplDevice *impl_device, return TRUE; } -static gboolean -disable_crtcs (MetaKmsImplDevice *impl_device, - drmModeAtomicReq *req, - GError **error) -{ - GList *l; - - for (l = meta_kms_impl_device_peek_crtcs (impl_device); l; l = l->next) - { - MetaKmsCrtc *crtc = l->data; - - if (!add_crtc_property (impl_device, - crtc, req, - META_KMS_CRTC_PROP_ACTIVE, - 0, - error)) - return FALSE; - - if (!add_crtc_property (impl_device, - crtc, req, - META_KMS_CRTC_PROP_MODE_ID, - 0, - error)) - return FALSE; - } - - return TRUE; -} - -static gboolean -disable_planes_and_connectors (MetaKmsImplDevice *impl_device, - drmModeAtomicReq *req, - GError **error) -{ - if (!disable_connectors (impl_device, req, error)) - return FALSE; - if (!disable_planes (impl_device, req, error)) - return FALSE; - - return TRUE; -} - static MetaKmsFeedback * meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, MetaKmsUpdate *update, @@ -1073,48 +1021,32 @@ err: static void meta_kms_impl_device_atomic_disable (MetaKmsImplDevice *impl_device) { - g_autoptr (GError) error = NULL; - drmModeAtomicReq *req; - int fd; - int ret; + MetaKmsDevice *device = meta_kms_impl_device_get_device (impl_device); + MetaKmsUpdate *update; + GList *l; meta_topic (META_DEBUG_KMS, "[atomic] Disabling '%s'", meta_kms_impl_device_get_path (impl_device)); - req = drmModeAtomicAlloc (); - if (!req) - { - g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to create atomic transaction request: %s", - g_strerror (errno)); - goto err; - } + update = meta_kms_update_new (device); - if (!disable_connectors (impl_device, req, &error)) - goto err; - if (!disable_planes (impl_device, req, &error)) - goto err; - if (!disable_crtcs (impl_device, req, &error)) - goto err; + for (l = meta_kms_impl_device_peek_crtcs (impl_device); l; l = l->next) + { + MetaKmsCrtc *crtc = l->data; - meta_topic (META_DEBUG_KMS, "[atomic] Committing disable-device transaction"); + if (!meta_kms_crtc_get_current_state (crtc)->is_active) + continue; - fd = meta_kms_impl_device_get_fd (impl_device); - ret = drmModeAtomicCommit (fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, impl_device); - drmModeAtomicFree (req); - if (ret < 0) - { - g_set_error (&error, G_IO_ERROR, g_io_error_from_errno (-ret), - "drmModeAtomicCommit: %s", g_strerror (-ret)); - goto err; - } + update = meta_kms_update_new (device); + meta_kms_update_set_flushing (update, crtc); + meta_kms_update_mode_set (update, crtc, NULL, NULL); - return; + meta_topic (META_DEBUG_KMS, "Posting disable update for CRTC %u", + meta_kms_crtc_get_id (crtc)); -err: - g_warning ("[atomic] Failed to disable device '%s': %s", - meta_kms_impl_device_get_path (impl_device), - error->message); + meta_kms_device_post_update (device, update, + META_KMS_UPDATE_FLAG_NONE); + } } static void -- GitLab From bab3c6c2e7a5462c594acc29dc4119eddb2c2cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 29 Sep 2023 18:49:24 +0200 Subject: [PATCH 3/3] kms/impl-device/atomic: Use non-blocking atomic commits for modesets If there are no page flip listeners, use the OUT_FENCE_PTR CRTC property to get a sync file descriptor which signals (becomes readable) when the atomic commit finishes. In the future, this could be extended to handle all modesets fully asynchronously, allowing them to be processed in parallel with other atomic commits by the kernel. For now though, just wait synchronously for the sync files to signal. This should result in mostly the same behaviour as far as the rest of mutter is concerned, and should be enough to avoid hitting the RT CPU time limit in the kernel. Issue: https://gitlab.gnome.org/GNOME/mutter/-/issues/3037 v2: * Use g_clear_fd in process_wait_out_fence (Pascal Nowack) * Set error as needed in process_wait_out_fence * Check return value of process_wait_out_fence in meta_kms_impl_device_atomic_process_update v3: * Get out fence only for enabled CRTCs, to avoid atomic commit ioctl failure * Queue mode set updates if there's a pending page flip in meta_kms_impl_device_handle_update * Get and wait for out fences only if there are no page flip listeners --- .../native/meta-kms-impl-device-atomic.c | 104 +++++++++++++++++- src/backends/native/meta-kms-impl-device.c | 3 +- src/backends/native/meta-kms-update-private.h | 1 + 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index abcb3b08178..4300edd7686 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -19,6 +19,8 @@ #include "backends/native/meta-kms-impl-device-atomic.h" +#include + #include "backends/native/meta-backend-native-private.h" #include "backends/native/meta-kms-connector-private.h" #include "backends/native/meta-kms-crtc-private.h" @@ -415,6 +417,77 @@ process_mode_set (MetaKmsImplDevice *impl_device, return TRUE; } +static gboolean +process_out_fence_ptr (MetaKmsImplDevice *impl_device, + MetaKmsUpdate *update, + drmModeAtomicReq *req, + GArray *blob_ids, + gpointer update_entry, + gpointer user_data, + GError **error) +{ + MetaKmsModeSet *mode_set = update_entry; + MetaKmsCrtc *crtc = mode_set->crtc; + + mode_set->out_fence_fd = -1; + + if ((mode_set->mode || meta_kms_crtc_get_current_state (crtc)->is_active) && + !add_crtc_property (impl_device, + crtc, req, + META_KMS_CRTC_PROP_OUT_FENCE_PTR, + (ptrdiff_t)&mode_set->out_fence_fd, + error)) + return FALSE; + + return TRUE; +} + +static gboolean +process_wait_out_fence (MetaKmsImplDevice *impl_device, + MetaKmsUpdate *update, + drmModeAtomicReq *req, + GArray *blob_ids, + gpointer update_entry, + gpointer user_data, + GError **error) +{ + MetaKmsModeSet *mode_set = update_entry; + GPollFD poll_fd; + int status; + + if (mode_set->out_fence_fd == -1) + return TRUE; + + poll_fd.fd = mode_set->out_fence_fd; + poll_fd.events = G_IO_IN; + poll_fd.revents = 0; + + do + { + status = g_poll (&poll_fd, 1, -1); + + if (status < 0 && errno != EINTR) + { + g_set_error_literal (error, G_IO_ERROR, + g_io_error_from_errno (errno), + strerror (errno)); + return FALSE; + } + } + while (status <= 0); + + if (!g_clear_fd (&mode_set->out_fence_fd, error)) + return FALSE; + + if (poll_fd.revents & G_IO_IN) + return TRUE; + + g_set_error (error, G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "Out fence failed to signal"); + return FALSE; +} + static gboolean add_plane_property (MetaKmsImplDevice *impl_device, MetaKmsPlane *plane, @@ -906,7 +979,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, drmModeAtomicReq *req; g_autoptr (GArray) blob_ids = NULL; int fd; - uint32_t commit_flags = 0; + uint32_t commit_flags = DRM_MODE_ATOMIC_NONBLOCK; int ret; blob_ids = g_array_new (FALSE, TRUE, sizeof (uint32_t)); @@ -970,11 +1043,23 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, if (meta_kms_update_get_needs_modeset (update)) commit_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; - else - commit_flags |= DRM_MODE_ATOMIC_NONBLOCK; if (meta_kms_update_get_page_flip_listeners (update)) - commit_flags |= DRM_MODE_PAGE_FLIP_EVENT; + { + commit_flags |= DRM_MODE_PAGE_FLIP_EVENT; + } + else + { + if (!process_entries (impl_device, + update, + req, + blob_ids, + meta_kms_update_get_mode_sets (update), + NULL, + process_out_fence_ptr, + &error)) + goto err; + } if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY) commit_flags |= DRM_MODE_ATOMIC_TEST_ONLY; @@ -1003,6 +1088,17 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, process_page_flip_listener, NULL); + if (!(commit_flags & DRM_MODE_PAGE_FLIP_EVENT) && + !process_entries (impl_device, + update, + req, + blob_ids, + meta_kms_update_get_mode_sets (update), + NULL, + process_wait_out_fence, + NULL)) + goto err; + release_blob_ids (impl_device, blob_ids); return meta_kms_feedback_new_passed (NULL); diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index bce64d309d4..2736167dd01 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -1464,8 +1464,7 @@ meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device, crtc_frame->await_flush = FALSE; - if (crtc_frame->pending_page_flip && - !meta_kms_update_get_mode_sets (update)) + if (crtc_frame->pending_page_flip) { g_assert (latch_crtc); diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index edddd3e4a43..1509fdbeb98 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -77,6 +77,7 @@ typedef struct _MetaKmsModeSet MetaKmsCrtc *crtc; GList *connectors; MetaKmsMode *mode; + int out_fence_fd; } MetaKmsModeSet; typedef struct _MetaKmsConnectorUpdate -- GitLab