[Glamor] [PATCH v2] Add DRI3 support to glamor

Axel Davy axel.davy at ens.fr
Tue Dec 3 13:04:00 PST 2013


This implements some DRI3 helpers to help the DDXs using
glamor to support DRI3.

Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
This contains some modifications to take account of the comments,
and add a configure option to enable/disable dri3 support.
Unfortunately, it seems
there is no way to check, when compiling, the equality between two types,
that's why this configure option is needed, to disable dri3 support on platforms
for which EGLNativePixmapType isn't a struct gbm_bo*. 

 configure.ac      |  13 ++++
 src/glamor.c      |  76 +++++++++++++++++-
 src/glamor.h      |  68 ++++++++++++++++-
 src/glamor_egl.c  | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/glamor_fbo.c  |  36 ++++++---
 src/glamor_priv.h |   1 +
 6 files changed, 405 insertions(+), 14 deletions(-)

diff --git a/configure.ac b/configure.ac
index b7b25d0..21bc794 100644
--- a/configure.ac
+++ b/configure.ac
@@ -134,6 +134,19 @@ if test "x$EGL = xyes"; then
    fi
 fi
 
+AC_MSG_CHECKING([Enable Glamor Dri3 helpers])
+AC_ARG_ENABLE(glamor-dri3, AS_HELP_STRING([--enable-glamor-dri3], [Build glamor Dri3 helpers (default: yes if gbm is detected)]), [GLAMOR_DRI3_HELPERS="$enableval"], [GLAMOR_DRI3_HELPERS=yes])
+
+if test "x$GLAMOR_DRI3_HELPERS" = xyes -a "x$GLAMOR_HAS_GBM" = xno; then
+   GLAMOR_DRI3_HELPERS=no
+fi
+
+AC_MSG_RESULT([$GLAMOR_DRI3_HELPERS])
+
+if test "x$GLAMOR_DRI3_HELPERS" = xyes; then
+    AC_DEFINE(GLAMOR_HAS_DRI3_SUPPORT, 1, [Enable Dri3 helpers])
+fi
+
 dnl
 dnl TLS detection
 dnl
diff --git a/src/glamor.c b/src/glamor.c
index e8e68be..e39624e 100644
--- a/src/glamor.c
+++ b/src/glamor.c
@@ -209,7 +209,12 @@ glamor_destroy_textured_pixmap(PixmapPtr pixmap)
 Bool
 glamor_destroy_pixmap(PixmapPtr pixmap)
 {
-	glamor_destroy_textured_pixmap(pixmap);
+	glamor_screen_private 
+	  *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+	if (glamor_priv->dri3_enabled)
+		glamor_egl_destroy_textured_pixmap(pixmap);
+	else
+		glamor_destroy_textured_pixmap(pixmap);
 	return fbDestroyPixmap(pixmap);
 }
 
@@ -552,3 +557,72 @@ glamor_fini(ScreenPtr screen)
 {
 	/* Do nothing currently. */
 }
+
+void glamor_enable_dri3(ScreenPtr screen)
+{
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(screen);
+	glamor_priv->dri3_enabled = TRUE;
+}
+
+Bool glamor_is_dri3_support_enabled(ScreenPtr screen)
+{
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(screen);
+	return glamor_priv->dri3_enabled;
+}
+
+int 
+glamor_dri3_fd_from_pixmap (ScreenPtr screen,
+                            PixmapPtr pixmap,
+                            CARD16 *stride,
+                            CARD32 *size)
+{
+	glamor_pixmap_private *pixmap_priv;
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(pixmap->drawable.pScreen);
+
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+	if (pixmap_priv == NULL || !glamor_priv->dri3_enabled)
+		return -1;
+	switch (pixmap_priv->type)
+	{
+		case GLAMOR_TEXTURE_DRM:
+		case GLAMOR_TEXTURE_ONLY:
+			glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0);
+			return glamor_egl_dri3_fd_name_from_tex(screen,
+								pixmap,
+								pixmap_priv->base.fbo->tex,
+								FALSE,
+								stride,
+								size);
+		default: break;
+	}
+	return -1;
+}
+
+int 
+glamor_dri3_name_from_pixmap (PixmapPtr pixmap)
+{
+	glamor_pixmap_private *pixmap_priv;
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(pixmap->drawable.pScreen);
+
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+	if (pixmap_priv == NULL || !glamor_priv->dri3_enabled)
+		return -1;
+	switch (pixmap_priv->type)
+	{
+		case GLAMOR_TEXTURE_DRM:
+		case GLAMOR_TEXTURE_ONLY:
+			glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0);
+			return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen,
+								pixmap,
+								pixmap_priv->base.fbo->tex,
+								TRUE,
+								NULL,
+								NULL);
+		default: break;
+	}
+	return -1;
+}
diff --git a/src/glamor.h b/src/glamor.h
index 927892f..4b8694f 100644
--- a/src/glamor.h
+++ b/src/glamor.h
@@ -164,6 +164,71 @@ extern _X_EXPORT void glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr bac
 
 extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back);
 
