mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 19:10:43 -05:00
wayland: Add zwp_linux_dmabuf_v1 support
https://bugzilla.gnome.org/show_bug.cgi?id=785262 Signed-off-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
parent
1455c402b9
commit
b7b5fb293d
@ -292,7 +292,7 @@ AS_IF([test "$have_wayland" = "yes"], [
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_DEFINE([HAVE_WAYLAND],[1],[Define if you want to enable Wayland support])
|
||||
|
||||
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.7],
|
||||
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.9],
|
||||
[ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`])
|
||||
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir)
|
||||
])
|
||||
|
@ -71,6 +71,8 @@ mutter_built_sources += \
|
||||
tablet-unstable-v2-server-protocol.h \
|
||||
xdg-foreign-unstable-v1-protocol.c \
|
||||
xdg-foreign-unstable-v1-server-protocol.h \
|
||||
linux-dmabuf-unstable-v1-protocol.c \
|
||||
linux-dmabuf-unstable-v1-server-protocol.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
@ -317,6 +319,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
wayland/meta-xwayland-private.h \
|
||||
wayland/meta-wayland-buffer.c \
|
||||
wayland/meta-wayland-buffer.h \
|
||||
wayland/meta-wayland-dma-buf.c \
|
||||
wayland/meta-wayland-dma-buf.h \
|
||||
wayland/meta-wayland-region.c \
|
||||
wayland/meta-wayland-region.h \
|
||||
wayland/meta-wayland-data-device.c \
|
||||
|
@ -66,6 +66,9 @@ struct _MetaEgl
|
||||
|
||||
PFNEGLSTREAMCONSUMERACQUIREKHRPROC eglStreamConsumerAcquireKHR;
|
||||
PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC eglStreamConsumerAcquireAttribNV;
|
||||
|
||||
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT;
|
||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaEgl, meta_egl, G_TYPE_OBJECT)
|
||||
@ -711,6 +714,51 @@ meta_egl_stream_consumer_acquire (MetaEgl *egl,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_egl_query_dma_buf_formats (MetaEgl *egl,
|
||||
EGLDisplay display,
|
||||
EGLint max_formats,
|
||||
EGLint *formats,
|
||||
EGLint *num_formats,
|
||||
GError **error)
|
||||
{
|
||||
if (!is_egl_proc_valid (egl->eglQueryDmaBufFormatsEXT, error))
|
||||
return FALSE;
|
||||
|
||||
if (!egl->eglQueryDmaBufFormatsEXT (display, max_formats, formats,
|
||||
num_formats))
|
||||
{
|
||||
set_egl_error (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_egl_query_dma_buf_modifiers (MetaEgl *egl,
|
||||
EGLDisplay display,
|
||||
EGLint format,
|
||||
EGLint max_modifiers,
|
||||
EGLuint64KHR *modifiers,
|
||||
EGLBoolean *external_only,
|
||||
EGLint *num_modifiers,
|
||||
GError **error)
|
||||
{
|
||||
if (!is_egl_proc_valid (egl->eglQueryDmaBufModifiersEXT, error))
|
||||
return FALSE;
|
||||
|
||||
if (!egl->eglQueryDmaBufModifiersEXT (display, format, max_modifiers,
|
||||
modifiers, external_only,
|
||||
num_modifiers))
|
||||
{
|
||||
set_egl_error (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define GET_EGL_PROC_ADDR(proc) \
|
||||
egl->proc = (void *) eglGetProcAddress (#proc);
|
||||
|
||||
@ -753,6 +801,9 @@ meta_egl_constructed (GObject *object)
|
||||
|
||||
GET_EGL_PROC_ADDR (eglStreamConsumerAcquireKHR);
|
||||
GET_EGL_PROC_ADDR (eglStreamConsumerAcquireAttribNV);
|
||||
|
||||
GET_EGL_PROC_ADDR (eglQueryDmaBufFormatsEXT);
|
||||
GET_EGL_PROC_ADDR (eglQueryDmaBufModifiersEXT);
|
||||
}
|
||||
|
||||
#undef GET_EGL_PROC_ADDR
|
||||
|
@ -167,4 +167,20 @@ gboolean meta_egl_stream_consumer_gl_texture_external (MetaEgl *egl,
|
||||
EGLStreamKHR stream,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_egl_query_dma_buf_formats (MetaEgl *egl,
|
||||
EGLDisplay display,
|
||||
EGLint max_formats,
|
||||
EGLint *formats,
|
||||
EGLint *num_formats,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_egl_query_dma_buf_modifiers (MetaEgl *egl,
|
||||
EGLDisplay display,
|
||||
EGLint format,
|
||||
EGLint max_modifiers,
|
||||
EGLuint64KHR *modifiers,
|
||||
EGLBoolean *external_only,
|
||||
EGLint *num_formats,
|
||||
GError **error);
|
||||
|
||||
#endif /* META_EGL_H */
|
||||
|
@ -25,11 +25,18 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-wayland-buffer.h"
|
||||
#include "meta-wayland-dma-buf.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl-egl.h>
|
||||
#include <meta/util.h>
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#ifndef DRM_FORMAT_MOD_INVALID
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||
#endif
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
|
||||
enum
|
||||
@ -97,6 +104,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
|
||||
MetaWaylandEglStream *stream;
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
|
||||
if (wl_shm_buffer_get (buffer->resource) != NULL)
|
||||
{
|
||||
@ -120,6 +128,14 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dma_buf = meta_wayland_dma_buf_from_buffer (buffer);
|
||||
if (dma_buf)
|
||||
{
|
||||
buffer->dma_buf.dma_buf = dma_buf;
|
||||
buffer->type = META_WAYLAND_BUFFER_TYPE_DMA_BUF;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -341,6 +357,8 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
|
||||
return egl_image_buffer_attach (buffer, error);
|
||||
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
|
||||
return egl_stream_buffer_attach (buffer, error);
|
||||
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
|
||||
return meta_wayland_dma_buf_buffer_attach (buffer, error);
|
||||
case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
@ -430,6 +448,7 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||
res = process_shm_buffer_damage (buffer, region, &error);
|
||||
case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
|
||||
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
|
||||
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
|
||||
res = TRUE;
|
||||
break;
|
||||
case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
|
||||
@ -453,6 +472,7 @@ meta_wayland_buffer_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&buffer->texture, cogl_object_unref);
|
||||
g_clear_object (&buffer->egl_stream.stream);
|
||||
g_clear_object (&buffer->dma_buf.dma_buf);
|
||||
|
||||
G_OBJECT_CLASS (meta_wayland_buffer_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "meta-wayland-types.h"
|
||||
#include "meta-wayland-egl-stream.h"
|
||||
#include "meta-wayland-dma-buf.h"
|
||||
|
||||
typedef enum _MetaWaylandBufferType
|
||||
{
|
||||
@ -38,6 +39,7 @@ typedef enum _MetaWaylandBufferType
|
||||
META_WAYLAND_BUFFER_TYPE_SHM,
|
||||
META_WAYLAND_BUFFER_TYPE_EGL_IMAGE,
|
||||
META_WAYLAND_BUFFER_TYPE_EGL_STREAM,
|
||||
META_WAYLAND_BUFFER_TYPE_DMA_BUF,
|
||||
} MetaWaylandBufferType;
|
||||
|
||||
struct _MetaWaylandBuffer
|
||||
@ -55,6 +57,10 @@ struct _MetaWaylandBuffer
|
||||
struct {
|
||||
MetaWaylandEglStream *stream;
|
||||
} egl_stream;
|
||||
|
||||
struct {
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
} dma_buf;
|
||||
};
|
||||
|
||||
#define META_TYPE_WAYLAND_BUFFER (meta_wayland_buffer_get_type ())
|
||||
|
585
src/wayland/meta-wayland-dma-buf.c
Normal file
585
src/wayland/meta-wayland-dma-buf.c
Normal file
@ -0,0 +1,585 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Red Hat Inc.
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by:
|
||||
* Jonas Ådahl <jadahl@gmail.com>
|
||||
* Daniel Stone <daniels@collabora.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "wayland/meta-wayland-dma-buf.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "cogl/cogl-egl.h"
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-egl.h"
|
||||
#include "backends/meta-egl-ext.h"
|
||||
#include "meta/meta-backend.h"
|
||||
#include "wayland/meta-wayland-buffer.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#include "wayland/meta-wayland-versions.h"
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#include "linux-dmabuf-unstable-v1-server-protocol.h"
|
||||
|
||||
#ifndef DRM_FORMAT_MOD_INVALID
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||
#endif
|
||||
|
||||
#define META_WAYLAND_DMA_BUF_MAX_FDS 4
|
||||
|
||||
struct _MetaWaylandDmaBufBuffer
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
uint32_t drm_format;
|
||||
uint64_t drm_modifier;
|
||||
bool is_y_inverted;
|
||||
int fds[META_WAYLAND_DMA_BUF_MAX_FDS];
|
||||
int offsets[META_WAYLAND_DMA_BUF_MAX_FDS];
|
||||
unsigned int strides[META_WAYLAND_DMA_BUF_MAX_FDS];
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT);
|
||||
|
||||
gboolean
|
||||
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
|
||||
GError **error)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaEgl *egl = meta_backend_get_egl (backend);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
|
||||
MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf;
|
||||
CoglPixelFormat cogl_format;
|
||||
EGLImageKHR egl_image;
|
||||
CoglTexture2D *texture;
|
||||
EGLint attribs[64];
|
||||
int attr_idx = 0;
|
||||
|
||||
if (buffer->texture)
|
||||
return TRUE;
|
||||
|
||||
/* DRM_FORMAT_* enums consider the entire pixel as a single packed quantity,
|
||||
* with little-endian ordering. COGL_PIXEL_FORMAT_* is in byte order when
|
||||
* each channel is an 8-byte unit. Hence these have order swapped. */
|
||||
switch (dma_buf->drm_format)
|
||||
{
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
cogl_format = COGL_PIXEL_FORMAT_BGR_888;
|
||||
break;
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
|
||||
break;
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
|
||||
break;
|
||||
case DRM_FORMAT_RGB565:
|
||||
cogl_format = COGL_PIXEL_FORMAT_RGB_565;
|
||||
break;
|
||||
default:
|
||||
g_set_error (error, G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Unsupported buffer format %d", dma_buf->drm_format);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
attribs[attr_idx++] = EGL_WIDTH;
|
||||
attribs[attr_idx++] = dma_buf->width;
|
||||
attribs[attr_idx++] = EGL_HEIGHT;
|
||||
attribs[attr_idx++] = dma_buf->height;
|
||||
attribs[attr_idx++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_format;
|
||||
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_FD_EXT;
|
||||
attribs[attr_idx++] = dma_buf->fds[0];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
|
||||
attribs[attr_idx++] = dma_buf->offsets[0];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
|
||||
attribs[attr_idx++] = dma_buf->strides[0];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
|
||||
|
||||
if (dma_buf->fds[1] >= 0)
|
||||
{
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_FD_EXT;
|
||||
attribs[attr_idx++] = dma_buf->fds[1];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
|
||||
attribs[attr_idx++] = dma_buf->offsets[1];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
|
||||
attribs[attr_idx++] = dma_buf->strides[1];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
|
||||
}
|
||||
|
||||
if (dma_buf->fds[2] >= 0)
|
||||
{
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_FD_EXT;
|
||||
attribs[attr_idx++] = dma_buf->fds[2];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
|
||||
attribs[attr_idx++] = dma_buf->offsets[2];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
|
||||
attribs[attr_idx++] = dma_buf->strides[2];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
|
||||
}
|
||||
|
||||
if (dma_buf->fds[3] >= 0)
|
||||
{
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_FD_EXT;
|
||||
attribs[attr_idx++] = dma_buf->fds[3];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
|
||||
attribs[attr_idx++] = dma_buf->offsets[3];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
|
||||
attribs[attr_idx++] = dma_buf->strides[3];
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
|
||||
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
|
||||
attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
|
||||
}
|
||||
|
||||
attribs[attr_idx++] = EGL_NONE;
|
||||
attribs[attr_idx++] = EGL_NONE;
|
||||
|
||||
/* The EXT_image_dma_buf_import spec states that EGL_NO_CONTEXT is to be used
|
||||
* in conjunction with the EGL_LINUX_DMA_BUF_EXT target. Similarly, the
|
||||
* native buffer is named in the attribs. */
|
||||
egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT, NULL, attribs,
|
||||
error);
|
||||
if (egl_image == EGL_NO_IMAGE_KHR)
|
||||
return FALSE;
|
||||
|
||||
texture = cogl_egl_texture_2d_new_from_image (cogl_context,
|
||||
dma_buf->width,
|
||||
dma_buf->height,
|
||||
cogl_format,
|
||||
egl_image,
|
||||
error);
|
||||
|
||||
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
|
||||
|
||||
if (!texture)
|
||||
return FALSE;
|
||||
|
||||
buffer->texture = COGL_TEXTURE (texture);
|
||||
buffer->is_y_inverted = dma_buf->is_y_inverted;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_add (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
int32_t fd,
|
||||
uint32_t plane_idx,
|
||||
uint32_t offset,
|
||||
uint32_t stride,
|
||||
uint32_t drm_modifier_hi,
|
||||
uint32_t drm_modifier_lo)
|
||||
{
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
uint64_t drm_modifier;
|
||||
|
||||
drm_modifier = ((uint64_t) drm_modifier_hi) << 32;
|
||||
drm_modifier |= ((uint64_t) drm_modifier_lo) & 0xffffffff;
|
||||
|
||||
dma_buf = wl_resource_get_user_data (resource);
|
||||
if (!dma_buf)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
|
||||
"params already used");
|
||||
return;
|
||||
}
|
||||
|
||||
if (plane_idx >= META_WAYLAND_DMA_BUF_MAX_FDS)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
|
||||
"out-of-bounds plane index %d",
|
||||
plane_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dma_buf->fds[plane_idx] != -1)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
|
||||
"plane index %d already set",
|
||||
plane_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID &&
|
||||
dma_buf->drm_modifier != drm_modifier)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
|
||||
"mismatching modifier between planes");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_buf->drm_modifier = drm_modifier;
|
||||
dma_buf->fds[plane_idx] = fd;
|
||||
dma_buf->offsets[plane_idx] = offset;
|
||||
dma_buf->strides[plane_idx] = stride;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_destructor (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
|
||||
/* The user-data for our MetaWaylandBuffer is only valid in between adding
|
||||
* FDs and creating the buffer; once it is created, we free it out into
|
||||
* the wild, where the ref is considered transferred to the wl_buffer. */
|
||||
dma_buf = wl_resource_get_user_data (resource);
|
||||
if (dma_buf)
|
||||
g_object_unref (dma_buf);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_interface dma_buf_buffer_impl =
|
||||
{
|
||||
buffer_destroy,
|
||||
};
|
||||
|
||||
MetaWaylandDmaBufBuffer *
|
||||
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer)
|
||||
{
|
||||
if (wl_resource_instance_of (buffer->resource, &wl_buffer_interface,
|
||||
&dma_buf_buffer_impl))
|
||||
return wl_resource_get_user_data (buffer->resource);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_create_common (struct wl_client *client,
|
||||
struct wl_resource *params_resource,
|
||||
uint32_t buffer_id,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t drm_format,
|
||||
uint32_t flags)
|
||||
{
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_resource *buffer_resource;
|
||||
GError *error = NULL;
|
||||
|
||||
dma_buf = wl_resource_get_user_data (params_resource);
|
||||
if (!dma_buf)
|
||||
{
|
||||
wl_resource_post_error (params_resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
|
||||
"params already used");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calling the 'create' method is the point of no return: after that point,
|
||||
* the params object cannot be used. This method must either transfer the
|
||||
* ownership of the MetaWaylandDmaBufBuffer to a MetaWaylandBuffer, or
|
||||
* destroy it. */
|
||||
wl_resource_set_user_data (params_resource, NULL);
|
||||
|
||||
if (dma_buf->fds[0] == -1)
|
||||
{
|
||||
wl_resource_post_error (params_resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
|
||||
"no planes added to params");
|
||||
g_object_unref (dma_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dma_buf->fds[3] >= 0 || dma_buf->fds[2] >= 0) &&
|
||||
(dma_buf->fds[2] == -1 || dma_buf->fds[1] == -1))
|
||||
{
|
||||
wl_resource_post_error (params_resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
|
||||
"gap in planes added to params");
|
||||
g_object_unref (dma_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_buf->width = width;
|
||||
dma_buf->height = height;
|
||||
dma_buf->drm_format = drm_format;
|
||||
dma_buf->is_y_inverted = !(flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
|
||||
|
||||
if (flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
|
||||
{
|
||||
wl_resource_post_error (params_resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
|
||||
"unknown flags 0x%x supplied", flags);
|
||||
g_object_unref (dma_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new MetaWaylandBuffer wrapping our dmabuf, and immediately try
|
||||
* to realize it, so we can give the client success/fail feedback for the
|
||||
* import. */
|
||||
buffer_resource =
|
||||
wl_resource_create (client, &wl_buffer_interface, 1, buffer_id);
|
||||
wl_resource_set_implementation (buffer_resource, &dma_buf_buffer_impl,
|
||||
dma_buf, NULL);
|
||||
buffer = meta_wayland_buffer_from_resource (buffer_resource);
|
||||
|
||||
if (!meta_wayland_buffer_attach (buffer, &error))
|
||||
{
|
||||
if (buffer_id == 0)
|
||||
{
|
||||
zwp_linux_buffer_params_v1_send_failed (params_resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_resource_post_error (params_resource,
|
||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
|
||||
"failed to import supplied dmabufs: %s",
|
||||
error ? error->message : "unknown error");
|
||||
}
|
||||
|
||||
/* will unref the MetaWaylandBuffer */
|
||||
wl_resource_destroy (buffer->resource);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If buffer_id is 0, we are using the non-immediate interface, so
|
||||
* need to send a success event with our buffer. */
|
||||
if (buffer_id == 0)
|
||||
zwp_linux_buffer_params_v1_send_created (params_resource,
|
||||
buffer->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_create (struct wl_client *client,
|
||||
struct wl_resource *params_resource,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t format,
|
||||
uint32_t flags)
|
||||
{
|
||||
buffer_params_create_common (client, params_resource, 0, width, height,
|
||||
format, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_params_create_immed (struct wl_client *client,
|
||||
struct wl_resource *params_resource,
|
||||
uint32_t buffer_id,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t format,
|
||||
uint32_t flags)
|
||||
{
|
||||
buffer_params_create_common (client, params_resource, buffer_id, width,
|
||||
height, format, flags);
|
||||
}
|
||||
|
||||
static const struct zwp_linux_buffer_params_v1_interface buffer_params_implementation =
|
||||
{
|
||||
buffer_params_destroy,
|
||||
buffer_params_add,
|
||||
buffer_params_create,
|
||||
buffer_params_create_immed,
|
||||
};
|
||||
|
||||
static void
|
||||
dma_buf_handle_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
dma_buf_handle_create_buffer_params (struct wl_client *client,
|
||||
struct wl_resource *dma_buf_resource,
|
||||
uint32_t params_id)
|
||||
{
|
||||
struct wl_resource *params_resource;
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
|
||||
dma_buf = g_object_new (META_TYPE_WAYLAND_DMA_BUF_BUFFER, NULL);
|
||||
|
||||
params_resource =
|
||||
wl_resource_create (client,
|
||||
&zwp_linux_buffer_params_v1_interface,
|
||||
wl_resource_get_version (dma_buf_resource),
|
||||
params_id);
|
||||
wl_resource_set_implementation (params_resource,
|
||||
&buffer_params_implementation,
|
||||
dma_buf,
|
||||
buffer_params_destructor);
|
||||
}
|
||||
|
||||
static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation =
|
||||
{
|
||||
dma_buf_handle_destroy,
|
||||
dma_buf_handle_create_buffer_params,
|
||||
};
|
||||
|
||||
static void
|
||||
send_modifiers (struct wl_resource *resource,
|
||||
uint32_t format)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaEgl *egl = meta_backend_get_egl (backend);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
|
||||
EGLint num_modifiers;
|
||||
EGLuint64KHR *modifiers;
|
||||
GError *error = NULL;
|
||||
gboolean ret;
|
||||
int i;
|
||||
|
||||
/* First query the number of available modifiers, then allocate an array,
|
||||
* then fill the array. */
|
||||
ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, 0, NULL,
|
||||
NULL, &num_modifiers, NULL);
|
||||
if (!ret || num_modifiers == 0)
|
||||
return;
|
||||
|
||||
modifiers = g_new0 (uint64_t, num_modifiers);
|
||||
ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format,
|
||||
num_modifiers, modifiers, NULL,
|
||||
&num_modifiers, &error);
|
||||
if (!ret)
|
||||
{
|
||||
g_warning ("Failed to query modifiers for format 0x%" PRIu32 ": %s",
|
||||
format, error ? error->message : "unknown error");
|
||||
g_free (modifiers);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_modifiers; i++)
|
||||
{
|
||||
zwp_linux_dmabuf_v1_send_modifier (resource, format,
|
||||
modifiers[i] >> 32,
|
||||
modifiers[i] & 0xffffffff);
|
||||
}
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
static void
|
||||
dma_buf_bind (struct wl_client *client,
|
||||
void *data,
|
||||
uint32_t version,
|
||||
uint32_t id)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = data;
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface,
|
||||
version, id);
|
||||
wl_resource_set_implementation (resource, &dma_buf_implementation,
|
||||
compositor, NULL);
|
||||
send_modifiers (resource, DRM_FORMAT_ARGB8888);
|
||||
send_modifiers (resource, DRM_FORMAT_XRGB8888);
|
||||
send_modifiers (resource, DRM_FORMAT_ARGB2101010);
|
||||
send_modifiers (resource, DRM_FORMAT_RGB565);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaEgl *egl = meta_backend_get_egl (backend);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
|
||||
|
||||
g_assert (backend && egl && clutter_backend && cogl_context && egl_display);
|
||||
|
||||
if (!meta_egl_has_extensions (egl, egl_display, NULL,
|
||||
"EGL_EXT_image_dma_buf_import_modifiers",
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!wl_global_create (compositor->wayland_display,
|
||||
&zwp_linux_dmabuf_v1_interface,
|
||||
META_ZWP_LINUX_DMABUF_V1_VERSION,
|
||||
compositor,
|
||||
dma_buf_bind))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_dma_buf_buffer_finalize (GObject *object)
|
||||
{
|
||||
MetaWaylandDmaBufBuffer *dma_buf = META_WAYLAND_DMA_BUF_BUFFER (object);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++)
|
||||
{
|
||||
if (dma_buf->fds[i] != -1)
|
||||
close (dma_buf->fds[i]);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_wayland_dma_buf_buffer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_dma_buf_buffer_init (MetaWaylandDmaBufBuffer *dma_buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
dma_buf->drm_modifier = DRM_FORMAT_MOD_INVALID;
|
||||
|
||||
for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++)
|
||||
dma_buf->fds[i] = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_dma_buf_buffer_class_init (MetaWaylandDmaBufBufferClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_wayland_dma_buf_buffer_finalize;
|
||||
}
|
50
src/wayland/meta-wayland-dma-buf.h
Normal file
50
src/wayland/meta-wayland-dma-buf.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Red Hat Inc.
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by:
|
||||
* Jonas Ådahl <jadahl@gmail.com>
|
||||
* Daniel Stone <daniels@collabora.com>
|
||||
*/
|
||||
|
||||
#ifndef META_WAYLAND_DMA_BUF_H
|
||||
#define META_WAYLAND_DMA_BUF_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "wayland/meta-wayland-types.h"
|
||||
|
||||
#define META_TYPE_WAYLAND_DMA_BUF_BUFFER (meta_wayland_dma_buf_buffer_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer,
|
||||
META, WAYLAND_DMA_BUF_BUFFER, GObject);
|
||||
|
||||
typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer;
|
||||
|
||||
gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor);
|
||||
|
||||
gboolean
|
||||
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
|
||||
GError **error);
|
||||
|
||||
MetaWaylandDmaBufBuffer *
|
||||
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
|
||||
|
||||
#endif /* META_WAYLAND_DMA_BUF_H */
|
@ -47,5 +47,6 @@
|
||||
#define META_ZWP_POINTER_GESTURES_V1_VERSION 1
|
||||
#define META_ZXDG_EXPORTER_V1_VERSION 1
|
||||
#define META_ZXDG_IMPORTER_V1_VERSION 1
|
||||
#define META_ZWP_LINUX_DMABUF_V1_VERSION 3
|
||||
|
||||
#endif
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "meta-wayland-data-device.h"
|
||||
#include "meta-wayland-tablet-manager.h"
|
||||
#include "meta-wayland-xdg-foreign.h"
|
||||
#include "meta-wayland-dma-buf.h"
|
||||
|
||||
static MetaWaylandCompositor _meta_wayland_compositor;
|
||||
static char *_display_name_override;
|
||||
@ -355,6 +356,7 @@ meta_wayland_init (void)
|
||||
meta_wayland_relative_pointer_init (compositor);
|
||||
meta_wayland_pointer_constraints_init (compositor);
|
||||
meta_wayland_xdg_foreign_init (compositor);
|
||||
meta_wayland_dma_buf_init (compositor);
|
||||
|
||||
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
|
||||
g_error ("Failed to start X Wayland");
|
||||
|
Loading…
Reference in New Issue
Block a user