移植至Ubuntu 20.04后Compute Shader无法写入Texture问题
Compute Shader无法在Ubuntu 20.04写入Texture的问题排查与解决
将应用从Windows移植到Ubuntu 20.04后,所有Compute Shader均无法写入Texture。复现程序将Texture初始化为全零值,运行Shader后Texture仍保持全零状态,代码如下:
import numpy import moderngl import OpenGL.GL compute_shader_source = ''' #version 450 core #extension GL_ARB_uniform_buffer_object : enable layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(r8ui) uniform uimage3D to_image; void main() { imageStore(to_image, ivec3(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y, gl_GlobalInvocationID.z), uvec4(255, 255, 255, 255)); return; } '''.strip() context = moderngl.create_context(require=450, standalone=True) compute_program = OpenGL.GL.glCreateProgram() shader = OpenGL.GL.glCreateShader(OpenGL.GL.GL_COMPUTE_SHADER) OpenGL.GL.glShaderSource(shader, [compute_shader_source]) OpenGL.GL.glCompileShader(shader) compiled = OpenGL.GL.glGetShaderiv(shader, OpenGL.GL.GL_COMPILE_STATUS, None) if not compiled: log = OpenGL.GL.glGetShaderInfoLog(shader).decode() raise RuntimeError("Couldn't compile shader:\n" + log) OpenGL.GL.glAttachShader(compute_program, shader) OpenGL.GL.glLinkProgram(compute_program) linked = OpenGL.GL.glGetProgramiv(compute_program, OpenGL.GL.GL_LINK_STATUS, None) if not linked: log = OpenGL.GL.glGetProgramInfoLog(compute_program).decode() raise RuntimeError("Couldn't link shader:\n" + log) OpenGL.GL.glUseProgram(compute_program) OpenGL.GL.glActiveTexture(OpenGL.GL.GL_TEXTURE0) to_image_location = OpenGL.GL.glGetUniformLocation(compute_program, 'to_image') OpenGL.GL.glUniform1i(to_image_location, 0) textures = OpenGL.GL.glGenTextures(1) zeros = numpy.zeros((32, 32, 32), dtype=numpy.uint8) OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, textures) OpenGL.GL.glTexImage3D(OpenGL.GL.GL_TEXTURE_3D, 0, OpenGL.GL.GL_RED, 32, 32, 32, 0, OpenGL.GL.GL_RED, OpenGL.GL.GL_UNSIGNED_BYTE, zeros) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_MIN_FILTER, OpenGL.GL.GL_NEAREST) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_MAG_FILTER, OpenGL.GL.GL_NEAREST) OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, 0) OpenGL.GL.glBindImageTexture(0, textures, 0, True, 0, OpenGL.GL.GL_READ_WRITE, OpenGL.GL.GL_R8UI) OpenGL.GL.glDispatchCompute(32, 32, 32) OpenGL.GL.glFinish() OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, textures) data = OpenGL.GL.glGetTexImage(OpenGL.GL.GL_TEXTURE_3D, 0, OpenGL.GL.GL_RED, OpenGL.GL.GL_UNSIGNED_BYTE) print('data', sum(data))
问题分析与解决步骤
1. 上下文冲突
代码同时混用moderngl和PyOpenGL创建上下文,导致后续OpenGL操作可能未在正确上下文执行,需移除moderngl相关代码,统一使用PyOpenGL的上下文初始化方式。
2. 纹理格式不匹配
- Shader中声明的是
r8ui(无符号8位整数单通道),但glTexImage3D使用了GL_RED(浮点格式)作为内部格式,两者不兼容。需将内部格式改为GL_R8UI,读取时使用GL_RED_INTEGER格式。
3. Image Binding配置错误
Image Texture无需通过glActiveTexture和glUniform1i绑定,应在Shader中显式指定binding值,与glBindImageTexture的unit参数对应。
4. 缺少内存屏障
Dispatch Compute后需添加内存屏障,确保Shader的写入操作完成后再读取纹理数据,避免数据同步问题。
修改后的代码
import numpy import OpenGL.GL compute_shader_source = ''' #version 450 core layout(local_size_x=1, local_size_y=1, local_size_z=1) in; // 显式指定binding为0,与glBindImageTexture的unit参数对应 layout(r8ui, binding = 0) uniform uimage3D to_image; void main() { // r8ui仅单通道有效,其余通道会被忽略 imageStore(to_image, ivec3(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y, gl_GlobalInvocationID.z), uvec4(255, 0, 0, 0)); } '''.strip() # 初始化PyOpenGL 4.5上下文 OpenGL.GL.glXCreateContextAttribsARB( OpenGL.GL.glXGetCurrentDisplay(), OpenGL.GL.glXGetCurrentDrawable(), None, True, [ OpenGL.GL.GLX_CONTEXT_MAJOR_VERSION_ARB, 4, OpenGL.GL.GLX_CONTEXT_MINOR_VERSION_ARB, 5, OpenGL.GL.GLX_CONTEXT_PROFILE_MASK_ARB, OpenGL.GL.GLX_CONTEXT_CORE_PROFILE_BIT_ARB, None ] ) compute_program = OpenGL.GL.glCreateProgram() shader = OpenGL.GL.glCreateShader(OpenGL.GL.GL_COMPUTE_SHADER) OpenGL.GL.glShaderSource(shader, [compute_shader_source]) OpenGL.GL.glCompileShader(shader) compiled = OpenGL.GL.glGetShaderiv(shader, OpenGL.GL.GL_COMPILE_STATUS, None) if not compiled: log = OpenGL.GL.glGetShaderInfoLog(shader).decode() raise RuntimeError("编译Shader失败:\n" + log) OpenGL.GL.glAttachShader(compute_program, shader) OpenGL.GL.glLinkProgram(compute_program) linked = OpenGL.GL.glGetProgramiv(compute_program, OpenGL.GL.GL_LINK_STATUS, None) if not linked: log = OpenGL.GL.glGetProgramInfoLog(compute_program).decode() raise RuntimeError("链接Program失败:\n" + log) OpenGL.GL.glUseProgram(compute_program) textures = OpenGL.GL.glGenTextures(1) zeros = numpy.zeros((32, 32, 32), dtype=numpy.uint8) OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, textures) # 内部格式改为GL_R8UI,匹配Shader的无符号整数格式 OpenGL.GL.glTexImage3D(OpenGL.GL.GL_TEXTURE_3D, 0, OpenGL.GL.GL_R8UI, 32, 32, 32, 0, OpenGL.GL.GL_RED_INTEGER, OpenGL.GL.GL_UNSIGNED_BYTE, zeros) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_MIN_FILTER, OpenGL.GL.GL_NEAREST) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_MAG_FILTER, OpenGL.GL.GL_NEAREST) # 设置纹理Wrap参数,避免访问越界 OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_WRAP_S, OpenGL.GL.GL_CLAMP_TO_EDGE) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_WRAP_T, OpenGL.GL.GL_CLAMP_TO_EDGE) OpenGL.GL.glTexParameteri(OpenGL.GL.GL_TEXTURE_3D, OpenGL.GL.GL_TEXTURE_WRAP_R, OpenGL.GL.GL_CLAMP_TO_EDGE) OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, 0) # 将纹理绑定到unit 0,与Shader中的binding=0对应 OpenGL.GL.glBindImageTexture(0, textures, 0, True, 0, OpenGL.GL.GL_READ_WRITE, OpenGL.GL.GL_R8UI) OpenGL.GL.glDispatchCompute(32, 32, 32) # 添加内存屏障,确保Shader写入操作完成 OpenGL.GL.glMemoryBarrier(OpenGL.GL.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) OpenGL.GL.glFinish() OpenGL.GL.glBindTexture(OpenGL.GL.GL_TEXTURE_3D, textures) # 使用GL_RED_INTEGER格式读取无符号整数纹理 data = OpenGL.GL.glGetTexImage(OpenGL.GL.GL_TEXTURE_3D, 0, OpenGL.GL.GL_RED_INTEGER, OpenGL.GL.GL_UNSIGNED_BYTE) print('data总和', sum(data))
内容的提问来源于stack exchange,提问作者HahaHortness
相关产品推荐
相关产品推荐

