Как скопировать текстуру в 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)