使用像素缓冲区对象从 gpu 异步读取数据

Reading data from gpu asynchronously with Pixel Buffer Objects

如果您想与您的应用程序同步读取数据,从 gpu 获取数据似乎是一项非常缓慢的任务。一种可能性是在像素缓冲区对象的帮助下异步读取。不幸的是,我无法看到这是如何完成的。

首先我创建一个像素缓冲区对象:

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);

然后我想从帧缓冲区对象中读取像素:

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);

但这怎么是异步的呢? glReadPixels 或 glMapBufferRange 是否会阻塞应用程序直到 gpu 为 'ready'?

glReadPixels 调用应该开始复制到 cpu-可见缓冲区。 (每当它提交给 GPU 时。您可以使用 glFlush 强制提交)。您正在异步开始读取。

glMapBufferRange 将强制 glReadPixels 调用完成(如果它没有完成)(因为您现在正在访问 CPU 上的指针,没有办法绕过它)。

所以...不要连续做 2 个,而是要晚得多。

补充 Bahbar 的回答:

  • glReadPixels之后,如果你打算回读数据,我相信你应该调用glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);

  • glReadPixelsglMemoryBarrier之后,你可以用glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)创建一个Fence Sync,然后在同步前检查GPU是否已经执行完所有指令使用 glGetSynciv(fence_sync, GL_SYNC_STATUS, sizeof(GLint), NULL, &result),或等待 GPU 完成所有指令的执行,然后再与 glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, nanosecond_timeout).

  • 同步