使用像素缓冲区对象将纹理从 GPU 复制到 CPU

copying texture from GPU to CPU using pixel buffer objects

我是 OpenGL 的新手,目前正在将 2D 纹理的内容复制回 CPU 内存,如下所示:

std::vector<unsigned char> frame-data(width * height * 4);
glBindTexture(GL_TEXTURE_2D, tid);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &frame_data[0]);                 

我注意到这非常缓慢,我开始阅读有关 PBO 的内容,并想看看这是否能让事情变得更顺利。所以我按如下方式创建 PBO:

GLuint  pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, width*height* 4, NULL, GL_STREAM_READ); 

我认为上面几行只需要执行一次来初始化 PBO。

我现在的问题是如何将纹理中的数据实际映射到此 PBO 对象?我知道在那之后我需要调用 glMapBuffer 但我不确定如何将此纹理附加到我的 PBO。

当缓冲区绑定到 GL_PIXEL_PACK_BUFFER 时,纹理下载函数将不将其最后一个 data 参数解释为客户端内存中的指针,而是解释为 offset 从当前绑定的像素包缓冲区开始的字节数。

换句话说,假设已经创建了纹理和大小合适的缓冲区:

// bind PBO
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer); 

// bind texture
glBindTexture(GL_TEXTURE_2D, texture);

// transfer texture into PBO
glGetTexImage(GL_TEXTURE_2D,                 
              level,
              pixelformat,
              pixeltype,
              (GLvoid*)0 // offset in bytes into "buffer",
                         // not pointer to client memory!
             ); 

传输完成后,您可以读取缓冲区中包含的纹理数据,例如通过映射它。

请注意,如果您立即映射缓冲区,您将不会从 PBO 中获得任何好处。这种方法的全部意义在于让传输异步发生,同时您通过提交其他命令让 GPU 保持忙碌。

您可以使用同步调用知道传输何时完成,例如在传输调用之后插入sync objects