我已经使用wxWidgets和OpenGL实现了一个Mandelbrot分形生成器。计算是在片段着色器中执行的,我使用wxGLCanvas小部件来显示结果。它工作得很好,但当我想要进行高分辨率导出时,线程会锁定几秒钟,这会冻结UI。
最初,我尝试将所有渲染代码(和上下文创建)移动到单独的渲染线程中,但我发现锁定的不只是渲染线程,而是所有线程。这可以通过在执行渲染之前生成一个新线程来轻松演示,该线程只在循环中将消息打印到stdout。它可以在冻结前打印一条消息,然后在渲染完成后恢复。
要执行文件导出,我首先渲染到纹理,然后使用glGetTexImage将像素读取到主存中。正如您所期望的那样,呈现是异步进行的,但是glGetTexImage函数将阻塞(同样,这也是预期的)。因此,我尝试将glFenceSync与glGetSynciv结合使用,以便只在到达栅栏时调用glGetTexImage,这表示渲染已完成。
我可以确认绘图调用立即返回,但是当我返回到wxWidgets事件循环等待渲染完成时,应用程序中的所有线程都会冻结。我想也许wxWidgets正在做一个强制同步的OpenGL调用(在wxGLCanvas中探测一些东西)--我相当确定这不是我的代码中的某些东西。
我不确定为什么所有的线程都阻塞了glGetTexImage调用,而不仅仅是渲染线程。我认为这可能是我的设置(硬件、驱动程序、操作系统等)的怪癖,但在完全不同的平台上得到了相同的结果。
我能想到的唯一选择是在另一个进程中使用它自己的OpenGL上下文进行导出呈现。如果我仍然使用wxGLCanvas来设置上下文,我可能需要在屏幕上有一个可见的窗口,这并不理想。此外,如果用户在渲染过程中尝试关闭窗口,它将没有响应。
有什么想法吗?
发布于 2019-03-06 23:00:00
与其说是一种解决方案,不如说是一种变通方法(由注释中的derhass建议)是将渲染拆分为几个较小的渲染。我在水平条带中绘制图像,每个条带有10个像素高,并在每个条带之间调用wxSafeYield(),以便UI保持一定的响应性(如果时间太长,用户可以中止渲染)。
另一个优点是GPU过载的危险较小。在实现这个之前,我曾经启动了一个长渲染,导致我的显示器关闭,我不得不进行一次硬重启。
https://stackoverflow.com/questions/54985007
复制相似问题