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) {