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
This commit is contained in:
parent
4b1805c306
commit
ff7a42b8bc
@ -58,6 +58,11 @@
|
|||||||
#include "meta/util.h"
|
#include "meta/util.h"
|
||||||
#include "wayland/meta-wayland-dma-buf.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
|
#ifndef DRM_FORMAT_MOD_INVALID
|
||||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||||
#endif
|
#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
|
static void
|
||||||
meta_wayland_buffer_finalize (GObject *object)
|
meta_wayland_buffer_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
|
@ -88,5 +88,7 @@ gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuff
|
|||||||
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||||
CoglTexture *texture,
|
CoglTexture *texture,
|
||||||
cairo_region_t *region);
|
cairo_region_t *region);
|
||||||
|
CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
|
||||||
|
CoglOnscreen *onscreen);
|
||||||
|
|
||||||
#endif /* META_WAYLAND_BUFFER_H */
|
#endif /* META_WAYLAND_BUFFER_H */
|
||||||
|
@ -51,6 +51,11 @@
|
|||||||
#include "wayland/meta-wayland-private.h"
|
#include "wayland/meta-wayland-private.h"
|
||||||
#include "wayland/meta-wayland-versions.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"
|
#include "linux-dmabuf-unstable-v1-server-protocol.h"
|
||||||
|
|
||||||
#ifndef DRM_FORMAT_MOD_INVALID
|
#ifndef DRM_FORMAT_MOD_INVALID
|
||||||
@ -178,6 +183,117 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
|
|||||||
return TRUE;
|
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
|
static void
|
||||||
buffer_params_add (struct wl_client *client,
|
buffer_params_add (struct wl_client *client,
|
||||||
struct wl_resource *resource,
|
struct wl_resource *resource,
|
||||||
|
@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
|
|||||||
MetaWaylandDmaBufBuffer *
|
MetaWaylandDmaBufBuffer *
|
||||||
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
|
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 */
|
#endif /* META_WAYLAND_DMA_BUF_H */
|
||||||
|
@ -131,6 +131,13 @@ meta_wayland_buffer_ref_new (void)
|
|||||||
return buffer_ref;
|
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
|
static void
|
||||||
meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref)
|
meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref)
|
||||||
{
|
{
|
||||||
@ -667,6 +674,12 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
|
|||||||
if (surface->buffer_held)
|
if (surface->buffer_held)
|
||||||
meta_wayland_surface_unref_buffer_use_count (surface);
|
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);
|
g_set_object (&surface->buffer_ref->buffer, state->buffer);
|
||||||
|
|
||||||
if (state->buffer)
|
if (state->buffer)
|
||||||
@ -1959,3 +1972,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface)
|
|||||||
return height / surface->scale;
|
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;
|
||||||
|
}
|
||||||
|
@ -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_width (MetaWaylandSurface *surface);
|
||||||
int meta_wayland_surface_get_height (MetaWaylandSurface *surface);
|
int meta_wayland_surface_get_height (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
|
CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
|
||||||
|
CoglOnscreen *onscreen);
|
||||||
|
|
||||||
static inline GNode *
|
static inline GNode *
|
||||||
meta_get_next_subsurface_sibling (GNode *n)
|
meta_get_next_subsurface_sibling (GNode *n)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user