应用Compute Shader后纹理未更新问题求助
问题分析与解决方案
你的程序核心问题在于SDL默认创建的OpenGL上下文不满足Compute Shader(4.3版本)的要求——默认上下文可能是兼容模式或版本过低,导致Compute Shader无法正确执行。此外,缺少Shader编译和程序链接的错误检查,无法及时发现潜在问题。
具体修复步骤
1. 显式指定OpenGL上下文版本与核心Profile
在创建SDL窗口前,添加以下代码强制创建4.3核心Profile的上下文,这是Compute Shader正常运行的基础:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
2. 添加Shader编译与程序链接的错误检查
编译Shader和链接Program时必须检查错误日志,避免隐藏的语法或兼容性问题:
// 检查Compute Shader编译错误 GLint compile_ok = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_ok); if (compile_ok == GL_FALSE) { GLint log_len; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); char* log = (char*)malloc(log_len); glGetShaderInfoLog(shader, log_len, NULL, log); fprintf(stderr, "Compute Shader compile error:\n%s\n", log); free(log); exit(1); } // 检查Program链接错误 GLint link_ok = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (link_ok == GL_FALSE) { GLint log_len; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); char* log = (char*)malloc(log_len); glGetProgramInfoLog(program, log_len, NULL, log); fprintf(stderr, "Program link error:\n%s\n", log); free(log); exit(1); }
3. 补充纹理参数设置(可选但推荐)
虽然不影响当前Compute Shader的写入操作,但创建纹理后设置过滤参数可以避免后续采样时的异常:
glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
修复后的完整代码
#define SDL_MAIN_HANDLED #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <GL/glew.h> #include <SDL2/SDL.h> #define WIDTH 512 #define HEIGHT WIDTH static const char *SHADER = "#version 430\n" "layout (local_size_x = 1, local_size_y = 1) in;\n" "layout (rgba32f, binding = 0) uniform image2D image;\n" "void main() {\n" "imageStore(image, ivec2(gl_GlobalInvocationID.xy), vec4(0.5f));\n" "}\n"; int main() { SDL_SetMainReady(); assert(!SDL_Init(SDL_INIT_VIDEO)); // 显式指定OpenGL 4.3核心Profile SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_Window *window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); assert(window); SDL_GLContext gl = SDL_GL_CreateContext(window); assert(gl); assert(glewInit() == GLEW_OK); GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); // 设置纹理参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL); glBindImageTexture(0, tex, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); GLuint shader = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(shader, 1, &SHADER, NULL); glCompileShader(shader); // 检查Shader编译错误 GLint compile_ok = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_ok); if (compile_ok == GL_FALSE) { GLint log_len; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); char* log = (char*)malloc(log_len); glGetShaderInfoLog(shader, log_len, NULL, log); fprintf(stderr, "Compute Shader compile error:\n%s\n", log); free(log); exit(1); } GLuint program = glCreateProgram(); glAttachShader(program, shader); glLinkProgram(program); // 检查Program链接错误 GLint link_ok = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (link_ok == GL_FALSE) { GLint log_len; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); char* log = (char*)malloc(log_len); glGetProgramInfoLog(program, log_len, NULL, log); fprintf(stderr, "Program link error:\n%s\n", log); free(log); exit(1); } glUseProgram(program); glDispatchCompute(WIDTH, HEIGHT, 1); // 确保Shader写入的纹理数据对后续glGetTexImage可见 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); glFinish(); static float a[WIDTH * HEIGHT * 4]; glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, a); puts((const char *)glGetString(GL_VERSION)); for (int i = 0; i < 16; ++i) printf("%f\n", a[i]); // 清理资源 glDeleteProgram(program); glDeleteShader(shader); glDeleteTextures(1, &tex); SDL_GL_DeleteContext(gl); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
额外说明
glMemoryBarrier使用GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT即可,无需用GL_ALL_BARRIER_BITS,更精准的屏障能避免不必要的性能开销。- 若你的硬件不支持OpenGL 4.3,可以尝试改用OpenGL ES 3.1(对应
#version 310 es),同时调整SDL的上下文参数为ES profile。
内容的提问来源于stack exchange,提问作者xiver77
相关产品推荐
相关产品推荐

