From d357e8830899ba1109b3bb7caefc917a4726bd8f Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 16 May 2022 22:18:59 +0200 Subject: [PATCH] Revert "packages/mutter: the dynamic triple buffering patch that never was" This reverts commit b6c0e1029d30ea9a1606dfa9b355b064a8e9b907. --- modules/autopatch/default.nix | 2 +- packages/patched-derivations.nix | 4 +- ...port-Dynamic-triple-double-buffering.patch | 3760 ----------------- 3 files changed, 2 insertions(+), 3764 deletions(-) delete mode 100644 patches/base/mutter/Support-Dynamic-triple-double-buffering.patch diff --git a/modules/autopatch/default.nix b/modules/autopatch/default.nix index 4db0a63..3b560e5 100644 --- a/modules/autopatch/default.nix +++ b/modules/autopatch/default.nix @@ -30,7 +30,7 @@ }; gnome = super.gnome.overrideScope' (self': super': { - inherit (patched) mutter nautilus; + inherit (patched) nautilus; gnome-control-center = patched.gnome-control-center.override { inherit (self') gnome-user-share; }; gnome-shell = super'.gnome-shell.overrideAttrs (old: { preFixup = old.preFixup + '' diff --git a/packages/patched-derivations.nix b/packages/patched-derivations.nix index b2f4361..e5adb32 100644 --- a/packages/patched-derivations.nix +++ b/packages/patched-derivations.nix @@ -9,9 +9,7 @@ super: rec { lain-ipfs = patch-rename super.ipfs "lain-ipfs" "patches/base/ipfs"; - gnome-control-center = (patch' super.gnome.gnome-control-center).override { inherit mutter; }; - - mutter = patch' super.gnome.mutter; + gnome-control-center = patch' super.gnome.gnome-control-center; nautilus = (patch' super.gnome.nautilus).overrideAttrs (attrs: { preFixup = with super; diff --git a/patches/base/mutter/Support-Dynamic-triple-double-buffering.patch b/patches/base/mutter/Support-Dynamic-triple-double-buffering.patch deleted file mode 100644 index 9a5fd74..0000000 --- a/patches/base/mutter/Support-Dynamic-triple-double-buffering.patch +++ /dev/null @@ -1,3760 +0,0 @@ -From 6b8d25eb6370a5040185ac83b44e32e3189e0533 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 10 Nov 2021 18:55:53 +0800 -Subject: [PATCH 01/44] onscreen/native: Tidy up secondary GPU buffer tracking - -The primary plane of a CRTC can only have one `current_fb` and therefore -only one `next_fb`, so don't confuse the situation by maintaining two of -each. In the past a single onscreen targeted multiple CRTCs meaning -separate tracking was necessary, but not anymore. - -If we're using `COPY_MODE_ZERO` then the `imported_buffer` will reference -the importee internally. We don't need to keep a redundant reference to -the old buffer after importation. - -If we're using `COPY_MODE_PRIMARY` or `COPY_MODE_SECONDARY_GPU` then we -only need to keep the final copy for the duration of scanout. - -All of that happens before the flip so only one `next_fb` needs to live on -after the flip. And if there's only one `next_fb` then there's only one -`current_fb`. - -In a related cleanup we now also ensure that `onscreen_native->gbm.next_fb` -is only assigned once per frame. ---- - src/backends/native/meta-onscreen-native.c | 193 +++++++++------------ - 1 file changed, 86 insertions(+), 107 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 3eb5503193..c41735d90b 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -67,8 +67,6 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState - - struct { - struct gbm_surface *surface; -- MetaDrmBuffer *current_fb; -- MetaDrmBuffer *next_fb; - } gbm; - - struct { -@@ -117,41 +115,12 @@ init_secondary_gpu_state (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, - GError **error); - --static void --swap_secondary_drm_fb (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -- -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- if (!secondary_gpu_state) -- return; -- -- g_set_object (&secondary_gpu_state->gbm.current_fb, -- secondary_gpu_state->gbm.next_fb); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); --} -- --static void --free_current_secondary_bo (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -- -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- if (!secondary_gpu_state) -- return; -- -- g_clear_object (&secondary_gpu_state->gbm.current_fb); --} -- - static void - free_current_bo (CoglOnscreen *onscreen) - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - - g_clear_object (&onscreen_native->gbm.current_fb); -- free_current_secondary_bo (onscreen); - } - - static void -@@ -166,8 +135,6 @@ meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen) - - g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb); - g_clear_object (&onscreen_native->gbm.next_fb); -- -- swap_secondary_drm_fb (onscreen); - } - - static void -@@ -436,7 +403,6 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - MetaKmsDevice *kms_device; - MetaKms *kms; - MetaKmsUpdate *kms_update; -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL; - MetaDrmBuffer *buffer; - MetaKmsPlaneAssignment *plane_assignment; - -@@ -455,15 +421,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- if (gpu_kms == render_gpu) -- { -- buffer = onscreen_native->gbm.next_fb; -- } -- else -- { -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- buffer = secondary_gpu_state->gbm.next_fb; -- } -+ buffer = onscreen_native->gbm.next_fb; - - plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms, - buffer, -@@ -566,8 +524,6 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta - NULL); - } - -- g_clear_object (&secondary_gpu_state->gbm.current_fb); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); - g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy); - - secondary_gpu_release_dumb (secondary_gpu_state); -@@ -575,11 +531,11 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta - g_free (secondary_gpu_state); - } - --static gboolean -+static MetaDrmBuffer * - import_shared_framebuffer (CoglOnscreen *onscreen, -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) -+ MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, -+ MetaDrmBuffer *primary_gpu_fb) - { -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRenderDevice *render_device; - g_autoptr (GError) error = NULL; - MetaDrmBuffer *imported_buffer; -@@ -587,7 +543,7 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - render_device = secondary_gpu_state->renderer_gpu_data->render_device; - imported_buffer = - meta_render_device_import_dma_buf (render_device, -- onscreen_native->gbm.next_fb, -+ primary_gpu_fb, - &error); - if (!imported_buffer) - { -@@ -601,16 +557,9 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE); - secondary_gpu_state->import_status = - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED; -- return FALSE; -+ return NULL; - } - -- /* -- * next_fb may already contain a fallback buffer, so clear it only -- * when we are sure to succeed. -- */ -- g_clear_object (&secondary_gpu_state->gbm.next_fb); -- secondary_gpu_state->gbm.next_fb = imported_buffer; -- - if (secondary_gpu_state->import_status == - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE) - { -@@ -627,16 +576,16 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - - secondary_gpu_state->import_status = - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK; -- return TRUE; -+ return imported_buffer; - } - --static void -+static MetaDrmBuffer * - copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - MetaRendererNativeGpuData *renderer_gpu_data, -- gboolean *egl_context_changed) -+ gboolean *egl_context_changed, -+ MetaDrmBuffer *primary_gpu_fb) - { -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; - MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); - MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native); -@@ -652,9 +601,6 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu, - "FB Copy (secondary GPU)"); - -- g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); -- - render_device = renderer_gpu_data->render_device; - egl_display = meta_render_device_get_egl_display (render_device); - -@@ -667,13 +613,13 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to make current: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - *egl_context_changed = TRUE; - - -- buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb); -+ buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb); - bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); - if (!meta_renderer_native_gles3_blit_shared_bo (egl, - gles3, -@@ -685,7 +631,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to blit shared framebuffer: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - if (!meta_egl_swap_buffers (egl, -@@ -695,7 +641,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to swap buffers: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - use_modifiers = meta_renderer_native_use_modifiers (renderer_native); -@@ -715,10 +661,10 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", - error->message); - g_error_free (error); -- return; -+ return NULL; - } - -- secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm); -+ return META_DRM_BUFFER (buffer_gbm); - } - - static MetaDrmBufferDumb * -@@ -733,7 +679,7 @@ secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *seconda - return secondary_gpu_state->cpu.dumb_fbs[0]; - } - --static gboolean -+static MetaDrmBuffer * - copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - const int *rectangles, -@@ -761,7 +707,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - primary_gpu_data = - meta_renderer_native_get_gpu_data (renderer_native, primary_gpu); - if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers) -- return FALSE; -+ return NULL; - - buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state); - buffer = META_DRM_BUFFER (buffer_dumb); -@@ -784,7 +730,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - { - meta_topic (META_DEBUG_KMS, - "Failed to create DMA buffer: %s", error->message); -- return FALSE; -+ return NULL; - } - - dmabuf_fb = -@@ -802,7 +748,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - meta_topic (META_DEBUG_KMS, - "Failed to create DMA buffer for blitting: %s", - error->message); -- return FALSE; -+ return NULL; - } - /* Limit the number of individual copies to 16 */ - #define MAX_RECTS 16 -@@ -815,7 +761,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - &error)) - { - g_object_unref (dmabuf_fb); -- return FALSE; -+ return NULL; - } - } - else -@@ -832,20 +778,19 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - &error)) - { - g_object_unref (dmabuf_fb); -- return FALSE; -+ return NULL; - } - } - } - - g_object_unref (dmabuf_fb); - -- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer); - secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb; - -- return TRUE; -+ return g_object_ref (buffer); - } - --static void -+static MetaDrmBuffer * - copy_shared_framebuffer_cpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - MetaRendererNativeGpuData *renderer_gpu_data) -@@ -897,17 +842,19 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen, - - cogl_object_unref (dumb_bitmap); - -- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer); - secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb; -+ -+ return g_object_ref (buffer); - } - --static void -+static MetaDrmBuffer * - update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - const int *rectangles, - int n_rectangles) - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -+ MetaDrmBuffer *copy = NULL; - - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers, - "Onscreen (secondary gpu pre-swap-buffers)"); -@@ -933,10 +880,11 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - /* prepare fallback */ - G_GNUC_FALLTHROUGH; - case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: -- if (!copy_shared_framebuffer_primary_gpu (onscreen, -- secondary_gpu_state, -- rectangles, -- n_rectangles)) -+ copy = copy_shared_framebuffer_primary_gpu (onscreen, -+ secondary_gpu_state, -+ rectangles, -+ n_rectangles); -+ if (!copy) - { - if (!secondary_gpu_state->noted_primary_gpu_copy_failed) - { -@@ -946,9 +894,9 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE; - } - -- copy_shared_framebuffer_cpu (onscreen, -- secondary_gpu_state, -- renderer_gpu_data); -+ copy = copy_shared_framebuffer_cpu (onscreen, -+ secondary_gpu_state, -+ renderer_gpu_data); - } - else if (!secondary_gpu_state->noted_primary_gpu_copy_ok) - { -@@ -960,11 +908,15 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - break; - } - } -+ -+ return copy; - } - - static void --update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, -- gboolean *egl_context_changed) -+update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, -+ gboolean *egl_context_changed, -+ MetaDrmBuffer *primary_gpu_fb, -+ MetaDrmBuffer **secondary_gpu_fb) - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRendererNative *renderer_native = onscreen_native->renderer_native; -@@ -977,6 +929,7 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, - if (secondary_gpu_state) - { - MetaRendererNativeGpuData *renderer_gpu_data; -+ g_autoptr (MetaDrmBuffer) next_fb = NULL; - - renderer_gpu_data = - meta_renderer_native_get_gpu_data (renderer_native, -@@ -984,23 +937,30 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, - switch (renderer_gpu_data->secondary.copy_mode) - { - case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO: -- if (import_shared_framebuffer (onscreen, secondary_gpu_state)) -+ next_fb = import_shared_framebuffer (onscreen, -+ secondary_gpu_state, -+ primary_gpu_fb); -+ if (next_fb) - break; -- -- /* The fallback was prepared in pre_swap_buffers */ -+ /* The fallback was prepared in pre_swap_buffers and is currently -+ * in secondary_gpu_fb. -+ */ - renderer_gpu_data->secondary.copy_mode = - META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY; - G_GNUC_FALLTHROUGH; - case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: -- /* Done before eglSwapBuffers. */ -+ next_fb = g_object_ref (*secondary_gpu_fb); - break; - case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU: -- copy_shared_framebuffer_gpu (onscreen, -- secondary_gpu_state, -- renderer_gpu_data, -- egl_context_changed); -+ next_fb = copy_shared_framebuffer_gpu (onscreen, -+ secondary_gpu_state, -+ renderer_gpu_data, -+ egl_context_changed, -+ primary_gpu_fb); - break; - } -+ -+ g_set_object (secondary_gpu_fb, next_fb); - } - } - -@@ -1050,6 +1010,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - g_autoptr (GError) error = NULL; - MetaDrmBufferFlags buffer_flags; - MetaDrmBufferGbm *buffer_gbm; -+ g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL; -+ g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL; - MetaKmsCrtc *kms_crtc; - MetaKmsDevice *kms_device; - MetaKmsUpdateFlag flags; -@@ -1059,9 +1021,10 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, - "Onscreen (swap-buffers)"); - -- update_secondary_gpu_state_pre_swap_buffers (onscreen, -- rectangles, -- n_rectangles); -+ secondary_gpu_fb = -+ update_secondary_gpu_state_pre_swap_buffers (onscreen, -+ rectangles, -+ n_rectangles); - - parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class); - parent_class->swap_buffers_with_damage (onscreen, -@@ -1077,9 +1040,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); -- g_clear_object (&onscreen_native->gbm.next_fb); -- - buffer_flags = META_DRM_BUFFER_FLAG_NONE; - if (!meta_renderer_native_use_modifiers (renderer_native)) - buffer_flags |= META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS; -@@ -1097,8 +1057,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - return; - } - -- onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm); -- -+ primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm)); - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - g_assert_not_reached (); -@@ -1109,7 +1068,27 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - #endif - } - -- update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); -+ update_secondary_gpu_state_post_swap_buffers (onscreen, -+ &egl_context_changed, -+ primary_gpu_fb, -+ &secondary_gpu_fb); -+ -+ switch (renderer_gpu_data->mode) -+ { -+ case META_RENDERER_NATIVE_MODE_GBM: -+ g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); -+ if (onscreen_native->secondary_gpu_state) -+ g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb); -+ else -+ g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb); -+ break; -+ case META_RENDERER_NATIVE_MODE_SURFACELESS: -+ break; -+#ifdef HAVE_EGL_DEVICE -+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE: -+ break; -+#endif -+ } - - /* - * If we changed EGL context, cogl will have the wrong idea about what is --- -GitLab - - -From 0c766c2cd903fc084dd186b4a30053ac3ca054d6 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 19 Jan 2022 18:43:15 +0800 -Subject: [PATCH 02/44] onscreen/native: Hold primary GPU FBs for the secondary - scanout lifetime - -This is out of an abundance of caution. In cases where we have copied the -primary GPU's buffer to a dumb buffer for secondary GPU (DisplayLink) -scanout, we don't really know how long OpenGL will take to complete that -copy in the background. And there is no swap buffers or locking of the -secondary GPU front buffer to guarantee when. - -So to avoid needing `glFinish` or similar we now reference the original -source FB for the scanout lifetime of the secondary (dumb) buffer. This -is effectively identical to the pre-!2087 behaviour. - -Although it's not theoretically optimal because the primary GPU FB is -not needed after scanout starts (`next_fb` is moved to `current_fb`), -this approach does give us the simplicity of only having to track the -lifetime of a single buffer after it is flipped. ---- - src/backends/native/meta-onscreen-native.c | 64 +++++++++++++++++++++- - 1 file changed, 61 insertions(+), 3 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index c41735d90b..55dbcfef7b 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -72,6 +72,7 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState - struct { - MetaDrmBufferDumb *current_dumb_fb; - MetaDrmBufferDumb *dumb_fbs[2]; -+ MetaDrmBuffer *source_fbs[2]; - } cpu; - - gboolean noted_primary_gpu_copy_ok; -@@ -493,13 +494,41 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, - kms_update); - } - -+static void -+hold_primary_gpu_fb_for_secondary_gpu_scanout (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, -+ MetaDrmBuffer *primary_gpu_fb, -+ MetaDrmBuffer *secondary_gpu_fb) -+{ -+ if (META_IS_DRM_BUFFER_DUMB (secondary_gpu_fb)) -+ { -+ MetaDrmBufferDumb *dumb_fb = META_DRM_BUFFER_DUMB (secondary_gpu_fb); -+ int i; -+ const int n = G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); -+ -+ for (i = 0; i < n; i++) -+ { -+ if (dumb_fb == secondary_gpu_state->cpu.dumb_fbs[i]) -+ { -+ g_set_object (&secondary_gpu_state->cpu.source_fbs[i], -+ primary_gpu_fb); -+ break; -+ } -+ } -+ -+ g_warn_if_fail (i < n); -+ } -+} -+ - static void - secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) - { - unsigned i; - - for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++) -- g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]); -+ { -+ g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]); -+ g_clear_object (&secondary_gpu_state->cpu.source_fbs[i]); -+ } - } - - static void -@@ -1078,9 +1107,17 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - case META_RENDERER_NATIVE_MODE_GBM: - g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); - if (onscreen_native->secondary_gpu_state) -- g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb); -+ { -+ g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb); -+ hold_primary_gpu_fb_for_secondary_gpu_scanout ( -+ onscreen_native->secondary_gpu_state, -+ primary_gpu_fb, -+ secondary_gpu_fb); -+ } - else -- g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb); -+ { -+ g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb); -+ } - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - break; -@@ -1960,6 +1997,21 @@ pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen) - return DRM_FORMAT_INVALID; - } - -+static void -+dumb_toggle_notify (gpointer data, -+ GObject *object, -+ gboolean is_last_ref) -+{ -+ MetaDrmBuffer **source_fb = data; -+ -+ g_return_if_fail (source_fb != NULL); -+ if (is_last_ref && *source_fb) -+ { -+ g_return_if_fail (META_IS_DRM_BUFFER (*source_fb)); -+ g_clear_object (source_fb); -+ } -+} -+ - static gboolean - init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, -@@ -2016,6 +2068,12 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_nat - } - - secondary_gpu_state->cpu.dumb_fbs[i] = META_DRM_BUFFER_DUMB (dumb_buffer); -+ g_object_add_toggle_ref (G_OBJECT (dumb_buffer), -+ dumb_toggle_notify, -+ &secondary_gpu_state->cpu.source_fbs[i]); -+ -+ /* It was incremented higher than we need by add_toggle_ref */ -+ g_object_unref (dumb_buffer); - } - - /* --- -GitLab - - -From 0a839e19f861390be42f10dc184f187bb163c8e2 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Mon, 16 Aug 2021 17:06:43 +0800 -Subject: [PATCH 03/44] kms/update: Hold a reference to the buffer used in a - plane assignment - ---- - src/backends/native/meta-kms-update.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c -index 53fc92eb86..2889338ec5 100644 ---- a/src/backends/native/meta-kms-update.c -+++ b/src/backends/native/meta-kms-update.c -@@ -149,6 +149,7 @@ static void - meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment) - { - g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free); -+ g_clear_object (&plane_assignment->buffer); - g_free (plane_assignment); - } - -@@ -228,7 +229,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, - .update = update, - .crtc = crtc, - .plane = plane, -- .buffer = buffer, -+ .buffer = g_object_ref (buffer), - .src_rect = src_rect, - .dst_rect = dst_rect, - .flags = flags, --- -GitLab - - -From 4a47a2221ef11c8e88d652860c189565536b7422 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Mon, 16 Aug 2021 18:04:10 +0800 -Subject: [PATCH 04/44] kms/crtc: Add an API to hold references to buffers - while asssigned to planes - ---- - src/backends/native/meta-kms-crtc.c | 80 +++++++++++++++++++++++++++++ - src/backends/native/meta-kms-crtc.h | 9 ++++ - 2 files changed, 89 insertions(+) - -diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c -index 685a3737ca..45c7eb78ee 100644 ---- a/src/backends/native/meta-kms-crtc.c -+++ b/src/backends/native/meta-kms-crtc.c -@@ -32,6 +32,12 @@ typedef struct _MetaKmsCrtcPropTable - MetaKmsProp props[META_KMS_CRTC_N_PROPS]; - } MetaKmsCrtcPropTable; - -+typedef struct -+{ -+ MetaDrmBuffer *front, *back; -+ gboolean back_is_set; -+} PlaneState; -+ - struct _MetaKmsCrtc - { - GObject parent; -@@ -44,6 +50,8 @@ struct _MetaKmsCrtc - MetaKmsCrtcState current_state; - - MetaKmsCrtcPropTable prop_table; -+ -+ GHashTable *plane_states; - }; - - G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) -@@ -441,20 +449,91 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device, - return crtc; - } - -+void -+meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc, -+ uint32_t plane_id, -+ MetaDrmBuffer *buffer) -+{ -+ gpointer key = GUINT_TO_POINTER (plane_id); -+ PlaneState *plane_state; -+ -+ plane_state = g_hash_table_lookup (crtc->plane_states, key); -+ if (plane_state == NULL) -+ { -+ plane_state = g_new0 (PlaneState, 1); -+ g_hash_table_insert (crtc->plane_states, key, plane_state); -+ } -+ -+ plane_state->back_is_set = TRUE; /* note buffer may be NULL */ -+ g_set_object (&plane_state->back, buffer); -+} -+ -+static void -+swap_plane_buffers (gpointer key, -+ gpointer value, -+ gpointer user_data) -+{ -+ PlaneState *plane_state = value; -+ -+ if (plane_state->back_is_set) -+ { -+ g_set_object (&plane_state->front, plane_state->back); -+ g_clear_object (&plane_state->back); -+ plane_state->back_is_set = FALSE; -+ } -+} -+ -+void -+meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc) -+{ -+ g_hash_table_foreach (crtc->plane_states, swap_plane_buffers, NULL); -+} -+ -+void -+meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc) -+{ -+ g_hash_table_remove_all (crtc->plane_states); -+} -+ -+static void -+meta_kms_crtc_dispose (GObject *object) -+{ -+ MetaKmsCrtc *crtc = META_KMS_CRTC (object); -+ -+ meta_kms_crtc_release_buffers (crtc); -+ -+ G_OBJECT_CLASS (meta_kms_crtc_parent_class)->dispose (object); -+} -+ - static void - meta_kms_crtc_finalize (GObject *object) - { - MetaKmsCrtc *crtc = META_KMS_CRTC (object); - - clear_gamma_state (&crtc->current_state); -+ g_hash_table_unref (crtc->plane_states); - - G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object); - } - -+static void -+destroy_plane_state (gpointer data) -+{ -+ PlaneState *plane_state = data; -+ -+ g_clear_object (&plane_state->front); -+ g_clear_object (&plane_state->back); -+ g_free (plane_state); -+} -+ - static void - meta_kms_crtc_init (MetaKmsCrtc *crtc) - { - crtc->current_state.gamma.size = 0; -+ crtc->plane_states = g_hash_table_new_full (NULL, -+ NULL, -+ NULL, -+ destroy_plane_state); - } - - static void -@@ -462,5 +541,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - -+ object_class->dispose = meta_kms_crtc_dispose; - object_class->finalize = meta_kms_crtc_finalize; - } -diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h -index 218bec9a15..29fdfcb5dd 100644 ---- a/src/backends/native/meta-kms-crtc.h -+++ b/src/backends/native/meta-kms-crtc.h -@@ -25,6 +25,7 @@ - #include - - #include "backends/native/meta-kms-types.h" -+#include "backends/native/meta-drm-buffer.h" - #include "core/util-private.h" - #include "meta/boxes.h" - -@@ -82,4 +83,12 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc, - const uint16_t *green, - const uint16_t *blue); - -+void meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc, -+ uint32_t plane_id, -+ MetaDrmBuffer *buffer); -+ -+void meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc); -+ -+void meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc); -+ - #endif /* META_KMS_CRTC_H */ --- -GitLab - - -From f9c6c62942cd3f7a849338b1b325f15d47619d7f Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 17 Aug 2021 16:35:18 +0800 -Subject: [PATCH 05/44] kms/page-flip: Pump the CRTC's buffer reference queue - on scanout - -Precise timing of this call is not important. We only need to notify -that the *previous* scanout is definitely no longer happening. So any -old buffers no longer used in the latest scanout can be released. ---- - src/backends/native/meta-kms-page-flip.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c -index 817f4e7c8d..148d237400 100644 ---- a/src/backends/native/meta-kms-page-flip.c -+++ b/src/backends/native/meta-kms-page-flip.c -@@ -24,6 +24,7 @@ - #include "backends/native/meta-kms-impl.h" - #include "backends/native/meta-kms-private.h" - #include "backends/native/meta-kms-update.h" -+#include "backends/native/meta-kms-crtc.h" - - typedef struct _MetaKmsPageFlipClosure - { -@@ -149,6 +150,8 @@ meta_kms_page_flip_data_flipped (MetaKms *kms, - - meta_assert_not_in_kms_impl (kms); - -+ meta_kms_crtc_on_scanout_started (page_flip_data->crtc); -+ - for (l = page_flip_data->closures; l; l = l->next) - { - MetaKmsPageFlipClosure *closure = l->data; --- -GitLab - - -From 10f25bb169e66ca36c63be37aa859514295adc1b Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 9 Feb 2022 16:44:09 +0800 -Subject: [PATCH 06/44] kms/impl-device: Release buffers from MetaKmsCrtc in - prepare_shutdown - -This allows them to release their buffers cleanly while all the -associated resources to do the release still exist. Otherwise we -might crash later in meta_drm_buffer_finalize. ---- - src/backends/native/meta-kms-impl-device.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c -index b05bf5fdab..1177707fae 100644 ---- a/src/backends/native/meta-kms-impl-device.c -+++ b/src/backends/native/meta-kms-impl-device.c -@@ -1022,8 +1022,12 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, - void - meta_kms_impl_device_prepare_shutdown (MetaKmsImplDevice *impl_device) - { -+ MetaKmsImplDevicePrivate *priv = -+ meta_kms_impl_device_get_instance_private (impl_device); - MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); - -+ g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_release_buffers, NULL); -+ - if (klass->prepare_shutdown) - klass->prepare_shutdown (impl_device); - --- -GitLab - - -From 5337749757f0873603c05ef7d361e15007d256e5 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Dec 2021 18:31:16 +0800 -Subject: [PATCH 07/44] kms/impl-device/simple: Pump the CRTC's buffer - reference queue on scanout - -In this case "on scanout" means when `drmModeSetCrtc` succeeds. This is -the only case where there won't be a `meta_kms_page_flip_data_flipped` to -do it for us. ---- - src/backends/native/meta-kms-impl-device-simple.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c -index 882cd97cc9..6f9dfee7ea 100644 ---- a/src/backends/native/meta-kms-impl-device-simple.c -+++ b/src/backends/native/meta-kms-impl-device-simple.c -@@ -470,6 +470,8 @@ process_mode_set (MetaKmsImplDevice *impl_device, - return FALSE; - } - -+ meta_kms_crtc_on_scanout_started (crtc); -+ - if (drm_mode) - { - g_hash_table_replace (impl_device_simple->cached_mode_sets, -@@ -859,6 +861,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple, - return FALSE; - } - -+ meta_kms_crtc_on_scanout_started (crtc); -+ - if (!impl_device_simple->mode_set_fallback_feedback_source) - { - GSource *source; --- -GitLab - - -From 40b469b97e30923453c2293549efd86eb9ffa5eb Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 17 Aug 2021 17:40:57 +0800 -Subject: [PATCH 08/44] kms/impl-device/simple: Keep a reference to buffers - assigned to planes - -The MetaKmsCrtc will hold these references during future scanouts until -such time as a new buffer is assigned to the plane AND another scanout -has occurred after that. ---- - src/backends/native/meta-kms-impl-device-simple.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c -index 6f9dfee7ea..c1e2707537 100644 ---- a/src/backends/native/meta-kms-impl-device-simple.c -+++ b/src/backends/native/meta-kms-impl-device-simple.c -@@ -1294,7 +1294,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - { - case META_KMS_PLANE_TYPE_PRIMARY: - /* Handled as part of the mode-set and page flip. */ -- return TRUE; -+ goto assigned; - case META_KMS_PLANE_TYPE_CURSOR: - if (!process_cursor_plane_assignment (impl_device, update, - plane_assignment, -@@ -1308,7 +1308,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - } - else - { -- return TRUE; -+ goto assigned; - } - case META_KMS_PLANE_TYPE_OVERLAY: - error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, -@@ -1321,6 +1321,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - } - - g_assert_not_reached (); -+ -+assigned: -+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ plane_assignment->buffer); -+ return TRUE; - } - - static gboolean --- -GitLab - - -From 2d8ac9727a89aac439c14d965a158f208571303e Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Dec 2021 17:54:15 +0800 -Subject: [PATCH 09/44] kms/impl-device/simple: Keep a reference to buffers - needed in retries - ---- - .../native/meta-kms-impl-device-simple.c | 24 ++++++++++++------- - 1 file changed, 15 insertions(+), 9 deletions(-) - -diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c -index c1e2707537..8aa78343a7 100644 ---- a/src/backends/native/meta-kms-impl-device-simple.c -+++ b/src/backends/native/meta-kms-impl-device-simple.c -@@ -536,7 +536,7 @@ is_timestamp_earlier_than (uint64_t ts1, - typedef struct _RetryPageFlipData - { - MetaKmsCrtc *crtc; -- uint32_t fb_id; -+ MetaDrmBuffer *fb; - MetaKmsPageFlipData *page_flip_data; - float refresh_rate; - uint64_t retry_time_us; -@@ -549,6 +549,7 @@ retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data) - g_assert (!retry_page_flip_data->page_flip_data); - g_clear_pointer (&retry_page_flip_data->custom_page_flip, - meta_kms_custom_page_flip_free); -+ g_clear_object (&retry_page_flip_data->fb); - g_free (retry_page_flip_data); - } - -@@ -616,16 +617,21 @@ retry_page_flips (gpointer user_data) - } - else - { -+ uint32_t fb_id = -+ retry_page_flip_data->fb ? -+ meta_drm_buffer_get_fb_id (retry_page_flip_data->fb) : -+ 0; -+ - meta_topic (META_DEBUG_KMS, - "[simple] Retrying page flip on CRTC %u (%s) with %u", - meta_kms_crtc_get_id (crtc), - meta_kms_impl_device_get_path (impl_device), -- retry_page_flip_data->fb_id); -+ fb_id); - - fd = meta_kms_impl_device_get_fd (impl_device); - ret = drmModePageFlip (fd, - meta_kms_crtc_get_id (crtc), -- retry_page_flip_data->fb_id, -+ fb_id, - DRM_MODE_PAGE_FLIP_EVENT, - retry_page_flip_data->page_flip_data); - } -@@ -712,7 +718,7 @@ retry_page_flips (gpointer user_data) - static void - schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple, - MetaKmsCrtc *crtc, -- uint32_t fb_id, -+ MetaDrmBuffer *fb, - float refresh_rate, - MetaKmsPageFlipData *page_flip_data, - MetaKmsCustomPageFlip *custom_page_flip) -@@ -727,7 +733,7 @@ schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple, - retry_page_flip_data = g_new0 (RetryPageFlipData, 1); - *retry_page_flip_data = (RetryPageFlipData) { - .crtc = crtc, -- .fb_id = fb_id, -+ .fb = fb ? g_object_ref (fb) : NULL, - .page_flip_data = page_flip_data, - .refresh_rate = refresh_rate, - .retry_time_us = retry_time_us, -@@ -987,20 +993,20 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device, - cached_mode_set = get_cached_mode_set (impl_device_simple, crtc); - if (cached_mode_set) - { -- uint32_t fb_id; -+ MetaDrmBuffer *fb; - drmModeModeInfo *drm_mode; - float refresh_rate; - - if (plane_assignment) -- fb_id = meta_drm_buffer_get_fb_id (plane_assignment->buffer); -+ fb = plane_assignment->buffer; - else -- fb_id = 0; -+ fb = NULL; - drm_mode = cached_mode_set->drm_mode; - refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode); - meta_kms_impl_device_hold_fd (impl_device); - schedule_retry_page_flip (impl_device_simple, - crtc, -- fb_id, -+ fb, - refresh_rate, - page_flip_data, - g_steal_pointer (&custom_page_flip)); --- -GitLab - - -From 84e908dc6707efd1befa1132d3264a8c28bec43f Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 17 Aug 2021 16:36:25 +0800 -Subject: [PATCH 10/44] kms/impl-device/atomic: Keep a reference to buffers - assigned to planes - -The MetaKmsCrtc will hold these references during future scanouts until -such time as a new buffer is assigned to the plane AND another scanout -has occurred after that. ---- - src/backends/native/meta-kms-impl-device-atomic.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c -index 73dd8e6971..787d05acda 100644 ---- a/src/backends/native/meta-kms-impl-device-atomic.c -+++ b/src/backends/native/meta-kms-impl-device-atomic.c -@@ -431,6 +431,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - { - MetaKmsPlaneAssignment *plane_assignment = update_entry; - MetaKmsPlane *plane = plane_assignment->plane; -+ MetaKmsUpdateFlag flags = (MetaKmsUpdateFlag) user_data; - MetaDrmBuffer *buffer; - MetaKmsFbDamage *fb_damage; - uint32_t prop_id; -@@ -586,6 +587,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - error)) - return FALSE; - } -+ -+ if (!(flags & META_KMS_UPDATE_FLAG_TEST_ONLY)) -+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ buffer); -+ - return TRUE; - } - -@@ -963,7 +970,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, - req, - blob_ids, - meta_kms_update_get_plane_assignments (update), -- NULL, -+ GUINT_TO_POINTER (flags), - process_plane_assignment, - &error)) - goto err; --- -GitLab - - -From 7891754a97fcb96f6d3b4103fd4d4482db10f70f Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 18 Aug 2021 15:04:27 +0800 -Subject: [PATCH 11/44] onscreen/native: Stop holding the current onscreen - buffer - -The scanout lifetime of the buffer is now automatically managed via -meta_crtc_kms_assign_primary_plane. Se we don't need `current_fb` at -all, and `next_fb` can be unreferenced as soon as we've passed it to -meta_crtc_kms_assign_primary_plane. ---- - src/backends/native/meta-onscreen-native.c | 34 +++------------------- - 1 file changed, 4 insertions(+), 30 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 55dbcfef7b..ac073901c4 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -93,7 +93,6 @@ struct _MetaOnscreenNative - - struct { - struct gbm_surface *surface; -- MetaDrmBuffer *current_fb; - MetaDrmBuffer *next_fb; - } gbm; - -@@ -116,28 +115,6 @@ init_secondary_gpu_state (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, - GError **error); - --static void --free_current_bo (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- -- g_clear_object (&onscreen_native->gbm.current_fb); --} -- --static void --meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- -- if (!onscreen_native->gbm.next_fb) -- return; -- -- free_current_bo (onscreen); -- -- g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb); -- g_clear_object (&onscreen_native->gbm.next_fb); --} -- - static void - maybe_update_frame_info (MetaCrtc *crtc, - CoglFrameInfo *frame_info, -@@ -202,7 +179,6 @@ notify_view_crtc_presented (MetaRendererView *view, - maybe_update_frame_info (crtc, frame_info, time_us, flags, sequence); - - meta_onscreen_native_notify_frame_complete (onscreen); -- meta_onscreen_native_swap_drm_fb (onscreen); - } - - static int64_t -@@ -313,7 +289,6 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - - meta_onscreen_native_notify_frame_complete (onscreen); -- meta_onscreen_native_swap_drm_fb (onscreen); - } - - static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = { -@@ -378,8 +353,9 @@ void - meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) - { - CoglFrameInfo *frame_info; -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - -- meta_onscreen_native_swap_drm_fb (onscreen); -+ g_clear_object (&onscreen_native->gbm.next_fb); - - frame_info = cogl_onscreen_peek_tail_frame_info (onscreen); - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; -@@ -404,7 +380,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - MetaKmsDevice *kms_device; - MetaKms *kms; - MetaKmsUpdate *kms_update; -- MetaDrmBuffer *buffer; -+ g_autoptr (MetaDrmBuffer) buffer = NULL; - MetaKmsPlaneAssignment *plane_assignment; - - COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs, -@@ -422,7 +398,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- buffer = onscreen_native->gbm.next_fb; -+ buffer = g_steal_pointer (&onscreen_native->gbm.next_fb); - - plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms, - buffer, -@@ -1374,7 +1350,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) - break; - -- g_clear_object (&onscreen_native->gbm.next_fb); - g_propagate_error (error, g_error_copy (feedback_error)); - return FALSE; - } -@@ -2174,7 +2149,6 @@ meta_onscreen_native_dispose (GObject *object) - { - case META_RENDERER_NATIVE_MODE_GBM: - g_clear_object (&onscreen_native->gbm.next_fb); -- free_current_bo (onscreen); - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - g_assert_not_reached (); --- -GitLab - - -From 210e53d132a3a494d70533c1a6c6b4839bd3661a Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 24 Sep 2021 21:49:45 +0800 -Subject: [PATCH 12/44] onscreen/native: Keep the onscreen alive longer than - `MetaDrmBufferGbm` - -Because `MetaDrmBufferGbm` uses `gbm_surface` in its destructor and -`gbm_surface` can't be refcounted directly. So we reference its owner -(the onscreen) instead. - -This avoids a crash that can otherwise occur when hotplugging monitors as -the old onscreen might get disposed before the new onscreen has presented -a replacement frame on the same `MetaKmsCrtc`. - -We could instead wrap and refcount all users of `gbm_surface`, but that -would be a lot more work for no additional benefit right now. ---- - src/backends/native/meta-onscreen-native.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index ac073901c4..8d36eb10c8 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1063,6 +1063,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - } - - primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm)); -+ -+ g_object_set_data_full (G_OBJECT (primary_gpu_fb), -+ "gbm_surface owner", -+ g_object_ref (onscreen), -+ (GDestroyNotify) g_object_unref); -+ - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - g_assert_not_reached (); --- -GitLab - - -From aa7b39fa8775db7c1bae839a38047bb816d572b0 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 18 Aug 2021 15:59:16 +0800 -Subject: [PATCH 13/44] cursor-renderer/native: Stop holding onto historical - cursor buffers - -Their scanout lifetimes are now managed automatically via the call -to meta_kms_update_assign_plane. ---- - .../native/meta-cursor-renderer-native.c | 83 ++++--------------- - 1 file changed, 14 insertions(+), 69 deletions(-) - -diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c -index df5862c4c0..b27afc8e6d 100644 ---- a/src/backends/native/meta-cursor-renderer-native.c -+++ b/src/backends/native/meta-cursor-renderer-native.c -@@ -64,19 +64,6 @@ - #define DRM_CAP_CURSOR_HEIGHT 0x9 - #endif - --/* When animating a cursor, we usually call drmModeSetCursor2 once per frame. -- * Though, testing shows that we need to triple buffer the cursor buffer in -- * order to avoid glitches when animating the cursor, at least when running on -- * Intel. The reason for this might be (but is not confirmed to be) due to -- * the user space gbm_bo cache, making us reuse and overwrite the kernel side -- * buffer content before it was scanned out. To avoid this, we keep a user space -- * reference to each buffer we set until at least one frame after it was drawn. -- * In effect, this means we three active cursor gbm_bo's: one that that just has -- * been set, one that was previously set and may or may not have been scanned -- * out, and one pending that will be replaced if the cursor sprite changes. -- */ --#define HW_CURSOR_BUFFER_COUNT 3 -- - static GQuark quark_cursor_sprite = 0; - - typedef struct _CrtcCursorData -@@ -120,9 +107,8 @@ typedef enum _MetaCursorBufferState - typedef struct _MetaCursorNativeGpuState - { - MetaGpu *gpu; -- unsigned int active_buffer_idx; - MetaCursorBufferState pending_buffer_state; -- MetaDrmBuffer *buffers[HW_CURSOR_BUFFER_COUNT]; -+ MetaDrmBuffer *buffer; - } MetaCursorNativeGpuState; - - typedef struct _MetaCursorNativePrivate -@@ -199,43 +185,17 @@ meta_cursor_renderer_native_finalize (GObject *object) - G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object); - } - --static unsigned int --get_pending_cursor_sprite_buffer_index (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- return (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT; --} -- --static MetaDrmBuffer * --get_pending_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- unsigned int pending_buffer_idx; -- -- pending_buffer_idx = -- get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- return cursor_gpu_state->buffers[pending_buffer_idx]; --} -- --static MetaDrmBuffer * --get_active_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- return cursor_gpu_state->buffers[cursor_gpu_state->active_buffer_idx]; --} -- - static void --set_pending_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, -- MetaGpuKms *gpu_kms, -- MetaDrmBuffer *buffer) -+set_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, -+ MetaGpuKms *gpu_kms, -+ MetaDrmBuffer *buffer) - { - MetaCursorNativePrivate *cursor_priv; - MetaCursorNativeGpuState *cursor_gpu_state; -- unsigned int pending_buffer_idx; - - cursor_priv = ensure_cursor_priv (cursor_sprite); - cursor_gpu_state = ensure_cursor_gpu_state (cursor_priv, gpu_kms); -- -- pending_buffer_idx = -- get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- cursor_gpu_state->buffers[pending_buffer_idx] = buffer; -+ cursor_gpu_state->buffer = buffer; - cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_SET; - } - -@@ -311,10 +271,7 @@ assign_cursor_plane (MetaCursorRendererNative *native, - MetaKmsUpdate *kms_update; - MetaKmsPlaneAssignment *plane_assignment; - -- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET) -- buffer = get_pending_cursor_sprite_buffer (cursor_gpu_state); -- else -- buffer = get_active_cursor_sprite_buffer (cursor_gpu_state); -+ buffer = cursor_gpu_state->buffer; - - kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - kms_device = meta_kms_crtc_get_device (kms_crtc); -@@ -365,13 +322,6 @@ assign_cursor_plane (MetaCursorRendererNative *native, - native); - - crtc_cursor_data->buffer = buffer; -- -- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET) -- { -- cursor_gpu_state->active_buffer_idx = -- (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT; -- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_NONE; -- } - } - - static float -@@ -602,7 +552,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, - switch (cursor_gpu_state->pending_buffer_state) - { - case META_CURSOR_BUFFER_STATE_NONE: -- return get_active_cursor_sprite_buffer (cursor_gpu_state) != NULL; -+ return cursor_gpu_state->buffer != NULL; - case META_CURSOR_BUFFER_STATE_SET: - return TRUE; - case META_CURSOR_BUFFER_STATE_INVALIDATED: -@@ -1115,16 +1065,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu, - static void - cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state) - { -- int i; - MetaDrmBuffer *active_buffer; - -- active_buffer = get_active_cursor_sprite_buffer (cursor_gpu_state); -+ active_buffer = cursor_gpu_state->buffer; - if (active_buffer) - unset_crtc_cursor_renderer_privates (cursor_gpu_state->gpu, - active_buffer); - -- for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++) -- g_clear_object (&cursor_gpu_state->buffers[i]); -+ g_clear_object (&cursor_gpu_state->buffer); - g_free (cursor_gpu_state); - } - -@@ -1162,10 +1110,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite) - g_hash_table_iter_init (&iter, cursor_priv->gpu_states); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state)) - { -- unsigned int pending_buffer_idx; -- -- pending_buffer_idx = get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- g_clear_object (&cursor_gpu_state->buffers[pending_buffer_idx]); -+ g_clear_object (&cursor_gpu_state->buffer); - cursor_gpu_state->pending_buffer_state = - META_CURSOR_BUFFER_STATE_INVALIDATED; - } -@@ -1306,8 +1251,8 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, - return; - } - -- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms, -- META_DRM_BUFFER (buffer_gbm)); -+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms, -+ META_DRM_BUFFER (buffer_gbm)); - } - else - { -@@ -1649,8 +1594,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, - return; - } - -- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms, -- META_DRM_BUFFER (buffer_gbm)); -+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms, -+ META_DRM_BUFFER (buffer_gbm)); - } - } - #endif --- -GitLab - - -From 00843efcc6f10befbefb34b2ce15a06071014212 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 18 Aug 2021 16:12:24 +0800 -Subject: [PATCH 14/44] cursor-renderer/native: Remove MetaCursorBufferState - -It was theoretically useful for flagging when a NULL buffer had been -SET, but in practice set_cursor_sprite_buffer is never called when the -buffer is NULL. So we can instead just compare the buffer with NULL to -tell when it is valid. ---- - .../native/meta-cursor-renderer-native.c | 61 ++----------------- - 1 file changed, 4 insertions(+), 57 deletions(-) - -diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c -index b27afc8e6d..998af173d3 100644 ---- a/src/backends/native/meta-cursor-renderer-native.c -+++ b/src/backends/native/meta-cursor-renderer-native.c -@@ -97,17 +97,9 @@ typedef struct _MetaCursorRendererNativeGpuData - uint64_t cursor_height; - } MetaCursorRendererNativeGpuData; - --typedef enum _MetaCursorBufferState --{ -- META_CURSOR_BUFFER_STATE_NONE, -- META_CURSOR_BUFFER_STATE_SET, -- META_CURSOR_BUFFER_STATE_INVALIDATED, --} MetaCursorBufferState; -- - typedef struct _MetaCursorNativeGpuState - { - MetaGpu *gpu; -- MetaCursorBufferState pending_buffer_state; - MetaDrmBuffer *buffer; - } MetaCursorNativeGpuState; - -@@ -196,7 +188,6 @@ set_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, - cursor_priv = ensure_cursor_priv (cursor_sprite); - cursor_gpu_state = ensure_cursor_gpu_state (cursor_priv, gpu_kms); - cursor_gpu_state->buffer = buffer; -- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_SET; - } - - static void -@@ -549,19 +540,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, - if (!cursor_gpu_state) - return FALSE; - -- switch (cursor_gpu_state->pending_buffer_state) -- { -- case META_CURSOR_BUFFER_STATE_NONE: -- return cursor_gpu_state->buffer != NULL; -- case META_CURSOR_BUFFER_STATE_SET: -- return TRUE; -- case META_CURSOR_BUFFER_STATE_INVALIDATED: -- return FALSE; -- } -- -- g_assert_not_reached (); -- -- return FALSE; -+ return cursor_gpu_state->buffer != NULL; - } - - static void -@@ -1109,11 +1088,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite) - - g_hash_table_iter_init (&iter, cursor_priv->gpu_states); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state)) -- { -- g_clear_object (&cursor_gpu_state->buffer); -- cursor_gpu_state->pending_buffer_state = -- META_CURSOR_BUFFER_STATE_INVALIDATED; -- } -+ g_clear_object (&cursor_gpu_state->buffer); - } - - static void -@@ -1260,34 +1235,6 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, - } - } - --static gboolean --is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite, -- MetaGpuKms *gpu_kms) --{ -- MetaCursorNativePrivate *cursor_priv; -- MetaCursorNativeGpuState *cursor_gpu_state; -- -- cursor_priv = get_cursor_priv (cursor_sprite); -- if (!cursor_priv) -- return FALSE; -- -- cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms); -- if (!cursor_gpu_state) -- return FALSE; -- -- switch (cursor_gpu_state->pending_buffer_state) -- { -- case META_CURSOR_BUFFER_STATE_SET: -- case META_CURSOR_BUFFER_STATE_NONE: -- return TRUE; -- case META_CURSOR_BUFFER_STATE_INVALIDATED: -- return FALSE; -- } -- -- g_assert_not_reached (); -- return FALSE; --} -- - static gboolean - is_cursor_scale_and_transform_valid (MetaCursorRenderer *renderer, - MetaCursorSprite *cursor_sprite) -@@ -1452,7 +1399,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, - if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken) - return; - -- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) && -+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) && - is_cursor_scale_and_transform_valid (renderer, cursor_sprite)) - return; - -@@ -1619,7 +1566,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer, - if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken) - return; - -- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) && -+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) && - is_cursor_scale_and_transform_valid (renderer, cursor_sprite)) - return; - --- -GitLab - - -From 4ee68afa39563ad62e4dfd4fc0ebdb3996cc6872 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 17 Sep 2021 17:48:20 +0800 -Subject: [PATCH 15/44] cogl/onscreen: Add function - cogl_onscreen_count_pending_frames - ---- - cogl/cogl/cogl-onscreen-private.h | 3 +++ - cogl/cogl/cogl-onscreen.c | 8 ++++++++ - 2 files changed, 11 insertions(+) - -diff --git a/cogl/cogl/cogl-onscreen-private.h b/cogl/cogl/cogl-onscreen-private.h -index dffe018d2e..e0215f750d 100644 ---- a/cogl/cogl/cogl-onscreen-private.h -+++ b/cogl/cogl/cogl-onscreen-private.h -@@ -97,4 +97,7 @@ cogl_onscreen_peek_tail_frame_info (CoglOnscreen *onscreen); - COGL_EXPORT CoglFrameInfo * - cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen); - -+COGL_EXPORT unsigned int -+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen); -+ - #endif /* __COGL_ONSCREEN_PRIVATE_H */ -diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c -index ff9e1749a7..b25b4af4ab 100644 ---- a/cogl/cogl/cogl-onscreen.c -+++ b/cogl/cogl/cogl-onscreen.c -@@ -510,6 +510,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen) - return g_queue_pop_head (&priv->pending_frame_infos); - } - -+unsigned int -+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen) -+{ -+ CoglOnscreenPrivate *priv = cogl_onscreen_get_instance_private (onscreen); -+ -+ return g_queue_get_length (&priv->pending_frame_infos); -+} -+ - CoglFrameClosure * - cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen, - CoglFrameCallback callback, --- -GitLab - - -From 4e3140f981374e88ede3ad25d4a14fb517786e63 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 26 Oct 2021 18:50:50 +0800 -Subject: [PATCH 16/44] renderer/native: Avoid requeuing the same onscreen for - a power save flip - -This is a case that triple buffering will encounter. We don't want it -to queue the same onscreen multiple times because that would represent -multiple flips occurring simultaneously. - -It's a linear search but the list length is typically only 1 or 2 so -no need for anything fancier yet. ---- - src/backends/native/meta-renderer-native.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c -index 41bf04d665..4e23121d1c 100644 ---- a/src/backends/native/meta-renderer-native.c -+++ b/src/backends/native/meta-renderer-native.c -@@ -678,6 +678,9 @@ meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_na - { - const unsigned int timeout_ms = 100; - -+ if (g_list_find (renderer_native->power_save_page_flip_onscreens, onscreen)) -+ return; -+ - if (!renderer_native->power_save_page_flip_source_id) - { - renderer_native->power_save_page_flip_source_id = --- -GitLab - - -From aa1039da9f0b5dbf87c42cbca8655025cb5bf693 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Mon, 1 Nov 2021 19:35:34 +0800 -Subject: [PATCH 17/44] renderer/native: Steal the power save flip list before - iterating over it - -Because a single iteration might also grow the list again. ---- - src/backends/native/meta-renderer-native.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c -index 4e23121d1c..a4ef05682d 100644 ---- a/src/backends/native/meta-renderer-native.c -+++ b/src/backends/native/meta-renderer-native.c -@@ -661,12 +661,18 @@ static gboolean - dummy_power_save_page_flip_cb (gpointer user_data) - { - MetaRendererNative *renderer_native = user_data; -+ GList *old_list = -+ g_steal_pointer (&renderer_native->power_save_page_flip_onscreens); - -- g_list_foreach (renderer_native->power_save_page_flip_onscreens, -+ g_list_foreach (old_list, - (GFunc) meta_onscreen_native_dummy_power_save_page_flip, - NULL); -- g_clear_list (&renderer_native->power_save_page_flip_onscreens, -+ g_clear_list (&old_list, - g_object_unref); -+ -+ if (renderer_native->power_save_page_flip_onscreens != NULL) -+ return G_SOURCE_CONTINUE; -+ - renderer_native->power_save_page_flip_source_id = 0; - - return G_SOURCE_REMOVE; --- -GitLab - - -From 9b1317cc05fc629192fe84a23b07f2652977136e Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 10 Dec 2021 16:40:58 +0800 -Subject: [PATCH 18/44] onscreen/native: Log swapbuffers and N-buffering when - MUTTER_DEBUG=kms - ---- - src/backends/native/meta-onscreen-native.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 8d36eb10c8..1a25156007 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1026,6 +1026,19 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, - "Onscreen (swap-buffers)"); - -+ if (meta_is_topic_enabled (META_DEBUG_KMS)) -+ { -+ unsigned int frames_pending = -+ cogl_onscreen_count_pending_frames (onscreen); -+ -+ meta_topic (META_DEBUG_KMS, -+ "Swap buffers: %u frames pending (%s-buffering)", -+ frames_pending, -+ frames_pending == 1 ? "double" : -+ frames_pending == 2 ? "triple" : -+ "?"); -+ } -+ - secondary_gpu_fb = - update_secondary_gpu_state_pre_swap_buffers (onscreen, - rectangles, --- -GitLab - - -From 7c0f2b01e54f4cfad3813e28e0a3bce5339ca755 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 28 Jul 2021 16:35:56 +0800 -Subject: [PATCH 19/44] onscreen/native: Replace an assertion that double - buffering is the maximum - -Because it soon won't be the maximum. But we do want to verify that the -frame info queue is not empty, to avoid NULL dereferencing and catch logic -errors. ---- - src/backends/native/meta-onscreen-native.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 1a25156007..6ff80d29c8 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -150,7 +150,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen) - - info = cogl_onscreen_pop_head_frame_info (onscreen); - -- g_assert (!cogl_onscreen_peek_head_frame_info (onscreen)); -+ g_assert (info); - - _cogl_onscreen_notify_frame_sync (onscreen, info); - _cogl_onscreen_notify_complete (onscreen, info); --- -GitLab - - -From ab849f90f3eb16715a279abdfc65697ea3f31654 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 16 Sep 2021 16:26:25 +0800 -Subject: [PATCH 20/44] onscreen/native: Deduplicate calls to - clutter_frame_set_result - -All paths out of `meta_onscreen_native_swap_buffers_with_damage` from -here onward would set the same `CLUTTER_FRAME_RESULT_PENDING_PRESENTED` -(or terminate with `g_assert_not_reached`). - -Even failed posts set this result because they will do a -`meta_onscreen_native_notify_frame_complete` in -`page_flip_feedback_discarded`. ---- - src/backends/native/meta-onscreen-native.c | 17 +++-------------- - 1 file changed, 3 insertions(+), 14 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 6ff80d29c8..ea13e60c90 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1122,6 +1122,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - #endif - } - -+ clutter_frame_set_result (frame, -+ CLUTTER_FRAME_RESULT_PENDING_PRESENTED); -+ - /* - * If we changed EGL context, cogl will have the wrong idea about what is - * current, making it fail to set it when it needs to. Avoid that by making -@@ -1146,8 +1149,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - { - meta_renderer_native_queue_power_save_page_flip (renderer_native, - onscreen); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - -@@ -1165,9 +1166,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - "Postponing primary plane composite update for CRTC %u (%s)", - meta_kms_crtc_get_id (kms_crtc), - meta_kms_device_get_path (kms_device)); -- -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - else if (meta_renderer_native_has_pending_mode_set (renderer_native)) -@@ -1177,8 +1175,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - - meta_renderer_native_notify_mode_sets_reset (renderer_native); - meta_renderer_native_post_mode_set_updates (renderer_native); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - break; -@@ -1191,8 +1187,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - { - meta_renderer_native_notify_mode_sets_reset (renderer_native); - meta_renderer_native_post_mode_set_updates (renderer_native); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - break; -@@ -1210,13 +1204,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - break; - case META_KMS_FEEDBACK_FAILED: -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); -- - feedback_error = meta_kms_feedback_get_error (kms_feedback); - if (!g_error_matches (feedback_error, - G_IO_ERROR, --- -GitLab - - -From 54a13dcb6e3f8a29752239573a8ee0a0fee14123 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 28 Jul 2021 16:29:27 +0800 -Subject: [PATCH 21/44] onscreen/native: Split swap_buffers_with_damage into - two functions - -1. The EGL part: meta_onscreen_native_swap_buffers_with_damage -2. The KMS part: post_latest_swap ---- - src/backends/native/meta-onscreen-native.c | 60 +++++++++++++++++----- - 1 file changed, 46 insertions(+), 14 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index ea13e60c90..1649a9383a 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -105,11 +105,19 @@ struct _MetaOnscreenNative - #endif - - MetaRendererView *view; -+ -+ struct { -+ int *rectangles; /* 4 x n_rectangles */ -+ int n_rectangles; -+ } next_post; - }; - - G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native, - COGL_TYPE_ONSCREEN_EGL) - -+static void -+post_latest_swap (CoglOnscreen *onscreen); -+ - static gboolean - init_secondary_gpu_state (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, -@@ -999,29 +1007,18 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; - MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; - MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; -- MetaRenderer *renderer = META_RENDERER (renderer_native); -- MetaBackend *backend = meta_renderer_get_backend (renderer); -- MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); -- MetaMonitorManager *monitor_manager = -- meta_backend_get_monitor_manager (backend); -- MetaKms *kms = meta_backend_native_get_kms (backend_native); - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaGpuKms *render_gpu = onscreen_native->render_gpu; - MetaDeviceFile *render_device_file; - ClutterFrame *frame = user_data; - CoglOnscreenClass *parent_class; - gboolean egl_context_changed = FALSE; -- MetaPowerSave power_save_mode; - g_autoptr (GError) error = NULL; - MetaDrmBufferFlags buffer_flags; - MetaDrmBufferGbm *buffer_gbm; - g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL; - g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL; -- MetaKmsCrtc *kms_crtc; -- MetaKmsDevice *kms_device; -- MetaKmsUpdateFlag flags; -- g_autoptr (MetaKmsFeedback) kms_feedback = NULL; -- const GError *feedback_error; -+ size_t rectangles_size; - - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, - "Onscreen (swap-buffers)"); -@@ -1134,6 +1131,39 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - if (egl_context_changed) - _cogl_winsys_egl_ensure_current (cogl_display); - -+ rectangles_size = n_rectangles * 4 * sizeof (int); -+ onscreen_native->next_post.rectangles = -+ g_realloc (onscreen_native->next_post.rectangles, rectangles_size); -+ memcpy (onscreen_native->next_post.rectangles, rectangles, rectangles_size); -+ onscreen_native->next_post.n_rectangles = n_rectangles; -+ -+ post_latest_swap (onscreen); -+} -+ -+static void -+post_latest_swap (CoglOnscreen *onscreen) -+{ -+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); -+ CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer); -+ CoglRenderer *cogl_renderer = cogl_context->display->renderer; -+ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; -+ MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; -+ MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; -+ MetaRenderer *renderer = META_RENDERER (renderer_native); -+ MetaBackend *backend = meta_renderer_get_backend (renderer); -+ MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); -+ MetaMonitorManager *monitor_manager = -+ meta_backend_get_monitor_manager (backend); -+ MetaKms *kms = meta_backend_native_get_kms (backend_native); -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -+ MetaPowerSave power_save_mode; -+ MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc); -+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); -+ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc); -+ MetaKmsUpdateFlag flags; -+ g_autoptr (MetaKmsFeedback) kms_feedback = NULL; -+ const GError *feedback_error; -+ - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - if (power_save_mode == META_POWER_SAVE_ON) - { -@@ -1142,8 +1172,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - onscreen_native->view, - onscreen_native->crtc, - META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, -- rectangles, -- n_rectangles); -+ onscreen_native->next_post.rectangles, -+ onscreen_native->next_post.n_rectangles); - } - else - { -@@ -2187,6 +2217,8 @@ meta_onscreen_native_dispose (GObject *object) - g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy); - g_clear_pointer (&onscreen_native->secondary_gpu_state, - secondary_gpu_state_free); -+ g_clear_pointer (&onscreen_native->next_post.rectangles, g_free); -+ onscreen_native->next_post.n_rectangles = 0; - } - - static void --- -GitLab - - -From 9621511d643cf361e877406866c9c6e0c227cd51 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 12 Aug 2021 18:28:57 +0800 -Subject: [PATCH 22/44] onscreen/native: Warn instead of crashing if posting - without an update - ---- - src/backends/native/meta-onscreen-native.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 1649a9383a..4fa354052c 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1230,6 +1230,7 @@ post_latest_swap (CoglOnscreen *onscreen) - - flags = META_KMS_UPDATE_FLAG_NONE; - kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags); -+ g_return_if_fail (kms_feedback != NULL); - - switch (meta_kms_feedback_get_result (kms_feedback)) - { --- -GitLab - - -From 6b22f7a3a2f36c3bdc1ccc5996810fcb21f6c75d Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 28 Oct 2021 17:24:11 +0800 -Subject: [PATCH 23/44] onscreen/native: Add a missing frame notification - -In the unlikely event that swap_buffers_with_damage drops the previous swap -it was forgetting to notify about the discarded frame. That could lead to -frame clock freezes. ---- - src/backends/native/meta-onscreen-native.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 4fa354052c..46e1672b53 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1098,6 +1098,15 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - { - case META_RENDERER_NATIVE_MODE_GBM: - g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); -+ if (onscreen_native->gbm.next_fb != NULL) -+ { -+ CoglFrameInfo *frame_info; -+ -+ frame_info = cogl_onscreen_peek_head_frame_info (onscreen); -+ frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; -+ meta_onscreen_native_notify_frame_complete (onscreen); -+ } -+ - if (onscreen_native->secondary_gpu_state) - { - g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb); --- -GitLab - - -From 86ac0c3a22246cac8be1a53f305d081d4d578555 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 17 Sep 2021 17:59:28 +0800 -Subject: [PATCH 24/44] onscreen/native: Defer posting if there's already a - post in progress - -And when the number of pending posts decreases we know it's safe to submit -a new one. Since KMS generally only supports one outstanding post right now, -"decreases" means equal to zero. ---- - src/backends/native/meta-onscreen-native.c | 83 ++++++++++++++++++---- - 1 file changed, 70 insertions(+), 13 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 46e1672b53..dc996001d7 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -94,6 +94,7 @@ struct _MetaOnscreenNative - struct { - struct gbm_surface *surface; - MetaDrmBuffer *next_fb; -+ MetaDrmBuffer *stalled_fb; - } gbm; - - #ifdef HAVE_EGL_DEVICE -@@ -106,6 +107,7 @@ struct _MetaOnscreenNative - - MetaRendererView *view; - -+ unsigned int swaps_pending; - struct { - int *rectangles; /* 4 x n_rectangles */ - int n_rectangles; -@@ -116,7 +118,7 @@ G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native, - COGL_TYPE_ONSCREEN_EGL) - - static void --post_latest_swap (CoglOnscreen *onscreen); -+try_post_latest_swap (CoglOnscreen *onscreen); - - static gboolean - init_secondary_gpu_state (MetaRendererNative *renderer_native, -@@ -187,6 +189,7 @@ notify_view_crtc_presented (MetaRendererView *view, - maybe_update_frame_info (crtc, frame_info, time_us, flags, sequence); - - meta_onscreen_native_notify_frame_complete (onscreen); -+ try_post_latest_swap (onscreen); - } - - static int64_t -@@ -248,6 +251,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc, - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - - meta_onscreen_native_notify_frame_complete (onscreen); -+ try_post_latest_swap (onscreen); - } - - static void -@@ -297,6 +301,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - - meta_onscreen_native_notify_frame_complete (onscreen); -+ try_post_latest_swap (onscreen); - } - - static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = { -@@ -357,19 +362,40 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data, - } - #endif /* HAVE_EGL_DEVICE */ - --void --meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) -+static void -+drop_stalled_swap (CoglOnscreen *onscreen) - { -- CoglFrameInfo *frame_info; - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -+ CoglFrameInfo *frame_info; -+ -+ /* Remember we can't compare stalled_fb because it's not used by -+ * META_RENDERER_NATIVE_MODE_EGL_DEVICE. So we judge stalled to be whenever -+ * swaps_pending > 1. -+ */ -+ if (onscreen_native->swaps_pending <= 1) -+ return; -+ -+ onscreen_native->swaps_pending--; - -- g_clear_object (&onscreen_native->gbm.next_fb); -+ g_clear_object (&onscreen_native->gbm.stalled_fb); - - frame_info = cogl_onscreen_peek_tail_frame_info (onscreen); - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - meta_onscreen_native_notify_frame_complete (onscreen); - } - -+void -+meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) -+{ -+ drop_stalled_swap (onscreen); -+ -+ /* If the monitor just woke up and the shell is fully idle (has nothing -+ * more to swap) then we just woke to an indefinitely black screen. Let's -+ * fix that using the last swap (which is never classified as "stalled"). -+ */ -+ try_post_latest_swap (onscreen); -+} -+ - static void - meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - MetaRendererView *view, -@@ -1097,14 +1123,13 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); - if (onscreen_native->gbm.next_fb != NULL) - { -- CoglFrameInfo *frame_info; -- -- frame_info = cogl_onscreen_peek_head_frame_info (onscreen); -- frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; -- meta_onscreen_native_notify_frame_complete (onscreen); -+ g_warn_if_fail (onscreen_native->gbm.stalled_fb == NULL); -+ drop_stalled_swap (onscreen); -+ g_assert (onscreen_native->gbm.stalled_fb == NULL); -+ onscreen_native->gbm.stalled_fb = -+ g_steal_pointer (&onscreen_native->gbm.next_fb); - } - - if (onscreen_native->secondary_gpu_state) -@@ -1146,11 +1171,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - memcpy (onscreen_native->next_post.rectangles, rectangles, rectangles_size); - onscreen_native->next_post.n_rectangles = n_rectangles; - -- post_latest_swap (onscreen); -+ onscreen_native->swaps_pending++; -+ try_post_latest_swap (onscreen); - } - - static void --post_latest_swap (CoglOnscreen *onscreen) -+try_post_latest_swap (CoglOnscreen *onscreen) - { - CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); - CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer); -@@ -1172,10 +1198,26 @@ post_latest_swap (CoglOnscreen *onscreen) - MetaKmsUpdateFlag flags; - g_autoptr (MetaKmsFeedback) kms_feedback = NULL; - const GError *feedback_error; -+ unsigned int frames_pending = cogl_onscreen_count_pending_frames (onscreen); -+ -+ if (onscreen_native->swaps_pending == 0) -+ return; -+ -+ g_assert (frames_pending >= onscreen_native->swaps_pending); - - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - if (power_save_mode == META_POWER_SAVE_ON) - { -+ unsigned int posts_pending; -+ -+ posts_pending = frames_pending - onscreen_native->swaps_pending; -+ if (posts_pending > 0) -+ return; /* wait for the next frame notification and then try again */ -+ -+ drop_stalled_swap (onscreen); -+ g_return_if_fail (onscreen_native->swaps_pending > 0); -+ onscreen_native->swaps_pending--; -+ - ensure_crtc_modes (onscreen); - meta_onscreen_native_flip_crtc (onscreen, - onscreen_native->view, -@@ -1332,6 +1374,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - return FALSE; - } - -+ /* Our direct scanout frame counts as 1, so more than that means we would -+ * be jumping the queue (and post would fail). -+ */ -+ if (cogl_onscreen_count_pending_frames (onscreen) > 1) -+ { -+ g_set_error_literal (error, -+ COGL_SCANOUT_ERROR, -+ COGL_SCANOUT_ERROR_INHIBITED, -+ "Direct scanout is inhibited during triple buffering"); -+ return FALSE; -+ } -+ - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); - -@@ -1433,6 +1487,9 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - g_autoptr (MetaKmsFeedback) kms_feedback = NULL; - const GError *error; - -+ if (cogl_onscreen_count_pending_frames (onscreen) > 0) -+ return; -+ - kms_update = meta_kms_get_pending_update (kms, kms_device); - if (!kms_update) - { --- -GitLab - - -From 73bbe3d6959e1ec49425127b6ed265665648bde3 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 2 Nov 2021 19:04:04 +0800 -Subject: [PATCH 25/44] onscreen/native: Keep a reference to the CRTC used - -Otherwise it may get destroyed during hotplug events. Meanwhile we're -still active and might try using it in the next/final frame notification -callbacks. ---- - src/backends/native/meta-onscreen-native.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index dc996001d7..86d191ee14 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -2233,7 +2233,7 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native, - onscreen_native->renderer_native = renderer_native; - onscreen_native->render_gpu = render_gpu; - onscreen_native->output = output; -- onscreen_native->crtc = crtc; -+ onscreen_native->crtc = g_object_ref (crtc); - - return onscreen_native; - } -@@ -2281,6 +2281,7 @@ meta_onscreen_native_dispose (GObject *object) - - G_OBJECT_CLASS (meta_onscreen_native_parent_class)->dispose (object); - -+ g_clear_object (&onscreen_native->crtc); - g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy); - g_clear_pointer (&onscreen_native->secondary_gpu_state, - secondary_gpu_state_free); --- -GitLab - - -From 1644e8ac2254e46f8e7de3495f9f2bb5662e4447 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 4 Nov 2021 16:09:26 +0800 -Subject: [PATCH 26/44] onscreen/native: Add function - meta_onscreen_native_discard_pending_swaps - ---- - src/backends/native/meta-onscreen-native.c | 11 +++++++++++ - src/backends/native/meta-onscreen-native.h | 2 ++ - 2 files changed, 13 insertions(+) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 86d191ee14..fb42ba7f4b 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -1529,6 +1529,17 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - } - } - -+void -+meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen) -+{ -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -+ -+ onscreen_native->swaps_pending = 0; -+ -+ g_clear_object (&onscreen_native->gbm.stalled_fb); -+ g_clear_object (&onscreen_native->gbm.next_fb); -+} -+ - static gboolean - should_surface_be_sharable (CoglOnscreen *onscreen) - { -diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h -index 3a85ace267..676c4c4459 100644 ---- a/src/backends/native/meta-onscreen-native.h -+++ b/src/backends/native/meta-onscreen-native.h -@@ -40,6 +40,8 @@ void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - - void meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen); - -+void meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen); -+ - gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, - MetaDrmBuffer *fb); - --- -GitLab - - -From eeb77174132bccdf585ffb01a8681a0e86579d2c Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 4 Nov 2021 16:09:52 +0800 -Subject: [PATCH 27/44] renderer/native: Discard pending swaps when rebuilding - views - -It's analogous to discard_pending_page_flips but represents swaps that -might become flips after the next frame notification callbacks, thanks -to triple buffering. Since the views are being rebuilt and their onscreens -are about to be destroyed, turning those swaps into more flips/posts would -just lead to unexpected behaviour (like trying to flip on a half-destroyed -inactive CRTC). ---- - src/backends/native/meta-renderer-native.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c -index a4ef05682d..58e6339a8c 100644 ---- a/src/backends/native/meta-renderer-native.c -+++ b/src/backends/native/meta-renderer-native.c -@@ -1395,6 +1395,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer, - return view; - } - -+static void -+discard_pending_swaps (MetaRenderer *renderer) -+{ -+ GList *views = meta_renderer_get_views (renderer);; -+ GList *l; -+ -+ for (l = views; l; l = l->next) -+ { -+ ClutterStageView *stage_view = l->data; -+ CoglFramebuffer *fb = clutter_stage_view_get_onscreen (stage_view); -+ CoglOnscreen *onscreen; -+ -+ if (!COGL_IS_ONSCREEN (fb)) -+ continue; -+ -+ onscreen = COGL_ONSCREEN (fb); -+ meta_onscreen_native_discard_pending_swaps (onscreen); -+ } -+} -+ - static void - keep_current_onscreens_alive (MetaRenderer *renderer) - { -@@ -1423,6 +1443,7 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer) - MetaRendererClass *parent_renderer_class = - META_RENDERER_CLASS (meta_renderer_native_parent_class); - -+ discard_pending_swaps (renderer); - meta_kms_discard_pending_page_flips (kms); - meta_kms_discard_pending_updates (kms); - --- -GitLab - - -From 5d93028632ebea30d2862f9415dfab97d58910a7 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 10 Aug 2021 17:46:49 +0800 -Subject: [PATCH 28/44] clutter/frame-clock: Lower the threshold for disabling - error diffusion - -Error diffusion was introduced in 0555a5bbc15 for Nvidia where last -presentation time is always unknown (zero). Dispatch times would drift -apart always being a fraction of a frame late, and accumulated to cause -periodic frame skips. So error diffusion corrected that precisely and -avoided the skips. - -That works great with double buffering but less great with triple -buffering. It's certainly still needed with triple buffering but -correcting for a lateness of many milliseconds isn't a good idea. That's -because a dispatch being that late is not due to main loop jitter but due -to Nvidia's swap buffers blocking when the queue is full. So scheduling -the next frame even earlier using last_dispatch_lateness_us would just -perpetuate the problem of swap buffers blocking for too long. - -So now we lower the threshold of when error diffusion gets disabled. It's -still high enough to fix the original smoothness problem it was for, but -now low enough to detect Nvidia's occasionally blocking swaps and backs -off in that case. - -Since the average duration of a blocking swap is half a frame interval -and we want to distinguish between that and sub-millisecond jitter, the -logical threshold is halfway again: refresh_interval_us/4. ---- - clutter/clutter/clutter-frame-clock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 6fa2b25887..bf6cf3ef4c 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -670,7 +670,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->refresh_interval_us; - - lateness_us = time_us - ideal_dispatch_time_us; -- if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us) -+ if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us / 4) - frame_clock->last_dispatch_lateness_us = 0; - else - frame_clock->last_dispatch_lateness_us = lateness_us; --- -GitLab - - -From e9f53325961918e8bc4522494ed99a98a1c9e5eb Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 24 Jul 2020 14:13:11 +0800 -Subject: [PATCH 29/44] clutter/frame-clock: Merge states DISPATCHING and - PENDING_PRESENTED - -Chronologically they already overlap in time as presentation may -complete in the middle of the dispatch function, otherwise they are -contiguous in time. And most switch statements treated the two states -the same already so they're easy to merge into a single `DISPATCHED` -state. - -Having fewer states now will make life easier when we add more states -later. ---- - clutter/clutter/clutter-frame-clock.c | 26 ++++++++++---------------- - 1 file changed, 10 insertions(+), 16 deletions(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index bf6cf3ef4c..26f2f681e5 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -65,8 +65,7 @@ typedef enum _ClutterFrameClockState - CLUTTER_FRAME_CLOCK_STATE_INIT, - CLUTTER_FRAME_CLOCK_STATE_IDLE, - CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, -- CLUTTER_FRAME_CLOCK_STATE_DISPATCHING, -- CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED, - } ClutterFrameClockState; - - struct _ClutterFrameClock -@@ -317,8 +316,7 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -@@ -337,8 +335,7 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -@@ -558,8 +555,7 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock) - frame_clock->pending_reschedule = TRUE; - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - break; - } - -@@ -598,8 +594,7 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - frame_clock->pending_reschedule = TRUE; - frame_clock->pending_reschedule_now = TRUE; - return; -@@ -637,8 +632,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - frame_clock->pending_reschedule = TRUE; - return; - } -@@ -678,7 +672,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->last_dispatch_time_us = time_us; - g_source_set_ready_time (frame_clock->source, -1); - -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING; -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED; - - frame_count = frame_clock->frame_count++; - -@@ -706,19 +700,19 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - switch (frame_clock->state) - { - case CLUTTER_FRAME_CLOCK_STATE_INIT: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: - g_warn_if_reached (); - break; - case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ /* Presentation completed synchronously in the above listener */ - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: - switch (result) - { - case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED; - break; - case CLUTTER_FRAME_RESULT_IDLE: -+ /* The frame was aborted; nothing to paint/present */ - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; --- -GitLab - - -From 856b06a53a6c74b5b7d7e2f52ae8c8f0072b03a5 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 10 Sep 2020 16:34:53 +0800 -Subject: [PATCH 30/44] clutter/frame-clock: Add triple buffering support - ---- - clutter/clutter/clutter-frame-clock.c | 101 ++++++++++++++++++++------ - 1 file changed, 80 insertions(+), 21 deletions(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 26f2f681e5..cacd4f6362 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -65,7 +65,9 @@ typedef enum _ClutterFrameClockState - CLUTTER_FRAME_CLOCK_STATE_INIT, - CLUTTER_FRAME_CLOCK_STATE_IDLE, - CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, -- CLUTTER_FRAME_CLOCK_STATE_DISPATCHED, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO, - } ClutterFrameClockState; - - struct _ClutterFrameClock -@@ -316,10 +318,18 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - } - -@@ -335,10 +345,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - } - -@@ -555,7 +573,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock) - frame_clock->pending_reschedule = TRUE; - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->pending_reschedule = TRUE; -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - break; - } - -@@ -591,10 +614,17 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_INIT: - case CLUTTER_FRAME_CLOCK_STATE_IDLE: - next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - frame_clock->pending_reschedule = TRUE; - frame_clock->pending_reschedule_now = TRUE; - return; -@@ -603,7 +633,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) - g_warn_if_fail (next_update_time_us != -1); - - g_source_set_ready_time (frame_clock->source, next_update_time_us); -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - frame_clock->is_next_presentation_time_valid = FALSE; - } - -@@ -622,6 +651,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - { - case CLUTTER_FRAME_CLOCK_STATE_INIT: - next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_IDLE: - calculate_next_update_time_us (frame_clock, -@@ -629,10 +659,20 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - &frame_clock->next_presentation_time_us); - frame_clock->is_next_presentation_time_valid = - (frame_clock->next_presentation_time_us != 0); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ calculate_next_update_time_us (frame_clock, -+ &next_update_time_us, -+ &frame_clock->next_presentation_time_us); -+ frame_clock->is_next_presentation_time_valid = -+ (frame_clock->next_presentation_time_us != 0); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - frame_clock->pending_reschedule = TRUE; - return; - } -@@ -640,7 +680,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - g_warn_if_fail (next_update_time_us != -1); - - g_source_set_ready_time (frame_clock->source, next_update_time_us); -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - } - - static void -@@ -672,7 +711,21 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->last_dispatch_time_us = time_us; - g_source_set_ready_time (frame_clock->source, -1); - -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED; -+ switch (frame_clock->state) -+ { -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ g_warn_if_reached (); -+ return; -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO; -+ break; -+ } - - frame_count = frame_clock->frame_count++; - -@@ -697,25 +750,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->listener.user_data); - COGL_TRACE_END (ClutterFrameClockFrame); - -- switch (frame_clock->state) -+ switch (result) - { -- case CLUTTER_FRAME_CLOCK_STATE_INIT: -- g_warn_if_reached (); -+ case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: - break; -- case CLUTTER_FRAME_CLOCK_STATE_IDLE: -- /* Presentation completed synchronously in the above listener */ -- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -- break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED: -- switch (result) -+ case CLUTTER_FRAME_RESULT_IDLE: -+ /* The frame was aborted; nothing to paint/present */ -+ switch (frame_clock->state) - { -- case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ g_warn_if_reached (); - break; -- case CLUTTER_FRAME_RESULT_IDLE: -- /* The frame was aborted; nothing to paint/present */ -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - break; - } --- -GitLab - - -From 171608c43d38761abc8933331a3750b72f7bf1f9 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 10 Dec 2021 16:28:04 +0800 -Subject: [PATCH 31/44] clutter/frame-clock: Log N-buffers in - CLUTTTER_DEBUG=frame-timings - ---- - clutter/clutter/clutter-frame-clock.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index cacd4f6362..e97c6f2ad4 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -229,6 +229,10 @@ void - clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - ClutterFrameInfo *frame_info) - { -+ const char *debug_state = -+ frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO ? -+ "Triple buffering" : "Double buffering"; -+ - COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented, - "Frame Clock (presented)"); - -@@ -290,7 +294,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - frame_info->cpu_time_before_buffer_swap_us; - - CLUTTER_NOTE (FRAME_TIMINGS, -- "dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs", -+ "%s: dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs", -+ debug_state, - dispatch_to_swap_us, - swap_to_rendering_done_us, - swap_to_flip_us); -@@ -304,6 +309,10 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - - frame_clock->got_measurements_last_frame = TRUE; - } -+ else -+ { -+ CLUTTER_NOTE (FRAME_TIMINGS, "%s", debug_state); -+ } - - if (frame_info->refresh_rate > 1) - { --- -GitLab - - -From 8dd2b170d40cf556ee4d7cdc5ff05b0ab653b85c Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Mon, 13 Dec 2021 17:03:44 +0800 -Subject: [PATCH 32/44] clutter/frame-clock: Don't clamp - compute_max_render_time_us - -Because values over refresh_interval_us are real and valid. They -tell us when we're not keeping up. ---- - clutter/clutter/clutter-frame-clock.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index e97c6f2ad4..ade6f2e4a5 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -415,8 +415,6 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - frame_clock->vblank_duration_us + - clutter_max_render_time_constant_us; - -- max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us); -- - return max_render_time_us; - } - --- -GitLab - - -From b9c6aaa146770ed47454db487dcac2e41323e17b Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 17 Feb 2022 15:54:57 +0800 -Subject: [PATCH 33/44] clutter/frame-clock: Subtract buffer queue latency from - max_swap_to_flip_us - -swap_to_flip times were getting stuck at over one frame interval -because of a positive feedback loop with triple buffering. - -The moment triple buffering started it would cause swap_to_flip times -to exceed one frame interval. Then that high value would feed back -through max_render_time which in turn ensured triple buffering -continued which ensured swap_to_flip stayed over one frame interval. -So even when actual GPU render times became low we were stuck with -a high value of max_render_time and stuck in triple buffering when we -should have switched to double buffering. - -By subtracting the constant buffer queue latency from max_swap_to_flip_us -we break this positive feedback loop and only include real performance -measurements. So now the frame clock is able to drop back to double -buffering when appropriate. ---- - clutter/clutter/clutter-frame-clock.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index ade6f2e4a5..cc4ac21c24 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -377,6 +377,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - int64_t max_swap_to_rendering_done_us = 0; - int64_t max_swap_to_flip_us = 0; - int64_t max_render_time_us; -+ int buffer_queue_latency_frames = 0; - int i; - - refresh_interval_us = frame_clock->refresh_interval_us; -@@ -399,6 +400,27 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - frame_clock->swap_to_flip_us.values[i]); - } - -+ switch (frame_clock->state) -+ { -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ buffer_queue_latency_frames = 0; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ buffer_queue_latency_frames = 1; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ g_warn_if_reached (); -+ buffer_queue_latency_frames = 2; -+ break; -+ } -+ -+ max_swap_to_flip_us -= refresh_interval_us * buffer_queue_latency_frames; -+ if (max_swap_to_flip_us < 0) -+ max_swap_to_flip_us = 0; -+ - /* Max render time shows how early the frame clock needs to be dispatched - * to make it to the predicted next presentation time. It is composed of: - * - An estimate of duration from dispatch start to buffer swap. --- -GitLab - - -From 4855f39c21b7e98c42df4c8e2573019c2573dc5a Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Sep 2021 19:08:15 +0800 -Subject: [PATCH 34/44] clutter/frame: Add ClutterFrameHint to ClutterFrame - -This will allow the backend to provide performance hints to the frame -clock in future. ---- - clutter/clutter/clutter-frame-clock.h | 6 ++++++ - clutter/clutter/clutter-frame-private.h | 1 + - clutter/clutter/clutter-frame.c | 13 +++++++++++++ - clutter/clutter/clutter-frame.h | 7 +++++++ - 4 files changed, 27 insertions(+) - -diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h -index 91e6b3a130..18c7676f4e 100644 ---- a/clutter/clutter/clutter-frame-clock.h -+++ b/clutter/clutter/clutter-frame-clock.h -@@ -34,6 +34,12 @@ typedef enum _ClutterFrameResult - CLUTTER_FRAME_RESULT_IDLE, - } ClutterFrameResult; - -+typedef enum _ClutterFrameHint -+{ -+ CLUTTER_FRAME_HINT_NONE = 0, -+ CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED = 1 << 0, -+} ClutterFrameHint; -+ - #define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ()) - CLUTTER_EXPORT - G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock, -diff --git a/clutter/clutter/clutter-frame-private.h b/clutter/clutter/clutter-frame-private.h -index e0088564fc..06581492f5 100644 ---- a/clutter/clutter/clutter-frame-private.h -+++ b/clutter/clutter/clutter-frame-private.h -@@ -24,6 +24,7 @@ struct _ClutterFrame - { - gboolean has_result; - ClutterFrameResult result; -+ ClutterFrameHint hints; - }; - - #define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 }) -diff --git a/clutter/clutter/clutter-frame.c b/clutter/clutter/clutter-frame.c -index 3c708da9dc..63ae302af7 100644 ---- a/clutter/clutter/clutter-frame.c -+++ b/clutter/clutter/clutter-frame.c -@@ -40,3 +40,16 @@ clutter_frame_set_result (ClutterFrame *frame, - frame->result = result; - frame->has_result = TRUE; - } -+ -+void -+clutter_frame_set_hint (ClutterFrame *frame, -+ ClutterFrameHint hint) -+{ -+ frame->hints |= hint; -+} -+ -+ClutterFrameHint -+clutter_frame_get_hints (ClutterFrame *frame) -+{ -+ return frame->hints; -+} -diff --git a/clutter/clutter/clutter-frame.h b/clutter/clutter/clutter-frame.h -index d3608e81ca..06c5f7f28a 100644 ---- a/clutter/clutter/clutter-frame.h -+++ b/clutter/clutter/clutter-frame.h -@@ -33,4 +33,11 @@ void clutter_frame_set_result (ClutterFrame *frame, - CLUTTER_EXPORT - gboolean clutter_frame_has_result (ClutterFrame *frame); - -+CLUTTER_EXPORT -+void clutter_frame_set_hint (ClutterFrame *frame, -+ ClutterFrameHint hint); -+ -+CLUTTER_EXPORT -+ClutterFrameHint clutter_frame_get_hints (ClutterFrame *frame); -+ - #endif /* CLUTTER_FRAME_H */ --- -GitLab - - -From 3bdb988fd0940922e53519f13486ae784f5131db Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Sep 2021 19:10:26 +0800 -Subject: [PATCH 35/44] backends: Flag that the frame attempted direct scanout - -We need this hint whether direct scanout succeeds or fails because it's -the mechanism by which we will tell the clock to enforce double buffering, -thus making direct scanout possible on future frames. Triple buffering -will be disabled until such time that direct scanout is not being attempted. ---- - src/backends/meta-stage-impl.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c -index c45aaf852e..683f4ff6c5 100644 ---- a/src/backends/meta-stage-impl.c -+++ b/src/backends/meta-stage-impl.c -@@ -720,6 +720,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window, - { - g_autoptr (GError) error = NULL; - -+ clutter_frame_set_hint (frame, CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED); -+ - if (meta_stage_impl_scanout_view (stage_impl, - stage_view, - scanout, --- -GitLab - - -From 97e6394f725c432ade1e824746a84f690227dbff Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Sep 2021 19:15:18 +0800 -Subject: [PATCH 36/44] clutter: Pass ClutterFrameHint(s) to the frame clock - ---- - clutter/clutter/clutter-frame-clock.c | 8 ++++++-- - clutter/clutter/clutter-frame-clock.h | 5 +++-- - clutter/clutter/clutter-stage-view.c | 5 +++-- - 3 files changed, 12 insertions(+), 6 deletions(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index cc4ac21c24..577f10ee71 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -97,6 +97,8 @@ struct _ClutterFrameClock - /* Last KMS buffer submission time. */ - int64_t last_flip_time_us; - -+ ClutterFrameHint last_flip_hints; -+ - /* Last few durations between dispatch start and buffer swap. */ - EstimateQueue dispatch_to_swap_us; - /* Last few durations between buffer swap and GPU rendering finish. */ -@@ -836,10 +838,12 @@ frame_clock_source_dispatch (GSource *source, - } - - void --clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock, -- int64_t flip_time_us) -+clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock, -+ int64_t flip_time_us, -+ ClutterFrameHint hints) - { - frame_clock->last_flip_time_us = flip_time_us; -+ frame_clock->last_flip_hints = hints; - } - - GString * -diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h -index 18c7676f4e..d750404d53 100644 ---- a/clutter/clutter/clutter-frame-clock.h -+++ b/clutter/clutter/clutter-frame-clock.h -@@ -96,8 +96,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock, - CLUTTER_EXPORT - float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock); - --void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock, -- int64_t flip_time_us); -+void clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock, -+ int64_t flip_time_us, -+ ClutterFrameHint hints); - - GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock); - -diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c -index 8a82de71ed..45d0093521 100644 ---- a/clutter/clutter/clutter-stage-view.c -+++ b/clutter/clutter/clutter-stage-view.c -@@ -1190,8 +1190,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock, - - _clutter_stage_window_redraw_view (stage_window, view, &frame); - -- clutter_frame_clock_record_flip_time (frame_clock, -- g_get_monotonic_time ()); -+ clutter_frame_clock_record_flip (frame_clock, -+ g_get_monotonic_time (), -+ clutter_frame_get_hints (&frame)); - - clutter_stage_emit_after_paint (stage, view); - --- -GitLab - - -From 9649fbb9cf95d8e0d044b48811ed753ccc25ae32 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Tue, 7 Sep 2021 19:15:55 +0800 -Subject: [PATCH 37/44] clutter/frame-clock: Throttle back to double buffering - for direct scanout - -There's no compositing during direct scanout so the "render" time is zero. -Thus there is no need to implement triple buffering for direct scanouts. -Stick to double buffering and enjoy the lower latency. ---- - clutter/clutter/clutter-frame-clock.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 577f10ee71..57176b3763 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -696,6 +696,13 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED) -+ { -+ /* Force double buffering, disable triple buffering */ -+ frame_clock->pending_reschedule = TRUE; -+ return; -+ } -+ - calculate_next_update_time_us (frame_clock, - &next_update_time_us, - &frame_clock->next_presentation_time_us); --- -GitLab - - -From e1d01f6cb3963a39e8c07e10f4e12e77b9762d18 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Thu, 10 Mar 2022 16:44:14 +0800 -Subject: [PATCH 38/44] clutter/frame-clock: Add env var - MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING - -You can set environment variable MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING=1 -to disable triple buffering. This shouldn't ever be needed except when -debugging. ---- - clutter/clutter/clutter-frame-clock.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 57176b3763..7a6444ec44 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -45,6 +45,8 @@ typedef struct _EstimateQueue - int next_index; - } EstimateQueue; - -+static gboolean triple_buffering_disabled = FALSE; -+ - #define SYNC_DELAY_FALLBACK_FRACTION 0.875 - - typedef struct _ClutterFrameListener -@@ -696,7 +698,8 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -- if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED) -+ if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED || -+ triple_buffering_disabled) - { - /* Force double buffering, disable triple buffering */ - frame_clock->pending_reschedule = TRUE; -@@ -981,6 +984,9 @@ clutter_frame_clock_class_init (ClutterFrameClockClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - -+ if (!g_strcmp0 (g_getenv ("MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING"), "1")) -+ triple_buffering_disabled = TRUE; -+ - object_class->dispose = clutter_frame_clock_dispose; - - signals[DESTROY] = --- -GitLab - - -From 1fe109cf7a96f8521bcef30910ac41007cd5d467 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 22 Sep 2021 17:01:42 +0800 -Subject: [PATCH 39/44] kms: Keep a hash table of CRTCs relating to the - KmsUpdate - -This will allow more efficient lookup than linear searching each of -the GLists. ---- - src/backends/native/meta-kms-update.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c -index 2889338ec5..5896d66dfe 100644 ---- a/src/backends/native/meta-kms-update.c -+++ b/src/backends/native/meta-kms-update.c -@@ -31,6 +31,7 @@ - struct _MetaKmsUpdate - { - MetaKmsDevice *device; -+ GHashTable *crtcs; - - gboolean is_locked; - uint64_t sequence_number; -@@ -238,6 +239,8 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, - update->plane_assignments = g_list_prepend (update->plane_assignments, - plane_assignment); - -+ g_hash_table_insert (update->crtcs, crtc, NULL); -+ - return plane_assignment; - } - -@@ -263,6 +266,8 @@ meta_kms_update_unassign_plane (MetaKmsUpdate *update, - update->plane_assignments = g_list_prepend (update->plane_assignments, - plane_assignment); - -+ g_hash_table_insert (update->crtcs, crtc, NULL); -+ - return plane_assignment; - } - -@@ -285,6 +290,8 @@ meta_kms_update_mode_set (MetaKmsUpdate *update, - }; - - update->mode_sets = g_list_prepend (update->mode_sets, mode_set); -+ -+ g_hash_table_insert (update->crtcs, crtc, NULL); - } - - static MetaKmsConnectorUpdate * -@@ -403,6 +410,8 @@ meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update, - gamma = meta_kms_crtc_gamma_new (crtc, size, red, green, blue); - - update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma); -+ -+ g_hash_table_insert (update->crtcs, crtc, NULL); - } - - void -@@ -694,12 +703,15 @@ meta_kms_update_new (MetaKmsDevice *device) - update->device = device; - update->sequence_number = sequence_number++; - -+ update->crtcs = g_hash_table_new (NULL, NULL); -+ - return update; - } - - void - meta_kms_update_free (MetaKmsUpdate *update) - { -+ g_hash_table_destroy (update->crtcs); - g_list_free_full (update->result_listeners, - (GDestroyNotify) meta_kms_result_listener_free); - g_list_free_full (update->plane_assignments, --- -GitLab - - -From 043be2e16d4c8afebb749181962d884d97451292 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 22 Sep 2021 17:19:45 +0800 -Subject: [PATCH 40/44] kms: Add functions meta_kms_update_include[s]_crtc() - ---- - src/backends/native/meta-kms-update-private.h | 6 ++++++ - src/backends/native/meta-kms-update.c | 14 ++++++++++++++ - 2 files changed, 20 insertions(+) - -diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h -index a613cbc5d6..1d964ff21f 100644 ---- a/src/backends/native/meta-kms-update-private.h -+++ b/src/backends/native/meta-kms-update-private.h -@@ -132,6 +132,12 @@ uint64_t meta_kms_update_get_sequence_number (MetaKmsUpdate *update); - META_EXPORT_TEST - MetaKmsDevice * meta_kms_update_get_device (MetaKmsUpdate *update); - -+gboolean meta_kms_update_includes_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc); -+ -+void meta_kms_update_include_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc); -+ - void meta_kms_plane_assignment_set_rotation (MetaKmsPlaneAssignment *plane_assignment, - uint64_t rotation); - -diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c -index 5896d66dfe..1e43f3f0f5 100644 ---- a/src/backends/native/meta-kms-update.c -+++ b/src/backends/native/meta-kms-update.c -@@ -675,6 +675,20 @@ meta_kms_update_get_device (MetaKmsUpdate *update) - return update->device; - } - -+gboolean -+meta_kms_update_includes_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc) -+{ -+ return g_hash_table_lookup_extended (update->crtcs, crtc, NULL, NULL); -+} -+ -+void -+meta_kms_update_include_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc) -+{ -+ g_hash_table_insert (update->crtcs, crtc, NULL); -+} -+ - MetaKmsCustomPageFlip * - meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update) - { --- -GitLab - - -From db5653698234487b006321b4198f4c225394ede0 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Wed, 22 Sep 2021 18:13:54 +0800 -Subject: [PATCH 41/44] kms: Add per-CRTC update functions - ---- - src/backends/native/meta-kms.c | 103 +++++++++++++++++++++++++++++++-- - src/backends/native/meta-kms.h | 10 ++++ - 2 files changed, 109 insertions(+), 4 deletions(-) - -diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c -index 052ec8a65c..9acc17b0d0 100644 ---- a/src/backends/native/meta-kms.c -+++ b/src/backends/native/meta-kms.c -@@ -23,6 +23,7 @@ - #include "backends/native/meta-kms-private.h" - - #include "backends/native/meta-backend-native.h" -+#include "backends/native/meta-kms-crtc.h" - #include "backends/native/meta-kms-device-private.h" - #include "backends/native/meta-kms-impl.h" - #include "backends/native/meta-kms-update-private.h" -@@ -181,6 +182,11 @@ struct _MetaKms - - G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT) - -+static MetaKmsFeedback * -+meta_kms_post_update_sync (MetaKms *kms, -+ MetaKmsUpdate *update, -+ MetaKmsUpdateFlag flags); -+ - void - meta_kms_discard_pending_updates (MetaKms *kms) - { -@@ -247,12 +253,105 @@ meta_kms_take_pending_update (MetaKms *kms, - return NULL; - } - -+MetaKmsUpdate * -+meta_kms_ensure_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ MetaKmsUpdate *update; -+ -+ update = meta_kms_get_pending_update_for_crtc (kms, crtc); -+ if (update == NULL) -+ { -+ update = meta_kms_update_new (meta_kms_crtc_get_device (crtc)); -+ meta_kms_update_include_crtc (update, crtc); -+ meta_kms_add_pending_update (kms, update); -+ } -+ -+ return update; -+} -+ -+static MetaKmsUpdate * -+meta_kms_find_compatible_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc, -+ gboolean take) -+{ -+ MetaKmsDevice *device; -+ MetaKmsUpdate *update; -+ GList *l; -+ -+ for (l = kms->pending_updates; l; l = l->next) -+ { -+ update = l->data; -+ if (meta_kms_update_includes_crtc (update, crtc)) -+ goto found; -+ } -+ -+ device = meta_kms_crtc_get_device (crtc); -+ -+ for (l = kms->pending_updates; l; l = l->next) -+ { -+ update = l->data; -+ if (meta_kms_update_get_device (update) == device && -+ meta_kms_update_get_mode_sets (update)) -+ goto found; -+ } -+ -+ return NULL; -+ -+found: -+ if (take) -+ kms->pending_updates = g_list_delete_link (kms->pending_updates, l); -+ return update; -+} -+ -+MetaKmsUpdate * -+meta_kms_get_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, FALSE); -+} -+ -+static MetaKmsUpdate * -+meta_kms_take_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, TRUE); -+} -+ - MetaKmsFeedback * - meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsDevice *device, - MetaKmsUpdateFlag flags) - { - MetaKmsUpdate *update; -+ -+ update = meta_kms_take_pending_update (kms, device); -+ if (!update) -+ return NULL; -+ -+ return meta_kms_post_update_sync (kms, update, flags); -+} -+ -+MetaKmsFeedback * -+meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms, -+ MetaKmsCrtc *crtc, -+ MetaKmsUpdateFlag flags) -+{ -+ MetaKmsUpdate *update; -+ -+ update = meta_kms_take_pending_update_for_crtc (kms, crtc); -+ if (!update) -+ return NULL; -+ -+ return meta_kms_post_update_sync (kms, update, flags); -+} -+ -+static MetaKmsFeedback * -+meta_kms_post_update_sync (MetaKms *kms, -+ MetaKmsUpdate *update, -+ MetaKmsUpdateFlag flags) -+{ -+ MetaKmsDevice *device = meta_kms_update_get_device (update); - MetaKmsFeedback *feedback; - GList *result_listeners; - GList *l; -@@ -260,10 +359,6 @@ meta_kms_post_pending_update_sync (MetaKms *kms, - COGL_TRACE_BEGIN_SCOPED (MetaKmsPostUpdateSync, - "KMS (post update)"); - -- update = meta_kms_take_pending_update (kms, device); -- if (!update) -- return NULL; -- - meta_kms_update_lock (update); - - feedback = meta_kms_device_process_update_sync (device, update, flags); -diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h -index bd9fe5cead..84f1bed498 100644 ---- a/src/backends/native/meta-kms.h -+++ b/src/backends/native/meta-kms.h -@@ -39,9 +39,15 @@ void meta_kms_discard_pending_updates (MetaKms *kms); - MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms, - MetaKmsDevice *device); - -+MetaKmsUpdate * meta_kms_ensure_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc); -+ - MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms, - MetaKmsDevice *device); - -+MetaKmsUpdate * meta_kms_get_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc); -+ - MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsDevice *device, - MetaKmsUpdateFlag flags); -@@ -49,6 +55,10 @@ MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsFeedback * meta_kms_post_test_update_sync (MetaKms *kms, - MetaKmsUpdate *update); - -+MetaKmsFeedback * meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms, -+ MetaKmsCrtc *device, -+ MetaKmsUpdateFlag flags); -+ - void meta_kms_discard_pending_page_flips (MetaKms *kms); - - void meta_kms_notify_modes_set (MetaKms *kms); --- -GitLab - - -From c48a8338a6a6ec7f20d9b072faf8f6d84509ea48 Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 28 Jan 2022 15:46:09 +0800 -Subject: [PATCH 42/44] cursor-renderer/native: Use CRTC-specific update - retrieval - ---- - src/backends/native/meta-cursor-renderer-native.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c -index 998af173d3..606fcad97f 100644 ---- a/src/backends/native/meta-cursor-renderer-native.c -+++ b/src/backends/native/meta-cursor-renderer-native.c -@@ -291,8 +291,8 @@ assign_cursor_plane (MetaCursorRendererNative *native, - flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED; - - kms_update = -- meta_kms_ensure_pending_update (meta_kms_device_get_kms (kms_device), -- meta_kms_crtc_get_device (kms_crtc)); -+ meta_kms_ensure_pending_update_for_crtc (meta_kms_device_get_kms (kms_device), -+ kms_crtc); - plane_assignment = meta_kms_update_assign_plane (kms_update, - kms_crtc, - cursor_plane, -@@ -440,7 +440,7 @@ unset_crtc_cursor (MetaCursorRendererNative *native, - MetaKms *kms = meta_kms_device_get_kms (kms_device); - MetaKmsUpdate *kms_update; - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - meta_kms_update_unassign_plane (kms_update, kms_crtc, cursor_plane); - } - --- -GitLab - - -From fe9b03f65bc168fd10aecdeae865405aa9e93aef Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 28 Jan 2022 15:50:24 +0800 -Subject: [PATCH 43/44] crtc/native: Use CRTC-specific update retrieval - ---- - src/backends/native/meta-crtc-kms.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c -index 584a780ba8..773b540b47 100644 ---- a/src/backends/native/meta-crtc-kms.c -+++ b/src/backends/native/meta-crtc-kms.c -@@ -211,6 +211,7 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, - MetaMonitorManagerNative *monitor_manager_native = - META_MONITOR_MANAGER_NATIVE (monitor_manager); - MetaKms *kms = meta_kms_device_get_kms (kms_device); -+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - MetaKmsUpdate *kms_update; - MetaKmsCrtcGamma *gamma; - -@@ -222,9 +223,9 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, - if (!gamma) - return; - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - meta_kms_update_set_crtc_gamma (kms_update, -- meta_crtc_kms_get_kms_crtc (crtc_kms), -+ kms_crtc, - gamma->size, - gamma->red, - gamma->green, --- -GitLab - - -From 163776ae49fa9af98405d8225be6e23473d550dc Mon Sep 17 00:00:00 2001 -From: Daniel van Vugt -Date: Fri, 28 Jan 2022 16:35:42 +0800 -Subject: [PATCH 44/44] onscreen/native: Use CRTC-specific update retrieval - -For mode setting we want all CRTCs to share the same MetaKmsUpdate, but -after that we don't want them to share the same update for regular flips -and cursor movement. The reason being that different CRTCs are attached to -different displays with different clocks. So each CRTC would finish the -same update at slightly different times. - -If you wait for all CRTCs to complete a shared update then you have waited -half a frame on average, possibly more. This waiting would consume most of -the render time for the next frame and risk stuttering. - -If you only wait for one CRTC to complete a shared update then the next -shared update may be posted before other CRTCs have finished the last, so -the next update would fail due to those other CRTCs still being busy. - -So the only safe answer for maintaining full framerate of multiple outputs -is to ensure unsynchronized CRTCs don't share the same update. At least -not after mode setting. - -This fixes a multi-monitor bug for atomic KMS whereby -`meta_onscreen_native_finish_frame` would fail its post because it was -trying to commit a cursor update on the wrong (busy) CRTC. ---- - src/backends/native/meta-onscreen-native.c | 20 ++++++++++++-------- - 1 file changed, 12 insertions(+), 8 deletions(-) - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index fb42ba7f4b..24d7f73852 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -423,7 +423,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - kms_device = meta_gpu_kms_get_kms_device (gpu_kms); - kms = meta_kms_device_get_kms (kms_device); -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - - g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); - -@@ -478,7 +478,7 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes, - "Onscreen (set CRTC modes)"); - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - - switch (renderer_gpu_data->mode) - { -@@ -1280,7 +1280,9 @@ try_post_latest_swap (CoglOnscreen *onscreen) - meta_kms_device_get_path (kms_device)); - - flags = META_KMS_UPDATE_FLAG_NONE; -- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); - g_return_if_fail (kms_feedback != NULL); - - switch (meta_kms_feedback_get_result (kms_feedback)) -@@ -1438,7 +1440,9 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - meta_kms_device_get_path (kms_device)); - - flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR; -- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: -@@ -1490,7 +1494,7 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - if (cogl_onscreen_count_pending_frames (onscreen) > 0) - return; - -- kms_update = meta_kms_get_pending_update (kms, kms_device); -+ kms_update = meta_kms_get_pending_update_for_crtc (kms, kms_crtc); - if (!kms_update) - { - clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); -@@ -1505,9 +1509,9 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - g_object_unref); - - flags = META_KMS_UPDATE_FLAG_NONE; -- kms_feedback = meta_kms_post_pending_update_sync (kms, -- kms_device, -- flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: --- -GitLab -