3

在愉快地使用 PyOpenGL 一段时间后,我现在严重卡住了。我正在开发一个 Python 包,它允许我使用 GLSL 着色器和 OpenCL 程序进行图像处理,使用纹理作为将我的数据进出 GLSL 着色器和 OpenCL 程序的标准化方式。

一切正常,除了我无法成功将纹理复制到 pbo(像素缓冲区对象)中。我正在使用 pbo 将我的纹理数据输入/输出 OpenCL,这在 PyOpenCL 中运行良好且快速:我可以将我的 OpenCL 输出从它的 pbo 复制到纹理并显示它,我还可以将数据从 cpu 加载到一个公益组织。但是我绝望地试图用 GPU 上已经存在的纹理数据填充我的 pbo,这是我需要做的才能将 GLSL 着色器生成的图像加载到 OpenCL 中以进行进一步处理。

我已经阅读了两种方法:变体 1 绑定 pbo,绑定纹理并使用 glGetTexImage() 变体 2 将纹理附加到帧缓冲区对象,绑定 fbo 和 pbo 并使用 glReadPixels()

我还读到 glReadPixels() 和 glGetTexImage() 的 PyOpenGL 版本在绑定 pbo 时应该使用的“空”指针有问题,因此我使用的是 OpenGL.raw.GL 变体。

但在这两种情况下,我都会收到“无效操作”错误,我真的看不出我做错了什么。下面是我的pixelbuffer Python类的load_texture()方法的两个版本,我希望我没有把它们剥离得太远......

变体1:

    def _load_texture(self, texture):
        glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, self.id)
        glEnable(texture.target)
        glActiveTexture(GL_TEXTURE0_ARB)
        glBindTexture(texture.target, texture.id)
        OpenGL.raw.GL.glGetTexImage(texture.target, 0, texture.gl_imageformat,
                                    texture.gl_dtype, ctypes.c_void_p(0))
        glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0)
        glDisable(texture.target)

变体 2:

    def _load_texture(self, texture):
        fbo = FrameBufferObject.from_textures([texture])
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        texture.target, texture.id, 0)
        glReadBuffer(GL_COLOR_ATTACHMENT0)
        glBindFramebuffer(GL_FRAMEBUFFER, fbo.id)
        glBindBuffer(GL_PIXEL_PACK_BUFFER, self.id)
        OpenGL.raw.GL.glReadPixels(0, 0, self.size[0], self.size[1],
                                   texture.gl_imageformat, texture.gl_dtype,  
                                   ctypes.c_void_p(0))
        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                               GL_TEXTURE_RECTANGLE_ARB, 0, 0)
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

编辑(添加一些关于我的 pbo 的错误和初始化的信息):

我得到的变体 1 的错误是:

OpenGL.error.GLError: GLError(
    err = 1282,
    description = 'invalid operation',
    baseOperation = glGetTexImage,
    cArguments = (
        GL_TEXTURE_RECTANGLE_ARB,
        0,
        GL_RGBA,
        GL_UNSIGNED_BYTE,
        c_void_p(None),
    )

我正在像这样初始化我的 pbo:

    self.usage = usage
    if isinstance(size, tuple):
        size = size[0] * size[1] * self.imageformat.planecount
    bytesize = self.imageformat.get_bytesize_per_plane() * size
    glBindBuffer(self.arraytype, self.id)
    glBufferData(self.arraytype, bytesize, None, self.usage)
    glBindBuffer(self.arraytype, 0)

'self.arraytype' 是 GL_ARRAY_BUFFER, self.usage 我已经尝试了所有可能性以防万一,但 GL_STREAM_READ 似乎最适合我的使用类型。我通常使用的大小是 1024 x 1024,4 个平面,每个平面 1 个字节,因为它是无符号整数。这在从主机传输像素数据时效果很好。

我也在 Kubuntu 11.10 上,使用 NVIDIA GeForce GTX 580,GPU 上有 3Gb 内存,使用专有驱动程序,版本 295.33

我错过了什么?

4

1 回答 1

1

我自己找到了一个解决方案,但并没有真正理解它为什么会产生如此巨大的差异。

我拥有的代码(对于两种变体)基本上是正确的,但需要在那里调用 glBufferData 才能工作。在我的原始代码中初始化我的 pbo 时,我已经进行了相同的调用,但我的猜测是,在初始化和我尝试加载纹理之间发生了足够的事情,导致 pbo 内存在此期间以某种方式被取消分配。

现在我只将该调用移近我的 glGetTexImage 调用,它可以在不更改任何其他内容的情况下工作。

奇怪,我不确定这是一个错误还是一个功能,如果它与 PyOpenGL、NVIDIA 驱动程序或其他东西有关。如果它是预期的行为,它肯定没有记录在任何容易找到的地方。

下面的变体 1 代码可以工作并且速度也非常快,当以相同的方式处理时,变体 2 也可以正常工作,但速度大约只有一半。

def _load_texture(self, texture):
    bytesize = (self.size[0] * self.size[1] *
                self.imageformat.planecount *
                self.imageformat.get_bytesize_per_plane())
    glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, self.id)
    glBufferData(GL_PIXEL_PACK_BUFFER_ARB,
                 bytesize,
                 None, self.usage)
    glEnable(texture.target)
    glActiveTexture(GL_TEXTURE0_ARB)
    glBindTexture(texture.target, texture.id)
    OpenGL.raw.GL.glGetTexImage(texture.target, 0, texture.gl_imageformat,
                                texture.gl_dtype, ctypes.c_void_p(0))
    glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0)
    glDisable(texture.target)
于 2012-05-10T01:24:14.647 回答