2014-07-22 50 views
1

我已經瞭解了爲Qt QGLWidget設置單獨的呈現線程here,herehere。 我也設法得到的是一種「工作」設置的:在viewport.Seems清除顏色是ok.But我收到以下警告:QT在單獨的線程中管理OpenGL上下文

QOpenGLContext :: swapBuffers()調用非暴露窗口,行爲 是不確定的

我首先創建一個從QGLWidget.Where我還設置OpenGL的格式繼承的插件:

在窗口部件的構造:

QGLFormat format; 
    format.setProfile(QGLFormat::CompatibilityProfile); 
    format.setVersion(4,3); 
    format.setDoubleBuffer(true); 
    format.setSwapInterval(1); 

    setFormat(format); 
    setAutoBufferSwap(false); 

然後我初始化在同一個插件的渲染線程:

void GLThreadedWidget::initRenderThread(void){ 
    doneCurrent(); 
    context()->moveToThread(&m_renderThread); 
    m_renderThread.start(); 
} 

,並從該點的整個渲染線程中完成的:

RenderThread構造:

RenderThread::RenderThread(GLThreadedWidget *parent) 
    :QThread(),glWidget(parent) 
{ 
    doRendering = true; 
} 

RenderThread run()方法:

void RenderThread::run(){ 
     glWidget->makeCurrent(); 

     GLenum err = glewInit(); 
     if (GLEW_OK != err) { 
      printf("GLEW error: %s\n", glewGetErrorString(err)); 
     } else { 
      printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION)); 
     } 
      glInit(); 
     while (doRendering){ 
      glWidget->makeCurrent(); 
      glClear(GL_COLOR_BUFFER_BIT); 

      paintGL(); // render actual frame 


      glWidget->swapBuffers(); 
      glWidget->doneCurrent(); 
      msleep(16); 
     } 

    } 

任何人都可以指出問題在哪裏?如果該消息可以被丟棄?同樣在渲染的Qt線程設置一個簡單和簡潔的解釋是非常helpful.Using的Qt 5.2(OpenGL的桌面版本)

+0

我把它'glWidget'既是'QOpenGLContext'和'QWindow'?我的假設是問題不在於多線程。你在'RenderThread'的某個地方做過show()嗎? – agrum

+0

如果你打算使用這個線程渲染屏幕外,你可能需要使用http://qt-project.org/doc/qt-5/qoffscreensurface.html我猜。 – agrum

+0

@agrum,不,我沒有,它真的好像那些警告彈出之前,小部件顯示 –

回答

1

有了你已經證明什麼,它看起來該消息處理程序警告你都拿到是因爲您開始在窗口設置序列中「過早地」觸發緩衝區交換,可以直接通過QGLContext ::/QOpenGLContext :: swapBuffers()或間接通過許多可能的方式間接觸發緩衝區交換,除了手動調試之外,其中沒有任何方法可以檢測到。我的意思是在窗口小部件的父窗口被標記爲「暴露」之前(窗口系統正在顯示之前)。

至於消息是否可以被丟棄,它可以......但是這樣做並不安全,因爲在前幾幀可能會得到未定義的行爲,或者在這樣做的地方,窗口還沒有準備好(特別是如果您在啓動時立即調整大小,而不是您的.ui文件指定的大小)。 Qt文檔說,在你的窗口暴露之前,Qt必須基本告訴OpenGL根據有效的不可信任的範圍進行繪製。我不確定這就是個人所能發生的一切。

隨着你顯示的代碼,有一個簡單的修復 - 避免甚至開始你的渲染邏輯,直到你的窗口說它暴露。使用QGLWidget檢測曝光並不明顯。這裏有一個大致類似於我使用的例子,假設你的QGLWidget的子類是'OGLRocksWidget',它是一箇中心部件的子部件,而且這個中心部件是你實現QMainWindow的子部件(這樣你的部件必須調用parentWidget() - > parentWidget()在其QMainWindow中獲得):

OGLRocksWidget::paintGL() 
{ 
    QMainWindow *window_ptr = 
     dynamic_cast<QMainWindow *>(parentWidget() ? parentWidget()->parentWidget() : 0); 
    QWindow *qwindow_ptr = (window_ptr ? window_ptr->windowHandle() : 0); 

    if (qwindow_ptr && qwindow_ptr->isExposed()) 
    { 
     // don't start rendering until you can get in here, just return... 
     // probably even better to make sure QGLWidget::isVisible() too 
    } 
} 

當然你不必爲此在您的實現QGLWidget來繪圖:: paintGL(),但在特定的設置你在你的窗口告訴你它已經被暴露之前,最好不要開始渲染線程。

看起來你可能會有比這個稍大的問題。你並沒有把正確的GL活動連接到你的代碼的正確位置與QGLWidget的意圖。我對你所處的位置感到很高興,因爲這方面的文件有點多斑點和分散。對於那部分,QGLWidget's detailed description下面寫着「這是QGLWidget子類可能看起來如何的一個粗略輪廓」,是開始獲得這個想法的好地方。您需要覆蓋那些您已經關聯代碼並將它們移動到那些調用中的任何關鍵虛擬。因此,例如,您的小部件的構造函數正在進行安裝工作,因爲QGLWidget的意圖是在您通過該調用安全地完成時間的情況下向您發出信號,所以可能更安全地放入initializeGL()覆蓋。無論何時我說這裏的是,你將不會得到看似隨機的調試異常(在發佈版本中可以默默地對運行時穩定性產生影響)。

副建議:安裝Qt源代碼,指向你的調試器,並觀察你的代碼運行,包括Qt。您上次看到它時,您的setFormat()調用實際上會刪除當前的基礎QOpenGLContext。這可能是很好的知道,因爲你很快就想創建一個新的或至少測試你的選項。

不穩定的風險就是爲什麼我在一年後試圖將至少某種答案放在一起。我剛剛通過很多(太多)調試瞭解到了這一點。我喜歡Qt團隊用它完成的任務,但是當Qt完成將所有內容遷移到QOpenGL *調用時(或者在他們看到OpenGL支持的最終適當位置,包括對它的永久考慮以及窗口支持)時,Qt會好得多, 。

相關問題