diff options
author | Joakim Soderlund | 2022-04-07 09:56:34 +0200 |
---|---|---|
committer | Joakim Soderlund | 2022-04-07 10:33:54 +0200 |
commit | c9b247f3a4669f7b0a505904a70968e1f8e3ea90 (patch) | |
tree | cbcbe3e758f380bbb1394a81b184e23b2c0a30d4 | |
parent | bb703a841934ed1cf3ef73ac5903b2394cddc070 (diff) | |
download | aur-c9b247f3a4669f7b0a505904a70968e1f8e3ea90.tar.gz |
Upgrade !1441 to commit 163776ae
-rw-r--r-- | .SRCINFO | 4 | ||||
-rw-r--r-- | PKGBUILD | 5 | ||||
-rw-r--r-- | backports.patch | 79 | ||||
-rw-r--r-- | mr1441.patch | 1591 |
4 files changed, 1354 insertions, 325 deletions
@@ -31,11 +31,9 @@ pkgbase = mutter-dynamic-buffering depends = libxkbfile depends = libsysprof-capture source = mutter-dynamic-buffering::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=9249aba72a5c4454894c08735a4963ca1665e34d - source = backports.patch source = mr1441.patch sha256sums = SKIP - sha256sums = 4bfebf11fd10d2829977cb3c77491bcb9eaa7779f9fc72cdbf10cb0f56adc813 - sha256sums = cf99896763558258f489ff0e9a1e8001f716d63b06366f740e044cc72a71d3e7 + sha256sums = fc1963c134b4548950241d175a7389ec5f1a0b6a86cefb6d0918d958d66252a2 pkgname = mutter-dynamic-buffering groups = gnome @@ -21,12 +21,10 @@ makedepends=(gobject-introspection git egl-wayland meson xorg-server #options=(debug) _commit=9249aba72a5c4454894c08735a4963ca1665e34d # tags/42.0^0 source=("$pkgname::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=$_commit" - 'backports.patch' 'mr1441.patch') sha256sums=('SKIP' - '4bfebf11fd10d2829977cb3c77491bcb9eaa7779f9fc72cdbf10cb0f56adc813' - 'cf99896763558258f489ff0e9a1e8001f716d63b06366f740e044cc72a71d3e7') + 'fc1963c134b4548950241d175a7389ec5f1a0b6a86cefb6d0918d958d66252a2') pkgver() { cd $pkgname @@ -36,7 +34,6 @@ pkgver() { prepare() { cd "$srcdir/$pkgname" patch -p1 < "$srcdir/mr1441.patch" - patch -p1 < "$srcdir/backports.patch" } build() { diff --git a/backports.patch b/backports.patch deleted file mode 100644 index 5852ba662557..000000000000 --- a/backports.patch +++ /dev/null @@ -1,79 +0,0 @@ -Author: Daniel van Vugt <daniel.van.vugt@canonical.com> -Editor: Joakim Soderlund <joakim.soderlund@gmail.com> -Source: https://gitlab.gnome.org/JockeTF/mutter/-/tree/41.1-2 -Commit: 3b3978c60e6c67e5fe5262d528d5330bc12181d0 -Rebase: Sat Nov 20 09:14:06 2021 +0100 - -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index eb1e7412a..eacfd2cc1 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -404,7 +406,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - kms = meta_kms_device_get_kms (kms_device); - kms_update = meta_kms_ensure_pending_update (kms, kms_device); - -- g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); -+ g_return_if_fail (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); - - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); -@@ -1011,7 +1013,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); - - use_modifiers = meta_renderer_native_use_modifiers (renderer_native); -@@ -2068,10 +2069,10 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native, - "height", height, - NULL); - -- onscreen_native->renderer_native = renderer_native; -- onscreen_native->render_gpu = render_gpu; -- onscreen_native->output = output; -- onscreen_native->crtc = crtc; -+ onscreen_native->renderer_native = g_object_ref (renderer_native); -+ onscreen_native->render_gpu = g_object_ref (render_gpu); -+ onscreen_native->output = g_object_ref (output); -+ onscreen_native->crtc = g_object_ref (crtc); - - return onscreen_native; - } -@@ -2126,6 +2127,11 @@ meta_onscreen_native_dispose (GObject *object) - secondary_gpu_state_free); - g_clear_pointer (&onscreen_native->next_post.rectangles, g_free); - onscreen_native->next_post.n_rectangles = 0; -+ -+ g_clear_object (&onscreen_native->crtc); -+ g_clear_object (&onscreen_native->output); -+ g_clear_object (&onscreen_native->render_gpu); -+ g_clear_object (&onscreen_native->renderer_native); - } - - static void -diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c -index eb6771b80..f39b0e004 100644 ---- a/src/backends/native/meta-renderer-native.c -+++ b/src/backends/native/meta-renderer-native.c -@@ -593,12 +593,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; diff --git a/mr1441.patch b/mr1441.patch index 90806337a369..f66842be8b48 100644 --- a/mr1441.patch +++ b/mr1441.patch @@ -1,13 +1,22 @@ Author: Daniel van Vugt <daniel.van.vugt@canonical.com> Source: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441 -Commit: 5bb8301fad0f10e5cb2f9058c2edd0e3e1a2fee6 -Rebase: Fri Sep 24 22:03:14 2021 +0800 +Commit: 163776ae49fa9af98405d8225be6e23473d550dc +Rebase: Fri Mar 11 14:09:17 2022 +0800 diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 16098b70f..27bbfd323 100644 +index 6fa2b2588..7a6444ec4 100644 --- a/clutter/clutter/clutter-frame-clock.c +++ b/clutter/clutter/clutter-frame-clock.c -@@ -68,8 +68,9 @@ typedef enum _ClutterFrameClockState +@@ -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 +@@ -65,8 +67,9 @@ typedef enum _ClutterFrameClockState CLUTTER_FRAME_CLOCK_STATE_INIT, CLUTTER_FRAME_CLOCK_STATE_IDLE, CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, @@ -19,7 +28,7 @@ index 16098b70f..27bbfd323 100644 } ClutterFrameClockState; struct _ClutterFrameClock -@@ -99,6 +100,8 @@ struct _ClutterFrameClock +@@ -96,6 +99,8 @@ struct _ClutterFrameClock /* Last KMS buffer submission time. */ int64_t last_flip_time_us; @@ -28,31 +37,60 @@ index 16098b70f..27bbfd323 100644 /* Last few durations between dispatch start and buffer swap. */ EstimateQueue dispatch_to_swap_us; /* Last few durations between buffer swap and GPU rendering finish. */ -@@ -278,9 +281,21 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, +@@ -228,6 +233,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)"); + +@@ -289,7 +298,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); +@@ -303,6 +313,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) + { +@@ -317,11 +331,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_DISPATCHING: - case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: + 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: -+ /* The GPU has caught up now so we can start using -+ * last_presentation_time_us again. But rather than dropping back to -+ * SCHEDULED, let's force a reschedule from IDLE. This way we'll get a -+ * more precise next update time based on last_presentation_time_us. -+ */ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; -+ clutter_frame_clock_schedule_update (frame_clock); + 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; ++ maybe_reschedule_update (frame_clock); ++ break; } -@@ -296,11 +311,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock) + } + +@@ -337,11 +358,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock) case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: g_warn_if_reached (); break; @@ -73,17 +111,52 @@ index 16098b70f..27bbfd323 100644 } } -@@ -375,7 +397,8 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock, +@@ -353,6 +381,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; +@@ -375,6 +404,27 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) + frame_clock->swap_to_flip_us.values[i]); + } -- if (frame_clock->last_presentation_time_us == 0) -+ if (frame_clock->last_presentation_time_us == 0 || -+ frame_clock->state >= CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE) - { - *out_next_update_time_us = - frame_clock->last_dispatch_time_us ? -@@ -518,8 +541,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock) ++ 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. +@@ -391,8 +441,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; + } + +@@ -558,8 +606,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock) frame_clock->pending_reschedule = TRUE; frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; break; @@ -98,7 +171,7 @@ index 16098b70f..27bbfd323 100644 break; } -@@ -555,11 +582,17 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) +@@ -595,11 +647,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 (); @@ -118,7 +191,7 @@ index 16098b70f..27bbfd323 100644 frame_clock->pending_reschedule = TRUE; frame_clock->pending_reschedule_now = TRUE; return; -@@ -568,7 +601,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) +@@ -608,7 +666,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); @@ -126,7 +199,7 @@ index 16098b70f..27bbfd323 100644 frame_clock->is_next_presentation_time_valid = FALSE; } -@@ -587,6 +619,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) +@@ -627,6 +684,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) { case CLUTTER_FRAME_CLOCK_STATE_INIT: next_update_time_us = g_get_monotonic_time (); @@ -134,7 +207,7 @@ index 16098b70f..27bbfd323 100644 break; case CLUTTER_FRAME_CLOCK_STATE_IDLE: calculate_next_update_time_us (frame_clock, -@@ -594,11 +627,27 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) +@@ -634,11 +692,28 @@ 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); @@ -146,7 +219,8 @@ index 16098b70f..27bbfd323 100644 - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: - case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: + 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; @@ -164,7 +238,7 @@ index 16098b70f..27bbfd323 100644 frame_clock->pending_reschedule = TRUE; return; } -@@ -606,7 +655,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) +@@ -646,7 +721,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); @@ -172,7 +246,7 @@ index 16098b70f..27bbfd323 100644 } static void -@@ -624,7 +672,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, +@@ -670,7 +744,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, frame_clock->refresh_interval_us; lateness_us = time_us - ideal_dispatch_time_us; @@ -181,7 +255,7 @@ index 16098b70f..27bbfd323 100644 frame_clock->last_dispatch_lateness_us = 0; else frame_clock->last_dispatch_lateness_us = lateness_us; -@@ -632,7 +680,21 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, +@@ -678,7 +752,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); @@ -204,7 +278,7 @@ index 16098b70f..27bbfd323 100644 frame_count = frame_clock->frame_count++; -@@ -656,25 +718,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, +@@ -703,25 +791,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, frame_clock->listener.user_data); COGL_TRACE_END (ClutterFrameClockFrame); @@ -214,11 +288,11 @@ index 16098b70f..27bbfd323 100644 - case CLUTTER_FRAME_CLOCK_STATE_INIT: - case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: - g_warn_if_reached (); -- break; -- case CLUTTER_FRAME_CLOCK_STATE_IDLE: -- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: + case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: break; +- case CLUTTER_FRAME_CLOCK_STATE_IDLE: +- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: +- break; - case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: - switch (result) + case CLUTTER_FRAME_RESULT_IDLE: @@ -248,7 +322,7 @@ index 16098b70f..27bbfd323 100644 } break; } -@@ -696,10 +764,12 @@ frame_clock_source_dispatch (GSource *source, +@@ -754,10 +848,12 @@ frame_clock_source_dispatch (GSource *source, } void @@ -263,8 +337,18 @@ index 16098b70f..27bbfd323 100644 } GString * +@@ -888,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] = diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h -index e71b54987..a37024e2d 100644 +index 91e6b3a13..d750404d5 100644 --- a/clutter/clutter/clutter-frame-clock.h +++ b/clutter/clutter/clutter-frame-clock.h @@ -34,6 +34,12 @@ typedef enum _ClutterFrameResult @@ -280,7 +364,7 @@ index e71b54987..a37024e2d 100644 #define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ()) CLUTTER_EXPORT G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock, -@@ -91,8 +97,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock, +@@ -90,8 +96,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock, CLUTTER_EXPORT float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock); @@ -342,10 +426,10 @@ index d3608e81c..06c5f7f28 100644 + #endif /* CLUTTER_FRAME_H */ diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c -index 9b7345983..f8da6e37c 100644 +index 8a82de71e..45d009352 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c -@@ -1189,8 +1189,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock, +@@ -1190,8 +1190,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock, _clutter_stage_window_redraw_view (stage_window, view, &frame); @@ -370,10 +454,10 @@ index dffe018d2..e0215f750 100644 + #endif /* __COGL_ONSCREEN_PRIVATE_H */ diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c -index cff5df50c..6f159cbb2 100644 +index ff9e1749a..b25b4af4a 100644 --- a/cogl/cogl/cogl-onscreen.c +++ b/cogl/cogl/cogl-onscreen.c -@@ -497,6 +497,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen) +@@ -510,6 +510,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen) return g_queue_pop_head (&priv->pending_frame_infos); } @@ -389,10 +473,10 @@ index cff5df50c..6f159cbb2 100644 cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen, CoglFrameCallback callback, diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c -index 28534ec81..bbed4fcf2 100644 +index c45aaf852..683f4ff6c 100644 --- a/src/backends/meta-stage-impl.c +++ b/src/backends/meta-stage-impl.c -@@ -670,6 +670,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window, +@@ -720,6 +720,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window, { g_autoptr (GError) error = NULL; @@ -401,8 +485,32 @@ index 28534ec81..bbed4fcf2 100644 if (meta_stage_impl_scanout_view (stage_impl, stage_view, scanout, +diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c +index 584a780ba..773b540b4 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, diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c -index effa0851d..24e089a88 100644 +index df5862c4c..606fcad97 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -64,19 +64,6 @@ @@ -507,6 +615,17 @@ index effa0851d..24e089a88 100644 kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); kms_device = meta_kms_crtc_get_device (kms_crtc); +@@ -343,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, @@ -365,13 +313,6 @@ assign_cursor_plane (MetaCursorRendererNative *native, native); @@ -521,6 +640,15 @@ index effa0851d..24e089a88 100644 } static float +@@ -499,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); + } + @@ -599,19 +540,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, if (!cursor_gpu_state) return FALSE; @@ -542,7 +670,7 @@ index effa0851d..24e089a88 100644 } static void -@@ -1114,16 +1043,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu, +@@ -1115,16 +1044,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu, static void cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state) { @@ -561,7 +689,7 @@ index effa0851d..24e089a88 100644 g_free (cursor_gpu_state); } -@@ -1160,14 +1087,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite) +@@ -1161,14 +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)) @@ -577,7 +705,7 @@ index effa0851d..24e089a88 100644 } static void -@@ -1302,8 +1222,8 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, +@@ -1306,8 +1226,8 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, return; } @@ -588,7 +716,7 @@ index effa0851d..24e089a88 100644 } else { -@@ -1311,34 +1231,6 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, +@@ -1315,34 +1235,6 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, } } @@ -623,7 +751,7 @@ index effa0851d..24e089a88 100644 static gboolean is_cursor_scale_and_transform_valid (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) -@@ -1503,7 +1395,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, +@@ -1507,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; @@ -632,7 +760,7 @@ index effa0851d..24e089a88 100644 is_cursor_scale_and_transform_valid (renderer, cursor_sprite)) return; -@@ -1642,8 +1534,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, +@@ -1649,8 +1541,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, return; } @@ -643,7 +771,7 @@ index effa0851d..24e089a88 100644 } } #endif -@@ -1667,7 +1559,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer, +@@ -1674,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; @@ -653,7 +781,7 @@ index effa0851d..24e089a88 100644 return; diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c -index 3e0506026..75109aa20 100644 +index 685a3737c..45c7eb78e 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -32,6 +32,12 @@ typedef struct _MetaKmsCrtcPropTable @@ -678,7 +806,7 @@ index 3e0506026..75109aa20 100644 }; G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) -@@ -435,20 +443,86 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device, +@@ -441,20 +449,91 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device, return crtc; } @@ -694,7 +822,6 @@ index 3e0506026..75109aa20 100644 + if (plane_state == NULL) + { + plane_state = g_new0 (PlaneState, 1); -+ g_return_if_fail (plane_state); + g_hash_table_insert (crtc->plane_states, key, plane_state); + } + @@ -723,12 +850,18 @@ index 3e0506026..75109aa20 100644 + 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); + -+ g_hash_table_remove_all (crtc->plane_states); ++ meta_kms_crtc_release_buffers (crtc); + + G_OBJECT_CLASS (meta_kms_crtc_parent_class)->dispose (object); +} @@ -765,7 +898,7 @@ index 3e0506026..75109aa20 100644 } static void -@@ -456,5 +530,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass) +@@ -462,5 +541,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -773,7 +906,7 @@ index 3e0506026..75109aa20 100644 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 406ca3ac1..1a0d9f1b6 100644 +index 218bec9a1..29fdfcb5d 100644 --- a/src/backends/native/meta-kms-crtc.h +++ b/src/backends/native/meta-kms-crtc.h @@ -25,6 +25,7 @@ @@ -781,10 +914,10 @@ index 406ca3ac1..1a0d9f1b6 100644 #include "backends/native/meta-kms-types.h" +#include "backends/native/meta-drm-buffer.h" + #include "core/util-private.h" #include "meta/boxes.h" - typedef struct _MetaKmsCrtcState -@@ -76,4 +77,10 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc, +@@ -82,4 +83,12 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc, const uint16_t *green, const uint16_t *blue); @@ -794,38 +927,150 @@ index 406ca3ac1..1a0d9f1b6 100644 + +void meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc); + ++void meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc); ++ #endif /* META_KMS_CRTC_H */ diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c -index 674a24902..718f4b3e1 100644 +index 73dd8e697..787d05acd 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c -@@ -495,6 +495,10 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - error)) - return FALSE; - } +@@ -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; + } + -+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ buffer); ++ 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; +diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c +index 882cd97cc..8aa78343a 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; } - else + ++ meta_kms_crtc_on_scanout_started (crtc); ++ + if (drm_mode) { -@@ -522,6 +526,10 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - error)) - return FALSE; + g_hash_table_replace (impl_device_simple->cached_mode_sets, +@@ -534,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; +@@ -547,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); + } + +@@ -614,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_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ NULL); + 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); + } +@@ -710,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) +@@ -725,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, +@@ -859,6 +867,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple, + return FALSE; } - if (plane_assignment->rotation) -diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c -index 28d512720..2f3c99928 100644 ---- a/src/backends/native/meta-kms-impl-device-simple.c -+++ b/src/backends/native/meta-kms-impl-device-simple.c -@@ -1275,7 +1275,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, ++ meta_kms_crtc_on_scanout_started (crtc); ++ + if (!impl_device_simple->mode_set_fallback_feedback_source) + { + GSource *source; +@@ -983,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)); +@@ -1290,7 +1300,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, { case META_KMS_PLANE_TYPE_PRIMARY: /* Handled as part of the mode-set and page flip. */ @@ -834,7 +1079,7 @@ index 28d512720..2f3c99928 100644 case META_KMS_PLANE_TYPE_CURSOR: if (!process_cursor_plane_assignment (impl_device, update, plane_assignment, -@@ -1289,7 +1289,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, +@@ -1304,7 +1314,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, } else { @@ -843,7 +1088,7 @@ index 28d512720..2f3c99928 100644 } case META_KMS_PLANE_TYPE_OVERLAY: error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, -@@ -1302,6 +1302,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, +@@ -1317,6 +1327,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, } g_assert_not_reached (); @@ -856,6 +1101,23 @@ index 28d512720..2f3c99928 100644 } static gboolean +diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c +index b05bf5fda..1177707fa 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); + diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c index 817f4e7c8..148d23740 100644 --- a/src/backends/native/meta-kms-page-flip.c @@ -877,11 +1139,36 @@ index 817f4e7c8..148d23740 100644 for (l = page_flip_data->closures; l; l = l->next) { MetaKmsPageFlipClosure *closure = l->data; +diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h +index a613cbc5d..1d964ff21 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 71e5b423f..a98e8ade6 100644 +index 53fc92eb8..1e43f3f0f 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c -@@ -140,6 +140,7 @@ static void +@@ -31,6 +31,7 @@ + struct _MetaKmsUpdate + { + MetaKmsDevice *device; ++ GHashTable *crtcs; + + gboolean is_locked; + uint64_t sequence_number; +@@ -149,6 +150,7 @@ static void meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment) { g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free); @@ -889,7 +1176,7 @@ index 71e5b423f..a98e8ade6 100644 g_free (plane_assignment); } -@@ -220,7 +221,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, +@@ -228,7 +230,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, .update = update, .crtc = crtc, .plane = plane, @@ -898,74 +1185,281 @@ index 71e5b423f..a98e8ade6 100644 .src_rect = src_rect, .dst_rect = dst_rect, .flags = flags, +@@ -237,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; + } + +@@ -262,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; + } + +@@ -284,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 * +@@ -402,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 +@@ -665,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) + { +@@ -693,12 +717,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, diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c -index 0750278ae..061460b38 100644 +index 052ec8a65..9acc17b0d 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c -@@ -177,6 +177,8 @@ struct _MetaKms +@@ -23,6 +23,7 @@ + #include "backends/native/meta-kms-private.h" - GList *pending_callbacks; - guint callback_source_id; -+ -+ gboolean shutting_down; - }; + #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) -@@ -277,6 +279,9 @@ meta_kms_post_pending_update_sync (MetaKms *kms, - COGL_TRACE_BEGIN_SCOPED (MetaKmsPostUpdateSync, - "KMS (post update)"); -+ if (kms->shutting_down) -+ return NULL; ++static MetaKmsFeedback * ++meta_kms_post_update_sync (MetaKms *kms, ++ MetaKmsUpdate *update, ++ MetaKmsUpdateFlag flags); + - update = meta_kms_take_pending_update (kms, device); - if (!update) - return NULL; -@@ -757,6 +762,7 @@ prepare_shutdown_in_impl (MetaKmsImpl *impl, void - meta_kms_prepare_shutdown (MetaKms *kms) + meta_kms_discard_pending_updates (MetaKms *kms) { -+ kms->shutting_down = TRUE; - meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL); - flush_callbacks (kms); +@@ -247,12 +253,105 @@ meta_kms_take_pending_update (MetaKms *kms, + return NULL; } -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 00b2d9f89..eb1e7412a 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -46,6 +46,8 @@ - #include "backends/native/meta-renderer-native-gles3.h" - #include "backends/native/meta-renderer-native-private.h" -+#define MAX_CONCURRENT_POSTS 1 ++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); ++} + - typedef enum _MetaSharedFramebufferImportStatus ++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) { - /* Not tried importing yet. */ -@@ -65,7 +67,6 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState + 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 bd9fe5cea..84f1bed49 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); +diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c +index 3eb550319..24d7f7385 100644 +--- a/src/backends/native/meta-onscreen-native.c ++++ b/src/backends/native/meta-onscreen-native.c +@@ -67,13 +67,12 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState struct { struct gbm_surface *surface; - MetaDrmBuffer *current_fb; - MetaDrmBuffer *next_fb; +- MetaDrmBuffer *next_fb; } gbm; -@@ -92,8 +93,13 @@ struct _MetaOnscreenNative + struct { + MetaDrmBufferDumb *current_dumb_fb; + MetaDrmBufferDumb *dumb_fbs[2]; ++ MetaDrmBuffer *source_fbs[2]; + } cpu; + + gboolean noted_primary_gpu_copy_ok; +@@ -94,8 +93,8 @@ struct _MetaOnscreenNative struct { struct gbm_surface *surface; - MetaDrmBuffer *current_fb; MetaDrmBuffer *next_fb; -+ -+ struct { -+ uint32_t format; -+ uint32_t stride; -+ uint64_t modifier; -+ } last_flip; ++ MetaDrmBuffer *stalled_fb; } gbm; #ifdef HAVE_EGL_DEVICE -@@ -105,69 +111,25 @@ struct _MetaOnscreenNative +@@ -107,69 +106,25 @@ struct _MetaOnscreenNative #endif MetaRendererView *view; @@ -981,7 +1475,7 @@ index 00b2d9f89..eb1e7412a 100644 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, @@ -1044,7 +1538,7 @@ index 00b2d9f89..eb1e7412a 100644 static void maybe_update_frame_info (MetaCrtc *crtc, CoglFrameInfo *frame_info, -@@ -203,7 +165,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen) +@@ -205,7 +160,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen) info = cogl_onscreen_pop_head_frame_info (onscreen); @@ -1053,102 +1547,479 @@ index 00b2d9f89..eb1e7412a 100644 _cogl_onscreen_notify_frame_sync (onscreen, info); _cogl_onscreen_notify_complete (onscreen, info); -@@ -230,7 +192,7 @@ notify_view_crtc_presented (MetaRendererView *view, +@@ -234,7 +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); - meta_onscreen_native_swap_drm_fb (onscreen); -+ post_latest_swap (onscreen); ++ try_post_latest_swap (onscreen); } static int64_t -@@ -292,6 +254,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc, +@@ -296,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); -+ post_latest_swap (onscreen); ++ try_post_latest_swap (onscreen); } static void -@@ -341,7 +304,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, +@@ -345,7 +301,7 @@ 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); -+ post_latest_swap (onscreen); ++ try_post_latest_swap (onscreen); } static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = { -@@ -405,11 +368,10 @@ meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) +@@ -406,18 +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) { ++ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); CoglFrameInfo *frame_info; - meta_onscreen_native_swap_drm_fb (onscreen); -- ++ /* 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.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); -+ post_latest_swap (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 -@@ -431,7 +393,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, + meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, + MetaRendererView *view, +@@ -436,8 +414,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, + MetaKmsDevice *kms_device; MetaKms *kms; MetaKmsUpdate *kms_update; - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL; +- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL; - MetaDrmBuffer *buffer; + g_autoptr (MetaDrmBuffer) buffer = NULL; MetaKmsPlaneAssignment *plane_assignment; COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs, -@@ -451,12 +413,14 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, +@@ -446,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)); + +@@ -455,15 +432,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, + switch (renderer_gpu_data->mode) + { case META_RENDERER_NATIVE_MODE_GBM: - if (gpu_kms == render_gpu) - { +- if (gpu_kms == render_gpu) +- { - buffer = onscreen_native->gbm.next_fb; -+ buffer = g_object_ref (onscreen_native->gbm.next_fb); -+ g_clear_object (&onscreen_native->gbm.next_fb); - } - else - { - secondary_gpu_state = onscreen_native->secondary_gpu_state; +- } +- else +- { +- secondary_gpu_state = onscreen_native->secondary_gpu_state; - buffer = secondary_gpu_state->gbm.next_fb; -+ buffer = g_object_ref (secondary_gpu_state->gbm.next_fb); -+ g_clear_object (&secondary_gpu_state->gbm.next_fb); - } +- } ++ buffer = g_steal_pointer (&onscreen_native->gbm.next_fb); plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms, -@@ -468,6 +432,21 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - meta_kms_plane_assignment_set_fb_damage (plane_assignment, - rectangles, n_rectangles); - } + buffer, +@@ -509,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) + { +@@ -535,13 +504,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); + -+ if (META_IS_DRM_BUFFER_GBM (buffer)) ++ for (i = 0; i < n; i++) + { -+ MetaDrmBufferGbm *buffer_gbm = META_DRM_BUFFER_GBM (buffer); -+ struct gbm_bo *gbm_bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); ++ if (dumb_fb == secondary_gpu_state->cpu.dumb_fbs[i]) ++ { ++ g_set_object (&secondary_gpu_state->cpu.source_fbs[i], ++ primary_gpu_fb); ++ break; ++ } ++ } + -+ onscreen_native->gbm.last_flip.format = gbm_bo_get_format (gbm_bo); -+ onscreen_native->gbm.last_flip.modifier = gbm_bo_get_modifier (gbm_bo); -+ onscreen_native->gbm.last_flip.stride = gbm_bo_get_stride (gbm_bo); ++ g_warn_if_fail (i < n); ++ } ++} + -+ g_object_set_data_full (G_OBJECT (buffer_gbm), -+ "gbm_surface owner", -+ g_object_ref (onscreen), -+ (GDestroyNotify) g_object_unref); -+ } - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - g_assert_not_reached (); -@@ -556,7 +535,6 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta + 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 +@@ -566,8 +563,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_object (&secondary_gpu_state->gbm.next_fb); g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy); -@@ -1004,12 +982,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, + secondary_gpu_release_dumb (secondary_gpu_state); +@@ -575,11 +570,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 +582,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 +596,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 +615,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 +640,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 +652,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 +670,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 +680,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 +700,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 +718,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 +746,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 +769,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 +787,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 +800,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre + &error)) + { + g_object_unref (dmabuf_fb); +- return FALSE; ++ return NULL; + } + } + else +@@ -832,20 +817,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 +881,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 +919,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 +933,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 +947,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 +968,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 +976,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); + } + } + +@@ -1034,34 +1033,39 @@ 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; @@ -1161,33 +2032,121 @@ index 00b2d9f89..eb1e7412a 100644 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaGpuKms *render_gpu = onscreen_native->render_gpu; MetaDeviceFile *render_device_file; -@@ -1017,14 +989,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, + ClutterFrame *frame = user_data; CoglOnscreenClass *parent_class; gboolean egl_context_changed = FALSE; - gboolean use_modifiers; - MetaPowerSave power_save_mode; g_autoptr (GError) error = NULL; + MetaDrmBufferFlags buffer_flags; MetaDrmBufferGbm *buffer_gbm; - MetaKmsCrtc *kms_crtc; - MetaKmsDevice *kms_device; - MetaKmsUpdateFlag flags; - g_autoptr (MetaKmsFeedback) kms_feedback = NULL; - const GError *feedback_error; ++ g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL; ++ g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL; + size_t rectangles_size; COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, "Onscreen (swap-buffers)"); -@@ -1073,6 +1040,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, + +- update_secondary_gpu_state_pre_swap_buffers (onscreen, +- rectangles, +- n_rectangles); ++ 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, ++ n_rectangles); + + parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class); + parent_class->swap_buffers_with_damage (onscreen, +@@ -1077,9 +1081,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,7 +1098,12 @@ 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)); ++ ++ 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: +@@ -1109,7 +1115,46 @@ 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: ++ if (onscreen_native->gbm.next_fb != NULL) ++ { ++ 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) ++ { ++ 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); ++ } ++ break; ++ case META_RENDERER_NATIVE_MODE_SURFACELESS: ++ break; ++#ifdef HAVE_EGL_DEVICE ++ case META_RENDERER_NATIVE_MODE_EGL_DEVICE: ++ break; ++#endif ++ } ++ + clutter_frame_set_result (frame, + CLUTTER_FRAME_RESULT_PENDING_PRESENTED); -+ - update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); /* -@@ -1084,6 +1054,48 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, + * If we changed EGL context, cogl will have the wrong idea about what is +@@ -1120,23 +1165,71 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, if (egl_context_changed) _cogl_winsys_egl_ensure_current (cogl_display); @@ -1198,14 +2157,11 @@ index 00b2d9f89..eb1e7412a 100644 + onscreen_native->next_post.n_rectangles = n_rectangles; + + onscreen_native->swaps_pending++; -+ -+ /* The new frame is already counted by cogl so that's why it is "<=" */ -+ if (cogl_onscreen_count_pending_frames (onscreen) <= MAX_CONCURRENT_POSTS) -+ post_latest_swap (onscreen); ++ 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); @@ -1227,16 +2183,28 @@ index 00b2d9f89..eb1e7412a 100644 + 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; + -+ onscreen_native->swaps_pending--; ++ 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) { -@@ -1092,15 +1104,13 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, ++ 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, onscreen_native->crtc, META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, @@ -1254,7 +2222,7 @@ index 00b2d9f89..eb1e7412a 100644 return; } -@@ -1118,9 +1128,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, +@@ -1154,9 +1247,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)); @@ -1264,7 +2232,7 @@ index 00b2d9f89..eb1e7412a 100644 return; } else if (meta_renderer_native_has_pending_mode_set (renderer_native)) -@@ -1130,8 +1137,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, +@@ -1166,8 +1256,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); @@ -1273,7 +2241,7 @@ index 00b2d9f89..eb1e7412a 100644 return; } break; -@@ -1144,8 +1149,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, +@@ -1180,8 +1268,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); @@ -1282,10 +2250,14 @@ index 00b2d9f89..eb1e7412a 100644 return; } break; -@@ -1159,17 +1162,13 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, +@@ -1194,18 +1280,16 @@ meta_onscreen_native_swap_buffers_with_damage (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_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)) @@ -1301,48 +2273,14 @@ index 00b2d9f89..eb1e7412a 100644 feedback_error = meta_kms_feedback_get_error (kms_feedback); if (!g_error_matches (feedback_error, G_IO_ERROR, -@@ -1187,8 +1186,6 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - const MetaCrtcConfig *crtc_config; -- MetaDrmBuffer *fb; -- struct gbm_bo *gbm_bo; - - crtc_config = meta_crtc_get_config (onscreen_native->crtc); - if (crtc_config->transform != META_MONITOR_TRANSFORM_NORMAL) -@@ -1200,23 +1197,13 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, - if (!onscreen_native->gbm.surface) - return FALSE; - -- fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb -- : onscreen_native->gbm.next_fb; -- if (!fb) -+ if (drm_format != onscreen_native->gbm.last_flip.format) - return FALSE; - -- if (!META_IS_DRM_BUFFER_GBM (fb)) -+ if (drm_modifier != onscreen_native->gbm.last_flip.modifier) - return FALSE; - -- gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb)); -- -- if (gbm_bo_get_format (gbm_bo) != drm_format) -- return FALSE; -- -- if (gbm_bo_get_modifier (gbm_bo) != drm_modifier) -- return FALSE; -- -- if (gbm_bo_get_stride (gbm_bo) != stride) -+ if (stride != onscreen_native->gbm.last_flip.stride) - return FALSE; - - return TRUE; -@@ -1272,6 +1259,16 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, +@@ -1292,6 +1376,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, return FALSE; } -+ /* The new frame is already counted by cogl so that's why it is ">" */ -+ if (cogl_onscreen_count_pending_frames (onscreen) > MAX_CONCURRENT_POSTS) ++ /* 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, @@ -1354,7 +2292,18 @@ index 00b2d9f89..eb1e7412a 100644 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, render_gpu); -@@ -1338,7 +1335,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, +@@ -1344,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: +@@ -1358,7 +1456,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) break; @@ -1362,17 +2311,94 @@ index 00b2d9f89..eb1e7412a 100644 g_propagate_error (error, g_error_copy (feedback_error)); return FALSE; } -@@ -1374,6 +1370,9 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, +@@ -1394,7 +1491,10 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, g_autoptr (MetaKmsFeedback) kms_feedback = NULL; const GError *error; -+ if (cogl_onscreen_count_pending_frames (onscreen) >= MAX_CONCURRENT_POSTS) +- kms_update = meta_kms_get_pending_update (kms, kms_device); ++ 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) { -@@ -2096,7 +2094,6 @@ meta_onscreen_native_dispose (GObject *object) + clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); +@@ -1409,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: +@@ -1433,6 +1533,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) + { +@@ -1981,6 +2092,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, +@@ -2037,6 +2163,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); + } + + /* +@@ -2116,7 +2248,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; + } +@@ -2137,7 +2269,6 @@ meta_onscreen_native_dispose (GObject *object) { case META_RENDERER_NATIVE_MODE_GBM: g_clear_object (&onscreen_native->gbm.next_fb); @@ -1380,7 +2406,11 @@ index 00b2d9f89..eb1e7412a 100644 break; case META_RENDERER_NATIVE_MODE_SURFACELESS: g_assert_not_reached (); -@@ -2127,6 +2124,8 @@ meta_onscreen_native_dispose (GObject *object) +@@ -2165,9 +2296,12 @@ 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); @@ -1389,3 +2419,86 @@ index 00b2d9f89..eb1e7412a 100644 } static void +diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h +index 3a85ace26..676c4c445 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); + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index 41bf04d66..58e6339a8 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; +@@ -678,6 +684,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 = +@@ -1386,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) + { +@@ -1414,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); + |