2016-10-11 3 views
1

私が理解する限り、GPUImageはDAGトラバーサルを行い、フレームバッファテクスチャキャッシュと一緒に単一使用リソースとして扱いながらOpenGLの使用を保護するためにセマフォを で使用しています。GPUImageはrunloopを持つスレッドの代わりにセマフォと処理キューを使用するのはなぜですか?

ここでセマフォを使用する理由はありますか?彼らは不必要に状況を複雑にしませんか? runloop内の別のスレッドで実行するのではなく、それぞれのフィルタDAGに個別のスレッド実装を使用することによって、それらが提供するメリットとどのような問題が発生するでしょうか。 現在のGPUImageアーキテクチャの決定を通知する特定の設計上の考慮事項がありましたか?

+0

GPUImageを知らない:グラフィックカードが1つしかないので、複数のOpenGLコンテキストを同時に使用するとパフォーマンスが低下する可能性があります。 – BDL

答えて

2

OpenGL(ES)コンテキストで作業する場合、一度に複数のスレッドからアクセスすると悪いことが起こります。メインスレッドですべてのレンダリングコードとインタラクションコードを実行するだけで済みますが、これはUIを妨害し、UIイベント(メニューをプルダウンするなど)中に画像やビデオの処理を停止します。また、バックグラウンドスレッドでOpenGL(ES)レンダリングを行うためにsignificant performance advantagesがあります。

したがって、同時アクセスから保護しながら、バックグラウンドスレッドでOpenGL(ES)レンダリングを実行する方法が必要です。手動で作成されたスレッドとロックがこれを行う方法の1つになりますが、ロックには大きなパフォーマンス上のオーバーヘッドがあり、手動で作成されたスレッドを適切に管理すると、多くのコードが追加される可能性があります。

1ブロックずつアクセスするGrand Central Dispatchキューは、このような共有リソースに対して安全でロックフリーなアクセスを提供するための効率的かつ比較的簡単な方法です。コンテキスト上でOpenGL(ES)レンダリングを行いたい場所は、コンテキストのシリアルディスパッチキューにディスパッチされるブロックにラップするだけです。これにより、コード内でこれらのアクセスがどこで発生するのかを簡単に確認でき、手動スレッド、runloops、ロックを維持するパフォーマンスとコードオーバーヘッドから逃れます。

私はmy answer hereでディスパッチセマフォを使用する理由について議論しますが、負荷に応じて受信フレームを選択的にドロップする方法です。

このようなシリアルディスパッチキューでは、ある時点で、単一のイメージまたはビデオフレームだけがキューを通過するようにしたいと考えています。単一のGPUを使用すると、一度に複数のイメージをレンダリングする利点はありません。

しかし、30-60フレーム/秒で処理されるフレームを提供するカメラがあり、処理パイプラインがこれらの画像を操作するために時々1/30秒または1/60秒以上かかる場合は、あなたは決断を下さなければなりません。入ってくるフレームをドロップしますか、または処理するためにエンキューしますか?後者の場合は、使用可能な処理とメモリリソースを使い切るまで、キュー内にフレームが増え続けることになります。処理にはさらに大きな遅延が発生します。

ディスパッチセマフォでは、すでにシリアルディスパッチキューで処理されているフレームがあればすぐにフレームを落とし、実行可能で安全な方法でフレームを廃棄することができます。また、わずか数行のコードを追加します。ほとんどすべてがmy answer hereにあります(これは、Swift 3ではさらに短くて読みやすくなります)。

上記のアーキテクチャーは完全にプロファイルされており、私がこれらのニーズに見合う最高のソリューションとなっています。私は古いiOSハードウェア上の分子モデルの60 FPS OpenGL ESレンダリング、Macでのマシンビジョン処理のライブ、iOS上のリアルタイムビデオフィルタリングを長年にわたって使用してきました。マルチスレッド化されたコードでは間違っている可能性があることを考えれば、かなり堅実で維持管理が容易であることが証明されています。 GCDキューとセマフォからのオーバヘッドは、私のビデオレンダリングでのパフォーマンスのボトルネックに近かったことはありません。

+0

素敵な拡張答え、ありがとう!また、余分なリンクが便利です。 – twerdster

関連する問題