EGLImage基于dmabuf创建失败(无法获取v3d句柄)的原因排查
生产者代码
EGLImage image = eglCreateImage(egl->dpy, egl->ctx, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(uint64_t)gl->texture, NULL); assert_and_log(image != EGL_NO_IMAGE, ""); ret = eglExportDMABUFImageQueryMESA(egl->dpy, image, NULL, NULL, NULL); if (ret == EGL_FALSE) { log_error_egl("eglExportDMABUFImageQueryMESA"); abort(); } int dmabuf_fd; ret = eglExportDMABUFImageMESA(egl->dpy, image, &dmabuf_fd, &strides[0], &offsets[0]);
消费者代码
EGLAttrib const attribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf_fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0], EGL_DMA_BUF_PLANE0_PITCH_EXT, strides[0], EGL_LINUX_DRM_FOURCC_EXT, drm_format, EGL_NONE, }; EGLImage image = eglCreateImage(egl->dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
问题描述
调用消费者代码中的eglCreateImage时失败,驱动报错:
Failed to get v3d handle for dmabuf 8
核心疑问:这是否与DMA驱动配置不当有关?若无关,可能的原因是什么?
补充信息
- 已确认变量值与调用流程,
eglCreateImage是首个出错的调用 - dmabuf_fd通过Unix套接字跨进程传递
- 运行环境:树莓派4、Ubuntu 22.04桌面版,使用MESA驱动
问题分析与解答
这个问题大概率和DMA驱动配置无关,更可能由以下原因导致:
1. DMABUF文件描述符传递异常
Unix套接字传递dmabuf_fd必须通过sendmsg/recvmsg完成,若传递过程出错,消费者进程中的fd会变为无效值。可以在消费者中用fcntl(dmabuf_fd, F_GETFD)验证fd有效性——返回-1则说明fd已失效。此外,要确保生产者在导出fd后未提前关闭该描述符。
2. DRM格式不匹配
生产者导出的DMABUF的DRM格式必须与消费者创建EGLImage时指定的drm_format完全一致。当前生产者代码中eglExportDMABUFImageQueryMESA第三个参数传NULL,未获取真实格式,应修改为:
uint32_t drm_fmt; ret = eglExportDMABUFImageQueryMESA(egl->dpy, image, &drm_fmt, NULL, NULL);
将获取到的drm_fmt传递给消费者使用,避免格式不兼容导致驱动无法映射缓冲区。
3. EGL上下文/设备兼容性问题
消费者使用EGL_NO_CONTEXT创建EGLImage,虽然符合EGL规范,但树莓派V3D驱动的MESA实现可能要求绑定有效上下文。可以尝试创建一个基础EGL上下文后再调用eglCreateImage。同时要确保生产者和消费者使用的EGL显示设备绑定到同一个DRM节点(如/dev/dri/card0),跨DRM节点无法共享DMABUF。
4. GPU同步未完成
生产者在导出DMABUF前,需确保GPU已完成对该缓冲区的所有操作。否则消费者尝试映射时,缓冲区可能处于未就绪状态,导致驱动报错。可在生产者调用eglExportDMABUFImageMESA前,添加glFinish()同步GPU操作。
内容的提问来源于stack exchange,提问作者hedgehog_o_tail

