2016-08-19 78 views
3

我正在嘗試使用Qt爲工作中的儀器仿真程序提供新的佈局。我們目前的sim在一個窗口中運行所有的東西(我們已經使用了glut(舊)和fltk),它使用glViewport(...)glScissor(...)將儀器讀數分成它們自己的視圖,然後它使用某種形式的「ortho2D」創建自己的虛擬像素空間。模擬器當前更新儀器,然後逐個繪製各自的視口,全部在同一個線程中。是否可以將Qt GUI分割爲GUI,模擬和OpenGL的多個線程?

我們想要找到一個更好的方法,並且我們在Qt上安頓下來。我在幾大約束下工作:

  1. 每個儀表板仍然需要在它們的OpenGL視口中。有很多按鈕和很多樂器。我的暫時解決方案是爲每個使用QOpenGLWidget。我在這方面取得了進展。
  2. 這個模擬器不僅僅是一個漂亮的讀數器,還可以模擬許多儀器作爲儀器設計者的反饋,所以它有時會有很大的CPU負載。它不是一個完整的硬件仿真器,但它確實模擬了邏輯。我不認爲告訴儀器在其關聯的小部件的方法開始時更新自己是不可行的,所以我希望模擬更新在單獨的線程中運行。
  3. 我們的客戶可能擁有舊電腦,因此已排除更新版本的OpenGL。我們仍然使用glBegin()glEnd()以及兩者之間的所有內容,儀器繪製了一大堆變量符號,因此繪圖需要很長時間,我想將繪圖拆分到它自己的線程中。我還不知道OpenGL 3是否在桌面上,這對於渲染到離屏緩衝區是必要的(我認爲)。

問題: QOpenGLWidget不會對覆寫投放「更新」的方法,並在小部件paintEvent(...)paintGL(...)電話只汲取。

暫定解:分割成模擬器三個線程:

  1. GUI:運行的用戶輸入,paintEvent(...),和paintGL(...)
  2. 模擬器:運行所有儀器邏輯並更新符號系統的值。
  3. 繪圖:將最新的符號體系呈現給離線緩衝區(將使用幀緩衝區對象(FBO))。

在此設計中,跨線程交談是循環和單向的,GUI線程提供輸入,仿真器線程在下一個循環中將輸入考慮在內,繪圖線程讀取最新的符號系統和呈現它給FBO並設置「下一幀可用」標誌爲真(或可能發出信號),然後paintGL(...)方法將採用該FBO並將其吐出到窗口小部件,從而保持事件處理和GUI響應性。繼續這個循環。

底線問題:我讀過here,GUI操作無法在單獨的線程中完成,那麼我的方法是否可行?

如果可行,任何其他謹慎或建議,將不勝感激。

+3

通常,所有繪圖和窗口小部件操作都需要位於擁有「窗口」的線程中,這適用於普通的GUI小部件和窗口以及OpenGL。其他一切都可以在線程中。您可以修改正在繪製的對象。另一個線程中的OpenGL,只是不做另一個線程上的繪圖。另外要小心,以免修改正在繪製的對象。 –

+0

你爲什麼需要這樣的設計? GUI系統中的事件隊列就是這樣的隊列。除非您處於專門的模式模式,否則不會錯過任何事件。這使得它非常合理,並且對於輸入延遲原因的規範,允許渲染阻止輸入處理。 –

+0

因爲事件處理在線程上被阻塞,並且我不想將事件處理與可能持續很長時間的paintEvent(...)綁定。我的印象是,如果事件系統如此捆綁,那麼GUI可能會失去響應能力。 –

回答

4

每個OpenGL小部件都有自己的OpenGL context,這些上下文是QObject s,因此可以移動到其他線程。和其他非線程安全的對象一樣,您只能從thread()訪問它們。

此外 - 這也可以移植到QML - 您可以使用工作者函數來計算顯示列表,然後將其提交給渲染線程以轉換爲繪製調用。渲染線程不執行任何邏輯,也不計算任何內容:它將數據(頂點數組等)提交給繪圖。使用QtConcurrent::run將工作者仿函數提交給線程池執行。

因此,您可以擁有一個主線程,一個渲染線程(可能每個窗口小部件有一個,但不一定),以及運行仿真步驟的仿函數。

無論如何,卷積邏輯和渲染是一個非常糟糕的想法。無論是在柵格小部件上使用QPainter進行繪製,還是在QOpenGLWidget上使用QPainter,或者使用直接的OpenGL調用,繪製的線程都不應計算要繪製的內容。

如果你不想惹OpenGL調用,你可以代表大部分工作基於陣列的QPainter呼叫(例如drawRectsdrawPolygons),這些幾乎是直接翻譯成OpenGL的繪圖調用和OpenGL的後端將渲染它們的速度與您對繪製調用進行手動編碼一樣快。如果你在QOpenGLWidget上使用它,QPainter會爲你做這一切!

+0

爲遲迴複道歉。在工作中挑剔的網絡限制阻止我發佈在計算器上,但不能讀取它。 >渲染線程不執行任何邏輯,也不計算任何東西:它將數據(頂點數組等)提交併繪製。 我認爲QWidget對象的繪圖不能放到另一個線程中。如果是這樣,那麼渲染線程將如何爲處於主線程中的小部件執行繪圖? –

+0

OpenGL'QWidget'是一個特例。它上面的繪畫必須在'widget.context() - > thread()'中完成。您可以將上下文移至任何線程。即使對於非OpenGL小部件,也可以通過渲染到「QImage」然後在主線程中對該圖像進行分塊來在另一個線程中進行繪製。 –