[Glamor] [PATCH] Add DRI3 support to glamor

Axel Davy axel.davy at ens.fr
Sat Nov 30 03:53:45 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>
---
 src/glamor.c      |  79 +++++++++++++++++++-
 src/glamor.h      |  69 ++++++++++++++++-
 src/glamor_egl.c  | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/glamor_fbo.c  |  36 ++++++---
 src/glamor_priv.h |   1 +
 5 files changed, 389 insertions(+), 14 deletions(-)

diff --git a/src/glamor.c b/src/glamor.c
index e8e68be..7b749aa 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,75 @@ glamor_fini(ScreenPtr screen)
 {
 	/* Do nothing currently. */
 }
+
+void glamor_egl_dri3_capabilities(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 = dixLookupPrivate(&pixmap->devPrivates,
+					glamor_pixmap_private_key);
+	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 (ScreenPtr screen,
+                              PixmapPtr pixmap)
+{
+	glamor_pixmap_private *pixmap_priv;
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(pixmap->drawable.pScreen);
+
+	pixmap_priv = dixLookupPrivate(&pixmap->devPrivates,
+					glamor_pixmap_private_key);
+	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,
+								TRUE,
+								NULL,
+								NULL);
+		default: break;
+	}
+	return -1;
+}
diff --git a/src/glamor.h b/src/glamor.h
index 927892f..e36fc80 100644
--- a/src/glamor.h
+++ b/src/glamor.h
@@ -164,6 +164,72 @@ 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_egl_dri3_capabilities(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.
+ * 
+ * @screen: Current screen pointer.
+ * @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 (ScreenPtr screen, 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 +309,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..0baa98a 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,40 @@ 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_GBM
+	struct gbm_bo *bo;
+	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;
+
+	image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+						 EGL_NO_CONTEXT,
+						 EGL_NATIVE_PIXMAP_KHR,
+						 bo, 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 +385,178 @@ done:
 	return ret;
 }
 
+#ifdef GLAMOR_HAS_GBM
+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_GBM
+	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_GBM
+	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 +766,11 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
 	GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_opengl);
 #endif
 
+#ifdef GLAMOR_HAS_GBM
+	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 +822,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 +832,8 @@ glamor_egl_init_textured_pixmap(ScreenPtr screen)
 			   screen->myNum);
 		return FALSE;
 	}
+	if (glamor_egl->dri3_capable)
+		glamor_egl_dri3_capabilities(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