July 9th, 2007 @ 04:14

Erm, I just found what was wrong with gShaderEdit on Intel & al. I wasn’t redrawing the window *cough*. This *problem* is now fixed, but I don’t like the end result anyway : moving the window is dodgy, enabling/disabling the shader is dodgy (by dodgy I mean that black frames or part of black frames appear for a few seconds), the gl area is drawn directly on the screen and not on the window (so that if you have a window above the gl area you still see the gl stuff on top of it). I am probably going to add some kind of buffering tomorrow, so that I would just draw the frame once (it would be a lot lighter for CPU/GPU by the way), or just completely change the way I am doing things *sigh*.

Update : I was unable to sleep with this issue running.. I have just fixed it in a much better way : the application just draws the GL frame once, dumps the pixels with glReadPixels, creates a python array from the pixels data and creates a Cairo ImageSurface from the data array. A quick Cairo transformation flips the surface vertically (the initial pixels are y-inverted). The result surface is then simply drawn on the widget, saving precious GPU and CPU clocks and avoiding ugly bugs.

Just for the record, I haven’t found a single “gl Pixels to cairo surface” function using Google Code Search & al, so I thought I could post mine here :

def dump (width, height):
    '''Dump current GL context pixels into a cairo surface'''
    glPixelStorei (GL_PACK_ALIGNMENT, 1)
    # Dump pixels to a string
    pixels = glReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)
    # Create a python array from pixels data
    data = array.array ("c", pixels)
    s = cairo.ImageSurface.create_for_data (data, cairo.FORMAT_ARGB32,
                                            width, height, 4 * width)
    # Flip surface vertically
    surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, width, height)
    cr = cairo.Context (surface)
    matrix = cairo.Matrix (yy = -1, y0 = height)
    cr.transform (matrix)
    cr.set_source_surface (s)
    cr.paint ()
    return surface

Update 2 : *sigh* I just figured the current code is buggy. It looks like the color format is wrong : glReadPixels produces RGBA data while cairo.ImageSurface.create_for_data expects BGRA… (I already faced this issue while writing the hue picker, but I’m not sure on the way I should fix it there :/)

Update 3 : actually, it was easy ^^ Just had to define GL_BGRA (PyOpenGL is definitely kinda outdated) and that did it!