Reading data from the GPU asynchronously with Pixel Buffer Objects

3.7k Views Asked by At

Getting data from the GPU seems to be a very slow task if you want to read it synchronized with the rest of your application. One possibility is to read asynchronously with the help of Pixel Buffer Objects. Unfortunately, I am not able to see how this is done.

First, I create a Pixel Buffer Object:

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, pbo_size, 0, GL_DYNAMIC_READ);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

Then I want to read pixels from a Frame Buffer Object:

glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, 0);
GLfloat *ptr = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, pbo_size, GL_MAP_READ_BIT);
memcpy(pixels, ptr, pbo_size);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

But how is this asynchronous? Is glReadPixels or glMapBufferRange blocking the application until the GPU is 'ready'?

2

There are 2 best solutions below

2
On BEST ANSWER

The glReadPixels call should start the copy to a cpu-visible buffer. (whenever it gets submitted to the GPU. You can force the submission with glFlush). You're starting the read asynchronously.

glMapBufferRange will force the glReadPixels call to finish if it wasn't (since you're now accessing the pointer on the CPU, there's no way around that).

So... don't do the 2 back-to-back, but rather significantly later.

1
On

To add on to Bahbar's answer:

  • After glReadPixels, if you plan on reading back the data, I believe you should call glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);.

  • After glReadPixels and glMemoryBarrier, you can create a Fence Sync with glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0), then either check that the GPU has finished executing all instructions before the sync with glGetSynciv(fence_sync, GL_SYNC_STATUS, sizeof(GLint), NULL, &result), or wait for GPU to finish executing all instructions before the sync with glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, nanosecond_timeout).