This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch devs/cedric/wl/gl-x11-dmabuf
in repository efl.

View the commit online.

commit 7e4cf639cc84aecdb48f20a7bdef781b29f7907a
Author: Cedric BAIL <[email protected]>
AuthorDate: Wed Aug 12 22:46:53 2026 -0600

    evas/gl_x11: import wl_dmabuf native surfaces
    
    The gl_drm engine has imported EVAS_NATIVE_SURFACE_WL_DMABUF for years.
    gl_x11 never learned to, so eng_image_native_set() falls through for that
    type and the image is left in error.
    
    That is what stops a compositor running on gl_x11 from taking a GPU buffer
    from a client. Enlightenment's wl_x11 backend disables dmabuf outright
    because of it, so Chromium and anything else with a GPU process falls back
    to wl_shm - every frame rendered on the CPU and copied across. With this,
    E can advertise zwp_linux_dmabuf_v1 there instead.
    
    Nothing about the import is drm-specific. It is EGL: eglCreateImage with
    EGL_LINUX_DMA_BUF_EXT, then glEGLImageTargetTexture2DOES, exactly as gl_drm
    does, and gl_x11 already resolves both glsym_evas_gl_common_eglCreateImage
    and glsym_evas_gl_common_eglDestroyImage. The ns_data.wl_surface_dmabuf
    union member is already in scope: gl_x11 includes the same
    software_generic/evas_native_common.h that gl_drm does.
    
    Carried over from gl_drm because both matter:
    
     - re-import on every bind, for coherency;
     - if the explicit modifier layout is refused, retry implicitly. A driver
       can advertise EGL_EXT_image_dma_buf_import_modifiers and still reject a
       particular modifier, and the failure mode is a silently black window.
    
    The plane attributes are built from a small table rather than gl_drm's four
    unrolled copies; same attributes, less of them.
    
    eng_image_native_init() answers 0 for the type when the driver has no
    EGL_EXT_image_dma_buf_import or the entry points are missing, so a
    compositor can ask first and fall back rather than be handed buffers it can
    only render black.
    
    Guarded on GL_GLES alone, as gl_drm is. Note the surrounding
    EVAS_NATIVE_SURFACE_WL code in this file sits behind HAVE_WAYLAND, which
    nothing in the tree ever defines - so it is dead in every build, and its
    wlid/wl_buf locals are not available here. This uses its own.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
 src/modules/evas/engines/gl_x11/evas_engine.c | 227 +++++++++++++++++++++++++-
 1 file changed, 225 insertions(+), 2 deletions(-)

diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c
index 8926c6afea..f4e3332596 100644
--- a/src/modules/evas/engines/gl_x11/evas_engine.c
+++ b/src/modules/evas/engines/gl_x11/evas_engine.c
@@ -31,6 +31,18 @@ static int initted = 0;
 static int gl_wins = 0;
 #ifdef GL_GLES
 static int extn_have_y_inverted = 1;
+#ifdef GL_GLES
+# ifdef HAVE_DRM_FOURCC_H
+#  include <drm_fourcc.h>
+# endif
+# ifndef DRM_FORMAT_MOD_INVALID
+#  define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
+# endif
+/* EGL_EXT_image_dma_buf_import and its modifiers companion. Checked once in
+ * gl_extn_veto(); a driver can have the first without the second. */
+static Eina_Bool dmabuf_present = EINA_FALSE;
+static Eina_Bool dmabuf_modifiers_present = EINA_FALSE;
+#endif
 #endif
 
 typedef void           *(*glsym_func_void_ptr) (void);
@@ -1451,6 +1463,12 @@ gl_extn_veto(Render_Engine *re)
           {
              glsym_eglSetDamageRegionKHR = NULL;
           }
