场景的 OpenGL 异步渲染需要几秒钟

OpenGL asynchronous render of scene that takes several seconds

我已经使用 wxWidgets 和 OpenGL 实现了 Mandelbrot 分形生成器。计算在片段着色器内执行,我使用 wxGLCanvas 小部件来显示结果。它运行良好,但是当我想要进行高分辨率导出时,线程会锁定几秒钟,从而冻结 UI.

最初我尝试将所有渲染代码(和上下文创建)移动到一个单独的渲染线程中,但我发现不仅仅是渲染线程会被锁定,所有线程都会被锁定。这可以通过在执行只在循环中将消息打印到标准输出的渲染之前生成一个新线程来轻松证明。它会在冻结之前打印 1 条消息,然后在渲染完成后恢复。

为了执行文件导出,我首先渲染到纹理,然后使用 glGetTexImage 将像素读入主内存。渲染如您所料异步发生,但 glGetTexImage 函数将阻塞(同样,这是预期的)。因此,我尝试将 glFenceSync 与 glGetSynciv 结合使用,以便仅在达到围栏时才调用 glGetTexImage,表示已完成渲染。

我可以确认绘图调用立即返回,但是当我返回到 wxWidgets 事件循环等待渲染完成时,应用程序中的所有线程都会冻结。我想也许 wxWidgets 正在调用一个强制同步的 OpenGL 调用(可能是 wxGLCanvas 中的某些东西)——我很确定它不是我的代码中的东西。

我不确定为什么所有线程都阻塞在 glGetTexImage 调用上,而不仅仅是渲染线程。我认为这可能是我的设置(硬件、驱动程序、OS 等)的一个怪癖,但在完全不同的平台上得到了相同的结果。

我能想到的唯一剩余选项是在另一个具有自己的 OpenGL 上下文的进程中进行导出渲染。如果我仍然使用 wxGLCanvas 来设置上下文,我可能需要在屏幕上显示一个可见的 window,这并不理想。此外,如果用户在渲染期间尝试关闭 window,它将没有响应。

有什么想法吗?

与其说是解决方案,不如说是解决方法(由 derhass 在评论中建议)是将渲染拆分为几个较小的渲染。我在水平条带中绘制图像,每个 10 像素高,并在每个水平条带之间调用 wxSafeYield() 以便 UI 保持一定程度的响应(如果渲染时间太长,用户可以中止渲染)。

另一个优点是 GPU 过载的危险较小。在实现这个之前,我曾经启动了一个长时间的渲染,导致我的显示器关闭,我不得不重新启动。