如何在PyOpenGL中将纹理复制到pbo中?

时间:2012-05-08 22:03:22

标签: opengl textures pyopengl pbo

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

一切正常,除了我无法成功将纹理复制到pbo(像素缓冲对象)。 我正在使用pbo来获取OpenCL中的纹理数据,并且在PyOpenCL中运行良好且快速:我可以从其复制我的OpenCL输出 pbo到纹理并显示它,我也可以将数据从cpu加载到pbo中。但我绝对没有试图用GPU上的纹理数据来填充我的pbo,这是我需要做的就是将GLSL着色器生成的图像加载到OpenCL中进行进一步处理。

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

我还读到glReadPixels()和glGetTexImage()的PyOpenGL版本在使用绑定pbo时应该使用的'Null'指针有问题,因此我使用的是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乘1024,4个平面,每个平面1个字节,因为它是unisgned int。从主机传输像素数据时,这种方法很有效。

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

我错过了什么?

1 个答案:

答案 0 :(得分: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)