summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <mdaenzer@redhat.com>2022-06-10 18:49:29 +0200
committerMichel Dänzer <michel@daenzer.net>2022-12-01 16:35:19 +0100
commit6e6a38342e651b3a64db8a242ce291c4e704e00e (patch)
treeb31d7e2edb9856649cf1d7f00d8684571e803dcd
parentb7599fb766832d0ed14b91414672ecf15582198a (diff)
downloadmutter-6e6a38342e651b3a64db8a242ce291c4e704e00e.tar.gz
wayland/surface: Defer meta_wayland_transaction_apply for dma-bufs
Until all dma-buf file descriptors for all buffers in the transaction are readable, which corresponds to when the client drawing to the buffers has finished. This fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1162 if the GPU & drivers support high priority contexts which can preempt lower priority contexts. v2: * Also remove dma-buf fds from transaction and try applying it from pending_buffer_resource_destroyed. Avoids freeze due to leaving a GSource based on a closed fd attached if a client destroys a wl_buffer which is part of a transaction which was committed but not applied yet. (Robert Mader) * Tweak transaction cleanup logic in wl_surface_destructor. v3: * Adapt to meta_wayland_dma_buf_get_source. v4: * Adapt to new commits using transactions for (sub-)surface destruction, drop code to remove destroyed surfaces from pending transactions. v5: * Use g_clear_pointer in meta_wayland_transaction_destroy. (Georges Basile Stavracas Neto) * Add spaces between type casts and values. (Carlos Garnacho) * Use (gpointer *) instead of (void**). (Carlos Garnacho) * Use gpointer instead of void * in meta_wayland_transaction_dma_buf_dispatch. v6: * Use g_hash_table_remove in meta_wayland_transaction_dma_buf_dispatch. (Carlos Garnacho) v7: (Jonas Ådahl) * Move include of glib-unix.h below that of meta-wayland-transaction.h. * Split up g_hash_table_iter_next call to multiple lines in meta_wayland_transaction_commit. * Call g_source_destroy as well as g_source_unref when freeing a committed but not yet applied transaction (during mutter shutdown). v8: * Drop dma_buf_source_destroy, can use g_source_destroy directly. (Jonas Ådahl) Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
-rw-r--r--src/wayland/meta-wayland-transaction.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c
index 6bf0376e9..5ca4cf87d 100644
--- a/src/wayland/meta-wayland-transaction.c
+++ b/src/wayland/meta-wayland-transaction.c
@@ -23,7 +23,10 @@
#include "wayland/meta-wayland-transaction.h"
+#include <glib-unix.h>
+
#include "wayland/meta-wayland.h"
+#include "wayland/meta-wayland-dma-buf.h"
#define META_WAYLAND_TRANSACTION_NONE ((void *)(uintptr_t) G_MAXSIZE)
@@ -39,6 +42,9 @@ struct _MetaWaylandTransaction
* Values: Pointer to MetaWaylandTransactionEntry for the surface
*/
GHashTable *entries;
+
+ /* Sources for buffers which are not ready yet */
+ GHashTable *buf_sources;
};
struct _MetaWaylandTransactionEntry
@@ -161,6 +167,9 @@ meta_wayland_transaction_apply (MetaWaylandTransaction *transaction,
MetaWaylandTransactionEntry *entry;
int i;
+ if (g_hash_table_size (transaction->entries) == 0)
+ goto free;
+
surfaces = (MetaWaylandSurface **)
g_hash_table_get_keys_as_array (transaction->entries, &num_surfaces);
states = g_new (MetaWaylandSurfaceState *, num_surfaces);
@@ -214,15 +223,20 @@ meta_wayland_transaction_apply (MetaWaylandTransaction *transaction,
meta_wayland_transaction_sync_child_states (surfaces[i]);
}
+free:
meta_wayland_transaction_free (transaction);
}
static gboolean
-has_unapplied_dependencies (MetaWaylandTransaction *transaction)
+has_dependencies (MetaWaylandTransaction *transaction)
{
GHashTableIter iter;
MetaWaylandSurface *surface;
+ if (transaction->buf_sources &&
+ g_hash_table_size (transaction->buf_sources) > 0)
+ return TRUE;
+
g_hash_table_iter_init (&iter, transaction->entries);
while (g_hash_table_iter_next (&iter, (gpointer *) &surface, NULL))
{
@@ -237,7 +251,7 @@ static void
meta_wayland_transaction_maybe_apply_one (MetaWaylandTransaction *transaction,
MetaWaylandTransaction **first_candidate)
{
- if (has_unapplied_dependencies (transaction))
+ if (has_dependencies (transaction))
return;
meta_wayland_transaction_apply (transaction, first_candidate);
@@ -261,6 +275,49 @@ meta_wayland_transaction_maybe_apply (MetaWaylandTransaction *transaction)
}
}
+static void
+meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer,
+ gpointer user_data)
+{
+ MetaWaylandTransaction *transaction = user_data;
+
+ if (!transaction->buf_sources ||
+ !g_hash_table_remove (transaction->buf_sources, buffer))
+ return;
+
+ meta_wayland_transaction_maybe_apply (transaction);
+}
+
+static gboolean
+meta_wayland_transaction_add_dma_buf_source (MetaWaylandTransaction *transaction,
+ MetaWaylandBuffer *buffer)
+{
+ GSource *source;
+
+ if (transaction->buf_sources &&
+ g_hash_table_contains (transaction->buf_sources, buffer))
+ return FALSE;
+
+ source = meta_wayland_dma_buf_create_source (buffer,
+ meta_wayland_transaction_dma_buf_dispatch,
+ transaction);
+ if (!source)
+ return FALSE;
+
+ if (!transaction->buf_sources)
+ {
+ transaction->buf_sources =
+ g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_source_destroy);
+ }
+
+ g_hash_table_insert (transaction->buf_sources, buffer, source);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ return TRUE;
+}
+
void
meta_wayland_transaction_commit (MetaWaylandTransaction *transaction)
{
@@ -269,6 +326,21 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction)
gboolean maybe_apply = TRUE;
GHashTableIter iter;
MetaWaylandSurface *surface;
+ MetaWaylandTransactionEntry *entry;
+
+ g_hash_table_iter_init (&iter, transaction->entries);
+ while (g_hash_table_iter_next (&iter,
+ (gpointer *) &surface, (gpointer *) &entry))
+ {
+ if (entry && entry->state)
+ {
+ MetaWaylandBuffer *buffer = entry->state->buffer;
+
+ if (buffer &&
+ meta_wayland_transaction_add_dma_buf_source (transaction, buffer))
+ maybe_apply = FALSE;
+ }
+ }
transaction->committed_sequence = ++committed_sequence;
transaction->node.data = transaction;
@@ -504,6 +576,7 @@ meta_wayland_transaction_free (MetaWaylandTransaction *transaction)
g_queue_unlink (committed_queue, &transaction->node);
}
+ g_clear_pointer (&transaction->buf_sources, g_hash_table_destroy);
g_hash_table_destroy (transaction->entries);
g_free (transaction);
}