wayland: Add timed transactions
Allow a transaction to have a timing constraint. Any transaction with a timing constraint will be deferred at its initial commit, without testing the target time. The timing constraints are cleared later in an on_before handler immediately before repaint. The new frame clock api to schedule later ticks is use to ensure we get an appropraitely timed tick to clear the constraint. Signed-off-by: Derek Foreman <derek.foreman@collabora.com> Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3355>
This commit is contained in:
parent
5b214dc2b7
commit
a645659440
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user