トップ回答者
画像の高速描画

質問
-
回答
-
質問するときはもっと詳しい開発環境・ターゲット環境(IDE、OS、CPU、メモリ、グラフィックスカードなど)を書きましょう。それによって提案・助言できることも変わってきます。
Windows Vista以降では、従来のGDIはほとんどハードウェアアクセラレートが効かず、ほぼCPUだけで描画することになってしまい、パフォーマンス不足に苦しむことになります。
高速なグラフィックス描画を求めるのであれば、Direct3D/Direct2DやWPF、OpenGLなどを経由して、グラフィックスカードやCPU内蔵GPUなどのアクセラレータを利用します。これらのAPIにまったく対応していないような古いハードウェアでないかぎり、2D描画程度であればたいてい十分な速度が得られると思います。
ターゲット環境がWindows Vista以降で、なおかつVisual C++を使って高速な2Dグラフィックス描画機能を実装したいのであれば、Direct2Dが最も適しています。
カメラのフレームバッファがどういったフォーマットか分かりませんが、24bit RGB/BGRや8bitグレースケールなどであれば、まず同一の幅と高さを持つ32bit BGRAフォーマットの中間画像バッファ(DWORD型もしくはRGBQUAD構造体の配列など)を用意しておき、フレームバッファから画像データを(C++のループコードなどを使って)Direct2D用フォーマットに変換します。次にこれまた事前作成しておいた、同一の幅と高さを持つID2D1BitmapのCopyFromMemoryメソッドを使って画像データを流し込みます。あとはID2D1RenderTarget::DrawBitmapメソッドを使って描画を行ないます。
Direct2Dの初期化と具体的な使い方は、Web検索するなりして自分で探してください。
なおVisual Studio 2010/2012/2013 Proを使えるのであれば、MFCにDirect2Dのラッパークラスがあります。
もしフレームバッファに複雑な画像処理を加えていて、それが描画のボトルネックになっている場合、Direct3D/OpenGLのプログラマブルシェーダーを活用して、画像処理をGPUアクセラレータに実行させることで、劇的に描画性能を向上させることが可能になる場合もありますが、プログラマブルシェーダーの修得にはそれなりの学習コストがかかります。
すべての返信
-
質問するときはもっと詳しい開発環境・ターゲット環境(IDE、OS、CPU、メモリ、グラフィックスカードなど)を書きましょう。それによって提案・助言できることも変わってきます。
Windows Vista以降では、従来のGDIはほとんどハードウェアアクセラレートが効かず、ほぼCPUだけで描画することになってしまい、パフォーマンス不足に苦しむことになります。
高速なグラフィックス描画を求めるのであれば、Direct3D/Direct2DやWPF、OpenGLなどを経由して、グラフィックスカードやCPU内蔵GPUなどのアクセラレータを利用します。これらのAPIにまったく対応していないような古いハードウェアでないかぎり、2D描画程度であればたいてい十分な速度が得られると思います。
ターゲット環境がWindows Vista以降で、なおかつVisual C++を使って高速な2Dグラフィックス描画機能を実装したいのであれば、Direct2Dが最も適しています。
カメラのフレームバッファがどういったフォーマットか分かりませんが、24bit RGB/BGRや8bitグレースケールなどであれば、まず同一の幅と高さを持つ32bit BGRAフォーマットの中間画像バッファ(DWORD型もしくはRGBQUAD構造体の配列など)を用意しておき、フレームバッファから画像データを(C++のループコードなどを使って)Direct2D用フォーマットに変換します。次にこれまた事前作成しておいた、同一の幅と高さを持つID2D1BitmapのCopyFromMemoryメソッドを使って画像データを流し込みます。あとはID2D1RenderTarget::DrawBitmapメソッドを使って描画を行ないます。
Direct2Dの初期化と具体的な使い方は、Web検索するなりして自分で探してください。
なおVisual Studio 2010/2012/2013 Proを使えるのであれば、MFCにDirect2Dのラッパークラスがあります。
もしフレームバッファに複雑な画像処理を加えていて、それが描画のボトルネックになっている場合、Direct3D/OpenGLのプログラマブルシェーダーを活用して、画像処理をGPUアクセラレータに実行させることで、劇的に描画性能を向上させることが可能になる場合もありますが、プログラマブルシェーダーの修得にはそれなりの学習コストがかかります。 -
sygh さんがおっしゃるように、Web 上でもそれなりに Direct2D のリソースは見つかりますので、Direct2D で試してみてはいかがでしょうか。 CopyFromMemory あたりが難しければ、ID2D1RenderTarget::CreateBitmap などを使えればより簡単にできると思います。
[連載! とことん VC++] 第 10 回 ネイティブ VC++ におけるグラフィックス オーバービュー、および Direct2D の基本的な利用方法 https://code.msdn.microsoft.com/windowsdesktop/VisualC-7e652493
これあたりが初心者向けです。
Direct2D アプリケーションのパフォーマンス向上 (Windows)
http://msdn.microsoft.com/ja-jp/library/windows/desktop/dd372260(v=vs.85).aspx#reuseResources
処理のパフォーマンス改善に関してはこちらが参考になるかと思います。
-
補足していただくことは嬉しいのですが、「CopyFromMemoryの代わりにID2D1RenderTarget::CreateBitmap」という表現は誤解を与えると思われます。
D2Dビットマップを作成してCopyFromMemoryを使うにはどのみちID2D1RenderTarget::CreateBitmapは必要になりますが、質問者さんはハイビジョン解像度での毎フレーム更新を行なっているので、ID2D1RenderTarget::CreateBitmapの際に画像データを流し込むだけ、という手法では質問者さんの要求は満たせません。要求するフレームレートや解像度にも依りますが、D2Dビットマップを毎フレーム確保し直すというのは概して大幅なパフォーマンスの低下を招きます。ビットマップの確保はアプリ起動時もしくは解像度変更時のみに限定するべきです。そういう意味を含めてCopyFromMemoryを使う手法を提案しています。- 編集済み sygh 2014年11月13日 5:57
-
他の回答者さんからD2Dのおすすめがありますので、
自分は現行コードの見直しのポイントを提案してみます。
ただし、自分も最終的にはDirect2Dの検討をおすすめする点は同じです。1.ストレッチの回数を減らせないか検討する。
・ストレッチはコストが高いです。2.ストレッチはメモリー上だけで行うようにし、
デバイスには、等倍で転送するように手直ししてみる。
・デバイスに対してのアクセスはコストが高いです。
メモリーデバイスコンテキスト上で操作したほうが早い場合が多いです。3.ストレッチ等の前処理部分と、デバイスへの転送部分を
別スレッドにできないか検討してみる。
・効果がない場合もありえますが、まぁ検討してみてはどうでしょう。
・特にリアルタイムに連続して処理す場合は考えてみてください。4.DIBではなく、デバイス依存のBMPにできないか検討してみる。
・つまりBitBlt()で最終デバイスに転送するわけですね。以上思いつくままに並べてみました。
-
qt6さん、ご返答ありがとうございます。確かに環境によって変わることもあると思います。GBクラスのビデオメモリと優秀なキャッシュ機構を備えたドライバーを擁するハードウェアであれば、私の考える小手先の最適化はかえって不要かもしれません。
ただリアルタイムグラフィックスの分野では、フレームごとのリソース再確保は避けるべき(ヒープメモリの確保は概して遅く、また頻繁なメモリの確保と解放は断片化のおそれもあるため)、というのがセオリーですので、質問者のmr54さん同様に自分のほうでもきちんと検証してみようと思います。- 編集済み sygh 2014年11月14日 13:00