Add DRI3 support to glamor
authorAxel Davy <axel.davy@ens.fr>
Thu, 5 Dec 2013 07:49:15 +0000 (08:49 +0100)
committerEric Anholt <eric@anholt.net>
Wed, 18 Dec 2013 19:23:54 +0000 (11:23 -0800)
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>
glamor/glamor.c
glamor/glamor.h
glamor/glamor_egl.c
glamor/glamor_fbo.c
glamor/glamor_priv.h

index e8e68be..93d3c5e 100644 (file)
@@ -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;
+}
index 927892f..1bb48ed 100644 (file)
@@ -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);
index 13b7f44..bf0db3a 100644 (file)
@@ -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;
 }
 
index 4838a27..d1b087e 100644 (file)
@@ -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;
 }
 
index b6a1075..7b8f762 100644 (file)
@@ -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;