如何在不同的线程上调用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);

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

您可以创建共享上下文,这将按照您的预期工作。参见wglShareLists(这个名字选得很糟糕,它共享的不仅仅是列表)。或者,使用WGL_ARB_create_context,它也直接支持共享上下文(你已经标记了问题"窗口",但类似的功能也存在于非wgl)。

然而,使用像素缓冲对象要容易得多,这将具有与多线程相同的净效果(传输将异步运行而不会阻塞渲染线程),并且它要简单得多。

你有不同的选择

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

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

我建议第一个选项,因为它更干净和简单。第二个过于复杂,我怀疑你能从使用它中获得好处:图像保存操作比ReadPixel慢得多。

即使ReadPixel不是流水线的,你的FPS真的变慢了吗?在你可以配置文件之前不要优化。

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

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

除此之外,您的代码示例中没有任何错误。

最新更新