summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Soderlund2023-05-03 20:26:54 +0200
committerJoakim Soderlund2023-05-06 22:56:03 +0200
commit871b43d6bc491c9f4ffac885ff8a627911e3ee86 (patch)
tree93451193da80a0ca3da72606cddd2038a8694829
parentbc570f3c3cbe2975cecd10e25a42797c1db4a241 (diff)
downloadaur-871b43d6bc491c9f4ffac885ff8a627911e3ee86.tar.gz
Upgrade !1441 to commit eb4f260f
-rw-r--r--.SRCINFO2
-rw-r--r--PKGBUILD2
-rw-r--r--mr1441.patch2154
3 files changed, 850 insertions, 1308 deletions
diff --git a/.SRCINFO b/.SRCINFO
index f3c34426ac66..da5ee8deda45 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -33,7 +33,7 @@ pkgbase = mutter-dynamic-buffering
source = mutter-dynamic-buffering::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=28a6447ff060ae1fbac8f20a13908d6e230eddc2
source = mr1441.patch
sha256sums = SKIP
- sha256sums = 690a31df2e61de3fbd0b51ec86ab4b84f54e6453926b06c14c9cd2ec93c27db0
+ sha256sums = 3003d63a665d80cae58cdf3db37af25e214bcff5e322768fe2544acb51adcf9b
pkgname = mutter-dynamic-buffering
provides = mutter
diff --git a/PKGBUILD b/PKGBUILD
index a4b125b95062..eaa5d0c972c6 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -53,7 +53,7 @@ source=(
)
sha256sums=(
'SKIP'
- '690a31df2e61de3fbd0b51ec86ab4b84f54e6453926b06c14c9cd2ec93c27db0'
+ '3003d63a665d80cae58cdf3db37af25e214bcff5e322768fe2544acb51adcf9b'
)
pkgver() {
diff --git a/mr1441.patch b/mr1441.patch
index e4df07f35cb9..977b714c7683 100644
--- a/mr1441.patch
+++ b/mr1441.patch
@@ -1,22 +1,29 @@
Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
Source: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441
-Commit: a6f23c151c94912c8fc074facd07b0d6aa70f939
-Rebase: Thu Feb 16 13:46:59 2023 +0800
+Commit: eb4f260f6921e65277ef1f0707ffdf39357438bb
+Rebase: Tue May 2 15:05:35 2023 +0200
diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
-index 34d676f54..78f8dde9b 100644
+index 3aeb29042..b1d6f7164 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
-@@ -45,6 +45,8 @@ typedef struct _EstimateQueue
- int next_index;
- } EstimateQueue;
+@@ -35,6 +35,15 @@ enum
-+static gboolean triple_buffering_disabled = FALSE;
+ static guint signals[N_SIGNALS];
+
++typedef enum
++{
++ TRIPLE_BUFFERING_MODE_NEVER,
++ TRIPLE_BUFFERING_MODE_AUTO,
++ TRIPLE_BUFFERING_MODE_ALWAYS,
++} TripleBufferingMode;
++
++static TripleBufferingMode triple_buffering_mode = TRIPLE_BUFFERING_MODE_AUTO;
+
#define SYNC_DELAY_FALLBACK_FRACTION 0.875
typedef struct _ClutterFrameListener
-@@ -65,8 +67,9 @@ typedef enum _ClutterFrameClockState
+@@ -55,8 +64,9 @@ typedef enum _ClutterFrameClockState
CLUTTER_FRAME_CLOCK_STATE_INIT,
CLUTTER_FRAME_CLOCK_STATE_IDLE,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
@@ -28,16 +35,25 @@ index 34d676f54..78f8dde9b 100644
} ClutterFrameClockState;
struct _ClutterFrameClock
-@@ -96,6 +99,8 @@ struct _ClutterFrameClock
+@@ -73,6 +83,7 @@ struct _ClutterFrameClock
+
+ ClutterFrameClockState state;
+ int64_t last_dispatch_time_us;
++ int64_t prev_last_dispatch_time_us;
+ int64_t last_dispatch_lateness_us;
+ int64_t last_presentation_time_us;
+ int64_t next_update_time_us;
+@@ -87,6 +98,9 @@ struct _ClutterFrameClock
+ int64_t vblank_duration_us;
/* Last KMS buffer submission time. */
int64_t last_flip_time_us;
-
-+ ClutterFrameHint last_flip_hints;
++ int64_t prev_last_flip_time_us;
+
- /* Last few durations between dispatch start and buffer swap. */
- EstimateQueue dispatch_to_swap_us;
- /* Last few durations between buffer swap and GPU rendering finish. */
-@@ -228,6 +233,12 @@ void
++ ClutterFrameHint last_flip_hints;
+
+ /* Last time we promoted short term durations to long term ones */
+ int64_t longterm_promotion_us;
+@@ -241,6 +255,12 @@ void
clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info)
{
@@ -50,28 +66,59 @@ index 34d676f54..78f8dde9b 100644
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented,
"Frame Clock (presented)");
-@@ -290,7 +301,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
+@@ -324,18 +344,38 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
+ frame_info->gpu_rendering_duration_ns != 0)
+ {
+ int64_t dispatch_to_swap_us, swap_to_rendering_done_us, swap_to_flip_us;
++ int64_t dispatch_time_us = 0, flip_time_us = 0;
++
++ switch (frame_clock->state)
++ {
++ case CLUTTER_FRAME_CLOCK_STATE_INIT:
++ case CLUTTER_FRAME_CLOCK_STATE_IDLE:
++ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
++ g_warn_if_reached ();
++ G_GNUC_FALLTHROUGH;
++ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
++ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
++ dispatch_time_us = frame_clock->last_dispatch_time_us;
++ flip_time_us = frame_clock->last_flip_time_us;
++ break;
++ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
++ dispatch_time_us = frame_clock->prev_last_dispatch_time_us;
++ flip_time_us = frame_clock->prev_last_flip_time_us;
++ break;
++ }
+
+ dispatch_to_swap_us =
+ frame_info->cpu_time_before_buffer_swap_us -
+- frame_clock->last_dispatch_time_us;
++ dispatch_time_us;
+ swap_to_rendering_done_us =
+ frame_info->gpu_rendering_duration_ns / 1000;
+ swap_to_flip_us =
+- frame_clock->last_flip_time_us -
++ flip_time_us -
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",
+- "update2dispatch %ld µs, dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
++ "%s: update2dispatch %ld µs, dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
+ debug_state,
+ frame_clock->last_dispatch_lateness_us,
dispatch_to_swap_us,
swap_to_rendering_done_us,
- swap_to_flip_us);
-@@ -304,6 +316,10 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
-
- frame_clock->got_measurements_last_frame = TRUE;
+@@ -352,7 +392,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
}
-+ else
-+ {
-+ CLUTTER_NOTE (FRAME_TIMINGS, "%s", debug_state);
-+ }
-
- if (frame_info->refresh_rate > 1.0)
+ else
{
-@@ -318,11 +334,18 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
+- CLUTTER_NOTE (FRAME_TIMINGS, "update2dispatch %ld µs",
++ CLUTTER_NOTE (FRAME_TIMINGS, "%s: update2dispatch %ld µs",
++ debug_state,
+ frame_clock->last_dispatch_lateness_us);
+ }
+
+@@ -383,11 +424,18 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
@@ -92,7 +139,7 @@ index 34d676f54..78f8dde9b 100644
}
}
-@@ -338,11 +361,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
+@@ -403,11 +451,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
@@ -113,43 +160,24 @@ index 34d676f54..78f8dde9b 100644
}
}
-@@ -354,6 +384,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;
-@@ -376,6 +407,27 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
- frame_clock->swap_to_flip_us.values[i]);
- }
-
-+ switch (frame_clock->state)
+@@ -426,7 +481,15 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
+ if (!frame_clock->got_measurements_last_frame ||
+ G_UNLIKELY (clutter_paint_debug_flags &
+ CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
+- return refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION;
+ {
-+ 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;
-+ }
++ int64_t ret = refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION;
+
-+ 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;
++ if (frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE &&
++ triple_buffering_mode != TRIPLE_BUFFERING_MODE_NEVER)
++ ret += refresh_interval_us;
+
- /* 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.
-@@ -392,8 +444,6 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
++ return ret;
++ }
+
+ max_dispatch_lateness_us =
+ MAX (frame_clock->longterm.max_dispatch_lateness_us,
+@@ -459,8 +522,6 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
frame_clock->vblank_duration_us +
clutter_max_render_time_constant_us;
@@ -158,7 +186,7 @@ index 34d676f54..78f8dde9b 100644
return max_render_time_us;
}
-@@ -407,7 +457,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
+@@ -475,7 +536,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
int64_t refresh_interval_us;
int64_t min_render_time_allowed_us;
int64_t max_render_time_allowed_us;
@@ -167,7 +195,7 @@ index 34d676f54..78f8dde9b 100644
int64_t next_update_time_us;
now_us = g_get_monotonic_time ();
-@@ -451,7 +501,24 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
+@@ -520,7 +581,24 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
*
*/
last_presentation_time_us = frame_clock->last_presentation_time_us;
@@ -193,7 +221,7 @@ index 34d676f54..78f8dde9b 100644
/*
* However, the last presentation could have happened more than a frame ago.
-@@ -562,8 +629,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
+@@ -635,8 +713,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
frame_clock->pending_reschedule = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
break;
@@ -208,35 +236,44 @@ index 34d676f54..78f8dde9b 100644
break;
}
-@@ -599,11 +670,17 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
+@@ -673,9 +755,15 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
next_update_time_us = g_get_monotonic_time ();
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- break;
- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
- return;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
++ break;
+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
++ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
+ next_update_time_us = g_get_monotonic_time ();
+ frame_clock->state =
+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
-+ break;
+ break;
+- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
+- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
return;
-@@ -612,7 +689,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
- g_warn_if_fail (next_update_time_us != -1);
+@@ -685,7 +773,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
+ frame_clock->next_update_time_us = next_update_time_us;
g_source_set_ready_time (frame_clock->source, next_update_time_us);
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
frame_clock->is_next_presentation_time_valid = FALSE;
}
-@@ -631,6 +707,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
+@@ -693,6 +780,10 @@ void
+ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
+ {
+ int64_t next_update_time_us = -1;
++ TripleBufferingMode current_mode = triple_buffering_mode;
++
++ if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED)
++ current_mode = TRIPLE_BUFFERING_MODE_NEVER;
+
+ if (frame_clock->inhibit_count > 0)
+ {
+@@ -704,6 +795,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
next_update_time_us = g_get_monotonic_time ();
@@ -244,8 +281,8 @@ index 34d676f54..78f8dde9b 100644
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
calculate_next_update_time_us (frame_clock,
-@@ -638,11 +715,28 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
- &frame_clock->next_presentation_time_us);
+@@ -712,11 +804,37 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
+ &frame_clock->min_render_time_allowed_us);
frame_clock->is_next_presentation_time_valid =
(frame_clock->next_presentation_time_us != 0);
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
@@ -256,35 +293,44 @@ index 34d676f54..78f8dde9b 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 ||
-+ triple_buffering_disabled)
++ switch (current_mode)
+ {
-+ /* Force double buffering, disable triple buffering */
++ case TRIPLE_BUFFERING_MODE_NEVER:
+ frame_clock->pending_reschedule = TRUE;
+ return;
++ case TRIPLE_BUFFERING_MODE_AUTO:
++ calculate_next_update_time_us (frame_clock,
++ &next_update_time_us,
++ &frame_clock->next_presentation_time_us,
++ &frame_clock->min_render_time_allowed_us);
++ frame_clock->is_next_presentation_time_valid =
++ (frame_clock->next_presentation_time_us != 0);
++ frame_clock->state =
++ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
++ break;
++ case TRIPLE_BUFFERING_MODE_ALWAYS:
++ next_update_time_us = g_get_monotonic_time ();
++ frame_clock->next_presentation_time_us = 0;
++ frame_clock->is_next_presentation_time_valid = FALSE;
++ frame_clock->state =
++ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
++ break;
+ }
-+
-+ calculate_next_update_time_us (frame_clock,
-+ &next_update_time_us,
-+ &frame_clock->next_presentation_time_us);
-+ frame_clock->is_next_presentation_time_valid =
-+ (frame_clock->next_presentation_time_us != 0);
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
+ break;
+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
frame_clock->pending_reschedule = TRUE;
return;
}
-@@ -650,7 +744,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
- g_warn_if_fail (next_update_time_us != -1);
+@@ -725,7 +843,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
+ frame_clock->next_update_time_us = next_update_time_us;
g_source_set_ready_time (frame_clock->source, next_update_time_us);
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
}
static void
-@@ -676,7 +769,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
- frame_clock->refresh_interval_us;
+@@ -756,7 +873,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
+ frame_clock->refresh_interval_us;
lateness_us = time_us - ideal_dispatch_time_us;
- if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us)
@@ -292,7 +338,11 @@ index 34d676f54..78f8dde9b 100644
frame_clock->last_dispatch_lateness_us = 0;
else
frame_clock->last_dispatch_lateness_us = lateness_us;
-@@ -684,7 +777,21 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
+@@ -765,10 +882,25 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
+ MAX (frame_clock->shortterm.max_dispatch_lateness_us,
+ frame_clock->last_dispatch_lateness_us);
+
++ frame_clock->prev_last_dispatch_time_us = frame_clock->last_dispatch_time_us;
frame_clock->last_dispatch_time_us = time_us;
g_source_set_ready_time (frame_clock->source, -1);
@@ -315,8 +365,8 @@ index 34d676f54..78f8dde9b 100644
frame_count = frame_clock->frame_count++;
-@@ -709,25 +816,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
- frame_clock->listener.user_data);
+@@ -797,25 +929,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
+ result = iface->frame (frame_clock, frame, frame_clock->listener.user_data);
COGL_TRACE_END (ClutterFrameClockFrame);
- switch (frame_clock->state)
@@ -359,7 +409,7 @@ index 34d676f54..78f8dde9b 100644
}
break;
}
-@@ -760,10 +873,12 @@ frame_clock_source_dispatch (GSource *source,
+@@ -848,10 +986,13 @@ frame_clock_source_dispatch (GSource *source,
}
void
@@ -369,23 +419,39 @@ index 34d676f54..78f8dde9b 100644
+ int64_t flip_time_us,
+ ClutterFrameHint hints)
{
++ frame_clock->prev_last_flip_time_us = frame_clock->last_flip_time_us;
frame_clock->last_flip_time_us = flip_time_us;
+ frame_clock->last_flip_hints = hints;
}
GString *
-@@ -894,6 +1009,9 @@ clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
+@@ -963,8 +1104,6 @@ clutter_frame_clock_dispose (GObject *object)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterFrameClock *frame_clock = CLUTTER_FRAME_CLOCK (object);
-+ if (!g_strcmp0 (g_getenv ("MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING"), "1"))
-+ triple_buffering_disabled = TRUE;
+- g_warn_if_fail (frame_clock->state != CLUTTER_FRAME_CLOCK_STATE_DISPATCHING);
+-
+ if (frame_clock->source)
+ {
+ g_signal_emit (frame_clock, signals[DESTROY], 0);
+@@ -985,6 +1124,15 @@ static void
+ clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
++ const char *mode_str;
+
++ mode_str = g_getenv ("MUTTER_DEBUG_TRIPLE_BUFFERING");
++ if (!g_strcmp0 (mode_str, "never"))
++ triple_buffering_mode = TRIPLE_BUFFERING_MODE_NEVER;
++ else if (!g_strcmp0 (mode_str, "auto"))
++ triple_buffering_mode = TRIPLE_BUFFERING_MODE_AUTO;
++ else if (!g_strcmp0 (mode_str, "always"))
++ triple_buffering_mode = TRIPLE_BUFFERING_MODE_ALWAYS;
+
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 91e6b3a13..d750404d5 100644
+index 6fd5de47a..6b44851a6 100644
--- a/clutter/clutter/clutter-frame-clock.h
+++ b/clutter/clutter/clutter-frame-clock.h
@@ -34,6 +34,12 @@ typedef enum _ClutterFrameResult
@@ -401,7 +467,7 @@ index 91e6b3a13..d750404d5 100644
#define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ())
CLUTTER_EXPORT
G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
-@@ -90,8 +96,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
+@@ -92,8 +98,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
CLUTTER_EXPORT
float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock);
@@ -414,22 +480,22 @@ index 91e6b3a13..d750404d5 100644
GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock);
diff --git a/clutter/clutter/clutter-frame-private.h b/clutter/clutter/clutter-frame-private.h
-index e0088564f..06581492f 100644
+index 1eceb8bc0..fb97abeaf 100644
--- a/clutter/clutter/clutter-frame-private.h
+++ b/clutter/clutter/clutter-frame-private.h
-@@ -24,6 +24,7 @@ struct _ClutterFrame
- {
+@@ -35,6 +35,7 @@ struct _ClutterFrame
+
gboolean has_result;
ClutterFrameResult result;
+ ClutterFrameHint hints;
};
- #define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 })
+ CLUTTER_EXPORT
diff --git a/clutter/clutter/clutter-frame.c b/clutter/clutter/clutter-frame.c
-index 3c708da9d..63ae302af 100644
+index 85baef274..413ce9c2b 100644
--- a/clutter/clutter/clutter-frame.c
+++ b/clutter/clutter/clutter-frame.c
-@@ -40,3 +40,16 @@ clutter_frame_set_result (ClutterFrame *frame,
+@@ -113,3 +113,16 @@ clutter_frame_set_result (ClutterFrame *frame,
frame->result = result;
frame->has_result = TRUE;
}
@@ -447,10 +513,10 @@ index 3c708da9d..63ae302af 100644
+ return frame->hints;
+}
diff --git a/clutter/clutter/clutter-frame.h b/clutter/clutter/clutter-frame.h
-index d3608e81c..06c5f7f28 100644
+index 6bac3f4e4..fa97e8bd5 100644
--- a/clutter/clutter/clutter-frame.h
+++ b/clutter/clutter/clutter-frame.h
-@@ -33,4 +33,11 @@ void clutter_frame_set_result (ClutterFrame *frame,
+@@ -55,6 +55,13 @@ void clutter_frame_set_result (ClutterFrame *frame,
CLUTTER_EXPORT
gboolean clutter_frame_has_result (ClutterFrame *frame);
@@ -461,22 +527,24 @@ index d3608e81c..06c5f7f28 100644
+CLUTTER_EXPORT
+ClutterFrameHint clutter_frame_get_hints (ClutterFrame *frame);
+
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFrame, clutter_frame_unref)
+
#endif /* CLUTTER_FRAME_H */
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
-index 14f21024c..914b91a18 100644
+index 5f66d6032..9e821155b 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
-@@ -1252,8 +1252,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
+@@ -1266,8 +1266,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
- _clutter_stage_window_redraw_view (stage_window, view, &frame);
+ _clutter_stage_window_redraw_view (stage_window, view, frame);
- clutter_frame_clock_record_flip_time (frame_clock,
- g_get_monotonic_time ());
+ clutter_frame_clock_record_flip (frame_clock,
+ g_get_monotonic_time (),
-+ clutter_frame_get_hints (&frame));
++ clutter_frame_get_hints (frame));
- clutter_stage_emit_after_paint (stage, view);
+ clutter_stage_emit_after_paint (stage, view, frame);
diff --git a/cogl/cogl/cogl-onscreen-private.h b/cogl/cogl/cogl-onscreen-private.h
index dffe018d2..e0215f750 100644
@@ -491,10 +559,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 ff9e1749a..b25b4af4a 100644
+index 842ececf7..1e2b11dee 100644
--- a/cogl/cogl/cogl-onscreen.c
+++ b/cogl/cogl/cogl-onscreen.c
-@@ -510,6 +510,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen)
+@@ -508,6 +508,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen)
return g_queue_pop_head (&priv->pending_frame_infos);
}
@@ -510,10 +578,10 @@ index ff9e1749a..b25b4af4a 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 ca6f1f44f..a4b1c8cd0 100644
+index db94c7e40..aed22960c 100644
--- a/src/backends/meta-stage-impl.c
+++ b/src/backends/meta-stage-impl.c
-@@ -721,6 +721,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window,
+@@ -770,6 +770,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window,
{
g_autoptr (GError) error = NULL;
@@ -522,24 +590,11 @@ index ca6f1f44f..a4b1c8cd0 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 0bfd3f5ad..3590608ee 100644
---- a/src/backends/native/meta-crtc-kms.c
-+++ b/src/backends/native/meta-crtc-kms.c
-@@ -394,7 +394,7 @@ 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,
- kms_crtc,
- gamma->size,
diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c
-index f4b42c56c..81ce0c627 100644
+index f1b7459fe..8080098a0 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
-@@ -58,19 +58,6 @@
+@@ -59,19 +59,6 @@
#include "wayland/meta-wayland-buffer.h"
#endif
@@ -559,7 +614,7 @@ index f4b42c56c..81ce0c627 100644
static GQuark quark_cursor_sprite = 0;
typedef struct _CrtcCursorData
-@@ -104,19 +91,10 @@ typedef struct _MetaCursorRendererNativeGpuData
+@@ -105,19 +92,10 @@ typedef struct _MetaCursorRendererNativeGpuData
uint64_t cursor_height;
} MetaCursorRendererNativeGpuData;
@@ -580,7 +635,7 @@ index f4b42c56c..81ce0c627 100644
} MetaCursorNativeGpuState;
typedef struct _MetaCursorNativePrivate
-@@ -197,44 +175,17 @@ meta_cursor_renderer_native_finalize (GObject *object)
+@@ -198,44 +176,17 @@ meta_cursor_renderer_native_finalize (GObject *object)
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
}
@@ -629,7 +684,7 @@ index f4b42c56c..81ce0c627 100644
}
static void
-@@ -309,10 +260,7 @@ assign_cursor_plane (MetaCursorRendererNative *native,
+@@ -312,10 +263,7 @@ assign_cursor_plane (MetaCursorRendererNative *native,
MetaKmsUpdate *kms_update;
MetaKmsPlaneAssignment *plane_assignment;
@@ -641,18 +696,7 @@ index f4b42c56c..81ce0c627 100644
kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
kms_device = meta_kms_crtc_get_device (kms_crtc);
-@@ -341,8 +289,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,
-@@ -363,13 +311,6 @@ assign_cursor_plane (MetaCursorRendererNative *native,
+@@ -365,13 +313,6 @@ assign_cursor_plane (MetaCursorRendererNative *native,
native);
crtc_cursor_data->buffer = buffer;
@@ -666,16 +710,7 @@ index f4b42c56c..81ce0c627 100644
}
static float
-@@ -494,7 +435,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);
- }
-
-@@ -602,19 +543,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite,
+@@ -613,19 +554,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite,
if (!cursor_gpu_state)
return FALSE;
@@ -696,7 +731,7 @@ index f4b42c56c..81ce0c627 100644
}
static void
-@@ -1119,16 +1048,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu,
+@@ -1132,16 +1061,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu,
static void
cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state)
{
@@ -715,7 +750,7 @@ index f4b42c56c..81ce0c627 100644
g_free (cursor_gpu_state);
}
-@@ -1165,14 +1092,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite)
+@@ -1178,14 +1105,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))
@@ -731,7 +766,7 @@ index f4b42c56c..81ce0c627 100644
}
static void
-@@ -1410,35 +1330,7 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
+@@ -1423,35 +1343,7 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
return;
}
@@ -768,7 +803,7 @@ index f4b42c56c..81ce0c627 100644
}
static gboolean
-@@ -1605,7 +1497,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
+@@ -1638,7 +1530,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
return;
@@ -777,7 +812,7 @@ index f4b42c56c..81ce0c627 100644
is_cursor_scale_and_transform_valid (renderer, cursor_sprite))
return;
-@@ -1750,8 +1642,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
+@@ -1783,8 +1675,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
return;
}
@@ -788,7 +823,7 @@ index f4b42c56c..81ce0c627 100644
}
}
#endif
-@@ -1775,7 +1667,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
+@@ -1808,7 +1700,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
return;
@@ -798,87 +833,41 @@ index f4b42c56c..81ce0c627 100644
return;
diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c
-index ee9e19d2d..0da9a7785 100644
+index e5405428c..48e864ca8 100644
--- a/src/backends/native/meta-kms-crtc.c
+++ b/src/backends/native/meta-kms-crtc.c
-@@ -32,6 +32,12 @@ typedef struct _MetaKmsCrtcPropTable
- MetaKmsProp props[META_KMS_CRTC_N_PROPS];
- } MetaKmsCrtcPropTable;
-
-+typedef struct
-+{
-+ MetaDrmBuffer *front, *back;
-+ gboolean back_is_set;
-+} PlaneState;
-+
- struct _MetaKmsCrtc
- {
- GObject parent;
-@@ -44,6 +50,8 @@ struct _MetaKmsCrtc
+@@ -46,6 +46,8 @@ struct _MetaKmsCrtc
MetaKmsCrtcState current_state;
MetaKmsCrtcPropTable prop_table;
+
-+ GHashTable *plane_states;
++ MetaSwapChain *swap_chain;
};
G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT)
-@@ -403,20 +411,91 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
- return crtc;
+@@ -97,6 +99,12 @@ meta_kms_crtc_get_prop_drm_value (MetaKmsCrtc *crtc,
+ return meta_kms_prop_convert_value (prop, value);
}
-+void
-+meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc,
-+ uint32_t plane_id,
-+ MetaDrmBuffer *buffer)
-+{
-+ gpointer key = GUINT_TO_POINTER (plane_id);
-+ PlaneState *plane_state;
-+
-+ plane_state = g_hash_table_lookup (crtc->plane_states, key);
-+ if (plane_state == NULL)
-+ {
-+ plane_state = g_new0 (PlaneState, 1);
-+ g_hash_table_insert (crtc->plane_states, key, plane_state);
-+ }
-+
-+ plane_state->back_is_set = TRUE; /* note buffer may be NULL */
-+ g_set_object (&plane_state->back, buffer);
-+}
-+
-+static void
-+swap_plane_buffers (gpointer key,
-+ gpointer value,
-+ gpointer user_data)
-+{
-+ PlaneState *plane_state = value;
-+
-+ if (plane_state->back_is_set)
-+ {
-+ g_set_object (&plane_state->front, plane_state->back);
-+ g_clear_object (&plane_state->back);
-+ plane_state->back_is_set = FALSE;
-+ }
-+}
-+
-+void
-+meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc)
++MetaSwapChain *
++meta_kms_crtc_get_swap_chain (MetaKmsCrtc *crtc)
+{
-+ g_hash_table_foreach (crtc->plane_states, swap_plane_buffers, NULL);
-+}
-+
-+void
-+meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc)
-+{
-+ g_hash_table_remove_all (crtc->plane_states);
++ return crtc->swap_chain;
+}
+
+ gboolean
+ meta_kms_crtc_is_active (MetaKmsCrtc *crtc)
+ {
+@@ -463,12 +471,23 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
+ return crtc;
+ }
+
+static void
+meta_kms_crtc_dispose (GObject *object)
+{
+ MetaKmsCrtc *crtc = META_KMS_CRTC (object);
+
-+ meta_kms_crtc_release_buffers (crtc);
++ meta_swap_chain_release_buffers (crtc->swap_chain);
+
+ G_OBJECT_CLASS (meta_kms_crtc_parent_class)->dispose (object);
+}
@@ -888,34 +877,20 @@ index ee9e19d2d..0da9a7785 100644
{
MetaKmsCrtc *crtc = META_KMS_CRTC (object);
- clear_gamma_state (&crtc->current_state);
-+ g_hash_table_unref (crtc->plane_states);
+ g_clear_pointer (&crtc->current_state.gamma.value, meta_gamma_lut_free);
++ g_clear_object (&crtc->swap_chain);
G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object);
}
-
-+static void
-+destroy_plane_state (gpointer data)
-+{
-+ PlaneState *plane_state = data;
-+
-+ g_clear_object (&plane_state->front);
-+ g_clear_object (&plane_state->back);
-+ g_free (plane_state);
-+}
-+
- static void
- meta_kms_crtc_init (MetaKmsCrtc *crtc)
+@@ -478,6 +497,7 @@ meta_kms_crtc_init (MetaKmsCrtc *crtc)
{
crtc->current_state.gamma.size = 0;
-+ crtc->plane_states = g_hash_table_new_full (NULL,
-+ NULL,
-+ NULL,
-+ destroy_plane_state);
+ crtc->current_state.gamma.value = NULL;
++ crtc->swap_chain = meta_swap_chain_new ();
}
static void
-@@ -424,5 +503,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass)
+@@ -485,5 +505,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -923,35 +898,29 @@ index ee9e19d2d..0da9a7785 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 54801dd96..deafeb61e 100644
+index 25fb71edb..61013bebd 100644
--- a/src/backends/native/meta-kms-crtc.h
+++ b/src/backends/native/meta-kms-crtc.h
@@ -25,6 +25,7 @@
#include <xf86drmMode.h>
#include "backends/native/meta-kms-types.h"
-+#include "backends/native/meta-drm-buffer.h"
++#include "backends/native/meta-swap-chain.h"
+ #include "backends/meta-backend-types.h"
#include "core/util-private.h"
#include "meta/boxes.h"
+@@ -64,4 +65,6 @@ int meta_kms_crtc_get_idx (MetaKmsCrtc *crtc);
+ META_EXPORT_TEST
+ gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc);
-@@ -84,4 +85,12 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc,
- const uint16_t *green,
- const uint16_t *blue);
-
-+void meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc,
-+ uint32_t plane_id,
-+ MetaDrmBuffer *buffer);
-+
-+void meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc);
-+
-+void meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc);
++MetaSwapChain * meta_kms_crtc_get_swap_chain (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 e938e4522..5271cbecf 100644
+index 83b217274..5024b876d 100644
--- a/src/backends/native/meta-kms-impl-device-atomic.c
+++ b/src/backends/native/meta-kms-impl-device-atomic.c
-@@ -457,6 +457,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
+@@ -507,6 +507,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
{
MetaKmsPlaneAssignment *plane_assignment = update_entry;
MetaKmsPlane *plane = plane_assignment->plane;
@@ -959,20 +928,20 @@ index e938e4522..5271cbecf 100644
MetaDrmBuffer *buffer;
MetaKmsFbDamage *fb_damage;
uint32_t prop_id;
-@@ -609,6 +610,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
+@@ -659,6 +660,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
error))
return FALSE;
}
+
+ if (!(flags & META_KMS_UPDATE_FLAG_TEST_ONLY))
-+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc,
-+ meta_kms_plane_get_id (plane),
-+ buffer);
++ meta_swap_chain_push_buffer (meta_kms_crtc_get_swap_chain (plane_assignment->crtc),
++ meta_kms_plane_get_id (plane),
++ G_OBJECT (buffer));
+
return TRUE;
}
-@@ -986,7 +993,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
+@@ -1002,7 +1009,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
req,
blob_ids,
meta_kms_update_get_plane_assignments (update),
@@ -982,19 +951,19 @@ index e938e4522..5271cbecf 100644
&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 648de51c6..53d76291a 100644
+index 341d54cc7..c739788ae 100644
--- a/src/backends/native/meta-kms-impl-device-simple.c
+++ b/src/backends/native/meta-kms-impl-device-simple.c
@@ -486,6 +486,8 @@ process_mode_set (MetaKmsImplDevice *impl_device,
return FALSE;
}
-+ meta_kms_crtc_on_scanout_started (crtc);
++ meta_swap_chain_swap_buffers (meta_kms_crtc_get_swap_chain (crtc));
+
if (drm_mode)
{
g_hash_table_replace (impl_device_simple->cached_mode_sets,
-@@ -550,7 +552,7 @@ is_timestamp_earlier_than (uint64_t ts1,
+@@ -555,7 +557,7 @@ is_timestamp_earlier_than (uint64_t ts1,
typedef struct _RetryPageFlipData
{
MetaKmsCrtc *crtc;
@@ -1003,7 +972,7 @@ index 648de51c6..53d76291a 100644
MetaKmsPageFlipData *page_flip_data;
float refresh_rate;
uint64_t retry_time_us;
-@@ -563,6 +565,7 @@ retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
+@@ -568,6 +570,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);
@@ -1011,7 +980,7 @@ index 648de51c6..53d76291a 100644
g_free (retry_page_flip_data);
}
-@@ -630,16 +633,21 @@ retry_page_flips (gpointer user_data)
+@@ -635,16 +638,21 @@ retry_page_flips (gpointer user_data)
}
else
{
@@ -1035,7 +1004,7 @@ index 648de51c6..53d76291a 100644
DRM_MODE_PAGE_FLIP_EVENT,
retry_page_flip_data->page_flip_data);
}
-@@ -726,7 +734,7 @@ retry_page_flips (gpointer user_data)
+@@ -731,7 +739,7 @@ retry_page_flips (gpointer user_data)
static void
schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple,
MetaKmsCrtc *crtc,
@@ -1044,7 +1013,7 @@ index 648de51c6..53d76291a 100644
float refresh_rate,
MetaKmsPageFlipData *page_flip_data,
MetaKmsCustomPageFlip *custom_page_flip)
-@@ -741,7 +749,7 @@ schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple,
+@@ -746,7 +754,7 @@ schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple,
retry_page_flip_data = g_new0 (RetryPageFlipData, 1);
*retry_page_flip_data = (RetryPageFlipData) {
.crtc = crtc,
@@ -1053,16 +1022,16 @@ index 648de51c6..53d76291a 100644
.page_flip_data = page_flip_data,
.refresh_rate = refresh_rate,
.retry_time_us = retry_time_us,
-@@ -875,6 +883,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple,
+@@ -880,6 +888,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple,
return FALSE;
}
-+ meta_kms_crtc_on_scanout_started (crtc);
++ meta_swap_chain_swap_buffers (meta_kms_crtc_get_swap_chain (crtc));
+
if (!impl_device_simple->mode_set_fallback_feedback_source)
{
GSource *source;
-@@ -999,20 +1009,20 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device,
+@@ -1004,20 +1014,20 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device,
cached_mode_set = get_cached_mode_set (impl_device_simple, crtc);
if (cached_mode_set)
{
@@ -1087,7 +1056,7 @@ index 648de51c6..53d76291a 100644
refresh_rate,
page_flip_data,
g_steal_pointer (&custom_page_flip));
-@@ -1302,7 +1312,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
+@@ -1298,7 +1308,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
{
case META_KMS_PLANE_TYPE_PRIMARY:
/* Handled as part of the mode-set and page flip. */
@@ -1096,7 +1065,7 @@ index 648de51c6..53d76291a 100644
case META_KMS_PLANE_TYPE_CURSOR:
if (!process_cursor_plane_assignment (impl_device, update,
plane_assignment,
-@@ -1316,7 +1326,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
+@@ -1312,7 +1322,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
}
else
{
@@ -1105,24 +1074,37 @@ index 648de51c6..53d76291a 100644
}
case META_KMS_PLANE_TYPE_OVERLAY:
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
-@@ -1329,6 +1339,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
+@@ -1325,6 +1335,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
}
g_assert_not_reached ();
+
+assigned:
-+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc,
-+ meta_kms_plane_get_id (plane),
-+ plane_assignment->buffer);
++ meta_swap_chain_push_buffer (meta_kms_crtc_get_swap_chain (plane_assignment->crtc),
++ meta_kms_plane_get_id (plane),
++ G_OBJECT (plane_assignment->buffer));
+ return TRUE;
}
static gboolean
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
-index d9ea27637..4eeb182f6 100644
+index d56636d55..b7a0ddd24 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
-@@ -1204,8 +1204,12 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
+@@ -1259,11 +1259,25 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
+ return TRUE;
+ }
+
++static void
++release_buffers (gpointer data,
++ gpointer user_data)
++{
++ MetaKmsCrtc *crtc = data;
++ MetaSwapChain *swap_chain = meta_kms_crtc_get_swap_chain (crtc);
++
++ meta_swap_chain_release_buffers (swap_chain);
++}
++
void
meta_kms_impl_device_prepare_shutdown (MetaKmsImplDevice *impl_device)
{
@@ -1130,13 +1112,13 @@ index d9ea27637..4eeb182f6 100644
+ 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);
++ g_list_foreach (priv->crtcs, 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 c1c29905c..a6fbaf2f8 100644
+index c1c29905c..09c2d8fad 100644
--- a/src/backends/native/meta-kms-page-flip.c
+++ b/src/backends/native/meta-kms-page-flip.c
@@ -25,6 +25,7 @@
@@ -1151,48 +1133,16 @@ index c1c29905c..a6fbaf2f8 100644
meta_assert_not_in_kms_impl (kms);
-+ meta_kms_crtc_on_scanout_started (page_flip_data->crtc);
++ meta_swap_chain_swap_buffers (meta_kms_crtc_get_swap_chain (page_flip_data->crtc));
+
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 3a648ba0d..cfcf4b050 100644
---- a/src/backends/native/meta-kms-update-private.h
-+++ b/src/backends/native/meta-kms-update-private.h
-@@ -137,6 +137,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,
- MetaKmsPlaneRotation rotation);
-
diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c
-index 4c34000ef..cbbf1a0da 100644
+index ceb298a80..02d9d0159 100644
--- a/src/backends/native/meta-kms-update.c
+++ b/src/backends/native/meta-kms-update.c
-@@ -25,12 +25,14 @@
- #include "backends/meta-display-config-shared.h"
- #include "backends/native/meta-kms-connector.h"
- #include "backends/native/meta-kms-crtc.h"
-+#include "backends/native/meta-kms-device.h"
- #include "backends/native/meta-kms-mode-private.h"
- #include "backends/native/meta-kms-plane.h"
-
- struct _MetaKmsUpdate
- {
- MetaKmsDevice *device;
-+ GHashTable *crtcs;
-
- gboolean is_locked;
- uint64_t sequence_number;
-@@ -149,6 +151,7 @@ static void
+@@ -183,6 +183,7 @@ static void
meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment)
{
g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free);
@@ -1200,7 +1150,7 @@ index 4c34000ef..cbbf1a0da 100644
g_free (plane_assignment);
}
-@@ -228,7 +231,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update,
+@@ -265,7 +266,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update,
.update = update,
.crtc = crtc,
.plane = plane,
@@ -1209,134 +1159,11 @@ index 4c34000ef..cbbf1a0da 100644
.src_rect = src_rect,
.dst_rect = dst_rect,
.flags = flags,
-@@ -237,6 +240,8 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update,
- update->plane_assignments = g_list_prepend (update->plane_assignments,
- plane_assignment);
-
-+ g_hash_table_add (update->crtcs, crtc);
-+
- return plane_assignment;
- }
-
-@@ -251,6 +256,8 @@ meta_kms_update_unassign_plane (MetaKmsUpdate *update,
- g_assert (meta_kms_crtc_get_device (crtc) == update->device);
- g_assert (meta_kms_plane_get_device (plane) == update->device);
-
-+ drop_plane_assignment (update, plane, NULL);
-+
- plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1);
- *plane_assignment = (MetaKmsPlaneAssignment) {
- .update = update,
-@@ -262,6 +269,8 @@ meta_kms_update_unassign_plane (MetaKmsUpdate *update,
- update->plane_assignments = g_list_prepend (update->plane_assignments,
- plane_assignment);
-
-+ g_hash_table_add (update->crtcs, crtc);
-+
- return plane_assignment;
- }
-
-@@ -284,6 +293,8 @@ meta_kms_update_mode_set (MetaKmsUpdate *update,
- };
-
- update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
-+
-+ g_hash_table_add (update->crtcs, crtc);
- }
-
- static MetaKmsConnectorUpdate *
-@@ -292,6 +303,8 @@ ensure_connector_update (MetaKmsUpdate *update,
- {
- GList *l;
- MetaKmsConnectorUpdate *connector_update;
-+ MetaKmsDevice *device;
-+ const MetaKmsConnectorState *state;
-
- for (l = update->connector_updates; l; l = l->next)
- {
-@@ -306,6 +319,23 @@ ensure_connector_update (MetaKmsUpdate *update,
-
- update->connector_updates = g_list_prepend (update->connector_updates,
- connector_update);
-+ device = meta_kms_connector_get_device (connector);
-+ state = meta_kms_connector_get_current_state (connector);
-+ if (device && state && state->current_crtc_id)
-+ {
-+ GList *l;
-+
-+ for (l = meta_kms_device_get_crtcs (device); l; l = l->next)
-+ {
-+ MetaKmsCrtc *kms_crtc = l->data;
-+
-+ if (meta_kms_crtc_get_id (kms_crtc) == state->current_crtc_id)
-+ {
-+ g_hash_table_add (update->crtcs, kms_crtc);
-+ break;
-+ }
-+ }
-+ }
-
- return connector_update;
- }
-@@ -416,6 +446,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_add (update->crtcs, crtc);
- }
-
- void
-@@ -679,6 +711,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_contains (update->crtcs, crtc);
-+}
-+
-+void
-+meta_kms_update_include_crtc (MetaKmsUpdate *update,
-+ MetaKmsCrtc *crtc)
-+{
-+ g_hash_table_add (update->crtcs, crtc);
-+}
-+
- MetaKmsCustomPageFlip *
- meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update)
- {
-@@ -707,12 +753,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 21be532a2..b8dba8d0e 100644
+index d3a840b31..ce6fb4337 100644
--- a/src/backends/native/meta-kms.c
+++ b/src/backends/native/meta-kms.c
-@@ -23,6 +23,7 @@
- #include "backends/native/meta-kms-private.h"
-
- #include "backends/native/meta-backend-native.h"
-+#include "backends/native/meta-kms-crtc.h"
- #include "backends/native/meta-kms-device-private.h"
- #include "backends/native/meta-kms-impl.h"
- #include "backends/native/meta-kms-update-private.h"
-@@ -177,10 +178,17 @@ struct _MetaKms
+@@ -177,6 +177,8 @@ struct _MetaKms
GList *pending_callbacks;
guint callback_source_id;
@@ -1345,141 +1172,17 @@ index 21be532a2..b8dba8d0e 100644
};
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
-
-+static MetaKmsFeedback *
-+meta_kms_post_update_sync (MetaKms *kms,
-+ MetaKmsUpdate *update,
-+ MetaKmsUpdateFlag flags);
-+
- void
- meta_kms_discard_pending_updates (MetaKms *kms)
- {
-@@ -247,12 +255,105 @@ meta_kms_take_pending_update (MetaKms *kms,
- return NULL;
- }
-
-+MetaKmsUpdate *
-+meta_kms_ensure_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ MetaKmsUpdate *update;
-+
-+ update = meta_kms_get_pending_update_for_crtc (kms, crtc);
-+ if (update == NULL)
-+ {
-+ update = meta_kms_update_new (meta_kms_crtc_get_device (crtc));
-+ meta_kms_update_include_crtc (update, crtc);
-+ meta_kms_add_pending_update (kms, update);
-+ }
-+
-+ return update;
-+}
-+
-+static MetaKmsUpdate *
-+meta_kms_find_compatible_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc,
-+ gboolean take)
-+{
-+ MetaKmsDevice *device;
-+ MetaKmsUpdate *update;
-+ GList *l;
-+
-+ for (l = kms->pending_updates; l; l = l->next)
-+ {
-+ update = l->data;
-+ if (meta_kms_update_includes_crtc (update, crtc))
-+ goto found;
-+ }
-+
-+ device = meta_kms_crtc_get_device (crtc);
-+
-+ for (l = kms->pending_updates; l; l = l->next)
-+ {
-+ update = l->data;
-+ if (meta_kms_update_get_device (update) == device &&
-+ meta_kms_update_get_mode_sets (update))
-+ goto found;
-+ }
-+
-+ return NULL;
-+
-+found:
-+ if (take)
-+ kms->pending_updates = g_list_delete_link (kms->pending_updates, l);
-+ return update;
-+}
-+
-+MetaKmsUpdate *
-+meta_kms_get_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, FALSE);
-+}
-+
-+static MetaKmsUpdate *
-+meta_kms_take_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, TRUE);
-+}
-+
- MetaKmsFeedback *
- meta_kms_post_pending_update_sync (MetaKms *kms,
- MetaKmsDevice *device,
- MetaKmsUpdateFlag flags)
- {
- MetaKmsUpdate *update;
-+
-+ update = meta_kms_take_pending_update (kms, device);
-+ if (!update)
-+ return NULL;
-+
-+ return meta_kms_post_update_sync (kms, update, flags);
-+}
-+
-+MetaKmsFeedback *
-+meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms,
-+ MetaKmsCrtc *crtc,
-+ MetaKmsUpdateFlag flags)
-+{
-+ MetaKmsUpdate *update;
-+
-+ update = meta_kms_take_pending_update_for_crtc (kms, crtc);
-+ if (!update)
-+ return NULL;
-+
-+ return meta_kms_post_update_sync (kms, update, flags);
-+}
-+
-+static MetaKmsFeedback *
-+meta_kms_post_update_sync (MetaKms *kms,
-+ MetaKmsUpdate *update,
-+ MetaKmsUpdateFlag flags)
-+{
-+ MetaKmsDevice *device = meta_kms_update_get_device (update);
- MetaKmsFeedback *feedback;
- GList *result_listeners;
- GList *l;
-@@ -260,10 +361,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);
-@@ -752,10 +849,18 @@ prepare_shutdown_in_impl (MetaKmsImpl *impl,
- void
- meta_kms_prepare_shutdown (MetaKms *kms)
+@@ -599,6 +601,7 @@ static void
+ on_prepare_shutdown (MetaBackend *backend,
+ MetaKms *kms)
{
+ kms->shutting_down = TRUE;
-+
meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL);
flush_callbacks (kms);
}
+@@ -639,6 +642,12 @@ meta_kms_new (MetaBackend *backend,
+ return kms;
+ }
+gboolean
+meta_kms_is_shutting_down (MetaKms *kms)
@@ -1491,39 +1194,12 @@ index 21be532a2..b8dba8d0e 100644
meta_kms_finalize (GObject *object)
{
diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h
-index bd9fe5cea..e8fe2e418 100644
+index fe4fef1a0..88421ed28 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);
-@@ -68,6 +78,8 @@ MetaKmsDevice * meta_kms_create_device (MetaKms *kms,
-
- void meta_kms_prepare_shutdown (MetaKms *kms);
+@@ -51,6 +51,8 @@ MetaKmsDevice * meta_kms_create_device (MetaKms *kms,
+ MetaKmsDeviceFlag flags,
+ GError **error);
+gboolean meta_kms_is_shutting_down (MetaKms *kms);
+
@@ -1531,85 +1207,56 @@ index bd9fe5cea..e8fe2e418 100644
MetaKmsFlags flags,
GError **error);
diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
-index a107a99bb..79cf78963 100644
+index 1ab117eb9..1c157ecf3 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;
- } gbm;
+@@ -72,7 +72,7 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState
struct {
MetaDrmBufferDumb *current_dumb_fb;
- MetaDrmBufferDumb *dumb_fbs[2];
+ MetaDrmBufferDumb *dumb_fbs[3];
-+ MetaDrmBuffer *source_fbs[3];
} cpu;
gboolean noted_primary_gpu_copy_ok;
-@@ -94,8 +93,8 @@ struct _MetaOnscreenNative
+@@ -93,8 +93,13 @@ struct _MetaOnscreenNative
struct {
struct gbm_surface *surface;
- MetaDrmBuffer *current_fb;
MetaDrmBuffer *next_fb;
+ MetaDrmBuffer *stalled_fb;
++
++ /* Temporary workaround for the scanout-failed signal wanting the buffer
++ * to live longer than it does, and then it doesn't use it anyway...
++ */
++ MetaDrmBuffer *direct_fb;
} gbm;
#ifdef HAVE_EGL_DEVICE
-@@ -107,69 +106,25 @@ struct _MetaOnscreenNative
- #endif
-
- MetaRendererView *view;
+@@ -116,6 +121,14 @@ struct _MetaOnscreenNative
+ gulong privacy_screen_changed_handler_id;
+ gulong color_space_changed_handler_id;
+ gulong hdr_metadata_changed_handler_id;
+
+ unsigned int swaps_pending;
++
+ struct {
+ int *rectangles; /* 4 x n_rectangles */
+ int n_rectangles;
++ ClutterFrame *frame;
+ } next_post;
};
G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
- COGL_TYPE_ONSCREEN_EGL)
+@@ -123,40 +136,17 @@ G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
-+static void
-+try_post_latest_swap (CoglOnscreen *onscreen);
-+
- static gboolean
- init_secondary_gpu_state (MetaRendererNative *renderer_native,
- CoglOnscreen *onscreen,
- GError **error);
+ static GQuark blit_source_quark = 0;
--static void
--swap_secondary_drm_fb (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
--
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- if (!secondary_gpu_state)
-- return;
--
-- g_set_object (&secondary_gpu_state->gbm.current_fb,
-- secondary_gpu_state->gbm.next_fb);
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
--}
--
--static void
--free_current_secondary_bo (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
--
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- if (!secondary_gpu_state)
-- return;
--
-- g_clear_object (&secondary_gpu_state->gbm.current_fb);
--}
+-static gboolean
+-init_secondary_gpu_state (MetaRendererNative *renderer_native,
+- CoglOnscreen *onscreen,
+- GError **error);
-
-static void
-free_current_bo (CoglOnscreen *onscreen)
@@ -1617,10 +1264,9 @@ index a107a99bb..79cf78963 100644
- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-
- g_clear_object (&onscreen_native->gbm.current_fb);
-- free_current_secondary_bo (onscreen);
-}
-
--static void
+ static void
-meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
-{
- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
@@ -1632,14 +1278,26 @@ index a107a99bb..79cf78963 100644
-
- g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
- g_clear_object (&onscreen_native->gbm.next_fb);
--
-- swap_secondary_drm_fb (onscreen);
-}
--
++try_post_latest_swap (CoglOnscreen *onscreen);
+
+ static void
+-meta_onscreen_native_clear_next_fb (CoglOnscreen *onscreen)
+-{
+- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
++post_finish_frame (MetaOnscreenNative *onscreen_native,
++ MetaKmsUpdate *kms_update);
+
+- g_clear_object (&onscreen_native->gbm.next_fb);
+-}
++static gboolean
++init_secondary_gpu_state (MetaRendererNative *renderer_native,
++ CoglOnscreen *onscreen,
++ GError **error);
+
static void
maybe_update_frame_info (MetaCrtc *crtc,
- CoglFrameInfo *frame_info,
-@@ -205,7 +160,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
+@@ -193,7 +183,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
info = cogl_onscreen_pop_head_frame_info (onscreen);
@@ -1648,7 +1306,7 @@ index a107a99bb..79cf78963 100644
_cogl_onscreen_notify_frame_sync (onscreen, info);
_cogl_onscreen_notify_complete (onscreen, info);
-@@ -234,7 +189,7 @@ notify_view_crtc_presented (MetaRendererView *view,
+@@ -228,7 +218,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);
@@ -1657,24 +1315,33 @@ index a107a99bb..79cf78963 100644
}
static int64_t
-@@ -296,6 +251,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
+@@ -284,15 +274,13 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
+ CoglFrameInfo *frame_info;
+
+ frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
+- g_warn_if_fail (!onscreen_native->gbm.next_fb);
+-
meta_onscreen_native_notify_frame_complete (onscreen);
+ try_post_latest_swap (onscreen);
}
static void
-@@ -345,7 +301,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc,
+@@ -342,7 +330,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);
+- meta_onscreen_native_clear_next_fb (onscreen);
+ try_post_latest_swap (onscreen);
}
static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
-@@ -406,18 +362,40 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data,
+@@ -403,18 +391,40 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data,
}
#endif /* HAVE_EGL_DEVICE */
@@ -1683,10 +1350,9 @@ index a107a99bb..79cf78963 100644
+static void
+drop_stalled_swap (CoglOnscreen *onscreen)
{
-+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
CoglFrameInfo *frame_info;
-
-- meta_onscreen_native_swap_drm_fb (onscreen);
++ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (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.
@@ -1695,7 +1361,8 @@ index a107a99bb..79cf78963 100644
+ return;
+
+ onscreen_native->swaps_pending--;
-+
+
+- meta_onscreen_native_swap_drm_fb (onscreen);
+ g_clear_object (&onscreen_native->gbm.stalled_fb);
frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
@@ -1718,43 +1385,25 @@ index a107a99bb..79cf78963 100644
static void
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;
+@@ -431,7 +441,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
+ MetaRendererNativeGpuData *renderer_gpu_data;
+ MetaGpuKms *gpu_kms;
- MetaDrmBuffer *buffer;
+ g_autoptr (MetaDrmBuffer) buffer = NULL;
MetaKmsPlaneAssignment *plane_assignment;
COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
-@@ -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,
+@@ -446,7 +456,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
switch (renderer_gpu_data->mode)
{
case META_RENDERER_NATIVE_MODE_GBM:
-- if (gpu_kms == render_gpu)
-- {
-- buffer = onscreen_native->gbm.next_fb;
-- }
-- else
-- {
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- buffer = secondary_gpu_state->gbm.next_fb;
-- }
+- buffer = onscreen_native->gbm.next_fb;
+ buffer = g_steal_pointer (&onscreen_native->gbm.next_fb);
plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms,
buffer,
-@@ -474,6 +443,11 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
+@@ -457,6 +467,11 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
meta_kms_plane_assignment_set_fb_damage (plane_assignment,
rectangles, n_rectangles);
}
@@ -1766,187 +1415,7 @@ index a107a99bb..79cf78963 100644
break;
case META_RENDERER_NATIVE_MODE_SURFACELESS:
g_assert_not_reached ();
-@@ -509,7 +483,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)
- {
-@@ -537,13 +511,41 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen,
- kms_update);
- }
-
-+static void
-+hold_primary_gpu_fb_for_secondary_gpu_scanout (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
-+ MetaDrmBuffer *primary_gpu_fb,
-+ MetaDrmBuffer *secondary_gpu_fb)
-+{
-+ if (META_IS_DRM_BUFFER_DUMB (secondary_gpu_fb))
-+ {
-+ MetaDrmBufferDumb *dumb_fb = META_DRM_BUFFER_DUMB (secondary_gpu_fb);
-+ int i;
-+ const int n = G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs);
-+
-+ for (i = 0; i < n; i++)
-+ {
-+ if (dumb_fb == secondary_gpu_state->cpu.dumb_fbs[i])
-+ {
-+ g_set_object (&secondary_gpu_state->cpu.source_fbs[i],
-+ primary_gpu_fb);
-+ break;
-+ }
-+ }
-+
-+ g_warn_if_fail (i < n);
-+ }
-+}
-+
- static void
- secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
- {
- unsigned i;
-
- for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
-- g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
-+ {
-+ g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
-+ g_clear_object (&secondary_gpu_state->cpu.source_fbs[i]);
-+ }
- }
-
- static void
-@@ -568,8 +570,6 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta
- NULL);
- }
-
-- g_clear_object (&secondary_gpu_state->gbm.current_fb);
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
- g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
-
- secondary_gpu_release_dumb (secondary_gpu_state);
-@@ -577,11 +577,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;
-@@ -589,7 +589,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)
- {
-@@ -603,16 +603,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)
- {
-@@ -629,16 +622,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);
-@@ -654,9 +647,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);
-
-@@ -669,13 +659,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,
-@@ -687,7 +677,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,
-@@ -697,7 +687,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);
-@@ -717,25 +707,30 @@ 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 *
+@@ -698,12 +713,17 @@ static MetaDrmBufferDumb *
secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
{
MetaDrmBufferDumb *current_dumb_fb;
@@ -1967,229 +1436,45 @@ index a107a99bb..79cf78963 100644
+ 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,13 +756,13 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
-
- if (!secondary_gpu_state ||
- secondary_gpu_state->egl_surface == EGL_NO_SURFACE)
-- return FALSE;
-+ return NULL;
-
- primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native);
- 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);
-@@ -790,7 +785,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 =
-@@ -808,7 +803,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
-@@ -821,7 +816,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
- &error))
- {
- g_object_unref (dmabuf_fb);
-- return FALSE;
-+ return NULL;
- }
- }
- else
-@@ -838,20 +833,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)
-@@ -903,17 +897,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 MetaDrmBuffer *
+@@ -1041,7 +1061,6 @@ on_swap_buffer_update_result (const MetaKmsFeedback *kms_feedback,
+ frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
--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)");
-@@ -939,10 +935,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)
- {
-@@ -952,9 +949,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)
- {
-@@ -966,11 +963,15 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
- break;
- }
- }
-+
-+ return copy;
+ meta_onscreen_native_notify_frame_complete (onscreen);
+- meta_onscreen_native_clear_next_fb (onscreen);
}
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;
-@@ -983,6 +984,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,
-@@ -990,23 +992,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);
- }
- }
-
-@@ -1040,34 +1049,39 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+@@ -1058,31 +1077,35 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
- MetaRenderer *renderer = META_RENDERER (renderer_native);
- MetaBackend *backend = meta_renderer_get_backend (renderer);
-- MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
- MetaMonitorManager *monitor_manager =
- meta_backend_get_monitor_manager (backend);
-- MetaKms *kms = meta_backend_native_get_kms (backend_native);
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
MetaDeviceFile *render_device_file;
ClutterFrame *frame = user_data;
+- MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
+- MetaKmsUpdate *kms_update;
CoglOnscreenClass *parent_class;
gboolean egl_context_changed = FALSE;
- MetaPowerSave power_save_mode;
g_autoptr (GError) error = NULL;
MetaDrmBufferFlags buffer_flags;
MetaDrmBufferGbm *buffer_gbm;
+ g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL;
+ g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL;
- MetaKmsCrtc *kms_crtc;
- MetaKmsDevice *kms_device;
-- MetaKmsUpdateFlag flags;
- g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-- const GError *feedback_error;
-+ 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)");
-- update_secondary_gpu_state_pre_swap_buffers (onscreen,
-- rectangles,
-- n_rectangles);
+ if (meta_is_topic_enabled (META_DEBUG_KMS))
+ {
+ unsigned int frames_pending =
@@ -2203,46 +1488,14 @@ index a107a99bb..79cf78963 100644
+ "?");
+ }
+
-+ 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,
-@@ -1083,9 +1097,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ secondary_gpu_fb =
+ update_secondary_gpu_state_pre_swap_buffers (onscreen,
+ rectangles,
+@@ -1138,7 +1161,15 @@ 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;
-@@ -1103,8 +1114,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- return;
- }
-
-- onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
--
-+ primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm));
- break;
- case META_RENDERER_NATIVE_MODE_SURFACELESS:
- g_assert_not_reached ();
-@@ -1115,7 +1125,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);
@@ -2252,42 +1505,34 @@ index a107a99bb..79cf78963 100644
+ 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
-+ }
-+
+ if (onscreen_native->secondary_gpu_state)
+ g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb);
+ else
+@@ -1152,6 +1183,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ #endif
+ }
+
+ clutter_frame_set_result (frame,
+ CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-
++
/*
* If we changed EGL context, cogl will have the wrong idea about what is
-@@ -1126,23 +1175,77 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ * current, making it fail to set it when it needs to. Avoid that by making
+@@ -1161,12 +1195,82 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
if (egl_context_changed)
_cogl_winsys_egl_ensure_current (cogl_display);
+- kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
+- kms_device = meta_kms_crtc_get_device (kms_crtc);
+ rectangles_size = n_rectangles * 4 * sizeof (int);
+ onscreen_native->next_post.rectangles =
+ g_realloc (onscreen_native->next_post.rectangles, rectangles_size);
+ memcpy (onscreen_native->next_post.rectangles, rectangles, rectangles_size);
+ onscreen_native->next_post.n_rectangles = n_rectangles;
+
++ g_clear_pointer (&onscreen_native->next_post.frame, clutter_frame_unref);
++ onscreen_native->next_post.frame = clutter_frame_ref (frame);
++
+ onscreen_native->swaps_pending++;
+ try_post_latest_swap (onscreen);
+}
@@ -2304,47 +1549,63 @@ index a107a99bb..79cf78963 100644
+ MetaRenderer *renderer = META_RENDERER (renderer_native);
+ MetaBackend *backend = meta_renderer_get_backend (renderer);
+ MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
++ MetaKms *kms = meta_backend_native_get_kms (backend_native);
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
-+ MetaKms *kms = meta_backend_native_get_kms (backend_native);
+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
+ MetaPowerSave power_save_mode;
+ MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
+ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
-+ MetaKmsUpdateFlag flags;
++ MetaKmsUpdate *kms_update;
+ g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-+ const GError *feedback_error;
-+ unsigned int frames_pending = cogl_onscreen_count_pending_frames (onscreen);
++ g_autoptr (ClutterFrame) frame = NULL;
++ MetaFrameNative *frame_native;
++
++ if (onscreen_native->next_post.frame == NULL)
++ return;
+
+ if (meta_kms_is_shutting_down (kms))
+ {
+ meta_onscreen_native_discard_pending_swaps (onscreen);
+ return;
+ }
-+
-+ if (onscreen_native->swaps_pending == 0)
-+ return;
-+
-+ g_assert (frames_pending >= onscreen_native->swaps_pending);
-+
+
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
if (power_save_mode == META_POWER_SAVE_ON)
{
++ unsigned int frames_pending =
++ cogl_onscreen_count_pending_frames (onscreen);
+ unsigned int posts_pending;
+
++ g_assert (frames_pending >= onscreen_native->swaps_pending);
+ posts_pending = frames_pending - onscreen_native->swaps_pending;
+ if (posts_pending > 0)
+ return; /* wait for the next frame notification and then try again */
+
++ frame = g_steal_pointer (&onscreen_native->next_post.frame);
++ frame_native = meta_frame_native_from_frame (frame);
++
++ if (onscreen_native->swaps_pending == 0)
++ {
++ if (frame_native)
++ {
++ kms_update = meta_frame_native_steal_kms_update (frame_native);
++ if (kms_update)
++ post_finish_frame (onscreen_native, kms_update);
++ }
++ return;
++ }
++
+ 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,
+ kms_update = meta_frame_native_ensure_kms_update (frame_native,
+ kms_device);
+ meta_kms_update_add_result_listener (kms_update,
+@@ -1179,15 +1283,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
onscreen_native->crtc,
+ kms_update,
META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
- rectangles,
- n_rectangles);
@@ -2353,6 +1614,7 @@ index a107a99bb..79cf78963 100644
}
else
{
++ frame = g_steal_pointer (&onscreen_native->next_post.frame);
meta_renderer_native_queue_power_save_page_flip (renderer_native,
onscreen);
- clutter_frame_set_result (frame,
@@ -2360,58 +1622,68 @@ index a107a99bb..79cf78963 100644
return;
}
-@@ -1160,9 +1263,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));
--
+@@ -1207,8 +1310,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ kms_update = meta_frame_native_steal_kms_update (frame_native);
+ meta_renderer_native_queue_mode_set_update (renderer_native,
+ kms_update);
- clutter_frame_set_result (frame,
- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
return;
}
else if (meta_renderer_native_has_pending_mode_set (renderer_native))
-@@ -1172,8 +1272,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+@@ -1222,8 +1323,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- meta_renderer_native_notify_mode_sets_reset (renderer_native);
+ meta_frame_native_steal_kms_update (frame_native);
meta_renderer_native_post_mode_set_updates (renderer_native);
- clutter_frame_set_result (frame,
- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
return;
}
break;
-@@ -1186,8 +1284,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- {
- meta_renderer_native_notify_mode_sets_reset (renderer_native);
+@@ -1239,8 +1338,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ kms_update);
+
meta_renderer_native_post_mode_set_updates (renderer_native);
- clutter_frame_set_result (frame,
- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
return;
}
break;
-@@ -1200,18 +1296,16 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- meta_kms_device_get_path (kms_device));
+@@ -1256,7 +1353,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ kms_feedback =
+ meta_kms_device_process_update_sync (kms_device, kms_update,
+ META_KMS_UPDATE_FLAG_NONE);
+- clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+ }
- flags = META_KMS_UPDATE_FLAG_NONE;
-- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms,
-+ kms_crtc,
-+ flags);
-+ g_return_if_fail (kms_feedback != NULL);
+ gboolean
+@@ -1301,6 +1397,7 @@ on_scanout_update_result (const MetaKmsFeedback *kms_feedback,
+ CoglOnscreen *onscreen = COGL_ONSCREEN (onscreen_native);
+ const GError *error;
+ CoglFrameInfo *frame_info;
++ g_autoptr (MetaDrmBuffer) direct_fb = g_steal_pointer (&onscreen_native->gbm.direct_fb);
- switch (meta_kms_feedback_get_result (kms_feedback))
- {
- case META_KMS_FEEDBACK_PASSED:
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- break;
- case META_KMS_FEEDBACK_FAILED:
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
--
- feedback_error = meta_kms_feedback_get_error (kms_feedback);
- if (!g_error_matches (feedback_error,
- G_IO_ERROR,
-@@ -1298,6 +1392,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
+ error = meta_kms_feedback_get_error (kms_feedback);
+ if (!error)
+@@ -1314,8 +1411,7 @@ on_scanout_update_result (const MetaKmsFeedback *kms_feedback,
+
+ g_warning ("Direct scanout page flip failed: %s", error->message);
+
+- cogl_scanout_notify_failed (COGL_SCANOUT (onscreen_native->gbm.next_fb),
+- onscreen);
++ cogl_scanout_notify_failed (COGL_SCANOUT (direct_fb), onscreen);
+ clutter_stage_view_add_redraw_clip (view, NULL);
+ clutter_stage_view_schedule_update_now (view);
+ }
+@@ -1324,7 +1420,6 @@ on_scanout_update_result (const MetaKmsFeedback *kms_feedback,
+ frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
+
+ meta_onscreen_native_notify_frame_complete (onscreen);
+- meta_onscreen_native_clear_next_fb (onscreen);
+ }
+
+ static gboolean
+@@ -1375,6 +1470,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
return FALSE;
}
@@ -2430,54 +1702,87 @@ index a107a99bb..79cf78963 100644
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
render_gpu);
-@@ -1350,7 +1456,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:
-@@ -1364,7 +1472,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
- G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
- break;
+@@ -1414,6 +1521,8 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
+ kms_device = meta_kms_crtc_get_device (kms_crtc);
+ kms_update = meta_frame_native_ensure_kms_update (frame_native, kms_device);
+
++ g_set_object (&onscreen_native->gbm.direct_fb,
++ onscreen_native->gbm.next_fb);
+ meta_kms_update_add_result_listener (kms_update,
+ on_scanout_update_result,
+ onscreen_native);
+@@ -1558,7 +1667,20 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
+ MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
+ MetaKmsUpdate *kms_update;
+- g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
++
++ if (meta_frame_native_has_kms_update (frame_native) &&
++ cogl_onscreen_count_pending_frames (onscreen) > 0 &&
++ onscreen_native->swaps_pending == 0)
++ {
++ /* Posts are busy AND we have no swaps pending so just retry the same
++ * frame later in try_post_latest_swap.
++ */
++ g_warn_if_fail (onscreen_native->next_post.frame == NULL);
++ g_clear_pointer (&onscreen_native->next_post.frame, clutter_frame_unref);
++ onscreen_native->next_post.frame = clutter_frame_ref (frame);
++ clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
++ return;
++ }
-- g_clear_object (&onscreen_native->gbm.next_fb);
- g_propagate_error (error, g_error_copy (feedback_error));
- return FALSE;
+ kms_update = meta_frame_native_steal_kms_update (frame_native);
+ if (!kms_update)
+@@ -1567,6 +1689,42 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+ return;
}
-@@ -1400,7 +1507,10 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
- g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
- const GError *error;
-- kms_update = meta_kms_get_pending_update (kms, kms_device);
+ if (cogl_onscreen_count_pending_frames (onscreen) > 0)
-+ return;
++ {
++ /* Posts are busy AND we have swaps pending so best to merge our cursor
++ * update into the pending swap.
++ */
++ MetaFrameNative *older_frame_native;
++ MetaKmsUpdate *older_kms_update;
++
++ g_return_if_fail (onscreen_native->swaps_pending > 0);
++ g_return_if_fail (onscreen_native->next_post.frame != NULL);
++
++ older_frame_native =
++ meta_frame_native_from_frame (onscreen_native->next_post.frame);
++ older_kms_update =
++ meta_frame_native_ensure_kms_update (older_frame_native, kms_device);
++ meta_kms_update_merge_from (older_kms_update, kms_update);
++ meta_kms_update_free (kms_update);
++
++ clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
++ return;
++ }
++
++ post_finish_frame (onscreen_native, kms_update);
++
++ clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
++}
++
++static void
++post_finish_frame (MetaOnscreenNative *onscreen_native,
++ MetaKmsUpdate *kms_update)
++{
++ MetaCrtc *crtc = onscreen_native->crtc;
++ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
++ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
++ g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
++
+ meta_kms_update_add_result_listener (kms_update,
+ on_finish_frame_update_result,
+ onscreen_native);
+@@ -1587,7 +1745,17 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+ kms_feedback =
+ meta_kms_device_process_update_sync (kms_device, kms_update,
+ META_KMS_UPDATE_FLAG_NONE);
+- clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
++}
+
-+ kms_update = meta_kms_get_pending_update_for_crtc (kms, kms_crtc);
- if (!kms_update)
- {
- clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
-@@ -1415,9 +1525,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:
-@@ -1439,6 +1549,17 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
- }
- }
-
+void
+meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen)
+{
@@ -2487,81 +1792,34 @@ index a107a99bb..79cf78963 100644
+
+ g_clear_object (&onscreen_native->gbm.stalled_fb);
+ g_clear_object (&onscreen_native->gbm.next_fb);
-+}
-+
- static gboolean
- should_surface_be_sharable (CoglOnscreen *onscreen)
- {
-@@ -1987,6 +2108,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,
-@@ -2043,6 +2179,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);
- }
-
- /*
-@@ -2132,7 +2274,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;
- }
-@@ -2153,7 +2295,6 @@ meta_onscreen_native_dispose (GObject *object)
+@@ -2414,7 +2582,7 @@ meta_onscreen_native_dispose (GObject *object)
{
case META_RENDERER_NATIVE_MODE_GBM:
g_clear_object (&onscreen_native->gbm.next_fb);
- free_current_bo (onscreen);
++ g_clear_object (&onscreen_native->gbm.direct_fb);
break;
case META_RENDERER_NATIVE_MODE_SURFACELESS:
g_assert_not_reached ();
-@@ -2181,9 +2322,12 @@ meta_onscreen_native_dispose (GObject *object)
+@@ -2448,6 +2616,10 @@ 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);
+ g_clear_object (&onscreen_native->output);
+ g_clear_object (&onscreen_native->crtc);
++
+ g_clear_pointer (&onscreen_native->next_post.rectangles, g_free);
++ g_clear_pointer (&onscreen_native->next_post.frame, clutter_frame_unref);
+ onscreen_native->next_post.n_rectangles = 0;
}
static void
diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h
-index 8ea7ec254..81b0eeaed 100644
+index 05a9ecdb8..a33ee3857 100644
--- a/src/backends/native/meta-onscreen-native.h
+++ b/src/backends/native/meta-onscreen-native.h
-@@ -42,6 +42,8 @@ void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+@@ -45,6 +45,8 @@ void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
void meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen);
@@ -2571,10 +1829,10 @@ index 8ea7ec254..81b0eeaed 100644
MetaDrmBuffer *fb);
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
-index e27805d91..a99142e97 100644
+index 4da361e2b..e5d995388 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
-@@ -684,12 +684,18 @@ static gboolean
+@@ -708,12 +708,18 @@ static gboolean
dummy_power_save_page_flip_cb (gpointer user_data)
{
MetaRendererNative *renderer_native = user_data;
@@ -2595,7 +1853,7 @@ index e27805d91..a99142e97 100644
renderer_native->power_save_page_flip_source_id = 0;
return G_SOURCE_REMOVE;
-@@ -701,6 +707,9 @@ meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_na
+@@ -725,6 +731,9 @@ meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_na
{
const unsigned int timeout_ms = 100;
@@ -2605,8 +1863,8 @@ index e27805d91..a99142e97 100644
if (!renderer_native->power_save_page_flip_source_id)
{
renderer_native->power_save_page_flip_source_id =
-@@ -1409,6 +1418,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
- return view;
+@@ -1473,6 +1482,26 @@ detach_onscreens (MetaRenderer *renderer)
+ }
}
+static void
@@ -2630,30 +1888,252 @@ index e27805d91..a99142e97 100644
+}
+
static void
- keep_current_onscreens_alive (MetaRenderer *renderer)
+ meta_renderer_native_rebuild_views (MetaRenderer *renderer)
{
-@@ -1437,6 +1466,7 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer)
+@@ -1483,6 +1512,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);
-
+ g_hash_table_remove_all (renderer_native->mode_set_updates);
+
+diff --git a/src/backends/native/meta-swap-chain.c b/src/backends/native/meta-swap-chain.c
+new file mode 100644
+index 000000000..c3bed569d
+--- /dev/null
++++ b/src/backends/native/meta-swap-chain.c
+@@ -0,0 +1,149 @@
++/*
++ * Copyright (C) 2022 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
++ */
++
++#include "backends/native/meta-swap-chain.h"
++
++typedef struct
++{
++ GObject *front, *back;
++ gboolean back_is_set;
++} PlaneState;
++
++typedef struct _MetaSwapChainPrivate MetaSwapChainPrivate;
++struct _MetaSwapChainPrivate
++{
++ GHashTable *plane_states;
++};
++
++G_DEFINE_TYPE_WITH_PRIVATE (MetaSwapChain, meta_swap_chain, G_TYPE_OBJECT)
++
++MetaSwapChain *
++meta_swap_chain_new (void)
++{
++ return g_object_new (META_TYPE_SWAP_CHAIN, NULL);
++}
++
++void
++meta_swap_chain_push_buffer (MetaSwapChain *swap_chain,
++ unsigned int plane_id,
++ GObject *buffer)
++{
++ MetaSwapChainPrivate *priv =
++ meta_swap_chain_get_instance_private (swap_chain);
++ gpointer key = GUINT_TO_POINTER (plane_id);
++ PlaneState *plane_state;
++
++ plane_state = g_hash_table_lookup (priv->plane_states, key);
++ if (plane_state == NULL)
++ {
++ plane_state = g_new0 (PlaneState, 1);
++ g_hash_table_insert (priv->plane_states, key, plane_state);
++ }
++
++ plane_state->back_is_set = TRUE; /* note buffer may be NULL */
++ g_set_object (&plane_state->back, buffer);
++}
++
++static void
++swap_plane_buffers (gpointer key,
++ gpointer value,
++ gpointer user_data)
++{
++ PlaneState *plane_state = value;
++
++ if (plane_state->back_is_set)
++ {
++ g_set_object (&plane_state->front, plane_state->back);
++ g_clear_object (&plane_state->back);
++ plane_state->back_is_set = FALSE;
++ }
++}
++
++void
++meta_swap_chain_swap_buffers (MetaSwapChain *swap_chain)
++{
++ MetaSwapChainPrivate *priv =
++ meta_swap_chain_get_instance_private (swap_chain);
++
++ g_hash_table_foreach (priv->plane_states, swap_plane_buffers, NULL);
++}
++
++void
++meta_swap_chain_release_buffers (MetaSwapChain *swap_chain)
++{
++ MetaSwapChainPrivate *priv =
++ meta_swap_chain_get_instance_private (swap_chain);
++
++ g_hash_table_remove_all (priv->plane_states);
++}
++
++static void
++meta_swap_chain_dispose (GObject *object)
++{
++ MetaSwapChain *swap_chain = META_SWAP_CHAIN (object);
++
++ meta_swap_chain_release_buffers (swap_chain);
++
++ G_OBJECT_CLASS (meta_swap_chain_parent_class)->dispose (object);
++}
++
++static void
++meta_swap_chain_finalize (GObject *object)
++{
++ MetaSwapChain *swap_chain = META_SWAP_CHAIN (object);
++ MetaSwapChainPrivate *priv =
++ meta_swap_chain_get_instance_private (swap_chain);
++
++ g_hash_table_unref (priv->plane_states);
++
++ G_OBJECT_CLASS (meta_swap_chain_parent_class)->finalize (object);
++}
++
++static void
++destroy_plane_state (gpointer data)
++{
++ PlaneState *plane_state = data;
++
++ g_clear_object (&plane_state->front);
++ g_clear_object (&plane_state->back);
++ g_free (plane_state);
++}
++
++static void
++meta_swap_chain_init (MetaSwapChain *swap_chain)
++{
++ MetaSwapChainPrivate *priv =
++ meta_swap_chain_get_instance_private (swap_chain);
++
++ priv->plane_states = g_hash_table_new_full (NULL,
++ NULL,
++ NULL,
++ destroy_plane_state);
++}
++
++static void
++meta_swap_chain_class_init (MetaSwapChainClass *klass)
++{
++ GObjectClass *object_class = G_OBJECT_CLASS (klass);
++
++ object_class->dispose = meta_swap_chain_dispose;
++ object_class->finalize = meta_swap_chain_finalize;
++}
+diff --git a/src/backends/native/meta-swap-chain.h b/src/backends/native/meta-swap-chain.h
+new file mode 100644
+index 000000000..bad772b89
+--- /dev/null
++++ b/src/backends/native/meta-swap-chain.h
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2022 Canonical Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
++ */
++
++#ifndef META_SWAP_CHAIN_H
++#define META_SWAP_CHAIN_H
++
++#include <glib-object.h>
++
++#define META_TYPE_SWAP_CHAIN (meta_swap_chain_get_type ())
++G_DECLARE_DERIVABLE_TYPE (MetaSwapChain,
++ meta_swap_chain,
++ META, SWAP_CHAIN,
++ GObject)
++
++struct _MetaSwapChainClass
++{
++ GObjectClass parent_class;
++};
++
++MetaSwapChain * meta_swap_chain_new (void);
++
++void meta_swap_chain_push_buffer (MetaSwapChain *swap_chain,
++ unsigned int plane_id,
++ GObject *buffer);
++
++void meta_swap_chain_swap_buffers (MetaSwapChain *swap_chain);
++
++void meta_swap_chain_release_buffers (MetaSwapChain *swap_chain);
++
++#endif /* META_SWAP_CHAIN_H */
+diff --git a/src/meson.build b/src/meson.build
+index a4fe0850c..ec7617944 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -820,6 +820,8 @@ if have_native_backend
+ 'backends/native/meta-seat-native.h',
+ 'backends/native/meta-stage-native.c',
+ 'backends/native/meta-stage-native.h',
++ 'backends/native/meta-swap-chain.c',
++ 'backends/native/meta-swap-chain.h',
+ 'backends/native/meta-udev.c',
+ 'backends/native/meta-udev.h',
+ 'backends/native/meta-virtual-input-device-native.c',
diff --git a/src/tests/native-kms-render.c b/src/tests/native-kms-render.c
-index 6595eb5a2..42f7e6276 100644
+index 1557b764e..c482d07e0 100644
--- a/src/tests/native-kms-render.c
+++ b/src/tests/native-kms-render.c
-@@ -36,6 +36,8 @@
+@@ -41,6 +41,8 @@
#include "tests/meta-wayland-test-driver.h"
#include "tests/meta-wayland-test-utils.h"
-+#define N_FRAMES_PER_TEST 10
++#define N_FRAMES_PER_TEST 30
+
typedef struct
{
int number_of_frames_left;
-@@ -43,7 +45,9 @@ typedef struct
+@@ -48,12 +50,15 @@ typedef struct
struct {
int n_paints;
@@ -2664,7 +2144,13 @@ index 6595eb5a2..42f7e6276 100644
} scanout;
gboolean wait_for_scanout;
-@@ -72,7 +76,7 @@ meta_test_kms_render_basic (void)
+
+ struct {
++ int scanouts_attempted;
+ gboolean scanout_sabotaged;
+ gboolean fallback_painted;
+ guint repaint_guard_id;
+@@ -103,7 +108,7 @@ meta_test_kms_render_basic (void)
gulong handler_id;
test = (KmsRenderingTest) {
@@ -2673,7 +2159,7 @@ index 6595eb5a2..42f7e6276 100644
.loop = g_main_loop_new (NULL, FALSE),
};
handler_id = g_signal_connect (stage, "after-update",
-@@ -93,7 +97,6 @@ on_scanout_before_update (ClutterStage *stage,
+@@ -125,7 +130,6 @@ on_scanout_before_update (ClutterStage *stage,
KmsRenderingTest *test)
{
test->scanout.n_paints = 0;
@@ -2681,7 +2167,7 @@ index 6595eb5a2..42f7e6276 100644
}
static void
-@@ -103,6 +106,7 @@ on_scanout_before_paint (ClutterStage *stage,
+@@ -136,6 +140,7 @@ on_scanout_before_paint (ClutterStage *stage,
{
CoglScanout *scanout;
MetaDrmBuffer *buffer;
@@ -2689,7 +2175,7 @@ index 6595eb5a2..42f7e6276 100644
scanout = clutter_stage_view_peek_scanout (stage_view);
if (!scanout)
-@@ -110,8 +114,14 @@ on_scanout_before_paint (ClutterStage *stage,
+@@ -143,8 +148,14 @@ on_scanout_before_paint (ClutterStage *stage,
g_assert_true (META_IS_DRM_BUFFER (scanout));
buffer = META_DRM_BUFFER (scanout);
@@ -2706,13 +2192,13 @@ index 6595eb5a2..42f7e6276 100644
}
static void
-@@ -138,12 +148,12 @@ on_scanout_presented (ClutterStage *stage,
+@@ -173,12 +184,12 @@ on_scanout_presented (ClutterStage *stage,
MetaDeviceFile *device_file;
GError *error = NULL;
drmModeCrtc *drm_crtc;
+ uint32_t first_fb_id_expected;
-- if (test->scanout.n_paints > 0)
+- if (test->wait_for_scanout && test->scanout.n_paints > 0)
+ if (test->wait_for_scanout && test->scanout.fb_ids == NULL)
return;
@@ -2722,7 +2208,7 @@ index 6595eb5a2..42f7e6276 100644
device_pool = meta_backend_native_get_device_pool (backend_native);
-@@ -162,15 +172,41 @@ on_scanout_presented (ClutterStage *stage,
+@@ -197,15 +208,41 @@ on_scanout_presented (ClutterStage *stage,
drm_crtc = drmModeGetCrtc (meta_device_file_get_fd (device_file),
meta_kms_crtc_get_id (kms_crtc));
g_assert_nonnull (drm_crtc);
@@ -2768,7 +2254,7 @@ index 6595eb5a2..42f7e6276 100644
}
typedef enum
-@@ -209,7 +245,9 @@ meta_test_kms_render_client_scanout (void)
+@@ -244,7 +281,9 @@ meta_test_kms_render_client_scanout (void)
g_assert_nonnull (wayland_test_client);
test = (KmsRenderingTest) {
@@ -2778,7 +2264,7 @@ index 6595eb5a2..42f7e6276 100644
.wait_for_scanout = TRUE,
};
-@@ -235,7 +273,8 @@ meta_test_kms_render_client_scanout (void)
+@@ -270,7 +309,8 @@ meta_test_kms_render_client_scanout (void)
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
g_main_loop_run (test.loop);
@@ -2788,7 +2274,7 @@ index 6595eb5a2..42f7e6276 100644
g_debug ("Unmake fullscreen");
window = meta_find_window_from_title (test_context, "dma-buf-scanout-test");
-@@ -257,10 +296,15 @@ meta_test_kms_render_client_scanout (void)
+@@ -292,10 +332,15 @@ meta_test_kms_render_client_scanout (void)
g_assert_cmpint (buffer_rect.y, ==, 10);
test.wait_for_scanout = FALSE;
@@ -2805,7 +2291,7 @@ index 6595eb5a2..42f7e6276 100644
g_debug ("Moving back to 0, 0");
meta_window_move_frame (window, TRUE, 0, 0);
-@@ -272,10 +316,15 @@ meta_test_kms_render_client_scanout (void)
+@@ -307,10 +352,15 @@ meta_test_kms_render_client_scanout (void)
g_assert_cmpint (buffer_rect.y, ==, 0);
test.wait_for_scanout = TRUE;
@@ -2822,3 +2308,59 @@ index 6595eb5a2..42f7e6276 100644
g_signal_handler_disconnect (stage, before_update_handler_id);
g_signal_handler_disconnect (stage, before_paint_handler_id);
+@@ -360,6 +410,15 @@ on_scanout_fallback_before_paint (ClutterStage *stage,
+ if (!scanout)
+ return;
+
++ test->scanout_fallback.scanouts_attempted++;
++
++ /* The first scanout candidate frame will get composited due to triple
++ * buffering draining the queue to drop to double buffering. So don't
++ * sabotage that first frame.
++ */
++ if (test->scanout_fallback.scanouts_attempted < 2)
++ return;
++
+ g_assert_false (test->scanout_fallback.scanout_sabotaged);
+
+ if (is_atomic_mode_setting (kms_device))
+@@ -394,6 +453,15 @@ on_scanout_fallback_paint_view (ClutterStage *stage,
+ g_clear_handle_id (&test->scanout_fallback.repaint_guard_id,
+ g_source_remove);
+ test->scanout_fallback.fallback_painted = TRUE;
++ test->scanout_fallback.scanout_sabotaged = FALSE;
++ }
++ else if (test->scanout_fallback.scanouts_attempted == 1)
++ {
++ /* Now that we've seen the first scanout attempt that was inhibited by
++ * triple buffering, try a second frame. The second one should scanout
++ * and will be sabotaged.
++ */
++ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+ }
+ }
+
+@@ -403,11 +471,11 @@ on_scanout_fallback_presented (ClutterStage *stage,
+ ClutterFrameInfo *frame_info,
+ KmsRenderingTest *test)
+ {
+- if (!test->scanout_fallback.scanout_sabotaged)
+- return;
++ if (test->scanout_fallback.fallback_painted)
++ g_main_loop_quit (test->loop);
+
+- g_assert_true (test->scanout_fallback.fallback_painted);
+- g_main_loop_quit (test->loop);
++ test->number_of_frames_left--;
++ g_assert_cmpint (test->number_of_frames_left, >, 0);
+ }
+
+ static void
+@@ -436,6 +504,7 @@ meta_test_kms_render_client_scanout_fallback (void)
+ g_assert_nonnull (wayland_test_client);
+
+ test = (KmsRenderingTest) {
++ .number_of_frames_left = N_FRAMES_PER_TEST,
+ .loop = g_main_loop_new (NULL, FALSE),
+ };
+