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

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

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

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

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

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

вариант 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 с 3 ГБ памяти на графическом процессоре, использую проприетарный драйвер версии 295.33.

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


person Joost Rekveld    schedule 08.05.2012    source источник
comment
Можете ли вы сказать, какие конкретно строки вызывают ошибку Invalid Operation?   -  person Tim    schedule 09.05.2012
comment
в варианте 1 вызов glGetTexImage, в варианте 2 вызов glReadPixels. Ошибка, которую я получаю, перечисляет значения, переданные C-вызову, и они соответствуют ожиданиям. Я успешно использовал большую часть связывающих вещей вокруг этих вызовов в других частях моего кода, поэтому я почти уверен, что ошибка — это то, чего нет в коде, а не то, что есть :)   -  person Joost Rekveld    schedule 10.05.2012
comment
Вы читали список ошибок на странице руководства glGetTexImage? В нем описаны все возможности, которые могут привести к недопустимой операции, возможно, вы сможете указать там свои. Я не вижу достаточно кода, чтобы узнать, верны ли какие-либо из них в вашем случае. opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml< /а>   -  person Tim    schedule 10.05.2012
comment
Привет, Тим, спасибо, я нашел этот список и просмотрел его несколько раз (и тоже смотрел на него). Единственные два, которые, на мой взгляд, могут указать на причину, связаны с привязанным буфером: ... данные будут упакованы в объект буфера, так что требуемая запись в память превысит размер хранилища данных. и ... img не делится нацело на количество байтов, необходимых для хранения в памяти данных, указанных типом. Но я без проблем использовал pbo с очень похожими данными, поступающими от процессора, того же типа и того же размера, что и здесь. Вот почему я не понимаю..   -  person Joost Rekveld    schedule 10.05.2012
comment
Я еще не совсем уверен. Какие параметры pbo и текстуры в variant1? Ширина текстуры, высота, формат пикселей, параметры инициализации pbo и т.д.   -  person Tim    schedule 10.05.2012
comment
Привет, Тим, я добавил часть этой информации к моему вопросу, есть ли что-то еще, что, по вашему мнению, может быть актуально?   -  person Joost Rekveld    schedule 10.05.2012


Ответы (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)
person Joost Rekveld    schedule 10.05.2012