The code I use, and is called in the program loop. The source
(surf_clip) is a cairo image surface.
s = str(surf_clip.get_data())
pitch = sw * len('BGRA') * -1
imagedata = image.ImageData(sw, sh, 'BGRA', s,pitch )
texture = self.texture
glBindTexture(texture.target, texture.id)
#rx and ry = 0, will be used to update only part that changed
imagedata.blit_to_texture(texture.target, 0, rx, ry, 0)
And the self.texture exactly like media/video:
def _get_texture(self):
if not self._texture:
glEnable(GL_TEXTURE_2D)
texture = image.Texture.create_for_size(GL_TEXTURE_2D,
self.width, self.height, GL_RGB)
if texture.width != self.width or texture.height !=
self.height:
self._texture = texture.get_region(
0, 0, self.width, self.height)
else:
self._texture = texture
return self._texture
texture = property(_get_texture)
The most obvious problem is using a negative pitch (top-to-bottom image
rows) -- GL has no way of accepting this data, so ImageData splits the
data and reorders it first. Use a positive pitch (or better, leave
pitch as the default, which is tightly packed) and swap the texture
coordinates instead (to render it "upside-down").
The other problem is the image format. We're lacking documentation on
which formats are supported by GL and which are mashed by ImageData, but
you can see what happens in pyglet/image/__init__.py, in
ImageData._get_gl_format_and_type() (line 798 atm). BGRA is not
supported on any platform (and so will be mashed -- slowly -- by
ImageData), so see if you can get Cairo to use a different surface
format. RGB or RGBA is supported everywhere, and BGR, ABGR or ARGB are
supported if certain GL extensions are present.
Good luck
Alex.
For future reference here is my solution:
negative pitch is countered by flipping the texture coordinates as
suggested:
#default: texture.tex_coords = ((0, 0, 0), (1, 0, 0), (1, 1, 0), (0,
1, 0))
texture.tex_coords = ((0, 1, 0), (1, 1, 0), (1, 0, 0), (0, 0, 0))
The image format was solved by converting it beforehand using numpy:
#BGRA TO RGB
a = numpy.frombuffer(surf_clip.get_data(), numpy.uint8)
a.shape = (sw, sh, 4)
a = a[:,:,0:3] #drop alpha channel
temp = copy(a[:,:,0])
a[:,:,0] = a[:,:,2]
a[:,:,2] = temp
After all that blit time was reduced to 0.0014 seconds a 7x
improvement :-)
My next optimization step is to use glitz, but first i have to make
python bindings...
Alex.
Alex.
elif (format == 'BGRA' and
gl_info.have_extension('GL_EXT_bgra')):
return GL_BGRA, GL_UNSIGNED_BYTE
The colour matrix optimization was not utilized since my ATI 9500 does
not support GL_ARB_imaging according to
gl_info.have_extension('GL_ARB_imaging') [verified with glview] and
according to some googling it is not common.
Thanks for all your help :-)
Gerdus.
Alex.