如何在不同的线程上调用glReadPixels?

时间:2011-09-09 13:33:22

标签: c++ windows opengl glreadpixels

当我在另一个线程上调用glReadPixels时,它不会返回任何数据。我读到某处建议我需要在调用线程中创建一个新的上下文并复制内存。我到底该怎么做?

这是我使用的glReadPixels代码:

pixels = new BYTE[ 3 * width * height];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0xFF0000, 0x00FF00, 0x0000FF, false);
FreeImage_Save(FIF_PNG, image, pngpath.c_str() , 0);

或者,我从这个thread读取他们建议使用另一段代码(见结尾),但我不明白什么是origX,origY,srcOrigX,srcOrigY?

3 个答案:

答案 0 :(得分:3)

您可以创建共享上下文,这将按预期工作。请参阅wglShareLists(名称选择严重,它共享的不仅仅是列表)。或者,使用WGL_ARB_create_context,它也直接支持共享上下文(您已经标记了问题“windows”,但非WGL也存在类似的功能)。

然而,使用像素缓冲区对象要容易得多,它将具有与多线程相同的净效果(传输将异步运行而不会阻塞渲染线程),并且复杂度要低很多倍。 / p>

答案 1 :(得分:3)

您有不同的选择。

使用呈现线程将 ReadPixel 与流水线相连。在这种情况下,返回的数据应存储在一个缓冲区中,该缓冲区可以排队到一个专门用于保存图片的线程。这可以通过缓冲队列,互斥锁和信号量轻松完成:渲染线程使用 ReadPixel 获取数据,锁定互斥锁,入队(系统内存)像素缓冲区,解锁互斥锁,增加信号量;工作线程(锁定在信号量上)将由渲染线程发出信号,锁定互斥锁,使像素缓冲区出列,解锁互斥锁并保存图像。

否则,您可以在纹理或像素缓冲区对象上复制当前帧缓冲区。在这种情况下,您必须有两个不同的线程,每个线程具有一个OpenGL上下文当前(通过 MakeCurrent ),彼此共享它们的对象空间(如 user771921 所建议的那样)。当第一个渲染线程调用 ReadPixels (或 CopyPixels )时,通知第二个线程有关操作(例如,使用信号量);第二个渲染线程将映射像素缓冲区对象(或获取纹理数据)。 此方法的优点是允许驱动程序管道第一个线程读取操作,但它实际上通过引入额外的支持缓冲区使存储器复制操作加倍。此外,当第二个线程映射缓冲区时,刷新 ReadPixel 操作,该缓冲区在第二个线程发出信号后立即执行(最有可能)。

我会建议第一种选择,因为它更清洁,更简单。第二个是过于复杂的,我怀疑你可以从使用它中获得好处:图像保存操作比 ReadPixel 慢很多。

即使ReadPixel没有流水线,你的FPS真的会慢下来吗?在分析之前不要进行优化。

您链接的示例使用GDI函数,这些函数与OpenGL无关。我认为代码会导致重绘表单事件,然后捕获窗口客户端区域内容。与 ReadPixel 相比,它似乎要慢得多,即使我没有在这个问题上实际执行任何分析。

答案 2 :(得分:1)

好吧,在多线程程序中使用opengl是一个坏主意 - 特别是如果你在没有创建上下文的线程中使用opengl函数。

除此之外,您的代码示例没有任何问题。