From 16ca8679b5e3b9e2937ab911397e78576fd23c45 Mon Sep 17 00:00:00 2001 From: Axel Davy Date: Thu, 5 Dec 2013 08:49:15 +0100 Subject: Add DRI3 support to glamor This implements some DRI3 helpers to help the DDXs using glamor to support DRI3. Signed-off-by: Axel Davy Reviewed-by: Zhigang Gong --- 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..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 +#include #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; -- cgit v1.2.3