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.
|
* order they were committed.
|
||||||
*/
|
*/
|
||||||
GQueue committed_transactions;
|
GQueue committed_transactions;
|
||||||
|
|
||||||
|
/* Transactions with time constraints. */
|
||||||
|
GQueue *timed_transactions;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor);
|
gboolean meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor);
|
||||||
|
@ -138,6 +138,9 @@ struct _MetaWaylandSurfaceState
|
|||||||
|
|
||||||
gboolean has_new_color_state;
|
gboolean has_new_color_state;
|
||||||
ClutterColorState *color_state;
|
ClutterColorState *color_state;
|
||||||
|
|
||||||
|
gboolean has_target_time;
|
||||||
|
int64_t target_time_us;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWaylandDragDestFuncs
|
struct _MetaWaylandDragDestFuncs
|
||||||
|
@ -45,6 +45,8 @@ struct _MetaWaylandTransaction
|
|||||||
|
|
||||||
/* Sources for buffers which are not ready yet */
|
/* Sources for buffers which are not ready yet */
|
||||||
GHashTable *buf_sources;
|
GHashTable *buf_sources;
|
||||||
|
|
||||||
|
int64_t target_presentation_time_us;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWaylandTransactionEntry
|
struct _MetaWaylandTransactionEntry
|
||||||
@ -60,6 +62,12 @@ struct _MetaWaylandTransactionEntry
|
|||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
meta_wayland_transaction_get_target_presentation_time_us (const MetaWaylandTransaction *transaction)
|
||||||
|
{
|
||||||
|
return transaction->target_presentation_time_us;
|
||||||
|
}
|
||||||
|
|
||||||
static MetaWaylandTransactionEntry *
|
static MetaWaylandTransactionEntry *
|
||||||
meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction,
|
meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction,
|
||||||
MetaWaylandSurface *surface)
|
MetaWaylandSurface *surface)
|
||||||
@ -241,6 +249,9 @@ has_dependencies (MetaWaylandTransaction *transaction)
|
|||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
MetaWaylandSurface *surface;
|
MetaWaylandSurface *surface;
|
||||||
|
|
||||||
|
if (transaction->target_presentation_time_us)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
if (transaction->buf_sources &&
|
if (transaction->buf_sources &&
|
||||||
g_hash_table_size (transaction->buf_sources) > 0)
|
g_hash_table_size (transaction->buf_sources) > 0)
|
||||||
return TRUE;
|
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
|
static void
|
||||||
meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer,
|
meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
@ -389,6 +414,8 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction)
|
|||||||
g_autoptr (GPtrArray) placement_states = NULL;
|
g_autoptr (GPtrArray) placement_states = NULL;
|
||||||
unsigned int num_placement_states = 0;
|
unsigned int num_placement_states = 0;
|
||||||
int i;
|
int i;
|
||||||
|
gint64 max_time_us = 0;
|
||||||
|
MetaWaylandSurface *max_time_surface = NULL;
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, transaction->entries);
|
g_hash_table_iter_init (&iter, transaction->entries);
|
||||||
while (g_hash_table_iter_next (&iter,
|
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);
|
g_ptr_array_add (placement_states, entry->state);
|
||||||
num_placement_states++;
|
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);
|
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->committed_sequence = ++committed_sequence;
|
||||||
transaction->node.data = transaction;
|
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_finalize (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
void meta_wayland_transaction_init (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 */
|
#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
|
static void
|
||||||
on_after_update (ClutterStage *stage,
|
on_after_update (ClutterStage *stage,
|
||||||
ClutterStageView *stage_view,
|
ClutterStageView *stage_view,
|
||||||
@ -605,6 +635,41 @@ meta_wayland_compositor_remove_presentation_feedback_surface (MetaWaylandComposi
|
|||||||
g_list_remove (compositor->presentation_time.feedback_surfaces, surface);
|
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 *
|
GQueue *
|
||||||
meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor)
|
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->wayland_display, wl_display_destroy);
|
||||||
g_clear_pointer (&compositor->source, g_source_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);
|
G_OBJECT_CLASS (meta_wayland_compositor_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,6 +808,7 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
|
|||||||
priv->frame_callback_sources =
|
priv->frame_callback_sources =
|
||||||
g_hash_table_new_full (NULL, NULL, NULL,
|
g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
(GDestroyNotify) g_source_destroy);
|
(GDestroyNotify) g_source_destroy);
|
||||||
|
compositor->timed_transactions = g_queue_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -854,6 +922,8 @@ meta_wayland_compositor_new (MetaContext *context)
|
|||||||
compositor->source = wayland_event_source;
|
compositor->source = wayland_event_source;
|
||||||
g_source_unref (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_signal_connect (stage, "after-update",
|
||||||
G_CALLBACK (on_after_update), compositor);
|
G_CALLBACK (on_after_update), compositor);
|
||||||
g_signal_connect (stage, "presented",
|
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,
|
void meta_wayland_compositor_remove_presentation_feedback_surface (MetaWaylandCompositor *compositor,
|
||||||
MetaWaylandSurface *surface);
|
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);
|
GQueue *meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
META_EXPORT_TEST
|
META_EXPORT_TEST
|
||||||
|
Loading…
x
Reference in New Issue
Block a user