+/* The DDX is not supposed to call these three functions */
+extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen);
+extern _X_EXPORT unsigned int glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h);
+extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr, unsigned int, Bool, CARD16*, CARD32*);
+
+/* @glamor_is_dri3_support_enabled: Returns if DRI3 support is enabled.
+ * 
+ * @screen: Current screen pointer.
+ * 
+ * To have DRI3 support enabled, glamor and glamor_egl need to be initialized,
+ * and glamor_egl_init_textured_pixmap need to be called. glamor also
+ * has to be compiled with gbm support.
+ * The EGL layer need to have the following extensions working:
+ * .EGL_KHR_gl_texture_2D_image
+ * .EGL_EXT_image_dma_buf_import
+ * If DRI3 support is not enabled, the following helpers will return an error.
+ * */
+extern _X_EXPORT Bool glamor_is_dri3_support_enabled(ScreenPtr screen);
+
+/* @glamor_dri3_fd_from_pixmap: DRI3 helper to get a dma-buf fd from a pixmap.
+ * 
+ * @screen: Current screen pointer.
+ * @pixmap: The pixmap from which we want the fd.
+ * @stride, @size: Pointers to fill the stride and size of the
+ * 		   buffer associated to the fd.
+ * 
+ * the pixmap and the buffer associated by the fd will share the same
+ * content.
+ * Returns the fd on success, -1 on error.
+ * */
+extern _X_EXPORT int glamor_dri3_fd_from_pixmap (ScreenPtr screen,
+						 PixmapPtr pixmap,
+						 CARD16 *stride,
+						 CARD32 *size);
+
+/* @glamor_dri3_name_from_pixmap: helper to get an gem name from a pixmap.
+ * 
+ * @pixmap: The pixmap from which we want the gem name.
+ * 
+ * the pixmap and the buffer associated by the gem name will share the same
+ * content. This function can be used by the DDX to support DRI2, but needs
+ * glamor DRI3 support to be activated.
+ * Returns the name on success, -1 on error.
+ * */
+extern _X_EXPORT int glamor_dri3_name_from_pixmap (PixmapPtr pixmap);
+
+/* @glamor_egl_dri3_pixmap_from_fd: DRI3 helper to get a pixmap from 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_egl_dri3_pixmap_from_fd (ScreenPtr screen,
+							   int fd,
+							   CARD16 width,
+							   CARD16 height,
+							   CARD16 stride,
+							   CARD8 depth,
+							   CARD8 bpp);
 
 #ifdef GLAMOR_FOR_XORG
 
@@ -243,9 +308,10 @@ extern _X_EXPORT Bool
 	glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
 						      void *bo);
 
-extern _X_EXPORT void glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap);
 #endif
 
+extern _X_EXPORT void glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap);
+
 extern _X_EXPORT int glamor_create_gc(GCPtr gc);
 
 extern _X_EXPORT void glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable);
diff --git a/src/glamor_egl.c b/src/glamor_egl.c
index 13b7f44..bb43ab5 100644
--- a/src/glamor_egl.c
+++ b/src/glamor_egl.c
@@ -45,6 +45,7 @@
 
 #ifdef GLAMOR_HAS_GBM
 #include <gbm.h>
+#include <drm_fourcc.h>
 #endif
 
 #if GLAMOR_GLES2
@@ -95,6 +96,7 @@ struct glamor_egl_screen_private {
 	void *glamor_context;
 	void *current_context;
 	int gl_context_depth;
+	int dri3_capable;
 
 	PFNEGLCREATEIMAGEKHRPROC egl_create_image_khr;
 	PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image_khr;
@@ -218,6 +220,47 @@ glamor_create_texture_from_image(struct glamor_egl_screen_private
 	return TRUE;
 }
 
+unsigned int 
+glamor_egl_create_argb8888_based_texture(ScreenPtr screen,
+					 int w,
+					 int h)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct glamor_egl_screen_private *glamor_egl;
+	EGLImageKHR image;
+	GLuint texture;
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+	struct gbm_bo *bo;
+	EGLNativePixmapType native_pixmap;
+	glamor_egl = glamor_egl_get_screen_private(scrn);
+	bo = gbm_bo_create (glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888,
+				      GBM_BO_USE_RENDERING |
+				      GBM_BO_USE_SCANOUT);
+	if (!bo)
+		return 0;
+	
+	/* If the following assignment raises an error or a warning
+	 * then that means EGLNativePixmapType is not struct gbm_bo *
+	 * on your platform: This code won't work and you should not 
+	 * compile with dri3 support enabled */
+	native_pixmap = bo;
+
+	image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+						 EGL_NO_CONTEXT,
+						 EGL_NATIVE_PIXMAP_KHR,
+						 native_pixmap, NULL);
+	gbm_bo_destroy(bo);
+	if (image == EGL_NO_IMAGE_KHR)
+		return 0;
+	glamor_create_texture_from_image(glamor_egl, image, &texture);
+	glamor_egl->egl_destroy_image_khr(glamor_egl->display, image);
+
+	return texture;
+#else
+	return 0; /* this path should never happen */
+#endif
+}
+
 Bool
 glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride)
 {
@@ -349,6 +392,178 @@ done:
 	return ret;
 }
 
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+int glamor_get_fd_from_bo (int gbm_fd, struct gbm_bo *bo, int *fd);
+void glamor_get_name_from_bo (int gbm_fd, struct gbm_bo *bo, int *name);
+int
+glamor_get_fd_from_bo (int gbm_fd, struct gbm_bo *bo, int *fd)
+{
+	union gbm_bo_handle handle;
+	struct drm_prime_handle args;
+
+	handle = gbm_bo_get_handle(bo);
+	args.handle = handle.u32;
+	args.flags = DRM_CLOEXEC;
+	if (ioctl (gbm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
+		return FALSE;
+	*fd = args.fd;
+	return TRUE;
+}
+
+void
+glamor_get_name_from_bo (int gbm_fd, struct gbm_bo *bo, int *name)
+{
+	union gbm_bo_handle handle;
+
+	handle = gbm_bo_get_handle(bo);
+	if (!glamor_get_flink_name(gbm_fd, handle.u32, name))
+		*name = -1;
+}
+#endif
+
+int glamor_egl_dri3_fd_name_from_tex (ScreenPtr screen,
+				      PixmapPtr pixmap,
+				      unsigned int tex,
+				      Bool want_name,
+				      CARD16 *stride,
+				      CARD32 *size)
+{
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct glamor_egl_screen_private *glamor_egl;
+	EGLImageKHR image;
+	struct gbm_bo* bo;
+	int fd = -1;
+
+	EGLint attribs[] = {
+		EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+		EGL_GL_TEXTURE_LEVEL_KHR, 0,
+		EGL_NONE
+	};
+
+	glamor_egl = glamor_egl_get_screen_private(scrn);
+
+	glamor_egl_make_current(screen);
+
+	image = dixLookupPrivate(&pixmap->devPrivates,
+				 glamor_egl_pixmap_private_key);
+
+	if (image == EGL_NO_IMAGE_KHR || image == NULL)
+	{
+		image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+							 glamor_egl->context,
+							 EGL_GL_TEXTURE_2D_KHR,
+							 tex, attribs);
+		if (image == EGL_NO_IMAGE_KHR)
+			goto failure;
+
+		dixSetPrivate(&pixmap->devPrivates,
+			      glamor_egl_pixmap_private_key,
+			      image);
+		glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+	}
+	
+	bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
+	if (!bo)
+		goto failure;
+	
+	pixmap->devKind = gbm_bo_get_stride(bo);
+
+	if (want_name)
+	{
+		if (glamor_egl->has_gem)
+			glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
+	} 
+	else
+	{
+		if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd))
+		{
+			*stride = pixmap->devKind;
+			*size = pixmap->devKind * gbm_bo_get_height(bo);
+		}
+	}
+
+	gbm_bo_destroy(bo);
+failure:
+	glamor_egl_restore_context(screen);
+	return fd;
+#else
+	return -1;
+#endif
+}
+
+PixmapPtr glamor_egl_dri3_pixmap_from_fd (ScreenPtr screen,
+					  int fd,
+					  CARD16 width,
+					  CARD16 height,
+					  CARD16 stride,
+					  CARD8 depth,
+					  CARD8 bpp)
+{
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct glamor_egl_screen_private *glamor_egl;
+	struct gbm_bo* bo;
+	EGLImageKHR image;
+	PixmapPtr pixmap;
+	Bool ret = FALSE;
+	EGLint attribs[] = {
+		EGL_WIDTH, 0,
+		EGL_HEIGHT, 0,
+		EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
+		EGL_DMA_BUF_PLANE0_FD_EXT, 0,
+		EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
+		EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
+		EGL_NONE
+	};
+
+	glamor_egl = glamor_egl_get_screen_private(scrn);
+
+	if (!glamor_egl->dri3_capable)
+		return NULL;
+
+	if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0)
+		return NULL;
+
+	attribs[1] = width;
+	attribs[3] = height;
+	attribs[7] = fd;
+	attribs[11] = stride;
+	image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+						 EGL_NO_CONTEXT,
+						 EGL_LINUX_DMA_BUF_EXT,
+						 NULL, attribs);
+
+	if (image == EGL_NO_IMAGE_KHR)
+		return NULL;
+
+	/* EGL_EXT_image_dma_buf_import can impose restrictions on the 
+	 * usage of the image. Use gbm_bo to bypass the limitations. */
+
+	bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
+	glamor_egl->egl_destroy_image_khr(glamor_egl->display, image);
+
+	if (!bo)
+		return NULL;
+
+	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+	screen->ModifyPixmapHeader (pixmap, width, height, 0, 0, stride, NULL);
+
+	ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
+	gbm_bo_destroy(bo);
+
+	if (ret)
+		return pixmap;
+	else
+	{
+		screen->DestroyPixmap(pixmap);
+		return NULL;
+	}
+#else
+	return NULL;
+#endif
+}
+
 static void
 _glamor_egl_destroy_pixmap_image(PixmapPtr pixmap)
 {
@@ -558,6 +773,11 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
 	GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_opengl);
 #endif
 
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+	if (glamor_egl_has_extension(glamor_egl, "EGL_KHR_gl_texture_2D_image") &&
+	    glamor_egl_has_extension(glamor_egl, "EGL_EXT_image_dma_buf_import") )
+	    glamor_egl->dri3_capable = TRUE;
+#endif
 	glamor_egl->egl_create_image_khr = (PFNEGLCREATEIMAGEKHRPROC)
 	    eglGetProcAddress("eglCreateImageKHR");
 
