[RFC xserver 05/16] DRI3/Glamor: Implement PixmapFromBuffers request
Daniel Stone
daniels at collabora.com
Thu Jun 8 18:43:31 UTC 2017
From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
dri3/dri3.h | 18 ++--
dri3/dri3_priv.h | 5 +-
dri3/dri3_request.c | 75 ++++++++++++---
dri3/dri3_screen.c | 12 ++-
glamor/glamor.c | 56 +++++++++++
glamor/glamor.h | 28 ++----
glamor/glamor_egl.c | 161 +++++++++++++++++++++++++++++---
hw/xwayland/xwayland-glamor.c | 211 ++++++++++++++++++++++++++++++++++++++----
hw/xwayland/xwayland.h | 1 +
9 files changed, 491 insertions(+), 76 deletions(-)
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 40b8474c0..4d6699f5e 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -39,13 +39,15 @@ typedef int (*dri3_open_client_proc)(ClientPtr client,
RRProviderPtr provider,
int *fd);
-typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
- int fd,
- CARD16 width,
- CARD16 height,
- CARD16 stride,
- CARD8 depth,
- CARD8 bpp);
+typedef PixmapPtr (*dri3_pixmap_from_fds_proc) (ScreenPtr screen,
+ CARD8 num_fds,
+ int *fds,
+ CARD16 width,
+ CARD16 height,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD32 format,
+ uint64_t modifiers);
typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
PixmapPtr pixmap,
@@ -66,7 +68,7 @@ typedef struct dri3_screen_info {
uint32_t version;
dri3_open_proc open;
- dri3_pixmap_from_fd_proc pixmap_from_fd;
+ dri3_pixmap_from_fds_proc pixmap_from_fds;
dri3_fd_from_pixmap_proc fd_from_pixmap;
dri3_get_formats_proc get_formats;
dri3_get_modifiers_proc get_modifiers;
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index c767f373e..5359a8a92 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -80,8 +80,9 @@ int
dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd);
int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp);
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height, CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier);
int
dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index 35f1c2533..182388232 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <xace.h>
#include "../Xext/syncsdk.h"
+#include <drm_fourcc.h>
#include <protocol-versions.h>
static int
@@ -117,6 +118,41 @@ proc_dri3_open(ClientPtr client)
return Success;
}
+static uint32_t
+drm_format_for_depth(uint32_t bpp, uint32_t depth)
+{
+ uint32_t fmt;
+
+ switch (bpp) {
+ case 8:
+ fmt = DRM_FORMAT_C8;
+ break;
+ case 16:
+ if (depth == 15)
+ fmt = DRM_FORMAT_XRGB1555;
+ else
+ fmt = DRM_FORMAT_RGB565;
+ break;
+ case 24:
+ fmt = DRM_FORMAT_RGB888;
+ break;
+ case 32:
+ if (depth == 24)
+ fmt = DRM_FORMAT_XRGB8888;
+ else if (depth == 30)
+ fmt = DRM_FORMAT_XRGB2101010;
+ else
+ fmt = DRM_FORMAT_ARGB8888;
+ break;
+ default:
+ // XXX error
+ fmt = DRM_FORMAT_XRGB8888;
+ break;
+ }
+
+ return fmt;
+}
+
static int
proc_dri3_pixmap_from_buffer(ClientPtr client)
{
@@ -124,6 +160,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
int fd;
DrawablePtr drawable;
PixmapPtr pixmap;
+ CARD32 stride, offset, format;
int rc;
SetReqFds(client, 1);
@@ -159,11 +196,13 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
if (fd < 0)
return BadValue;
- rc = dri3_pixmap_from_fd(&pixmap,
- drawable->pScreen, fd,
- stuff->width, stuff->height,
- stuff->stride, stuff->depth,
- stuff->bpp);
+ offset = 0;
+ stride = stuff->stride;
+ format = drm_format_for_depth(stuff->bpp, stuff->depth);
+ rc = dri3_pixmap_from_fds(&pixmap,
+ drawable->pScreen, 1, &fd,
+ stuff->width, stuff->height,
+ &stride, &offset, format, 0);
close (fd);
if (rc != Success)
return rc;
@@ -402,8 +441,10 @@ proc_dri3_pixmap_from_buffers(ClientPtr client)
{
REQUEST(xDRI3PixmapFromBuffersReq);
int fds[4];
+ CARD32 strides[4], offsets[4];
DrawablePtr drawable;
PixmapPtr pixmap;
+ uint64_t modifier;
int rc;
int i;
@@ -435,12 +476,24 @@ proc_dri3_pixmap_from_buffers(ClientPtr client)
return BadValue;
}
- /* XXX: DTRT */
- rc = dri3_pixmap_from_fd(&pixmap,
- drawable->pScreen, fds[0],
- stuff->width, stuff->height,
- stuff->stride0,
- 0, 0);
+ modifier = (uint64_t) stuff->modifier_hi << 32;
+ modifier |= ((uint64_t) stuff->modifier_lo & 0xffffffff);
+ strides[0] = stuff->stride0;
+ strides[1] = stuff->stride1;
+ strides[2] = stuff->stride2;
+ strides[3] = stuff->stride3;
+ offsets[0] = stuff->offset0;
+ offsets[1] = stuff->offset1;
+ offsets[2] = stuff->offset2;
+ offsets[3] = stuff->offset3;
+
+ rc = dri3_pixmap_from_fds(&pixmap,
+ drawable->pScreen,
+ stuff->num_buffers, fds,
+ stuff->width, stuff->height,
+ strides, offsets,
+ stuff->format, modifier);
+
if (rc != Success)
goto error;
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 4d4f77bcf..65c262ba0 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -60,17 +60,21 @@ dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
}
int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier)
{
dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
dri3_screen_info_ptr info = ds->info;
PixmapPtr pixmap;
- if (!info || !info->pixmap_from_fd)
+ if (!info || !info->pixmap_from_fds)
return BadImplementation;
- pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+ pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+ strides, offsets, format, modifier);
if (!pixmap)
return BadAlloc;
diff --git a/glamor/glamor.c b/glamor/glamor.c
index 91236e29c..66b081272 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -35,11 +35,67 @@
#include "glamor_priv.h"
#include "mipict.h"
+#include <drm_fourcc.h>
DevPrivateKeyRec glamor_screen_private_key;
DevPrivateKeyRec glamor_pixmap_private_key;
DevPrivateKeyRec glamor_gc_private_key;
+_X_EXPORT const struct drm_format_info *
+drm_format_get_info(uint32_t format)
+{
+ static const struct drm_format_info formats[] = {
+ { .format = DRM_FORMAT_C8, .depth = 8, .bpp = 8 },
+ { .format = DRM_FORMAT_RGB332, .depth = 8, .bpp = 8 },
+ { .format = DRM_FORMAT_BGR233, .depth = 8, .bpp = 8 },
+ { .format = DRM_FORMAT_XRGB4444, .depth = 12, .bpp = 16 },
+ { .format = DRM_FORMAT_XBGR4444, .depth = 12, .bpp = 16 },
+ { .format = DRM_FORMAT_RGBX4444, .depth = 12, .bpp = 16 },
+ { .format = DRM_FORMAT_BGRX4444, .depth = 12, .bpp = 16 },
+ { .format = DRM_FORMAT_ARGB4444, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_ABGR4444, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_RGBA4444, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_BGRA4444, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_XRGB1555, .depth = 15, .bpp = 16 },
+ { .format = DRM_FORMAT_XBGR1555, .depth = 15, .bpp = 16 },
+ { .format = DRM_FORMAT_RGBX5551, .depth = 15, .bpp = 16 },
+ { .format = DRM_FORMAT_BGRX5551, .depth = 15, .bpp = 16 },
+ { .format = DRM_FORMAT_ARGB1555, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_ABGR1555, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_RGBA5551, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_BGRA5551, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_RGB565, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_BGR565, .depth = 16, .bpp = 16 },
+ { .format = DRM_FORMAT_RGB888, .depth = 24, .bpp = 24 },
+ { .format = DRM_FORMAT_BGR888, .depth = 24, .bpp = 24 },
+ { .format = DRM_FORMAT_XRGB8888, .depth = 24, .bpp = 32 },
+ { .format = DRM_FORMAT_XBGR8888, .depth = 24, .bpp = 32 },
+ { .format = DRM_FORMAT_RGBX8888, .depth = 24, .bpp = 32 },
+ { .format = DRM_FORMAT_BGRX8888, .depth = 24, .bpp = 32 },
+ { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .bpp = 32 },
+ { .format = DRM_FORMAT_ARGB8888, .depth = 32, .bpp = 32 },
+ { .format = DRM_FORMAT_ABGR8888, .depth = 32, .bpp = 32 },
+ { .format = DRM_FORMAT_RGBA8888, .depth = 32, .bpp = 32 },
+ { .format = DRM_FORMAT_BGRA8888, .depth = 32, .bpp = 32 },
+ };
+
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (formats[i].format == format)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
/**
* glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable.
*
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 4ad28df17..fdf265075 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -60,6 +60,14 @@ typedef enum glamor_pixmap_type {
GLAMOR_TEXTURE_ONLY,
} glamor_pixmap_type_t;
+struct drm_format_info {
+ uint32_t format;
+ uint32_t depth;
+ uint32_t bpp;
+};
+
+extern _X_EXPORT const struct drm_format_info * drm_format_get_info(uint32_t format);
+
#define GLAMOR_EGL_EXTERNAL_BUFFER 3
#define GLAMOR_USE_EGL_SCREEN (1 << 0)
#define GLAMOR_NO_DRI3 (1 << 1)
@@ -225,26 +233,6 @@ extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap,
extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap);
-/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd.
- *
- * @screen: Current screen pointer.
- * @fd: The dma-buf fd to import.
- * @width: The width of the buffer.
- * @height: The height of the buffer.
- * @stride: The stride of the buffer.
- * @depth: The depth of the buffer.
- * @bpp: The number of bpp of the buffer.
- *
- * Returns a valid pixmap if the import succeeded, else NULL.
- * */
-extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen,
- int fd,
- CARD16 width,
- CARD16 height,
- CARD16 stride,
- CARD8 depth,
- CARD8 bpp);
-
/* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd.
*
* @pixmap: Pixmap to change backing for
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index 91b34a4bb..762908203 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -56,6 +56,7 @@ struct glamor_egl_screen_private {
CloseScreenProcPtr CloseScreen;
int fd;
struct gbm_device *gbm;
+ int dmabuf_capable;
int modifiers_capable;
CloseScreenProcPtr saved_close_screen;
@@ -235,6 +236,121 @@ glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
return ret;
}
+static Bool
+glamor_egl_create_textured_pixmap_from_dmabuf(PixmapPtr pixmap,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+ return FALSE;
+#else
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLImageKHR image;
+ GLuint texture;
+ EGLint attribs[30];
+ int atti = 0;
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+ assert(glamor_egl->dmabuf_capable);
+
+ glamor_make_current(glamor_priv);
+
+ attribs[atti++] = EGL_WIDTH;
+ attribs[atti++] = width;
+ attribs[atti++] = EGL_HEIGHT;
+ attribs[atti++] = height;
+ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+ attribs[atti++] = format;
+
+ if (num_fds > 0) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+ attribs[atti++] = fds[0];
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+ attribs[atti++] = offsets[0];
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+ attribs[atti++] = strides[0];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 1) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+ attribs[atti++] = fds[1];
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+ attribs[atti++] = offsets[1];
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+ attribs[atti++] = strides[1];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 2) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+ attribs[atti++] = fds[2];
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+ attribs[atti++] = offsets[2];
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+ attribs[atti++] = strides[2];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 3) {
+ if (!glamor_egl->modifiers_capable) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ return FALSE;
+ }
+#ifdef EGL_EXT_image_dma_buf_import_modifiers
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT;
+ attribs[atti++] = fds[3];
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
+ attribs[atti++] = offsets[3];
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
+ attribs[atti++] = strides[3];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+#endif
+ }
+
+ attribs[atti++] = EGL_NONE;
+
+ image = eglCreateImageKHR(glamor_egl->display, EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ return FALSE;
+ }
+ glamor_create_texture_from_image(screen, image, &texture);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+ glamor_set_pixmap_texture(pixmap, texture);
+ glamor_egl_set_pixmap_image(pixmap, image);
+
+ return TRUE;
+#endif
+}
+
static void
glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name)
{
@@ -396,20 +512,39 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap,
return ret;
}
-_X_EXPORT PixmapPtr
-glamor_pixmap_from_fd(ScreenPtr screen,
- int fd,
- CARD16 width,
- CARD16 height,
- CARD16 stride, CARD8 depth, CARD8 bpp)
+static PixmapPtr
+glamor_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier)
{
PixmapPtr pixmap;
- Bool ret;
+ struct glamor_egl_screen_private *glamor_egl;
+ const struct drm_format_info *info;
+ Bool ret = FALSE;
+ int i;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+ info = drm_format_get_info(format);
+
+ pixmap = screen->CreatePixmap(screen, 0, 0, info->depth, 0);
+
+ if (glamor_egl->dmabuf_capable) {
+ screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL); // XXX what is the stride used for?
+ ret = glamor_egl_create_textured_pixmap_from_dmabuf(pixmap, num_fds, fds,
+ width, height,
+ strides, offsets,
+ format, modifier);
+ } else if (num_fds == 1) {
+ ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
+ strides[0], info->depth, info->bpp);
+ }
- pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
- ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
- stride, depth, bpp);
if (ret == FALSE) {
+ for (i = 0; i < num_fds; i++)
+ close(fds[i]);
screen->DestroyPixmap(pixmap);
return NULL;
}
@@ -501,6 +636,7 @@ glamor_egl_destroy_pixmap(PixmapPtr pixmap)
struct glamor_egl_screen_private *glamor_egl =
glamor_egl_get_screen_private(scrn);
Bool ret;
+ int i;
if (pixmap->refcnt == 1) {
struct glamor_pixmap_private *pixmap_priv =
@@ -612,7 +748,7 @@ glamor_dri3_open_client(ClientPtr client,
static dri3_screen_info_rec glamor_dri3_info = {
.version = 1,
.open_client = glamor_dri3_open_client,
- .pixmap_from_fd = glamor_pixmap_from_fd,
+ .pixmap_from_fds = glamor_pixmap_from_fds,
.fd_from_pixmap = glamor_fd_from_pixmap,
.get_formats = glamor_get_formats,
.get_modifiers = glamor_get_modifiers,
@@ -815,6 +951,9 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
glGetString(GL_RENDERER));
if (epoxy_has_egl_extension(glamor_egl->display,
+ "EXT_image_dma_buf_import"))
+ glamor_egl->dmabuf_capable = TRUE;
+ if (epoxy_has_egl_extension(glamor_egl->display,
"EXT_image_dma_buf_import_modifiers"))
glamor_egl->modifiers_capable = TRUE;
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 0273f5f16..ddf93bce6 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -45,6 +45,13 @@ struct xwl_pixmap {
struct gbm_bo *bo;
void *image;
unsigned int texture;
+
+ int num_fds;
+ int fds[4];
+ uint32_t strides[4];
+ uint32_t offsets[4];
+ uint32_t format;
+ uint64_t modifier;
};
static void
@@ -152,6 +159,147 @@ xwl_glamor_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, int depth)
return pixmap;
}
+static PixmapPtr
+xwl_glamor_create_pixmap_for_dmabuf(ScreenPtr screen, CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier)
+{
+#ifndef EGL_EXT_image_dma_buf_import
+ return NULL;
+#else
+ PixmapPtr pixmap;
+ struct xwl_pixmap *xwl_pixmap;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ const struct drm_format_info *info;
+ EGLint attribs[30];
+ int atti = 0;
+ int i;
+
+ xwl_pixmap = malloc(sizeof *xwl_pixmap);
+ if (xwl_pixmap == NULL)
+ return NULL;
+
+ info = drm_format_get_info(format);
+ pixmap = glamor_create_pixmap(screen, width, height, info->depth,
+ GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
+ if (pixmap == NULL) {
+ free(xwl_pixmap);
+ return NULL;
+ }
+
+ attribs[atti++] = EGL_WIDTH;
+ attribs[atti++] = width;
+ attribs[atti++] = EGL_HEIGHT;
+ attribs[atti++] = height;
+ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+ attribs[atti++] = format;
+
+ if (num_fds > 0) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+ attribs[atti++] = fds[0];
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+ attribs[atti++] = offsets[0];
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+ attribs[atti++] = strides[0];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 1) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+ attribs[atti++] = fds[1];
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+ attribs[atti++] = offsets[1];
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+ attribs[atti++] = strides[1];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 2) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+ attribs[atti++] = fds[2];
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+ attribs[atti++] = offsets[2];
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+ attribs[atti++] = strides[2];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+ }
+
+ if (num_fds > 3) {
+ if (!xwl_screen->modifiers_capable) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ return NULL;
+ }
+#ifdef EGL_EXT_image_dma_buf_import_modifiers
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT;
+ attribs[atti++] = fds[3];
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
+ attribs[atti++] = offsets[3];
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
+ attribs[atti++] = strides[3];
+ if (modifier) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
+ attribs[atti++] = modifier & 0xffffffff;
+ attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
+ attribs[atti++] = modifier >> 32;
+ }
+#endif
+ }
+
+ attribs[atti++] = EGL_NONE;
+
+ if (lastGLContext != xwl_screen->glamor_ctx) {
+ lastGLContext = xwl_screen->glamor_ctx;
+ xwl_glamor_egl_make_current(xwl_screen->glamor_ctx);
+ }
+
+ xwl_pixmap->bo = NULL;
+ xwl_pixmap->buffer = NULL;
+ xwl_pixmap->num_fds = num_fds;
+ for (i = 0; i < num_fds; i++) {
+ xwl_pixmap->fds[i] = fds[i];
+ xwl_pixmap->strides[i] = strides[i];
+ xwl_pixmap->offsets[i] = offsets[i];
+ }
+ xwl_pixmap->format = format;
+ xwl_pixmap->modifier = modifier;
+ xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
+ xwl_screen->egl_context,
+ EGL_LINUX_DMA_BUF_EXT,
+ NULL, attribs);
+
+ glGenTextures(1, &xwl_pixmap->texture);
+ glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ xwl_pixmap_set_private(pixmap, xwl_pixmap);
+
+ glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+
+ return pixmap;
+#endif
+}
+
struct wl_buffer *
xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
{
@@ -162,6 +310,10 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
if (xwl_pixmap->buffer)
return xwl_pixmap->buffer;
+ /* XXX If xwl_pimxap is not backed by a bo (dmabuf),
+ * should we create a wl_buffer using the zwp_linux_dmabuf
+ * interface? Is it safe to use in Xorg server? */
+
prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
if (prime_fd == -1)
return NULL;
@@ -213,7 +365,8 @@ xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
wl_buffer_destroy(xwl_pixmap->buffer);
eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
- gbm_bo_destroy(xwl_pixmap->bo);
+ if (xwl_pixmap->bo)
+ gbm_bo_destroy(xwl_pixmap->bo);
free(xwl_pixmap);
}
@@ -332,6 +485,9 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
}
if (epoxy_has_egl_extension(xwl_screen->egl_display,
+ "EXT_image_dma_buf_import"))
+ xwl_screen->dmabuf_capable = TRUE;
+ if (epoxy_has_egl_extension(xwl_screen->egl_display,
"EXT_image_dma_buf_import_modifiers"))
xwl_screen->modifiers_capable = TRUE;
@@ -527,33 +683,48 @@ xwl_dri3_open_client(ClientPtr client,
}
static PixmapPtr
-xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride,
- CARD8 depth, CARD8 bpp)
+xwl_dri3_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD32 format, uint64_t modifier)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct gbm_import_fd_data data;
struct gbm_bo *bo;
+ const struct drm_format_info *info;
PixmapPtr pixmap;
- if (width == 0 || height == 0 ||
- depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8)
- return NULL;
+ info = drm_format_get_info(format);
- data.fd = fd;
- data.width = width;
- data.height = height;
- data.stride = stride;
- data.format = gbm_format_for_depth(depth);
- bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
- if (bo == NULL)
+ if (width == 0 || height == 0 || num_fds == 0 ||
+ info->depth < 15 || info->bpp != BitsPerPixel(info->depth) ||
+ strides[0] < width * info->bpp / 8) // XXX Does this condition still make sense?
return NULL;
- pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
- if (pixmap == NULL) {
- gbm_bo_destroy(bo);
- return NULL;
+ if (xwl_screen->dmabuf_capable) {
+ pixmap = xwl_glamor_create_pixmap_for_dmabuf(screen, num_fds, fds,
+ width, height,
+ strides, offsets,
+ format, modifier);
+ } else if (num_fds == 1) {
+ data.fd = fds[0];
+ data.width = width;
+ data.height = height;
+ data.stride = strides[0];
+ data.format = gbm_format_for_depth(info->depth);
+ bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ if (bo == NULL)
+ return NULL;
+
+ pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, info->depth);
+ if (pixmap == NULL) {
+ gbm_bo_destroy(bo);
+ return NULL;
+ }
+ } else {
+ return NULL;
}
return pixmap;
@@ -649,7 +820,7 @@ xwl_dri3_get_modifiers(ScreenPtr screen, CARD32 format,
static dri3_screen_info_rec xwl_dri3_info = {
.version = 1,
.open = NULL,
- .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
+ .pixmap_from_fds = xwl_dri3_pixmap_from_fds,
.fd_from_pixmap = xwl_dri3_fd_from_pixmap,
.open_client = xwl_dri3_open_client,
.get_formats = xwl_dri3_get_formats,
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 30f7de026..df2a3087d 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -99,6 +99,7 @@ struct xwl_screen {
void *egl_display, *egl_context;
struct gbm_device *gbm;
struct glamor_context *glamor_ctx;
+ int dmabuf_capable;
int modifiers_capable;
Atom allow_commits_prop;
--
2.13.0
More information about the xorg-devel
mailing list