[Mesa-dev] [RFC 01/22] RFC: egl/x11: Support DRI3 v1.1
Daniel Stone
daniels at collabora.com
Thu Jun 8 18:43:59 UTC 2017
From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Add support for DRI3 v1.1, which allows pixmaps to be backed by
multi-planar buffers, or those with format modifiers. This is both
for allocating render buffers, as well as EGLImage imports from a
native pixmap (EGL_NATIVE_PIXMAP_KHR).
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
src/egl/drivers/dri2/egl_dri2.c | 3 +
src/egl/drivers/dri2/egl_dri2.h | 1 +
src/egl/drivers/dri2/platform_x11_dri3.c | 62 +++++++-
src/glx/dri3_glx.c | 10 +-
src/loader/loader_dri3_helper.c | 250 +++++++++++++++++++++++++------
src/loader/loader_dri3_helper.h | 16 +-
6 files changed, 293 insertions(+), 49 deletions(-)
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 7175e827c9..5b0799fcc4 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -804,6 +804,9 @@ dri2_setup_extensions(_EGLDisplay *disp)
if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false))
return EGL_FALSE;
+ dri2_dpy->multibuffers_available &=
+ (dri2_dpy->image && dri2_dpy->image->base.version >= 15);
+
dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
return EGL_TRUE;
}
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index a71b4489cd..a1a676d867 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -194,6 +194,7 @@ struct dri2_egl_display
xcb_screen_t *screen;
int swap_available;
#ifdef HAVE_DRI3
+ int multibuffers_available;
struct loader_dri3_extensions loader_dri3_ext;
#endif
#endif
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c
index 041da3208d..0db2d7872a 100644
--- a/src/egl/drivers/dri2/platform_x11_dri3.c
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c
@@ -198,7 +198,9 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
dri2_dpy->dri_screen,
- dri2_dpy->is_different_gpu, dri_config,
+ dri2_dpy->is_different_gpu,
+ dri2_dpy->multibuffers_available,
+ dri_config,
&dri2_dpy->loader_dri3_ext,
&egl_dri3_vtable,
&dri3_surf->loader_drawable)) {
@@ -344,15 +346,71 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
return &dri2_img->base;
}
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+static _EGLImage *
+dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLClientBuffer buffer,
+ const EGLint *attr_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_image *dri2_img;
+ xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
+ xcb_drawable_t drawable;
+
+ drawable = (xcb_drawable_t) (uintptr_t) buffer;
+ bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
+ bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
+ bp_cookie, NULL);
+
+ if (!bp_reply) {
+ _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
+ return NULL;
+ }
+
+ dri2_img = malloc(sizeof *dri2_img);
+ if (!dri2_img) {
+ _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ if (!_eglInitImage(&dri2_img->base, disp)) {
+ free(dri2_img);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
+ bp_reply,
+ dri2_dpy->dri_screen,
+ dri2_dpy->image,
+ dri2_img);
+ free(bp_reply);
+
+ if (!dri2_img->dri_image) {
+ _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+ free(dri2_img);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ return &dri2_img->base;
+}
+#endif
+
static _EGLImage *
dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
_EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list)
{
(void) drv;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
switch (target) {
case EGL_NATIVE_PIXMAP_KHR:
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+ if (dri2_dpy->multibuffers_available)
+ return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
+ attr_list);
+#endif
return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
default:
return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
@@ -504,6 +562,8 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
free(error);
return EGL_FALSE;
}
+ dri2_dpy->multibuffers_available = dri3_query->major_version > 1 ||
+ dri3_query->minor_version >= 1;
free(dri3_query);
present_query =
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index 509160697f..4b599ef897 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -374,7 +374,10 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
{
struct dri3_drawable *pdraw;
struct dri3_screen *psc = (struct dri3_screen *) base;
+ const struct dri3_display *const pdp = (struct dri3_display *)
+ base->display->dri3Display;
__GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+ int has_multibuffer = 0;
pdraw = calloc(1, sizeof(*pdraw));
if (!pdraw)
@@ -385,11 +388,16 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
pdraw->base.drawable = drawable;
pdraw->base.psc = &psc->base;
+ if ((psc->image && psc->image->base.version >= 15) &&
+ (pdp->dri3Major > 1 || pdp->dri3Minor >= 1))
+ has_multibuffer = 1;
+
(void) __glXInitialize(psc->base.dpy);
if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy),
xDrawable, psc->driScreen,
- psc->is_different_gpu, config->driConfig,
+ psc->is_different_gpu, has_multibuffer,
+ config->driConfig,
&psc->loader_dri3_ext, &glx_dri3_vtable,
&pdraw->loader_drawable)) {
free(pdraw);
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index 493a7f5218..3908512b9f 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -40,6 +40,10 @@
#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
static inline void
dri3_fence_reset(xcb_connection_t *c, struct loader_dri3_buffer *buffer)
{
@@ -128,6 +132,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
xcb_drawable_t drawable,
__DRIscreen *dri_screen,
bool is_different_gpu,
+ bool multiplanes_available,
const __DRIconfig *dri_config,
struct loader_dri3_extensions *ext,
const struct loader_dri3_vtable *vtable,
@@ -145,6 +150,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
draw->drawable = drawable;
draw->dri_screen = dri_screen;
draw->is_different_gpu = is_different_gpu;
+ draw->multiplanes_available = multiplanes_available;
draw->have_back = 0;
draw->have_fake_front = 0;
@@ -814,6 +820,27 @@ dri3_cpp_for_format(uint32_t format) {
}
}
+/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
+ * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
+ * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
+ * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
+ */
+static int
+image_format_to_fourcc(int format)
+{
+
+ /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
+ switch (format) {
+ case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
+ case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
+ case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
+ case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
+ case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
+ case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
+ }
+ return 0;
+}
+
/** loader_dri3_alloc_render_buffer
*
* Use the driver createImage function to construct a __DRIimage, then
@@ -830,8 +857,10 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
xcb_pixmap_t pixmap;
xcb_sync_fence_t sync_fence;
struct xshmfence *shm_fence;
- int buffer_fd, fence_fd;
- int stride;
+ int buffer_fds[4], fence_fd;
+ uint32_t fourcc_format;
+ int num_planes = 0;
+ int i, mod;
/* Create an xshmfence object and
* prepare to send that to the X server
@@ -855,14 +884,67 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
if (!buffer->cpp)
goto no_image;
+ fourcc_format = image_format_to_fourcc(format);
+ if (!fourcc_format)
+ goto no_image;
+
if (!draw->is_different_gpu) {
- buffer->image = draw->ext->image->createImage(draw->dri_screen,
- width, height,
- format,
- __DRI_IMAGE_USE_SHARE |
- __DRI_IMAGE_USE_SCANOUT |
- __DRI_IMAGE_USE_BACKBUFFER,
- buffer);
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+ if (draw->multiplanes_available &&
+ draw->ext->image->base.version >= 15 &&
+ draw->ext->image->queryDmaBufModifiers &&
+ draw->ext->image->createImageWithModifiers) {
+ xcb_dri3_get_supported_modifiers_cookie_t mod_cookie;
+ xcb_dri3_get_supported_modifiers_reply_t *mod_reply;
+ xcb_generic_error_t *error = NULL;
+ uint64_t *modifiers = NULL;
+ uint32_t *mod_parts;
+ int i, count;
+
+ mod_cookie = xcb_dri3_get_supported_modifiers(draw->conn,
+ draw->drawable,
+ fourcc_format);
+ mod_reply = xcb_dri3_get_supported_modifiers_reply(draw->conn,
+ mod_cookie,
+ &error);
+ if (!mod_reply)
+ goto no_image;
+
+ count = mod_reply->num_modifiers;
+ if (count) {
+ modifiers = malloc(count * sizeof(uint64_t));
+ if (!modifiers) {
+ free(mod_reply);
+ goto no_image;
+ }
+
+ mod_parts = xcb_dri3_get_supported_modifiers_modifiers(mod_reply);
+ for (i = 0; i < count; i++) {
+ modifiers[i] = (uint64_t) mod_parts[i * 2] << 32;
+ modifiers[i] |= (uint64_t) mod_parts[i * 2 + 1] & 0xffffff;
+ }
+ }
+
+ free(mod_reply);
+
+ buffer->image = draw->ext->image->createImageWithModifiers(draw->dri_screen,
+ width, height,
+ format,
+ modifiers, count,
+ buffer);
+ free(modifiers);
+ }
+#endif
+
+ if (!buffer->image)
+ buffer->image = draw->ext->image->createImage(draw->dri_screen,
+ width, height,
+ format,
+ __DRI_IMAGE_USE_SHARE |
+ __DRI_IMAGE_USE_SCANOUT |
+ __DRI_IMAGE_USE_BACKBUFFER,
+ buffer);
+
pixmap_buffer = buffer->image;
if (!buffer->image)
@@ -890,25 +972,82 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
goto no_linear_buffer;
}
- /* X wants the stride, so ask the image for it
+ /* X want some information about the planes, so ask the image for it
*/
- if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE,
- &stride))
- goto no_buffer_attrib;
-
- buffer->pitch = stride;
+ draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_NUM_PLANES,
+ &num_planes);
+ if (num_planes <= 0)
+ num_planes = 1;
+
+ for (i = 0; i < num_planes; i++) {
+ __DRIimage *image = draw->ext->image->fromPlanar(pixmap_buffer, i, NULL);
+ int ret;
+ if (!image)
+ image = pixmap_buffer;
+ ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD,
+ &buffer_fds[i]);
+ if (!ret) {
+ if (image != pixmap_buffer)
+ draw->ext->image->destroyImage(image);
+ goto no_buffer_attrib;
+ }
+ ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE,
+ &buffer->strides[i]);
+ if (!ret) {
+ if (image != pixmap_buffer)
+ draw->ext->image->destroyImage(image);
+ goto no_buffer_attrib;
+ }
+ ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET,
+ &buffer->offsets[i]);
+ if (!ret)
+ buffer->offsets[i] = 0;
+ if (image != pixmap_buffer)
+ draw->ext->image->destroyImage(image);
+ }
- if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD,
- &buffer_fd))
- goto no_buffer_attrib;
+ if (!draw->ext->image->queryImage(pixmap_buffer,
+ __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
+ &mod)) {
+ buffer->modifier = DRM_FORMAT_MOD_INVALID;
+ } else {
+ buffer->modifier = (uint64_t) mod << 32;
+ if (!draw->ext->image->queryImage(pixmap_buffer,
+ __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
+ &mod)) {
+ buffer->modifier = DRM_FORMAT_MOD_INVALID;
+ } else {
+ buffer->modifier |= (uint64_t)(mod & 0xffffffff);
+ }
+ }
- xcb_dri3_pixmap_from_buffer(draw->conn,
- (pixmap = xcb_generate_id(draw->conn)),
- draw->drawable,
- buffer->size,
- width, height, buffer->pitch,
- depth, buffer->cpp * 8,
- buffer_fd);
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+ if (draw->multiplanes_available) {
+ xcb_dri3_pixmap_from_buffers(draw->conn,
+ (pixmap = xcb_generate_id(draw->conn)),
+ draw->drawable,
+ num_planes,
+ width, height,
+ buffer->strides[0], buffer->offsets[0],
+ buffer->strides[1], buffer->offsets[1],
+ buffer->strides[2], buffer->offsets[2],
+ buffer->strides[3], buffer->offsets[3],
+ fourcc_format,
+ buffer->modifier >> 32,
+ buffer->modifier & 0xffffffff,
+ buffer_fds);
+ }
+ else
+#endif
+ {
+ xcb_dri3_pixmap_from_buffer(draw->conn,
+ (pixmap = xcb_generate_id(draw->conn)),
+ draw->drawable,
+ buffer->size,
+ width, height, buffer->strides[0],
+ depth, buffer->cpp * 8,
+ buffer_fds[0]);
+ }
xcb_dri3_fence_from_fd(draw->conn,
pixmap,
@@ -930,6 +1069,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
return buffer;
no_buffer_attrib:
+ while (--i >= 0)
+ close(buffer_fds[i]);
draw->ext->image->destroyImage(pixmap_buffer);
no_linear_buffer:
if (draw->is_different_gpu)
@@ -1037,27 +1178,6 @@ dri3_update_drawable(__DRIdrawable *driDrawable,
return true;
}
-/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
- * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
- * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
- * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
- */
-static int
-image_format_to_fourcc(int format)
-{
-
- /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
- switch (format) {
- case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
- case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
- case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
- case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
- case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
- case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
- }
- return 0;
-}
-
__DRIimage *
loader_dri3_create_image(xcb_connection_t *c,
xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
@@ -1099,6 +1219,44 @@ loader_dri3_create_image(xcb_connection_t *c,
return ret;
}
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+ __DRIscreen *dri_screen,
+ const __DRIimageExtension *image,
+ void *loaderPrivate)
+{
+ int *fds;
+ uint32_t *strides_in, *offsets_in;
+ int strides[4], offsets[4];
+ uint64_t modifier;
+ unsigned error;
+ int i;
+
+ fds = xcb_dri3_buffers_from_pixmap_reply_fds(c, bp_reply);
+ strides_in = xcb_dri3_buffers_from_pixmap_strides(bp_reply);
+ offsets_in = xcb_dri3_buffers_from_pixmap_offsets(bp_reply);
+ for (i = 0; i < bp_reply->nfd; i++) {
+ strides[i] = strides_in[i];
+ offsets[i] = offsets_in[i];
+ }
+
+ modifier = (uint64_t) bp_reply->modifier_hi << 32;
+ modifier |= ((uint64_t) bp_reply->modifier_lo) & 0xffffffff;
+
+ return image->createImageFromDmaBufs2(dri_screen,
+ bp_reply->width,
+ bp_reply->height,
+ bp_reply->format,
+ modifier,
+ fds, bp_reply->nfd,
+ strides, offsets,
+ 0, 0, 0, 0, /* UNDEFINED */
+ &error, loaderPrivate);
+}
+#endif
+
/** dri3_get_pixmap_buffer
*
* Get the DRM object for a pixmap from the X server and
diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
index a865e46355..6bac25e607 100644
--- a/src/loader/loader_dri3_helper.h
+++ b/src/loader/loader_dri3_helper.h
@@ -61,8 +61,11 @@ struct loader_dri3_buffer {
bool busy; /* Set on swap, cleared on IdleNotify */
bool own_pixmap; /* We allocated the pixmap ID, free on destroy */
+ uint32_t num_planes;
uint32_t size;
- uint32_t pitch;
+ int strides[4];
+ int offsets[4];
+ uint64_t modifier;
uint32_t cpp;
uint32_t flags;
uint32_t width, height;
@@ -125,6 +128,7 @@ struct loader_dri3_drawable {
/* Information about the GPU owning the buffer */
__DRIscreen *dri_screen;
bool is_different_gpu;
+ bool multiplanes_available;
/* Present extension capabilities
*/
@@ -174,6 +178,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
xcb_drawable_t drawable,
__DRIscreen *dri_screen,
bool is_different_gpu,
+ bool is_multiplanes_available,
const __DRIconfig *dri_config,
struct loader_dri3_extensions *ext,
const struct loader_dri3_vtable *vtable,
@@ -231,6 +236,15 @@ loader_dri3_create_image(xcb_connection_t *c,
const __DRIimageExtension *image,
void *loaderPrivate);
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+ __DRIscreen *dri_screen,
+ const __DRIimageExtension *image,
+ void *loaderPrivate);
+#endif
+
int
loader_dri3_get_buffers(__DRIdrawable *driDrawable,
unsigned int format,
--
2.13.0
More information about the mesa-dev
mailing list