[RFC xserver 04/16] DRI3: Implement GetSupportedFormats and GetSupportedModifiers
Daniel Stone
daniels at collabora.com
Thu Jun 8 18:43:30 UTC 2017
From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Use EGL extension EXT_image_dma_buf_modifiers to query supported
DMA-BUF formats and modifiers to return to DRI3 clients. The
information is cached to avoid having to fetch it again for
each new client.
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
dri3/dri3.h | 12 +++++
dri3/dri3_priv.h | 18 +++++++
dri3/dri3_request.c | 13 +++--
dri3/dri3_screen.c | 121 ++++++++++++++++++++++++++++++++++++++++++
glamor/glamor_egl.c | 84 +++++++++++++++++++++++++++++
hw/xwayland/xwayland-glamor.c | 79 +++++++++++++++++++++++++++
hw/xwayland/xwayland.h | 1 +
7 files changed, 325 insertions(+), 3 deletions(-)
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..40b8474c0 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -52,12 +52,24 @@ typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
CARD16 *stride,
CARD32 *size);
+typedef int (*dri3_get_formats_proc) (ScreenPtr screen,
+ CARD32 *num_formats,
+ CARD32 **formats);
+
+typedef int (*dri3_get_modifiers_proc) (ScreenPtr screen,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ uint64_t **modifiers);
+
+
typedef struct dri3_screen_info {
uint32_t version;
dri3_open_proc open;
dri3_pixmap_from_fd_proc pixmap_from_fd;
dri3_fd_from_pixmap_proc fd_from_pixmap;
+ dri3_get_formats_proc get_formats;
+ dri3_get_modifiers_proc get_modifiers;
/* Version 1 */
dri3_open_client_proc open_client;
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..c767f373e 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,22 @@
extern DevPrivateKeyRec dri3_screen_private_key;
+typedef struct dri3_dmabuf_format {
+ CARD32 format;
+ CARD32 num_modifiers;
+ CARD32 *modifiers_hi;
+ CARD32 *modifiers_lo;
+} dri3_dmabuf_format_rec, *dri3_dmabuf_format_ptr;
+
typedef struct dri3_screen_priv {
CloseScreenProcPtr CloseScreen;
ConfigNotifyProcPtr ConfigNotify;
DestroyWindowProcPtr DestroyWindow;
+ Bool formats_cached;
+ CARD32 num_formats;
+ dri3_dmabuf_format_ptr formats;
+
dri3_screen_info_ptr info;
} dri3_screen_priv_rec, *dri3_screen_priv_ptr;
@@ -75,4 +86,11 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
int
dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+int
+dri3_get_supported_formats(ScreenPtr screen, CARD32 *num_formats, CARD32 **formats);
+
+int
+dri3_get_supported_modifiers(ScreenPtr screen, CARD32 format, CARD32 *num_modifiers,
+ CARD32 **modifiers_hi, CARD32 **modifiers_lo);
+
#endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index 336175d92..35f1c2533 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -310,9 +310,9 @@ proc_dri3_get_supported_formats(ClientPtr client)
DrawablePtr drawable;
ScreenPtr pScreen;
CARD32 *formats = NULL;
- int nformats = 0;
+ CARD32 nformats = 0;
+ CARD32 i;
int status;
- int i;
REQUEST_SIZE_MATCH(xDRI3GetSupportedFormatsReq);
@@ -322,6 +322,8 @@ proc_dri3_get_supported_formats(ClientPtr client)
return status;
pScreen = drawable->pScreen;
+ dri3_get_supported_formats(pScreen, &nformats, &formats);
+
rep.numFormats = nformats;
rep.length = bytes_to_int32(rep.numFormats * sizeof(CARD32));
@@ -336,6 +338,8 @@ proc_dri3_get_supported_formats(ClientPtr client)
WriteToClient(client, sizeof(rep), &rep);
WriteToClient(client, nformats * sizeof(CARD32), formats);
+ free(formats);
+
return Success;
}
@@ -351,7 +355,7 @@ proc_dri3_get_supported_modifiers(ClientPtr client)
ScreenPtr pScreen;
CARD32 *modifiers_hi = NULL;
CARD32 *modifiers_lo = NULL;
- int nmodifiers = 0;
+ CARD32 nmodifiers = 0;
int status;
int i;
@@ -363,6 +367,9 @@ proc_dri3_get_supported_modifiers(ClientPtr client)
return status;
pScreen = drawable->pScreen;
+ dri3_get_supported_modifiers(pScreen, stuff->format, &nmodifiers,
+ &modifiers_hi, &modifiers_lo);
+
rep.numModifiers = nmodifiers;
rep.length = bytes_to_int32(2 * rep.numModifiers * sizeof(CARD32));
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..4d4f77bcf 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -96,3 +96,124 @@ dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
return Success;
}
+static int
+cache_formats_and_modifiers(ScreenPtr screen)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ dri3_screen_info_ptr info = ds->info;
+ CARD32 *formats = NULL;
+ uint64_t *modifiers = NULL;
+ int i, j;
+
+ if (ds->formats_cached)
+ return Success;
+
+ if (!info || !info->get_formats || !info->get_modifiers)
+ return BadImplementation;
+
+ (*info->get_formats) (screen, &ds->num_formats, &formats);
+ ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+ if (!ds->formats)
+ return BadAlloc;
+
+ for (i = 0; i < ds->num_formats; i++) {
+ dri3_dmabuf_format_ptr iter = &ds->formats[i];
+
+ iter->format = formats[i];
+ (*info->get_modifiers) (screen, formats[i],
+ &iter->num_modifiers,
+ &modifiers);
+
+ iter->modifiers_hi = malloc(iter->num_modifiers * sizeof(CARD32));
+ if (iter->modifiers_hi == NULL)
+ goto error;
+ iter->modifiers_lo = malloc(iter->num_modifiers * sizeof(CARD32));
+ if (iter->modifiers_lo == NULL)
+ goto error;
+
+ for (j = 0; j < iter->num_modifiers; j++) {
+ iter->modifiers_hi[j] = modifiers[j] >> 32;
+ iter->modifiers_lo[j] = modifiers[j] & 0xffffffff;
+ }
+ goto done;
+
+error:
+ iter->num_modifiers = 0;
+ free(iter->modifiers_hi);
+ free(iter->modifiers_lo);
+done:
+ free(modifiers);
+ }
+ free(formats);
+ ds->formats_cached = TRUE;
+
+ return Success;
+}
+
+int
+dri3_get_supported_formats(ScreenPtr screen, CARD32 *num_formats,
+ CARD32 **formats)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ int i;
+ int ret;
+
+ ret = cache_formats_and_modifiers(screen);
+ if (ret != Success)
+ return ret;
+
+ *formats = malloc(ds->num_formats * sizeof(CARD32));
+ if (!*formats) {
+ *num_formats = 0;
+ return BadAlloc;
+ }
+
+ *num_formats = ds->num_formats;
+ for (i = 0; i < ds->num_formats; i++)
+ *formats[i] = ds->formats[i].format;
+
+ return Success;
+}
+
+int
+dri3_get_supported_modifiers(ScreenPtr screen,
+ CARD32 format, CARD32 *num_modifiers,
+ CARD32 **modifiers_hi, CARD32 **modifiers_lo)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ int i;
+ int ret;
+
+ ret = cache_formats_and_modifiers(screen);
+ if (ret != Success)
+ return ret;
+
+ // XXX We don't really need a copy, but without it we're kind of asymetric
+ // with the get_formats API...
+ for (i = 0; i < ds->num_formats; i++) {
+ if (ds->formats[i].format == format) {
+ *modifiers_hi = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+ if (!*modifiers_hi) {
+ *num_modifiers = 0;
+ return BadAlloc;
+ }
+ *modifiers_lo = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+ if (!*modifiers_lo) {
+ *num_modifiers = 0;
+ free(*modifiers_hi);
+ *modifiers_hi = NULL;
+ return BadAlloc;
+ }
+
+ *num_modifiers = ds->formats[i].num_modifiers;
+ memcpy(*modifiers_hi, ds->formats[i].modifiers_hi,
+ ds->formats[i].num_modifiers * sizeof(CARD32));
+ memcpy(*modifiers_lo, ds->formats[i].modifiers_lo,
+ ds->formats[i].num_modifiers * sizeof(CARD32));
+
+ return Success;
+ }
+ }
+
+ return BadMatch;
+}
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index b0d3e9efe..91b34a4bb 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 modifiers_capable;
CloseScreenProcPtr saved_close_screen;
DestroyPixmapProcPtr saved_destroy_pixmap;
@@ -416,6 +417,83 @@ glamor_pixmap_from_fd(ScreenPtr screen,
}
static Bool
+glamor_get_formats(ScreenPtr screen,
+ CARD32 *num_formats, CARD32 **formats)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+ return FALSE;
+#else
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLint num;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+ if (!glamor_egl->modifiers_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ *formats = calloc(num, sizeof(CARD32));
+ if (*formats == NULL) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
+ (EGLint *) *formats, &num)) {
+ *num_formats = 0;
+ free(*formats);
+ return FALSE;
+ }
+
+ *num_formats = num;
+ return TRUE;
+#endif
+}
+
+static Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+ CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+ return FALSE;
+#else
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLint num;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+ if (!glamor_egl->modifiers_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
+ NULL, &num)) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ *modifiers = calloc(num, sizeof(uint64_t));
+ if (*modifiers == NULL) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
+ (EGLuint64KHR *) *modifiers, NULL, &num)) {
+ *num_modifiers = 0;
+ free(*modifiers);
+ return FALSE;
+ }
+
+ *num_modifiers = num;
+ return TRUE;
+#endif
+}
+
+static Bool
glamor_egl_destroy_pixmap(PixmapPtr pixmap)
{
ScreenPtr screen = pixmap->drawable.pScreen;
@@ -536,6 +614,8 @@ static dri3_screen_info_rec glamor_dri3_info = {
.open_client = glamor_dri3_open_client,
.pixmap_from_fd = glamor_pixmap_from_fd,
.fd_from_pixmap = glamor_fd_from_pixmap,
+ .get_formats = glamor_get_formats,
+ .get_modifiers = glamor_get_modifiers,
};
#endif /* DRI3 */
@@ -734,6 +814,10 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
glGetString(GL_RENDERER));
+ if (epoxy_has_egl_extension(glamor_egl->display,
+ "EXT_image_dma_buf_import_modifiers"))
+ glamor_egl->modifiers_capable = TRUE;
+
glamor_egl->saved_free_screen = scrn->FreeScreen;
scrn->FreeScreen = glamor_egl_free_screen;
return TRUE;
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 87622839e..0273f5f16 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -331,6 +331,10 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
return;
}
+ if (epoxy_has_egl_extension(xwl_screen->egl_display,
+ "EXT_image_dma_buf_import_modifiers"))
+ xwl_screen->modifiers_capable = TRUE;
+
return;
}
@@ -569,12 +573,87 @@ xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
return gbm_bo_get_fd(xwl_pixmap->bo);
}
+static int
+xwl_dri3_get_formats(ScreenPtr screen,
+ CARD32 *num_formats, CARD32 **formats)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+ return FALSE;
+#else
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ EGLint num;
+
+ if (!xwl_screen->modifiers_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, 0, NULL, &num)) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ *formats = calloc(num, sizeof(CARD32));
+ if (*formats == NULL) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, num, (EGLint *) *formats, &num)) {
+ *num_formats = 0;
+ free(*formats);
+ return FALSE;
+ }
+
+ *num_formats = num;
+ return TRUE;
+#endif
+}
+
+static int
+xwl_dri3_get_modifiers(ScreenPtr screen, CARD32 format,
+ CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+ return FALSE;
+#else
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ EGLint num;
+
+ if (!xwl_screen->modifiers_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, 0, NULL,
+ NULL, &num)) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ *modifiers = calloc(num, sizeof(uint64_t));
+ if (*modifiers == NULL) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, num,
+ *modifiers, NULL, &num)) {
+ *num_modifiers = 0;
+ free(*modifiers);
+ return FALSE;
+ }
+
+ *num_modifiers = num;
+ return TRUE;
+#endif
+}
+
+
static dri3_screen_info_rec xwl_dri3_info = {
.version = 1,
.open = NULL,
.pixmap_from_fd = xwl_dri3_pixmap_from_fd,
.fd_from_pixmap = xwl_dri3_fd_from_pixmap,
.open_client = xwl_dri3_open_client,
+ .get_formats = xwl_dri3_get_formats,
+ .get_modifiers = xwl_dri3_get_modifiers,
};
Bool
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a05e0862c..30f7de026 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 modifiers_capable;
Atom allow_commits_prop;
};
--
2.13.0
More information about the xorg-devel
mailing list