diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h index 5016f7465..7eed4b55a 100644 --- a/src/wayland/meta-wayland-private.h +++ b/src/wayland/meta-wayland-private.h @@ -115,6 +115,9 @@ struct _MetaWaylandCompositor * order they were committed. */ GQueue committed_transactions; + + /* Transactions with time constraints. */ + GQueue *timed_transactions; }; gboolean meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-surface-private.h b/src/wayland/meta-wayland-surface-private.h index b1c5ac00f..7a791770d 100644 --- a/src/wayland/meta-wayland-surface-private.h +++ b/src/wayland/meta-wayland-surface-private.h @@ -138,6 +138,9 @@ struct _MetaWaylandSurfaceState gboolean has_new_color_state; ClutterColorState *color_state; + + gboolean has_target_time; + int64_t target_time_us; }; struct _MetaWaylandDragDestFuncs diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c index 85a8ca76f..39f9c1803 100644 --- a/src/wayland/meta-wayland-transaction.c +++ b/src/wayland/meta-wayland-transaction.c @@ -45,6 +45,8 @@ struct _MetaWaylandTransaction /* Sources for buffers which are not ready yet */ GHashTable *buf_sources; + + int64_t target_presentation_time_us; }; struct _MetaWaylandTransactionEntry @@ -60,6 +62,12 @@ struct _MetaWaylandTransactionEntry int y; }; +int64_t +meta_wayland_transaction_get_target_presentation_time_us (const MetaWaylandTransaction *transaction) +{ + return transaction->target_presentation_time_us; +} + static MetaWaylandTransactionEntry * meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction, MetaWaylandSurface *surface) @@ -241,6 +249,9 @@ has_dependencies (MetaWaylandTransaction *transaction) GHashTableIter iter; MetaWaylandSurface *surface; + if (transaction->target_presentation_time_us) + return TRUE; + if (transaction->buf_sources && g_hash_table_size (transaction->buf_sources) > 0) return TRUE; @@ -283,6 +294,20 @@ meta_wayland_transaction_maybe_apply (MetaWaylandTransaction *transaction) } } +gboolean +meta_wayland_transaction_unblock_timed (MetaWaylandTransaction *transaction, + int64_t target_time_us) +{ + if (target_time_us < transaction->target_presentation_time_us) + return FALSE; + + transaction->target_presentation_time_us = 0; + + meta_wayland_transaction_maybe_apply (transaction); + + return TRUE; +} + static void meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer, gpointer user_data) @@ -389,6 +414,8 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) g_autoptr (GPtrArray) placement_states = NULL; unsigned int num_placement_states = 0; int i; + gint64 max_time_us = 0; + MetaWaylandSurface *max_time_surface = NULL; g_hash_table_iter_init (&iter, transaction->entries); while (g_hash_table_iter_next (&iter, @@ -413,6 +440,13 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) g_ptr_array_add (placement_states, entry->state); num_placement_states++; } + + if (entry->state->has_target_time && + entry->state->target_time_us > max_time_us) + { + max_time_us = entry->state->target_time_us; + max_time_surface = surface; + } } } @@ -425,6 +459,23 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) placement_state); } + /* If we have a time constraint, we always defer application until just before the + * appropriate frame clock tick. + */ + if (max_time_us) + { + MetaSurfaceActor *actor = meta_wayland_surface_get_actor (max_time_surface); + ClutterFrameClock *frame_clock = + clutter_actor_pick_frame_clock (CLUTTER_ACTOR (actor), NULL); + + if (frame_clock) + { + maybe_apply = FALSE; + transaction->target_presentation_time_us = max_time_us; + meta_wayland_compositor_add_timed_transaction (transaction->compositor, transaction); + clutter_frame_clock_add_future_time (frame_clock, max_time_us); + } + } transaction->committed_sequence = ++committed_sequence; transaction->node.data = transaction; diff --git a/src/wayland/meta-wayland-transaction.h b/src/wayland/meta-wayland-transaction.h index 6674d2c2c..b45c0e5ad 100644 --- a/src/wayland/meta-wayland-transaction.h +++ b/src/wayland/meta-wayland-transaction.h @@ -52,3 +52,8 @@ void meta_wayland_transaction_free (MetaWaylandTransaction *transaction); void meta_wayland_transaction_finalize (MetaWaylandCompositor *compositor); void meta_wayland_transaction_init (MetaWaylandCompositor *compositor); + +int64_t meta_wayland_transaction_get_target_presentation_time_us (const MetaWaylandTransaction *transaction); + +gboolean meta_wayland_transaction_unblock_timed (MetaWaylandTransaction *transaction, + int64_t target_time_us); diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 9ce6bf301..48e1dee4b 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -357,6 +357,36 @@ ensure_source_for_stage_view (MetaWaylandCompositor *compositor, } #endif /* HAVE_NATIVE_BACKEND */ +static void +clear_time_constraints_for_stage_view_transactions (MetaWaylandCompositor *compositor, + ClutterStageView *stage_view, + int64_t target_time_us) +{ + MetaWaylandTransaction *transaction; + + while ((transaction = g_queue_peek_head (compositor->timed_transactions))) + { + if (meta_wayland_transaction_unblock_timed (transaction, target_time_us)) + g_queue_pop_head (compositor->timed_transactions); + else + break; + } +} + +static void +on_before_update (ClutterStage *stage, + ClutterStageView *stage_view, + ClutterFrame *frame, + MetaWaylandCompositor *compositor) +{ + int64_t target_time_us; + + if (!clutter_frame_get_target_presentation_time (frame, &target_time_us)) + target_time_us = g_get_monotonic_time (); + + clear_time_constraints_for_stage_view_transactions (compositor, stage_view, target_time_us); +} + static void on_after_update (ClutterStage *stage, ClutterStageView *stage_view, @@ -605,6 +635,41 @@ meta_wayland_compositor_remove_presentation_feedback_surface (MetaWaylandComposi g_list_remove (compositor->presentation_time.feedback_surfaces, surface); } +static int +compare_transaction_times (const MetaWaylandTransaction *a, + const MetaWaylandTransaction *b, + void *data) +{ + int64_t target_time_us_a = meta_wayland_transaction_get_target_presentation_time_us (a); + int64_t target_time_us_b = meta_wayland_transaction_get_target_presentation_time_us (b); + + if (target_time_us_a > target_time_us_b) + return 1; + + if (target_time_us_a < target_time_us_b) + return -1; + + return 0; +} + +void +meta_wayland_compositor_add_timed_transaction (MetaWaylandCompositor *compositor, + MetaWaylandTransaction *transaction) +{ + if (g_queue_find (compositor->timed_transactions, transaction)) + return; + + g_queue_insert_sorted (compositor->timed_transactions, transaction, + (GCompareDataFunc)compare_transaction_times, NULL); +} + +void +meta_wayland_compositor_remove_timed_transaction (MetaWaylandCompositor *compositor, + MetaWaylandTransaction *transaction) +{ + g_queue_remove (compositor->timed_transactions, transaction); +} + GQueue * meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor) { @@ -716,6 +781,8 @@ meta_wayland_compositor_finalize (GObject *object) g_clear_pointer (&compositor->wayland_display, wl_display_destroy); g_clear_pointer (&compositor->source, g_source_destroy); + g_queue_free (compositor->timed_transactions); + G_OBJECT_CLASS (meta_wayland_compositor_parent_class)->finalize (object); } @@ -741,6 +808,7 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor) priv->frame_callback_sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_source_destroy); + compositor->timed_transactions = g_queue_new (); } static void @@ -854,6 +922,8 @@ meta_wayland_compositor_new (MetaContext *context) compositor->source = wayland_event_source; g_source_unref (wayland_event_source); + g_signal_connect (stage, "before-update", + G_CALLBACK (on_before_update), compositor); g_signal_connect (stage, "after-update", G_CALLBACK (on_after_update), compositor); g_signal_connect (stage, "presented", diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h index 0a0476eba..a8a35e224 100644 --- a/src/wayland/meta-wayland.h +++ b/src/wayland/meta-wayland.h @@ -63,6 +63,12 @@ void meta_wayland_compositor_add_presentation_feedback_surfac void meta_wayland_compositor_remove_presentation_feedback_surface (MetaWaylandCompositor *compositor, MetaWaylandSurface *surface); +void meta_wayland_compositor_add_timed_transaction (MetaWaylandCompositor *compositor, + MetaWaylandTransaction *transaction); + +void meta_wayland_compositor_remove_timed_transaction (MetaWaylandCompositor *compositor, + MetaWaylandTransaction *transaction); + GQueue *meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor); META_EXPORT_TEST