1

当我在另一个线程上调用 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?

4

3 回答 3

4

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

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

于 2011-09-09T17:59:37.827 回答
3

你有不同的选择。

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

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

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

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

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

于 2011-09-10T18:05:00.740 回答
1

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

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

于 2011-09-09T13:45:57.380 回答