You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wayland环境下将Cairo表面数据绑定到EGL及eglBindTexImage报错解决

问题原因

eglBindTexImage 仅支持pbuffer或pixmap类型的EGL表面,你当前用的是窗口表面(EGL_WINDOW_BIT类型),本身就不支持绑定为纹理,所以必然触发EGL_BAD_SURFACE错误。同时你完全不需要调用这个接口,也不需要额外创建pbuffer表面,你的实现思路走了弯路。

解决方法

你已经将Cairo绘制的像素数据通过glTexImage2D上传到了GL纹理中,只需要将这个纹理绘制到当前绑定的窗口表面即可,步骤如下:

  1. 补充纹理参数设置,OpenGL ES默认使用Mipmap过滤,你没有生成Mipmap的情况下纹理会显示为纯黑,上传纹理后添加:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1. 准备最简单的全屏绘制着色器,用于把纹理贴到窗口上:
// 顶点着色器,输入位置和UV,直接输出UV
const char* vert_shader = 
"attribute vec2 aPos;\n"
"attribute vec2 aUV;\n"
"varying vec2 vUV;\n"
"void main() {\n"
"  gl_Position = vec4(aPos, 0.0, 1.0);\n"
"  vUV = aUV;\n"
"}";

// 片段着色器,采样纹理输出
const char* frag_shader =
"precision mediump float;\n"
"varying vec2 vUV;\n"
"uniform sampler2D uTex;\n"
"void main() {\n"
"  gl_FragColor = texture2D(uTex, vUV);\n"
"}";

你可以自行补充基础的着色器编译、链接逻辑和错误检查代码。
3. 绘制全屏矩形,替换你原来的eglBindTexImage相关代码:

// 全屏四边形的顶点和UV,坐标范围覆盖整个窗口
float vertices[] = {
// 位置(x,y)  UV(u,v)
  -1.0f,  1.0f,  0.0f, 0.0f,
  -1.0f, -1.0f,  0.0f, 1.0f,
   1.0f, -1.0f,  1.0f, 1.0f,
   1.0f,  1.0f,  1.0f, 0.0f
};
unsigned int indices[] = {0, 1, 2, 0, 2, 3};

// 绑定顶点数据
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices + 2);
glEnableVertexAttribArray(1);

// 绑定着色器和纹理
glUseProgram(shader_program);
glUniform1i(glGetUniformLocation(shader_program, "uTex"), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

// 绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices);
  1. 绘制完成后直接调用eglSwapBuffers即可,不需要其他操作。

额外注意事项

  • Cairo的CAIRO_FORMAT_ARGB32格式是预乘Alpha,且字节顺序为BGRA,你当前用GL_RGBA上传会出现颜色颠倒的问题,可将glTexImage2D的格式参数改为GL_BGRA_EXT(绝大多数EGL实现都支持该扩展),或在片段着色器中交换R和B通道。
  • 如果你确实需要用到离屏渲染再拷贝到窗口的逻辑,才需要创建pbuffer表面,创建时需要把EGLConfig的EGL_SURFACE_TYPE属性加上EGL_PBUFFER_BIT,再调用eglCreatePbufferSurface生成pbuffer,绘制完成后用glReadPixels读回或者绑定为纹理再绘制到窗口,对你当前的场景来说完全没有必要,反而会增加性能开销。

内容的提问来源于stack exchange,提问作者hardboiled65

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 20:06:08