8

2 つの QGLWidget を使用します。1 つはテクスチャの読み込み用、もう 1 つはレンダリング用ですが、機能していません。

http://blog.qt.digia.com/blog/2011/06/03/threaded-opengl-in-4-8/から次の説明を使用しました

テクスチャのアップロード スレッド 多くの (または大きな) テクスチャのアップロードは、GPU に大量のデータがプッシュされるため、通常は負荷の高い操作です。繰り返しますが、これはメイン スレッドを不必要にブロックする操作の 1 つです。4.8 では、共有 QGLWidget のペアを作成することで、この問題を解決できます。ウィジェットの 1 つが別のスレッドで現在の状態になりますが、画面に表示されることはありません。メイン スレッドは、アップロードする画像をアップロード スレッドに通知します。アップロード スレッドは、これらの各画像に対して bindTexture() を呼び出すだけで、各画像が終了するとメイン スレッドに通知し、画面に描画できるようにします。

Qt 4.8 と MinGW では正常に動作しますが、現在は Qt 5.1 と MSVC を使用しています。スレッド内のウィジェットを最新にしたいときにエラーが発生します。

別のスレッドで QOpenGLContext を最新にすることはできません

エラーは理解できますが、どうすれば修正できますか。ウィジェットを現在に設定しないと、テクスチャをロードできません (bindTexture() 関数でフリーズします)。また、なぜ私の古い QT バージョンで動作するのか疑問に思っています。エラーが表示されたら、「エラーを無視する」を押すと、プログラムはとにかくテクスチャをロードします。

サンプルコードは次のとおりです。

テクスチャを読み込んでいます:

GLContext::GLContext(QWidget *parent, QGLWidget *myDisplayWidget) :
  QGLWidget(parent,myDisplayWidget)
{
}

...

GLContext* myTextureWidget = new GLContext(this,myDisplayWidget);

...

void TextureLoadingThread::run()
{    
    makeCurrent(); //Here is the bug!
    QImage *im = new QImage(filename);
    GLuint textid = myTextureWidget->bindTexture(*im, GL_TEXTURE_2D, GL_RGBA);
}

編集:

myTextureWidget のコンテキストをスレッドに移動すると動作しますが、GUI がビルドされるときに API から makeCurrent エラーが発生します (スタック トレースは QT5Widgetsd の QLineEdit::setPlaceHolderText 関数で述べられています)。メインウィンドウが表示されてから数秒後に myTextureWidget をスレッドに移動すると、すべて正常に動作します。しかし、qt がすべての GUI 構築作業をいつ終了したかをどのように知ることができますか? QGLWidget ビューポートを使用して QGraphicsView に GUI を描画します。

myTextureWidget->context()->moveToThread(myTextureLoadingThread);
4

2 に答える 2

4

新しいスレッドを開始して makeCurrent() を呼び出す前に、doneCurrent() を開始する必要があります。

void QGLWidget::startRendering()
{
    doneCurrent();
    context()->moveToThread(mTextureLoadingThread);
}

そして電話する

void TextureLoadingThread::run()
{    
    makeCurrent(); //Here is the bug!
    ...
}

これは、このエラーを回避するために私が行ったことです。残念ながら、レンダリングにスレッドを使用するための完璧なソリューションはありません。

// 編集

例をアップロードしました: https://dl.dropboxusercontent.com/u/165223/thread_example.zip

于 2013-10-09T18:59:01.887 に答える
1

おそらく手遅れですが、私は同じ問題を抱えていて解決策を見つけたので、将来のコーダーに役立つことを期待して、私がやったことを以下に示します。

オムゴディは正しい軌道に乗っていました。メインスレッドもおそらくコンテキストを最新のものにしようとする paintEvent() を呼び出しているため、同じエラーが引き続き発生すると思います。ただし、同じコンテキストが 2 番目のスレッドで既に最新であるため、エラーが発生します。

したがって、基本的には、2 番目のスレッドがアクティブな間、メイン スレッドがウィジェットでレンダリングしようとするのを停止する必要があります。QGLWidget に boolean 属性を追加し、2 番目のスレッドを作成する前にそれを true に設定し、スレッドが完了したら false に戻すことでそれを行いました。次に、ウィジェットの paintEvent() を、ブール値が false に設定されている場合にのみレンダリングするように変更しました。最後に、2 番目のスレッドから render 関数を手動で呼び出します。ここにいくつかのコードがあります:

//GLWidget derives from QGLWidget:
void GLWidget::paintEvent(QPaintEvent *e) {
      if ( !_second_thread_active )
           render();
}

//Then in your thread:
void Thread::doWork() {
      //Do stuff
      render();
}

スレッドが完了したら、2 番目のスレッドからメイン スレッドにコンテキストを戻すことを忘れないでください。

doneCurrent();
context()->moveToThread(&qapp->thread());

HTH

于 2014-12-02T05:50:24.513 に答える