Как скопировать текстуру в pbo в PyOpenGL?

После того, как я какое-то время счастливо использовал PyOpenGL, теперь я серьезно застрял. Я работаю над пакетом Python, который позволяет мне использовать шейдеры GLSL и программы OpenCL для обработки изображений, используя текстуры как стандартизированный способ ввода и вывода моих данных из шейдеров GLSL и программ OpenCL.

Все работает, за исключением того, что мне не удается скопировать текстуру в pbo (объект буфера пикселей). Я использую pbo для ввода / вывода моих текстурных данных из OpenCL, и это хорошо и быстро работает в PyOpenCL: я могу скопировать мой вывод OpenCL из pbo в текстуру и отобразить его, а также могу загрузить данные из процессора в pbo. Но я безнадежно застрял, пытаясь заполнить свой pbo данными текстуры, уже находящимися в графическом процессоре, и это то, что мне нужно сделать, чтобы загрузить свои изображения, созданные шейдерами GLSL, в OpenCL для дальнейшей обработки.

Я читал о двух способах сделать это: вариант 1 связывает pbo, связывает текстуру и использует glGetTexImage(), вариант 2 присоединяет текстуру к объекту буфера кадра, связывает fbo и pbo и использует glReadPixels()

Я также читал, что версии PyOpenGL как glReadPixels(), так и glGetTexImage() имеют проблемы с указателями 'Null', которые следует использовать при наличии привязанного pbo, поэтому по этой причине я использую варианты OpenGL.raw.GL.

Но в обоих этих случаях я получаю ошибку "Недопустимая операция", и я действительно не вижу, что я делаю неправильно. Ниже двух версий метода load_texture() моего Python-класса pixelbuffer, я надеюсь, что я не урезал их слишком далеко...

вариант 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 байт на плоскость, поскольку это целые целые. Это прекрасно работает при передаче данных пикселей с хоста.

Также я на Kubuntu 11.10, использую NVIDIA GeForce GTX 580 с 3Gb памяти на GPU, используя проприетарный драйвер, версия 295.33

что мне не хватает?

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)
Другие вопросы по тегам