2013-03-30 22 views
5

3Dアプリケーションの実行中にテクスチャを非同期にロードするにはどうすればよいですか?私が理解していることは、OpenGLのコンテキストはスレッドセーフではなく、別のスレッドでそれらを分離する必要があるということです。非同期テクスチャローディングの機能

しかし、私の主な問題は、WindowsとC++でこれを実際に実装するための適切なマルチスレッド機能/フレームワークを選ぶことです。標準のlbraryでスレッドサポートを含むC++ 11についてよく聞きましたが、基本的な手順は?

これを行う最も安全な方法は何ですか?そして、他のスレッドで行われた変更を登録する他のコンテキストの状態をどのように更新するのでしょうか?私はglFlushglBind*と思われますか?

+0

実際、OpenGLおよびOpenGLのコンテキスト**は**スレッドセーフです。一度に複数のスレッドで単一のコンテキストをアクティブにすることができます。 – datenwolf

答えて

5

テクスチャの読み込みに最も時間がかかる部分は、通常、ディスクアクセスとフォーマット変換で、どちらもOpenGLから独立しているため、別のスレッドでも安全に実行できます。テクスチャがメモリに読み込まれ、必要な形式で読み込まれると、OpenGLバッファへの実際のコピーはかなり速くなります。

スレッドプログラミングの詳細については、この回答には完全に複雑すぎますが、頭に浮かび上がるような文書がありますが、ポインタやメモリのように簡単です。

ここでの一般的な概念は、テクスチャホルダオブジェクトのリスト(ファイル/名前、最初にnullバッファ、ロード完了フラグなどを含む)を作成し、ロード時のスレッドに渡します。ロードスレッドはリストを通過し、各ファイルを開き、メモリにロードし、バッファをリストエントリに接続し、ロードされたフラグをセットし、カウンタをインクリメントします。メインスレッドは、新たにロードされたテクスチャを取り込み、それをOpenGLテクスチャにコピーし、プログレスバーまたはローディングインジケータが何であっても増加させます。リスト内のすべてのテクスチャにバッファがあり、ロードされたとフラグが立てられると、他のスレッドの作業は完了し、停止することができます(または、将来のテクスチャをロードするために残しておくことができます)。

このモデルの主な利点は、実際のグラフィックスコンテキストを共有する必要がないためです。スレッドセーフな(DirectX)APIであれば、パフォーマンスが低下することがあります。OpenGLでは、複数のコンテキストを持ったり、正しく共有しているかどうか、かなりの作業が必要です。テクスチャをロードする際の重い持ち上げは、フォーマット変換や回転を行わない限り、通常はファイルの読み込みとパラメータのチェックであり、ディスクへのアクセスも邪魔になることがあります。ビデオメモリへの実際のコピーは高度に最適化されており、ボトルネックになる可能性は低い(GPUコールコストを認識できるツールでプロファイリングを試みることを心配している場合は参照してください)。この作業のどれもOpenGLに直接依存しないので、少しでも心配することなく別のスレッドにプッシュすることができます。

特にWindowsの場合は、単純なコールバックモデル(関数と初期パラメータ、この場合はテクスチャリストを提供し、APIを作成する)を使い、組み込みのスレッド関数を使用できますコール)。私は個人的にC++ 11のスレッディングサポートに精通していませんし、Visual Studioでの動作もどうでしょうか、それでチェックしなければなりません。

+0

良い答え。はい、C++ 11の 'std :: thread'はMSVC++で動作します。使い方は 'boost :: thread'と非常に似ています。 –

0

@ssubeの回答は、タスクの複雑さの問題については正しいですが、「OpenGLでは、複数のコンテキストを持つために適切な作業が必要です。正しく共有していることを確認してください。同意しない。

容易溶液を用いて、例えば、プログラムの開始時に、(描画)メインコンテキストと(テクスチャローディング用)、二次コンテキストを作成することである。

m_hRCDrawing = wglCreateContext(m_hDC); 
m_hRCSecondary = wglCreateContext(m_hDC); 

し、データを共有しますあなたは「テクスチャの読み込み」から何のGLコンテキストを持っていないスレッドをテクスチャを読み込むしようとしているとき

wglShareLists(m_hRCSecondary, m_hRCDrawing); 

最後に、あなたは、単に呼び出すことができます:m_hRCSecondarym_hRCDrawingコンテキスト間で行うことができます

wglMakeCurrent(m_hDC, m_hRCSecondary); 

このスレッド内にロードされたアセットは、その後、描画スレッドのコンテキストで共有されます。

もう少し詳しい説明はhereです。

関連する問題