Performance tipps/optimization regarding glRead...

Hi everyone.
I simple need a hint.
Currently my code looks like this<snip>:

gl.glPixelTransferf(GL.GL_RED_SCALE, 0.299f);
gl.glPixelTransferf(GL.GL_GREEN_SCALE, 0.587f);
gl.glPixelTransferf(GL.GL_BLUE_SCALE, 0.114f);

//define from wich Buffer you want to read the pixel

// read the BGR values into the image buffer

// must restore scales to default values
gl.glPixelTransferf(gl.GL_RED_SCALE, 1);
gl.glPixelTransferf(gl.GL_GREEN_SCALE, 1);
gl.glPixelTransferf(gl.GL_BLUE_SCALE, 1);

So my aim is to perform a screenshot from an area (640x480) grayscale.
Everything works fine…except the performance.
Everytime I take this screenshot the application stops for a moment.

Do you have any ideas to reach my aim, with using the above features but without slowing down the application?
Btw. new hardware isn’t an option ;).

Please be kind with me, its the first time that I’ve been using OpenGL, never done anything with it before.
Thanks in advance for your suggestions!

p.s. I’ve read that glPixelTransferf is a performance-killer?!
Btw. if I comment it out it works flawlessly, except that the screenshot looks terrible.

It depends on where the bottle neck is.
glReadPixels is a sync operations. That means the driver waits for the GPU to finish rendering, then reads back.
The driver checks to see if it needs to convert the data. In your case, yes it does. It uses the CPU to convert and copies to your array.

You can try to readback pixels in their native format. Perhaps GL_BGRA.
The next thing to try is PBO, which can readback in async mode.

Once you have the pixel, you can convert it to luminance yourself with secondary thread.

Instead of glReadPixels you can also try rendering to texture and using glGetTexImage:

  1. Render your scene
  2. Was screenshot taken in previous frame?
    If yes, bind texture X and call glGetTexImage. Save screenshot.
  3. Take screenshot in this frame?
    If yes, copy scene to texture X (glCopyTexSubImage)

Very simple and very effective. OpenGL 1.1 compatible.

IME, the simplest and fastest is to set up a transfer buffer (system memory for the frambuffer copy) the same format as your backbuffer, do the Read, and then use the CPU convert from RGB to (in this case the usual NTSC-scaled) luminance. Using LUT(s) that are so small as to completely fit in L1 cache, this last step is so fast it’s silly.

AFAIK, glReadPixels with RGB color scale is not accelerated and probably processed by CPU. It is better to use simple GLSL shader to convert RGB to grayscale and then do readback.

Thanks everyone for your suggestions!!
Currently I am stucked at another problem…(programming is so much fun gargl) and didnt touch the colour/screenshot problem anymore.
This changes in a few days (hopefully).

Then I’ll come back to your suggestions.
The PBO isn’t an option (I superficially informed me about that), because it takes too much time for me, I am really not into graphic’s programming nor OpenGL at all.

Ill report you in a few days which suggestion I’ve tested.

So long, thank you very much for your ideas!