summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Soderlund2022-04-07 09:56:34 +0200
committerJoakim Soderlund2022-04-07 10:33:54 +0200
commitc9b247f3a4669f7b0a505904a70968e1f8e3ea90 (patch)
treecbcbe3e758f380bbb1394a81b184e23b2c0a30d4
parentbb703a841934ed1cf3ef73ac5903b2394cddc070 (diff)
downloadaur-c9b247f3a4669f7b0a505904a70968e1f8e3ea90.tar.gz
Upgrade !1441 to commit 163776ae
-rw-r--r--.SRCINFO4
-rw-r--r--PKGBUILD5
-rw-r--r--backports.patch79
-rw-r--r--mr1441.patch1591
4 files changed, 1354 insertions, 325 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 63914ebc5be1..29dbfb8e4604 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -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
diff --git a/PKGBUILD b/PKGBUILD
index c0039104b741..fb4395bbc0e6 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -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);
+