diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index cc74afad5..05e812eca 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -763,6 +763,153 @@ meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer) return buffer->dma_buf.dma_buf; } +typedef struct _MetaWaylandDmaBufSource +{ + GSource base; + + MetaWaylandDmaBufSourceDispatch dispatch; + MetaWaylandBuffer *buffer; + gpointer user_data; + + gpointer fd_tags[META_WAYLAND_DMA_BUF_MAX_FDS]; +} MetaWaylandDmaBufSource; + +static gboolean +meta_wayland_dma_buf_fd_readable (int fd) +{ + GPollFD poll_fd; + + poll_fd.fd = fd; + poll_fd.events = G_IO_IN; + poll_fd.revents = 0; + + if (!g_poll (&poll_fd, 1, 0)) + return FALSE; + + return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0; +} + +static gboolean +meta_wayland_dma_buf_source_dispatch (GSource *base, + GSourceFunc callback, + gpointer user_data) +{ + MetaWaylandDmaBufSource *source; + MetaWaylandDmaBufBuffer *dma_buf; + gboolean ready; + uint32_t i; + + source = (MetaWaylandDmaBufSource *) base; + dma_buf = source->buffer->dma_buf.dma_buf; + ready = TRUE; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + + if (!fd_tag) + continue; + + if (!meta_wayland_dma_buf_fd_readable (dma_buf->fds[i])) + { + ready = FALSE; + continue; + } + + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + + if (!ready) + return G_SOURCE_CONTINUE; + + source->dispatch (source->buffer, source->user_data); + + return G_SOURCE_REMOVE; +} + +static void +meta_wayland_dma_buf_source_finalize (GSource *base) +{ + MetaWaylandDmaBufSource *source; + uint32_t i; + + source = (MetaWaylandDmaBufSource *) base; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + + if (fd_tag) + { + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + } + + g_clear_object (&source->buffer); +} + +static GSourceFuncs meta_wayland_dma_buf_source_funcs = { + .dispatch = meta_wayland_dma_buf_source_dispatch, + .finalize = meta_wayland_dma_buf_source_finalize +}; + +/** + * meta_wayland_dma_buf_create_source: + * @buffer: A #MetaWaylandBuffer object + * @dispatch: Callback + * @user_data: User data for the callback + * + * Creates a GSource which will call the specified dispatch callback when all + * dma-buf file descriptors for the buffer have become readable. + * + * Returns: The new GSource (or + * %NULL if there are no dma-buf file descriptors, or they were all readable + * already) + */ +GSource * +meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, + MetaWaylandDmaBufSourceDispatch dispatch, + gpointer user_data) +{ + MetaWaylandDmaBufBuffer *dma_buf; + MetaWaylandDmaBufSource *source = NULL; + uint32_t i; + + dma_buf = buffer->dma_buf.dma_buf; + if (!dma_buf) + return NULL; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + int fd = dma_buf->fds[i]; + + if (fd < 0) + break; + + if (meta_wayland_dma_buf_fd_readable (fd)) + continue; + + if (!source) + { + source = + (MetaWaylandDmaBufSource *) g_source_new (&meta_wayland_dma_buf_source_funcs, + sizeof (*source)); + source->buffer = g_object_ref (buffer); + source->dispatch = dispatch; + source->user_data = user_data; + } + + source->fd_tags[i] = g_source_add_unix_fd (&source->base, fd, G_IO_IN); + } + + if (!source) + return NULL; + + return &source->base; +} + static void buffer_params_create_common (struct wl_client *client, struct wl_resource *params_resource, diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index 57b1ef68e..716b8c778 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -57,6 +57,14 @@ meta_wayland_dma_buf_fds_for_wayland_buffer (MetaWaylandBuffer *buffer); MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); +typedef void (*MetaWaylandDmaBufSourceDispatch) (MetaWaylandBuffer *buffer, + gpointer user_data); + +GSource * +meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, + MetaWaylandDmaBufSourceDispatch dispatch, + gpointer user_data); + CoglScanout * meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, CoglOnscreen *onscreen);