MFC VC++ 2005です。
ダブルバッファリングによって、ビットマップ(DIB)を定期的に描画するプログラムを
作っています。
メモリデバイスコンテキストに描画して、そのメモリデバイスコンテキストから実際の画
面に転送(BitBlt)しています。
この場合は画面は一気に塗り変わるはずですよね?
時々、画面の左から右に向かってゆっくり塗り変わっていくことがあるのですが、このた
び初めてダブルバッファリングを使ったので原因がわかりません。
CPU使用率が高いのって、原因でしょうか?
> この場合は画面は一気に塗り変わるはずですよね?
そうです。
CPU使用率が高ければゆっくり描画しているように見えることはあり
ます。しかし、この手の話は実際に動かしてみないとなんとも。
> び初めてダブルバッファリングを使ったので原因がわかりません。
描画途中が見えないという話?
であれば、いったん表画面への直接描画に切り替えてみるといいよ。
>この場合は画面は一気に塗り変わるはずですよね?
>時々、画面の左から右に向かってゆっくり塗り変わっていくことがあるのですが
ここの一行目をみると「変わるはずなのに変わってない」とも受け取れるが
2行目では「時々ゆっくり」とある。・・・・よくわからない
「一応変わるが、時々ゆっくりになる」のか?
「ほとんど変わることはなく、時々だけゆっくり画面が変わる」
のどっちかな?
他、
1:毎秒何回ぐらい更新している?
2:時々発生の「時々」とはどのくらい?(頻度、継続性)
3:現象発生時、PCそのものは快適?それとも、重い?
4:CPU負荷は普段から高いのか?それとも高いときだけ発生するのか?
5:左から右とは?(□:変更前、■変更後)
A:全体が左から右へ
■□□
■□□
■□□
B:幅をもって左から右へ行き、それが上から下へと
■■■
■□□
□□□
(Aだとしたら・・・怖いな)
6:ゆっくりかわるってどのくらい?
バックバッファへの書込部分や、表画面への転送時のソースもあるとわかるかもしれない
それとWORLDさんの現象にあてはまるかどうかは保証できないが
「垂直同期」って単語でネット検索してみて
一般論だけで書いてしまうとWindowsでは画面描画処理は
他の部分が忙しければ後回しにされてしまう程度の優先度です。
何が原因でCPUの使用率が高いのかわかりませんけれど、
一般的にCPUが忙しいと画面描画は後回しにされる事が多いと思います。
CPUの使用率が異常に高い状態だとエクセルやワードでも
画面更新の様子が見えたりする事があるのでCPUの使用率を高くしている
原因がわかっていて対策が可能なら改善の余地はあるかもしれません。
実際にどの位の使用率になっているのかも提示した方が良いと
思いますよ。単に高い、低いでは主観の話になってしまうので。
>ここの一行目をみると「変わるはずなのに変わってない」とも受け取れるが
>2行目では「時々ゆっくり」とある。・・・・よくわからない
>「一応変わるが、時々ゆっくりになる」のか?
>「ほとんど変わることはなく、時々だけゆっくり画面が変わる」
>のどっちかな?
「一応変わるが、時々ゆっくりになる」ですね。
>1:毎秒何回ぐらい更新している?
300ms間隔でInvalidate()しています。
>2:時々発生の「時々」とはどのくらい?(頻度、継続性)
重いときはほぼ毎回です。
>3:現象発生時、PCそのものは快適?それとも、重い?
重いです。
>4:CPU負荷は普段から高いのか?それとも高いときだけ発生するのか?
高いときだけです。
>5:左から右とは?(□:変更前、■変更後)
>A:全体が左から右へ
>B:幅をもって左から右へ行き、それが上から下へ
よく見てから回答します。
>6:ゆっくりかわるってどのくらい?
どのくらいとは・・・?
>バックバッファへの書込部分や、表画面への転送時のソースもあるとわかるかもしれない
しばらくお待ちください。
>実際にどの位の使用率になっているのかも提示した方が良いと
>思いますよ。
ほぼ100%に近いです。
タスクマネージャ(タスクトレイ)では、ゲージが満杯です。
書き忘れました。
>>1:毎秒何回ぐらい更新している?
>300ms間隔でInvalidate()しています。
複数台のカメラの画像を1画面に表示させています。
カメラ1台ごとにスレッドを割り当てて、それらのスレッドでカメラから画像を取得して
います。
スレッドで画像を取得したら、画像を描画用のバッファにコピーしてInvalidate()します。
これらの処理の間隔が300msです。
描画処理では、OnDraw()で描画用のバッファにある画像を描画します。
>描画途中が見えないという話?
そうではなくて、ダブルバッファリングという手法を使ったのが初めて、という意味です
^^;
>>6:ゆっくりかわるってどのくらい?
>どのくらいとは・・・?
「左から右」へという「変化の開始から終了までの時間」。
で、
1:300msは、どのスレッド(メインか、カメラごとか)が測っている?
2:バッファにコピーしたり、Invalidateを呼んでいるのは個々のスレッドごと?
それとも、全部のカメラ分更新されたことを確認してから一回?
3:もしOnDraw内の1回の処理に時間がかかってしまった場合に、
その間スレッドのほうはどんどん進むようになっていますか?
それとも、バッファの更新は待機しますか?
それと、二つほど実験を
1:カメラを一個だけにしてもおきるのか?
他のカメラ(スレッド)を完全にとめて一個だけ動かしたり、
カメラは動かすが、バッファの更新とIvalidateをするのは一個のカメラ分だけにする
など条件を変えてみる
2:OnDrawの最初と最後に、TRACEでも入れて「OnDraw」が呼ばれる頻度を調べる。
ゆっくり」中に、OnDrawが何度も呼ばれているのか?
もしくは、OnDrawの一回がすごーく長いのか?などがわかると思います。
♯それはそれとして、一番最初にやらないといけないのは
♯PC全体が重くなるほどの重さだとは思いますが…
♯リークしまくって、重さとメモリ破壊おこしてるとかもありえそう
> そうではなくて、ダブルバッファリングという手法を使ったのが初めて、という意味です
> ^^;
可能性としてはダブルバッファリングの方法が不適切というのもあります。
スクリーンセーバーの「ラインアート」のように、計算でPCへの負荷が小さいプログラ
ムを作り、
ダブルバッファリングの手法に問題がないことを確認してみてはいかがでしょうか。
テスト用なので「ラインアート」よりもずっと単純で結構です。
普通に描画するとちらつき、ダブルバッファリングだとちらつかないことを確認できれば
成功です。
CPU使用率からして、いくらなんでも重すぎる気がする。
描画処理が後回しにされてもしょうがない。
ゆっくり描画されても仕方ない状況かな。
で、どうするか?
重すぎる物は仕方がないのでとれる手段は、
1) 頑張って(ソフトウェア的に)高速化する
2) パソコンのハード性能を上げる
3) 更新周期を300msよりのばす
プログラマなら1)にチャレンジしたいのが本音でしょうから(笑)お勧めは
DIBの最適化です。ご存じかどうか分かりませんが、実はDIBはものすごく
遅いのです。
http://lamoo.s53.xrea.com/develop/gdiplus/gdiplus_blt.html
で、高速化にチャレンジしてみた人のお話。
http://miyano.s53.xrea.com/cgi-bin/sb/log/eid77.html
やってみましたが、余裕で動きますね。
スレッドは使いませんでしたが、50[ms]毎にリソース
にある9枚のBMPを1枚にStretchBltしたものを、
表DCにBitBltしてみました。
Pentium4(2.66GHz)のしょぼいPCで、フルスクリーン
にしてもCPU稼働率20%程度ですね。
1.画像取得スレッドは十分早いか
2.裏DCはWM_SIZE時のみ作成しなおし、という方法になっているか
3.裏->表転送はBitBltとする。
などをチェックしてみたらどうでしょう。
既に皆さんから意見が出ていますけれど、
CPUの使用率が100%近いという状況がそもそも問題ですね。
そこまでいっていると言う事は他の処理は動かなくて当たり前です。
CPUの使用率が100%になっている原因を特定する必要が有るでしょう。
原因が特定されない限り対策も何も有りません。
これ、参考になりますか。
http://blogs.msdn.com/e7/archive/2009/04/25/engineering-windows-7-for-graphics-
performance.aspx
みなさん、たくさんの回答ありがとうございます<(_ _)>
やはり、負荷が高いのが有力のようですね。
負荷が高いのは、私のコーディングもあるとは思いますが、カメラの数ではないかと思っ
ています。
カメラの数を減らしたところ、発生しなくなりました。
カメラの画像は、某メーカーから提供されているDLLのコールバック関数で取得しています。
その関数はDLLからコールされるのですが、コールされる頻度はこちらでコントロールで
きないのです。
カメラ1台でも数百ms間隔でコールされています。
それがカメラ数分、並列でコールされるために負荷が上がっているのだと思っています。
対策については、他の人と相談したいと思います。
別件で申し訳ないのですが、この画像描画プログラムにはもう1つ問題があります。
画面をリサイズすると、画像も画面サイズに合わせて拡大縮小しているのですが、
そのときに古い画像が残ってしまうことがあるのです。
必ずではなくて、これまた時々です。
この問題はカメラの数が1台でも発生します。
■■■■■□
■■■■■□
■■■■■□
■■■■■□
(□の部分が古い画像)
カメラの画像を取得したら、新しい画像を再描画しているので、動画っぽくなっているの
ですが、
□の部分だけは再描画されず、静止画のようになっています。
描画は裏画面のメモリデバイスコンテキストからOnDraw()の引数のpDCに対してBitBlt()
しているのに、
このようなこと(一部分だけ描画されないこと)が起こるのはなぜなのでしょうか?