15

Is there a way to increase the speed of glReadPixels? Currently I do:

Gdx.gl.glReadPixels(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixels);

The problem is that it blocks the rendering and is slow.

I have heard of Pixel Buffer Objects, but I am quite unsure on how to wire it up and whether it is faster or not.

Also is there any other solutation than glReadPixels?

Basically, I want to take a screenshot as fast as possible, without blocking the drawing of the next scene.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Niklas
  • 23,674
  • 33
  • 131
  • 170
  • PBOs will definitely be faster, as you can call `glReadPixels` to read into the PBO, then draw frames until the command is complete. You'll need a sync object to determine when the PBO has been fully written to though. – Colonel Thirty Two Aug 04 '14 at 21:25
  • Related to `glReadPixels` performance: http://stackoverflow.com/q/7368765/103167 – Ben Voigt Aug 04 '14 at 21:54
  • A good starting point on PBOs: http://www.songho.ca/opengl/gl_pbo.html – glampert Aug 04 '14 at 21:58

1 Answers1

21

Is there a way to increase the speed of glReadPixels?

Well, the speed of that operation is actually not the main issue. It has to transfer a certain amount of bytes from the framebuffer to your system memory. In your typical desktop system with a discrete GPU, that involves sending the data over PCI-Express, and there is no way around that.

But as you already stated, the implicit synchronization is a big issue. If you need that pixel data as soon as possible, you can't really do much better than that synchronous readback. But if you can live with getting that data later, asynchronous readback via pixel buffer objects (PBOs) is the way to go.

The pseudo code for that is:

  1. create PBO
  2. bind PBO as GL_PIXEL_PACK_BUFFER
  3. do the glReadPixels
  4. do something else. Both work on the CPU and issuing new commands for the GPU is ideal.
  5. Read back the data from PBO by either using glGetBufferSubData or by mapping the PBO for reading.

The crucial point is the timing of step 5. I you do that to early, you still blocking the client side, as it will wait for the data to become available. For some screenshots, It should not be hard to delay that step for even one or two frames. That way, it will have only a slight impact on the overall render performance, and it will neither stall the GPU nor the CPU.

genpfault
  • 51,148
  • 11
  • 85
  • 139
derhass
  • 43,833
  • 2
  • 57
  • 78
  • 1
    you can use a sync object to query if the operation is done by doing glFenceSync right after glReadPixels and checking glClientWaitSync with a timeout of 0 – ratchet freak Aug 05 '14 at 11:37
  • 1
    Do you have some code to create plus bind the PBO as well as reading it with `glGetBufferSubData`. I am kinda lost in OpenGL. Also Libgdx seems to have no `Gdx.gl.glGetBufferSubData` – Niklas Aug 05 '14 at 17:34
  • @Niklas: I don't know anything about libgdx. The [GL_ARB_pixel_buffer_object extension spec](https://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt) itself has a section on usage examples. Example 3 is a more advanced version of async readback: they read back two image halfes, and start processing the first half while the second one might still be transfered. They also directly map the buffers for reading, but if you want to use `glGetBufferSubData`, the [manual page](https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetBufferSubData.xml) should explain all you need. – derhass Aug 05 '14 at 17:54