+#ifdef HAVE_WAYLAND
+        if (strstr(str, "EGL_EXT_image_dma_buf_import"))
+          dmabuf_present = EINA_TRUE;
+        if (strstr(str, "EGL_EXT_image_dma_buf_import_modifiers"))
+          dmabuf_modifiers_present = EINA_TRUE;
+#endif
         if (!strstr(str, "EGL_NOK_texture_from_pixmap"))
           {
              extn_have_y_inverted = 0;
@@ -1928,12 +1946,123 @@ end:
 //
 //#define GLX_TEX_PIXMAP_RECREATE 1
 
+#ifdef GL_GLES
+/* Code from weston's gl-renderer, by way of the gl_drm engine. */
+static EGLImageKHR
+_gl_import_dmabuf(EGLDisplay display, struct dmabuf_attributes *attributes, Eina_Bool with_modifier)
+{
+   EGLAttrib attribs[50];
+   int atti = 0, i;
+   Eina_Bool has_modifier = EINA_FALSE;
+   static const EGLint fd_attr[4] =
+     { EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE1_FD_EXT,
+       EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE3_FD_EXT };
+   static const EGLint off_attr[4] =
+     { EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT,
+       EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT };
+   static const EGLint pitch_attr[4] =
+     { EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT,
+       EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT };
+   static const EGLint mod_lo_attr[4] =
+     { EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
+       EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT };
+   static const EGLint mod_hi_attr[4] =
+     { EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
+       EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT };
+
+   if (!dmabuf_present) return NULL;
+   if (!glsym_evas_gl_common_eglCreateImage) return NULL;
+   if (!glsym_evas_gl_common_eglDestroyImage) return NULL;
+
+   /* Passing modifier attributes to a driver without
+    * EGL_EXT_image_dma_buf_import_modifiers gets the whole import rejected
+    * with EGL_BAD_ATTRIBUTE, which surfaces as a silently black window. */
+   if ((with_modifier) && (dmabuf_modifiers_present) &&
+       (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID))
+     has_modifier = EINA_TRUE;
+
+   attribs[atti++] = EGL_WIDTH;
+   attribs[atti++] = attributes->width;
+   attribs[atti++] = EGL_HEIGHT;
+   attribs[atti++] = attributes->height;
+   attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+   attribs[atti++] = attributes->format;
+
+   for (i = 0; (i < attributes->n_planes) && (i < 4); i++)
+     {
+        attribs[atti++] = fd_attr[i];
+        attribs[atti++] = attributes->fd[i];
+        attribs[atti++] = off_attr[i];
+        attribs[atti++] = attributes->offset[i];
+        attribs[atti++] = pitch_attr[i];
+        attribs[atti++] = attributes->stride[i];
+        if (has_modifier)
+          {
+             attribs[atti++] = mod_lo_attr[i];
+             attribs[atti++] = attributes->modifier[i] & 0xFFFFFFFF;
+             attribs[atti++] = mod_hi_attr[i];
+             attribs[atti++] = attributes->modifier[i] >> 32;
+          }
+     }
+
+   attribs[atti++] = EGL_NONE;
+
+   return glsym_evas_gl_common_eglCreateImage(display, EGL_NO_CONTEXT,
+                                              EGL_LINUX_DMA_BUF_EXT,
+                                              NULL, attribs);
+}
+
+static EGLImageKHR
+_gl_import_simple_dmabuf(EGLDisplay display, struct dmabuf_attributes *attributes)
+{
+   EGLImageKHR img;
+
+   img = _gl_import_dmabuf(display, attributes, EINA_TRUE);
+   if (img) return img;
+
+   /* The explicit layout was refused - a driver may advertise
+    * import_modifiers and still reject a particular modifier. Retry
+    * implicitly before giving up and rendering nothing. */
+   if ((dmabuf_modifiers_present) &&
+       (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID))
+     {
+        DBG("dmabuf import with modifier %#" PRIx64 " failed (%#x), "
+            "retrying without", attributes->modifier[0], eglGetError());
+        img = _gl_import_dmabuf(display, attributes, EINA_FALSE);
+     }
+
+   return img;
+}
+#endif
+
 static void
 _native_bind_cb(void *image)
 {
    Evas_GL_Image *im = image;
    Native *n = im->native.data;
 
+#ifdef GL_GLES
+  if (n->ns.type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+    {
+       /* Must re-import every time for coherency. */
+       if (n->ns_data.wl_surface_dmabuf.image)
+         glsym_evas_gl_common_eglDestroyImage(im->native.disp,
+                                              n->ns_data.wl_surface_dmabuf.image);
+       n->ns_data.wl_surface_dmabuf.image =
+         _gl_import_simple_dmabuf(im->native.disp,
+                                  &n->ns_data.wl_surface_dmabuf.attr);
+       if (!n->ns_data.wl_surface_dmabuf.image)
+         {
+            im->native.invalid = EINA_TRUE;
+            return;
+         }
+       im->native.invalid = EINA_FALSE;
+       if (glsym_glEGLImageTargetTexture2DOES)
+         glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                                            n->ns_data.wl_surface_dmabuf.image);
+       return;
+    }
+#endif
   if (n->ns.type == EVAS_NATIVE_SURFACE_X11)
     {
 #ifdef GL_GLES
@@ -2059,6 +2188,18 @@ _native_unbind_cb(void *image)
    Evas_GL_Image *im = image;
    Native *n = im->native.data;
 
+#ifdef GL_GLES
+   if (n->ns.type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+     {
+        if (n->ns_data.wl_surface_dmabuf.image)
+          {
+             glsym_evas_gl_common_eglDestroyImage(im->native.disp,
+                                                  n->ns_data.wl_surface_dmabuf.image);
+             n->ns_data.wl_surface_dmabuf.image = NULL;
+          }
+        return;
+     }
+#endif
    if (n->ns.type == EVAS_NATIVE_SURFACE_X11)
      {
 #ifdef GL_GLES
@@ -2186,6 +2327,20 @@ _native_free_cb(void *image)
     {
        eina_hash_del(im->native.shared->native_evasgl_hash, &n->ns.data.evasgl.surface, im);
     }
+  else if (n->ns.type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+     {
+#ifdef GL_GLES
+        void *dmaid = (void*)n->ns_data.wl_surface_dmabuf.resource;
+
+        eina_hash_del(im->native.shared->native_wl_hash, &dmaid, image);
+        if (n->ns_data.wl_surface_dmabuf.image)
+          {
+             glsym_evas_gl_common_eglDestroyImage(im->native.disp,
+                                                  n->ns_data.wl_surface_dmabuf.image);
+             n->ns_data.wl_surface_dmabuf.image = NULL;
+          }
+#endif
+     }
   else if (n->ns.type == EVAS_NATIVE_SURFACE_WL)
      {
 #ifdef GL_GLES
@@ -2266,9 +2421,15 @@ eng_image_native_init(void *engine EINA_UNUSED, Evas_Native_Surface_Type type)
       case EVAS_NATIVE_SURFACE_OPENGL:
       case EVAS_NATIVE_SURFACE_EVASGL:
         return 1;
-#if defined(GL_GLES) && defined(HAVE_WAYLAND)
+#ifdef GL_GLES
       case EVAS_NATIVE_SURFACE_WL:
         return (glsym_eglQueryWaylandBufferWL != NULL) ? 1 : 0;
+      case EVAS_NATIVE_SURFACE_WL_DMABUF:
+        /* Say no when the driver cannot import, so a compositor can fall
+         * back rather than hand us buffers we will only render black. */
+        return (dmabuf_present &&
+                glsym_evas_gl_common_eglCreateImage &&
+                glsym_glEGLImageTargetTexture2DOES) ? 1 : 0;
 #endif
       default:
         ERR("Native surface type %d not supported!", type);
@@ -2289,8 +2450,9 @@ eng_image_native_shutdown(void *engine EINA_UNUSED, Evas_Native_Surface_Type typ
       case EVAS_NATIVE_SURFACE_X11:
       case EVAS_NATIVE_SURFACE_OPENGL:
       case EVAS_NATIVE_SURFACE_EVASGL:
-#if defined(GL_GLES) && defined(HAVE_WAYLAND)
+#ifdef GL_GLES
       case EVAS_NATIVE_SURFACE_WL:
+      case EVAS_NATIVE_SURFACE_WL_DMABUF:
 #endif
         return;
       default:
@@ -2313,6 +2475,9 @@ eng_image_native_set(void *engine, void *image, void *native)
   unsigned int fbo = 0;
   void *buffer = NULL;
   Outbuf *ob;
+#ifdef GL_GLES
+  void *dmaid, *dmabuf_res = NULL;
+#endif
 #ifdef GL_GLES
 # ifdef HAVE_WAYLAND
   void *wlid, *wl_buf = NULL;
@@ -2381,6 +2546,12 @@ eng_image_native_set(void *engine, void *image, void *native)
                    return im;
               }
          }
+       else if (ns->type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+         {
+#ifdef GL_GLES
+            dmabuf_res = ns->data.wl_dmabuf.resource;
+#endif
+         }
        else if (ns->type == EVAS_NATIVE_SURFACE_WL)
           {
 #ifdef GL_GLES
@@ -2467,6 +2638,23 @@ eng_image_native_set(void *engine, void *image, void *native)
               }
          }
     }
+  else if (ns->type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+     {
+#ifdef GL_GLES
+        dmaid = dmabuf_res;
+        im2 = eina_hash_find(gl_context->shared->native_wl_hash, &dmaid);
+        if (im2 == im) return im;
+        if (im2)
+          {
+             if ((n = im2->native.data))
+               {
+                  glsym_evas_gl_common_image_ref(im2);
+                  glsym_evas_gl_common_image_free(im);
+                  return im2;
+               }
+          }
+#endif
+     }
   else if (ns->type == EVAS_NATIVE_SURFACE_WL)
      {
 #ifdef GL_GLES
@@ -2908,6 +3096,41 @@ eng_image_native_set(void *engine, void *image, void *native)
               }
          }
     }
+   else if (ns->type == EVAS_NATIVE_SURFACE_WL_DMABUF)
+     {
+#ifdef GL_GLES
+        if (native)
+          {
+             struct dmabuf_attributes *a = ns->data.wl_dmabuf.attr;
+
+             if ((!a) || (a->version != EVAS_DMABUF_ATTRIBUTE_VERSION))
+               {
+                  glsym_evas_gl_common_image_free(im);
+                  return NULL;
+               }
+             if ((n = calloc(1, sizeof(Native))))
+               {
+                  memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface));
+                  memcpy(&n->ns_data.wl_surface_dmabuf.attr, a, sizeof(*a));
+                  dmaid = dmabuf_res;
+                  eina_hash_add(gl_context->shared->native_wl_hash, &dmaid, im);
+
+                  n->ns_data.wl_surface_dmabuf.resource = dmabuf_res;
+                  im->native.yinvert = 1;
+                  im->native.loose = 0;
+                  im->native.disp = ob->egl_disp;
+                  im->native.shared = gl_context->shared;
+                  im->native.data = ""
+                  im->native.func.bind = _native_bind_cb;
+                  im->native.func.unbind = _native_unbind_cb;
+                  im->native.func.free = _native_free_cb;
+                  im->native.target = GL_TEXTURE_2D;
+                  im->native.mipmap = 0;
+                  glsym_evas_gl_common_image_native_enable(im);
+               }
+          }
+#endif
+     }
    else if (ns->type == EVAS_NATIVE_SURFACE_WL)
      {
 #ifdef GL_GLES

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to