summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAxel Davy <axel.davy@ens.fr>2013-12-05 08:49:15 +0100
committerZhigang Gong <zhigang.gong@gmail.com>2013-12-06 23:53:02 +0800
commit16ca8679b5e3b9e2937ab911397e78576fd23c45 (patch)
tree57680608b6bb5ae3c874edaf4d43c31eb40370b5
parent71e7168d7af236e43cea0658b612129bb1d46ff7 (diff)
Add DRI3 support to glamor
This implements some DRI3 helpers to help the DDXs using glamor to support DRI3. Signed-off-by: Axel Davy <axel.davy@ens.fr> Reviewed-by: Zhigang Gong <zhigang.gong@linux.intel.com>
-rw-r--r--configure.ac13
-rw-r--r--src/glamor.c76
-rw-r--r--src/glamor.h68
-rw-r--r--src/glamor_egl.c225
-rw-r--r--src/glamor_fbo.c36
-rw-r--r--src/glamor_priv.h1
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..93d3c5e 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..1bb48ed 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..bf0db3a 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..d1b087e 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;