@@ -609,6 +829,9 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
 Bool
 glamor_egl_init_textured_pixmap(ScreenPtr screen)
 {
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct glamor_egl_screen_private *glamor_egl =
+	    glamor_egl_get_screen_private(scrn);
 	if (!dixRegisterPrivateKey
 	    (glamor_egl_pixmap_private_key, PRIVATE_PIXMAP, 0)) {
 		LogMessage(X_WARNING,
@@ -616,6 +839,8 @@ glamor_egl_init_textured_pixmap(ScreenPtr screen)
 			   screen->myNum);
 		return FALSE;
 	}
+	if (glamor_egl->dri3_capable)
+		glamor_enable_dri3(screen);
 	return TRUE;
 }
 
diff --git a/src/glamor_fbo.c b/src/glamor_fbo.c
index 4838a27..2327e86 100644
--- a/src/glamor_fbo.c
+++ b/src/glamor_fbo.c
@@ -328,18 +328,30 @@ _glamor_create_tex(glamor_screen_private *glamor_priv,
 		   int w, int h, GLenum format)
 {
 	glamor_gl_dispatch *dispatch;
-	unsigned int tex;
-
-	dispatch = glamor_get_dispatch(glamor_priv);
-	dispatch->glGenTextures(1, &tex);
-	dispatch->glBindTexture(GL_TEXTURE_2D, tex);
-	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-				  GL_NEAREST);
-	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-				  GL_NEAREST);
-	dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format,
-			       GL_UNSIGNED_BYTE, NULL);
-	glamor_put_dispatch(glamor_priv);
+	unsigned int tex = 0;
+
+	/* With dri3, we want to allocate ARGB8888 pixmaps only.
+	 * Depending on the implementation, GL_RGBA might not
+	 * give us ARGB8888. We ask glamor_egl to use get
+	 * an ARGB8888 based texture for us. */
+	if (glamor_priv->dri3_enabled && format == GL_RGBA)
+	{
+		tex = glamor_egl_create_argb8888_based_texture(glamor_priv->screen,
+								w, h);
+	}
+	if (!tex)
+	{
+		dispatch = glamor_get_dispatch(glamor_priv);
+		dispatch->glGenTextures(1, &tex);
+		dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+		dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+					  GL_NEAREST);
+		dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+				  	  GL_NEAREST);
+		dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0,
+				       format, GL_UNSIGNED_BYTE, NULL);
+		glamor_put_dispatch(glamor_priv);
+	}
 	return tex;
 }
 
diff --git a/src/glamor_priv.h b/src/glamor_priv.h
index b6a1075..7b8f762 100644
--- a/src/glamor_priv.h
+++ b/src/glamor_priv.h
@@ -305,6 +305,7 @@ typedef struct glamor_screen_private {
 	int state;
 	unsigned int render_idle_cnt;
 	ScreenPtr screen;
+	int dri3_enabled;
 
 	/* xv */
 	GLint xv_prog;
-- 
1.8.1.2



More information about the Glamor mailing list