OpenGL读回缓冲区快
OpenGL reading back buffer quickly
我正试图将后缓冲区的内容读取到我自己的缓冲区中。glReadPixels
本身太慢了,使我的FPS从50下降到30。
所以我决定尝试使用PBuffer进行"异步"读取,但它崩溃了。
我的代码如下:如果缓冲区不存在,创建它们。否则,将返回缓冲区读入指定的内存位置:
static int readIndex = 0;
static int writeIndex = 1;
static GLuint pbo[2] = {0};
void FastCaptureBackBuffer()
{
//Create PBOs:
if (!initBuffers)
{
initBuffers = true;
glGenBuffers(2, pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[0]);
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[1]);
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
//swap read and write.
writeIndex = (writeIndex + 1) % 2;
readIndex = (writeIndex + 1) % 2;
//read back-buffer.
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]);
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]);
void* data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if (data)
{
memcpy(myBuffer, data, width * height * 4);
data = nullptr;
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
然后我做:
BOOL __stdcall HookSwapBuffers(HDC DC)
{
FastCaptureBackBufferPBO();
return CallFunction<BOOL>(GetOriginalAddress(353), DC);
}
所以每次应用程序调用wglSwapBuffers
时,我在交换之前读取回缓冲区。
如何快速读取回缓冲区?我在上面遗漏了什么?
理想情况下,我想:指定一个游戏可以直接渲染的指针,而不是屏幕,然后我可以手动渲染内存的内容。
任何其他方式,我最终复制回缓冲区到我的内存块,它很慢。
任何想法?
您没有在缓冲区中保留足够的内存:
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ);
由于您使用GL_RGBA
作为格式,您将需要每像素4字节,这也匹配您在memcpy()
调用中使用的内容:
memcpy(myBuffer, data, width * height * 4);
所以glBufferData()
调用应该是:
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4, 0, GL_STREAM_READ);
此外,从你的问题中并不完全清楚你为什么使用HookSwapBuffers()
。我相信人们使用它来拦截SwapBuffers()
调用,如果他们没有源代码。如果您想在自己的代码中捕获渲染,您可以在完成渲染帧后立即调用glReadPixels()
。它将与所有其他OpenGL调用一起按顺序执行,因此它将包含您发出的所有draw调用的结果。
小术语点:你在这里问的不叫"PBuffer"。它的全称是"像素缓冲对象",通常简称为"PBO"。PBuffer是完全不同的东西。
任何想法?
如果你不滥用主framebuffer你不应该做的事情(渲染到窗口framebuffer并从中读取),而是使用framebuffer对象和renderbuffer来渲染。您仍然必须使用glReadPixels,但由于您使用的是离屏幕表面,因此可以避免与窗口系统的所有同步。使用PBO进行数据传输仍然是值得推荐的,因为它使OpenGL实现在调度操作方面更自由。我的建议如下:
- 渲染到FBO渲染缓冲区
- glReadPixels from renderbuffer到GL_PIXEL_PACK_BUFFER PBO
- 将渲染缓冲区Blit到主帧缓冲区
- SwapBuffers
- 从PBO中检索数据
这种操作的安排和顺序给了OpenGL实现足够的余地来异步重叠一些发生在那里的操作,而不会强加一些延迟同步点。例如,glReadPixels和将renderbuffer置位到主framebuffer不会相互干扰(都只从renderbuffer读取)。OpenGL驱动程序可能会重新安排glReadPixels在blit之后执行,或者同时执行。实际上,您可能会交换2和3,在某些实现中,这可能会产生更好的性能。哎呀,你甚至可以在4之后移动2,但这样你就失去了一些操作重新排序的自由。
- OpenGL 16 位模板缓冲区?
- 在 openGL 中多次绑定缓冲区
- 是否可以从 OpenGL 缓冲区获取原始大小的像素?
- 是否可以在 OpenGL 中的同一调用中呈现两个具有不同索引起点的不同缓冲区?
- OpenGL 调试上下文警告 -"将使用视频内存作为缓冲区异议的来源
- Opengl 3/4 : 我可以将相同的缓冲区对象绑定到不同的目标吗?
- OpenGL 更新缓冲区如何影响速度
- 从OpenGL应用程序中提取颜色/深度缓冲区
- 使用 OpenGL 插值数据缓冲区?
- 写入渲染缓冲区并使用单个渲染调用使用 OpenGL 显示
- OpenGL 顶点缓冲区类重定义和模板方法错误
- 绘制的 OpenGL 点消失,绘制调用和交换缓冲区问题
- OpenGL:使用指向静态数据的指针数组传递缓冲区数据
- 使用推力使用sort_by_key对两个OpenGL缓冲区进行排序
- OpenGL - 深度缓冲区在渲染半透明立方体时剪切掉不应该剪切的面
- 无法获取索引缓冲区以在 OpenGL 中绘制正方形
- 写入 OpenGL 模具缓冲区
- 如何使用 new 和 delete 与 OpenGL 的缓冲区对象一起使用?
- OpenGL:缓冲区对象/着色器超出范围
- OpenGL-缓冲区更新下一个渲染对象