繁体   English   中英

将Qt GUI拆分为GUI,模拟和OpenGL的多个线程是否可行?

[英]Is it feasible to split Qt GUI into multiple threads for GUI, simulation, and OpenGL?

我正在试验Qt的工作中的仪器模拟程序的新布局。 我们当前的sim在一个窗口中运行所有内容(我们使用了glut(旧)和fltk),它使用glViewport(...)glScissor(...)将仪器读数分成他们自己的视图,然后它使用某种形式的“ortho2D”调用来创建自己的虚拟像素空间。 模拟器当前更新仪器,然后逐个在各自的视口中绘制每个仪器,所有这些都在同一个线程中。

我们想找到一个更好的方法,我们选择了Qt。 我正在一些很大的限制下工作:

  1. 每个仪表板仍然需要在其OpenGL视口中。 有很多按钮和很多乐器。 我的初步解决方案是为每个使用QOpenGLWidget。 我在这方面取得了进展。
  2. SIM不仅仅是一个非常好的读数,而且还模拟了许多仪器作为仪器设计人员的反馈,因此它有时会有很大的CPU负载。 它不是一个完整的硬件模拟器,但它确实模拟了逻辑。 我不认为告诉仪器在其关联的小部件的paintEvent(...)方法的开头更新自己是可行的,所以我希望模拟更新在单独的线程中运行。
  3. 我们的客户可能拥有旧计算机,因此排除了更新版本的OpenGL。 我们仍然使用glBegin()glEnd()以及介于两者之间的所有东西,并且仪器绘制了一堆垃圾变量符号,因此绘制需要花费大量时间,我想将绘制分割成它自己的线程。 我还不知道OpenGL 3是否在桌面上,这对于渲染到屏幕外缓冲区是必要的(我认为)。

问题: QOpenGLWidget没有可重写的“update”方法,它只在窗口小部件的paintEvent(...)paintGL(...)调用期间绘制。

暂定解决方案 :将模拟器拆分为三个线程:

  1. GUI:运行用户输入, paintEvent(...)paintGL(...)
  2. 模拟器:运行所有仪器逻辑并更新符号系统的值。
  3. 绘图:将最新的符号系统渲染到屏幕外缓冲区(将使用帧缓冲区对象(FBO))。

在这个设计中,跨线程说话是循环的,单向的,GUI线程提供输入,模拟器线程在下一个循环中考虑该输入,绘图线程读取最新的符号系统并将其呈现给FBO并设置“下一帧可用”标志为true(或者可能发出信号),然后paintGL(...)方法将该FBO并将其吐出到小部件,从而保持事件处理能力下降和GUI响应能力提高。 继续这个循环。

底线问题 :我在这里读到GUI操作无法在单独的线程中完成,所以我的方法是否可行?

如果可行,任何其他谨慎或建议将不胜感激。

每个OpenGL小部件都有自己的OpenGL上下文 ,这些上下文是QObject ,因此可以移动到其他线程。 与任何其他非线程安全对象一样,您只应从其thread()访问它们。

另外 - 这也可以移植到QML - 您可以使用工作器函数来计算显示列表,然后将其提交到渲染线程以转换为绘制调用。 渲染线程不做任何逻辑并且不计算任何东西:它接受数据(顶点数组等)并提交它以进行绘制。 工作QtConcurrent::run函数将使用QtConcurrent::run提交在线程池上QtConcurrent::run

因此,您可以拥有一个主线程,一个渲染线程(可能每个小部件一个,但不一定),以及运行模拟步骤的仿函数。

无论如何,卷积逻辑和渲染是一个非常糟糕的主意 无论您是在栅格小部件上使用QPainter进行绘制,还是在QOpenGLWidget上使用QPainter ,或者使用直接OpenGL调用,执行绘图的线程都不应该计算要绘制的内容。

如果您不想搞乱OpenGL调用,并且您可以将大部分工作表示为基于数组的QPainter调用(例如drawRectsdrawPolygons ),则这些调用几乎直接转换为OpenGL绘制调用,而OpenGL后端将使它们呈现为很快,好像你手动编写了绘制调用。 如果你在QOpenGLWidget上使用它, QPainter会为你做这QOpenGLWidget

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM