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.