我试图将后台缓冲区的内容读入我自己的缓冲区。 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);
}
因此,每次应用程序调用{{1}}时,我都会在交换之前读取后台缓冲区。
如何快速阅读后台缓冲区?我在上面遗漏了什么?
理想情况下我想:指定游戏可以直接渲染的指针,而不是屏幕,然后我可以手动渲染内存的内容。
任何其他方式,我最终将后台缓冲区复制到我的内存块中,而且速度很慢。
有什么想法吗?
答案 0 :(得分:3)
你没有在缓冲区中保留足够的内存:
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调用一起执行,因此它将包含您发出的所有绘制调用的结果。
次要术语点:您在此处所询问的内容未被称为&#34; PBuffer&#34;。全名是&#34; Pixel Buffer Object&#34;,通常以其简短形式使用&#34; PBO&#34;。 PBuffer是完全不同的东西。这是一种旧的屏幕外渲染机制,幸好这些日子已经过时了。
答案 1 :(得分:0)
有什么想法吗?
你不要滥用主帧缓冲区来做你不应该做的事情(渲染到窗口帧缓冲区并从中读取),而是使用帧缓冲区对象和渲染缓冲区来渲染。您仍然必须使用glReadPixels,但由于您使用的是屏幕外表面,因此您将避免与窗口系统进行所有同步。仍然建议使用PBO进行数据传输,因为它为OpenGL实现提供了更多调度操作的自由度。我建议如下:
这种安排和操作顺序为OpenGL实现提供了足够的余地,可以异步地重叠那里发生的一些操作,而不会产生一些停顿同步点。例如,glReadPixels和将渲染缓冲区blitting到主帧缓冲区不会相互干扰(两者都只从渲染缓冲区读取)。 OpenGL驱动程序可以重新排列glReadPixels,以便在blit之后或同时执行。实际上,您可以交换2和3,在某些实现中,这可能会产生更好的性能。哎呀,你可以在4点之后移动2,但是你会松开一些重新排序自由的操作。