[mutter] wayland: Add API to acquire a CoglScanout from a surface
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] wayland: Add API to acquire a CoglScanout from a surface
- Date: Thu, 16 Apr 2020 14:09:28 +0000 (UTC)
commit ff7a42b8bc25c24d3e0fc0a277b1d628f5ea599a
Author: Jonas Ådahl <jadahl gmail com>
Date: Thu Sep 12 11:44:59 2019 +0200
wayland: Add API to acquire a CoglScanout from a surface
This will check whether the current backing buffer is compatible with
the primary plane of the passed CoglOnscreen. Since this will extend the
time before a buffer is released, the MetaWaylandBufferRef is swapped
and orphaned if a new buffer is committed before the previous one was
released. It'll eventually be released, usually by the next page flip
callback.
Currently implemented for EGLImage and DMA-BUF buffer types.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
src/wayland/meta-wayland-buffer.c | 92 +++++++++++++++++++++++++++++
src/wayland/meta-wayland-buffer.h | 2 +
src/wayland/meta-wayland-dma-buf.c | 116 +++++++++++++++++++++++++++++++++++++
src/wayland/meta-wayland-dma-buf.h | 4 ++
src/wayland/meta-wayland-surface.c | 48 +++++++++++++++
src/wayland/meta-wayland-surface.h | 3 +
6 files changed, 265 insertions(+)
---
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index 6236579e7..9c0195501 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -58,6 +58,11 @@
#include "meta/util.h"
#include "wayland/meta-wayland-dma-buf.h"
+#ifdef HAVE_NATIVE_BACKEND
+#include "backends/native/meta-drm-buffer-gbm.h"
+#include "backends/native/meta-renderer-native.h"
+#endif
+
#ifndef DRM_FORMAT_MOD_INVALID
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
#endif
@@ -577,6 +582,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
}
}
+static CoglScanout *
+try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer,
+ CoglOnscreen *onscreen)
+{
+#ifdef HAVE_NATIVE_BACKEND
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+ MetaGpuKms *gpu_kms;
+ struct gbm_device *gbm_device;
+ struct gbm_bo *gbm_bo;
+ uint32_t drm_format;
+ uint64_t drm_modifier;
+ uint32_t stride;
+ MetaDrmBufferGbm *fb;
+ g_autoptr (GError) error = NULL;
+
+ gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
+ gbm_device = meta_gbm_device_from_gpu (gpu_kms);
+
+ gbm_bo = gbm_bo_import (gbm_device,
+ GBM_BO_IMPORT_WL_BUFFER, buffer->resource,
+ GBM_BO_USE_SCANOUT);
+ if (!gbm_bo)
+ return NULL;
+
+ drm_format = gbm_bo_get_format (gbm_bo);
+ drm_modifier = gbm_bo_get_modifier (gbm_bo);
+ stride = gbm_bo_get_stride (gbm_bo);
+ if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
+ drm_format,
+ drm_modifier,
+ stride))
+ {
+ gbm_bo_destroy (gbm_bo);
+ return NULL;
+ }
+
+ fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
+ drm_modifier != DRM_FORMAT_MOD_INVALID,
+ &error);
+ if (!fb)
+ {
+ g_debug ("Failed to create scanout buffer: %s", error->message);
+ gbm_bo_destroy (gbm_bo);
+ return NULL;
+ }
+
+ return COGL_SCANOUT (fb);
+#else
+ return NULL;
+#endif
+}
+
+CoglScanout *
+meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
+ CoglOnscreen *onscreen)
+{
+ switch (buffer->type)
+ {
+ case META_WAYLAND_BUFFER_TYPE_SHM:
+ return NULL;
+ case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+ return try_acquire_egl_image_scanout (buffer, onscreen);
+#ifdef HAVE_WAYLAND_EGLSTREAM
+ case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
+ return NULL;
+#endif
+ case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
+ {
+ MetaWaylandDmaBufBuffer *dma_buf;
+
+ dma_buf = meta_wayland_dma_buf_from_buffer (buffer);
+ if (!dma_buf)
+ return NULL;
+
+ return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen);
+ }
+ case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
+ g_warn_if_reached ();
+ return NULL;
+ }
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
static void
meta_wayland_buffer_finalize (GObject *object)
{
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index 4a503b183..77e68e724 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -88,5 +88,7 @@ gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuff
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture,
cairo_region_t *region);
+CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
+ CoglOnscreen *onscreen);
#endif /* META_WAYLAND_BUFFER_H */
diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c
index e50389aec..21560cd54 100644
--- a/src/wayland/meta-wayland-dma-buf.c
+++ b/src/wayland/meta-wayland-dma-buf.c
@@ -51,6 +51,11 @@
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-versions.h"
+#ifdef HAVE_NATIVE_BACKEND
+#include "backends/native/meta-drm-buffer-gbm.h"
+#include "backends/native/meta-renderer-native.h"
+#endif
+
#include "linux-dmabuf-unstable-v1-server-protocol.h"
#ifndef DRM_FORMAT_MOD_INVALID
@@ -178,6 +183,117 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
return TRUE;
}
+#ifdef HAVE_NATIVE_BACKEND
+static struct gbm_bo *
+create_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf,
+ MetaGpuKms *gpu_kms,
+ int n_planes,
+ gboolean *use_modifier)
+{
+ struct gbm_device *gbm_device;
+
+ gbm_device = meta_gbm_device_from_gpu (gpu_kms);
+
+ if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID ||
+ n_planes > 1 ||
+ dma_buf->offsets[0] > 0)
+ {
+ struct gbm_import_fd_modifier_data import_with_modifier;
+
+ import_with_modifier = (struct gbm_import_fd_modifier_data) {
+ .width = dma_buf->width,
+ .height = dma_buf->height,
+ .format = dma_buf->drm_format,
+ .num_fds = n_planes,
+ .modifier = dma_buf->drm_modifier,
+ };
+ memcpy (import_with_modifier.fds,
+ dma_buf->fds,
+ sizeof (dma_buf->fds));
+ memcpy (import_with_modifier.strides,
+ dma_buf->strides,
+ sizeof (import_with_modifier.strides));
+ memcpy (import_with_modifier.offsets,
+ dma_buf->offsets,
+ sizeof (import_with_modifier.offsets));
+
+ *use_modifier = TRUE;
+ return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER,
+ &import_with_modifier,
+ GBM_BO_USE_SCANOUT);
+ }
+ else
+ {
+ struct gbm_import_fd_data import_legacy;
+
+ import_legacy = (struct gbm_import_fd_data) {
+ .width = dma_buf->width,
+ .height = dma_buf->height,
+ .format = dma_buf->drm_format,
+ .stride = dma_buf->strides[0],
+ .fd = dma_buf->fds[0],
+ };
+
+ *use_modifier = FALSE;
+ return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD,
+ &import_legacy,
+ GBM_BO_USE_SCANOUT);
+ }
+}
+#endif
+
+CoglScanout *
+meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
+ CoglOnscreen *onscreen)
+{
+#ifdef HAVE_NATIVE_BACKEND
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+ MetaGpuKms *gpu_kms;
+ int n_planes;
+ uint32_t drm_format;
+ uint64_t drm_modifier;
+ uint32_t stride;
+ struct gbm_bo *gbm_bo;
+ gboolean use_modifier;
+ g_autoptr (GError) error = NULL;
+ MetaDrmBufferGbm *fb;
+
+ for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
+ {
+ if (dma_buf->fds[n_planes] < 0)
+ break;
+ }
+
+ drm_format = dma_buf->drm_format;
+ drm_modifier = dma_buf->drm_modifier;
+ stride = dma_buf->strides[0];
+ if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
+ drm_format,
+ drm_modifier,
+ stride))
+ return NULL;
+
+ gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
+ gbm_bo = create_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier);
+
+ fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
+ use_modifier,
+ &error);
+ if (!fb)
+ {
+ g_debug ("Failed to create scanout buffer: %s", error->message);
+ gbm_bo_destroy (gbm_bo);
+ return NULL;
+ }
+
+ return COGL_SCANOUT (fb);
+#else
+ return NULL;
+#endif
+}
+
static void
buffer_params_add (struct wl_client *client,
struct wl_resource *resource,
diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h
index b7f712d8d..cdc65aeb5 100644
--- a/src/wayland/meta-wayland-dma-buf.h
+++ b/src/wayland/meta-wayland-dma-buf.h
@@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
MetaWaylandDmaBufBuffer *
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
+CoglScanout *
+meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
+ CoglOnscreen *onscreen);
+
#endif /* META_WAYLAND_DMA_BUF_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 99f3fc58b..fa84944bd 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -131,6 +131,13 @@ meta_wayland_buffer_ref_new (void)
return buffer_ref;
}
+static MetaWaylandBufferRef *
+meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref)
+{
+ g_ref_count_inc (&buffer_ref->ref_count);
+ return buffer_ref;
+}
+
static void
meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref)
{
@@ -667,6 +674,12 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
if (surface->buffer_held)
meta_wayland_surface_unref_buffer_use_count (surface);
+ if (surface->buffer_ref->use_count > 0)
+ {
+ meta_wayland_buffer_ref_unref (surface->buffer_ref);
+ surface->buffer_ref = meta_wayland_buffer_ref_new ();
+ }
+
g_set_object (&surface->buffer_ref->buffer, state->buffer);
if (state->buffer)
@@ -1959,3 +1972,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface)
return height / surface->scale;
}
}
+
+static void
+scanout_destroyed (gpointer data,
+ GObject *where_the_object_was)
+{
+ MetaWaylandBufferRef *buffer_ref = data;
+
+ meta_wayland_buffer_ref_dec_use_count (buffer_ref);
+ meta_wayland_buffer_ref_unref (buffer_ref);
+}
+
+CoglScanout *
+meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
+ CoglOnscreen *onscreen)
+{
+ CoglScanout *scanout;
+ MetaWaylandBufferRef *buffer_ref;
+
+ if (!surface->buffer_ref->buffer)
+ return NULL;
+
+ if (surface->buffer_ref->use_count == 0)
+ return NULL;
+
+ scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer,
+ onscreen);
+ if (!scanout)
+ return NULL;
+
+ buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref);
+ meta_wayland_buffer_ref_inc_use_count (buffer_ref);
+ g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref);
+
+ return scanout;
+}
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 9cedba506..50736758a 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -346,6 +346,9 @@ void meta_wayland_surface_update_outputs_recursively (MetaWayland
int meta_wayland_surface_get_width (MetaWaylandSurface *surface);
int meta_wayland_surface_get_height (MetaWaylandSurface *surface);
+CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
+ CoglOnscreen *onscreen);
+
static inline GNode *
meta_get_next_subsurface_sibling (GNode *n)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]