使用SDL2+GLES3时glLinkProgram触发段错误问题求助
解决glLinkProgram在nouveau驱动下的段错误问题
问题分析
段错误发生在Mesa的link_interface_blocks.cpp中遍历着色器IR指令的环节,说明着色器对象虽编译成功,但驱动在处理内部中间表示时访问了无效内存。结合现象(注释glAttachShader无崩溃),核心问题大概率出在GLES上下文初始化不匹配或驱动对GLES特性的兼容性处理上。
修复步骤
1. 修正GLES上下文初始化参数
你当前请求的是桌面OpenGL 3.2 Core Profile,但实际使用的是GLES3,两者上下文参数不兼容。修改上下文配置代码:
SDL_Init(SDL_INIT_EVERYTHING); // 配置GLES 3.0上下文,而非桌面GL SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // 移除SDL_GL_CONTEXT_PROFILE_MASK设置,GLES无Core/Compatibility Profile之分 SDL_Window *window = SDL_CreateWindow("Void", 100, 100, 800, 600, SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window);
nouveau驱动对GLES和桌面GL的上下文隔离严格,混用桌面GL的profile参数会导致上下文内部状态异常,进而触发链接时的内存访问错误。
2. 对齐着色器与GLES3规范
虽然旧关键字能编译,但驱动在兼容性模式下的IR处理可能存在bug,将着色器调整为GLES3 Core风格:
顶点着色器:
in vec2 pos; void main() { gl_Position = vec4(pos, 0.0, 1.0); }
片段着色器:
out vec4 fragColor; void main() { fragColor = vec4(1.0, 1.0, 1.0, 1.0); }
替换attribute为in,gl_FragColor为自定义输出变量,避免驱动处理兼容性语法时的异常。
3. 调整着色器销毁时机
链接后立即删除着色器可能导致驱动内部仍在访问已释放的对象,将销毁步骤移至链接状态检查完成后:
static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); if (!vert) goto error; GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); if (!frag) { glDeleteShader(vert); goto error; } GLuint prog = glCreateProgram(); glAttachShader(prog, vert); glAttachShader(prog, frag); glLinkProgram(prog); // 先检查链接状态,再销毁着色器 GLint ok; glGetProgramiv(prog, GL_LINK_STATUS, &ok); if (ok == GL_FALSE) { printf("Failed to link shader\n"); glDeleteProgram(prog); glDeleteShader(vert); glDeleteShader(frag); goto error; } glDetachShader(prog, vert); glDetachShader(prog, frag); glDeleteShader(vert); glDeleteShader(frag); return prog; error: return 0; }
4. 排查驱动版本问题
旧版本nouveau Mesa驱动存在GLES3上下文处理bug,建议更新至Mesa 22.0以上版本,或临时切换到闭源NVIDIA驱动验证,确认是否为驱动本身问题。
内容的提问来源于stack exchange,提问作者Oleg Sleva
相关产品推荐
相关产品推荐

