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

移植至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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 04:31:18