描画速度の違いについて

返信する


答えを正確に入力してください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: 描画速度の違いについて

レスありがとうございます。

by jacoby » 2006年8月17日(木) 02:18

マティさん、BitBltの性能について、詳しく説明していただいて
ありがとうございました。
性能改善方法としては、Promptで行っているように画面とビットマップ(再描画用)の両方に描画する方法では、線描画に関しては(斜線の場合に)軌跡が一致しない問題もあり、使用しない方が良い時もあります。
(画面とビットマップでXORを行うと良くわかります。)
速い、速いと単に喜んでいたのですが、そうなんですか、うーん、となると
これはやっぱりちょっと考えた方がいいかも知れませんね。
(ただこれは一体どういう状況で、そうなるもんなのですか? 同じ2点を
繋ぐなら、必ず同じドットで描かれるようにも単純に思ったりするるのですが。。
ちょっと奥の深そうな問題ですね。)
また、ビットマップを使う場合に変更のあった部分のみを転送することで性能を改善する方法もありますので、色々試してみてください。
(変更のあった左上と右下の範囲をInvalidateRectで指定するとか)
BeginPaintでセットされるPAINTSTRUCT構造体をPaintイベント内で
取得出来ればいいのだろうと思うのですが。。。

 これから色々試してみて、改めて報告したいと思います。
レクありがとうごさいます。またよろしくお願いします。

by マティ » 2006年8月14日(月) 21:27

BitBLTの性能についてですが
'
'●ペイント・イベント
'
Sub MainWnd_Paint(hDC As HDC)
BitBlt(hDC,0,0,clientRc.right,clientRc.bottom,hMemDC,0,0,SRCCOPY)
End Sub

※clientRc.right=クライアントエリアの幅
clientRc.bottom=クライアントエリアの高さ
で全画面を描画するように指定していますが、実際に画面に転送されるデータはGDIにり画面に表示可能な範囲に分割後、ディスプレイドライバーで転送を行います。
(表示可能な領域の形状によっては、分割の必要が無い場合もあります。)
したがって表示可能なサイズと、分割される個数によって性能に変化がでる事になります。

性能改善方法としては、Promptで行っているように画面とビットマップ(再描画用)の両方に描画する方法では、線描画に関しては(斜線の場合に)軌跡が一致しない問題もあり、使用しない方が良い時もあります。
(画面とビットマップでXORを行うと良くわかります。)

また、画面描画の方がビットマップに描画するよりも格段に早い場合は、描画コマンドを全て記憶し、再描画(クリッピングを指定して)を行うときに全描画コマンドを実行します。
(メモリーの少なかった時代は、この方法が主流でした。)

また、ビットマップを使う場合に変更のあった部分のみを転送することで性能を改善する方法もありますので、色々試してみてください。
(変更のあった左上と右下の範囲をInvalidateRectで指定するとか)

その後の報告です。

by jacoby » 2006年8月14日(月) 04:30

前の返信で僕は

ただそれにしてもpromptウインドウでは何故あれだけ高速に
表示されるのかがやはり疑問なんです。
promptウインドウだって、結局のとこ内部で「BitBlt」してビットマップを
表示してるのでは?と思ったりして。

と書きましたが、それはどうやら違っていたみたいです。

 速度の差がどうしても気になって、あれから「prompt.sbp」を開いて
「Macro LINE」の所を見てみたんですが、
「InvalidateRect」等のPaintイベントをコールする命令が無い。!
どうやって表示しているのかと不思議で仕方なかったのですが、
代わりに、

コード: 全て選択


'line
  MoveToEx(_PromptSys_hMemDC,sx,sy,ByVal NULL)
  LineTo(_PromptSys_hMemDC,ex,ey)
  SetPixel(_PromptSys_hMemDC,ex,ey,GetBasicColor(ColorCode))
  MoveToEx(hDC,sx,sy,ByVal NULL)
  LineTo(hDC,ex,ey)
  SetPixel(hDC,ex,ey,GetBasicColor(ColorCode))
こんな風に、「2回」セットで命令が繰り返し書かれていました。
つまりhDC(ウインドウのDC、直前にGetDCで取得)と、
そのウインドウのメモリビットマップのDCであるhMemDCに
それぞれ描画命令を行っている。
これによりわざわざPaintイベントでビットマップ転送命令を使うことなく
見た目の表示も、裏画面のメモリビットマップにも描画出来、高速に
処理を終えられる。
 なるほどなーと、

 早速、それに倣って自分のプログラムの
「DrawLine()」を次の様に書き直してみました。

コード: 全て選択


'
' ●ライン描画 (MoveToEx & LineTo)
'
Sub DrawLine(ByVal hWnd As HWND, ByVal hMemDC As HDC)

 Dim hDC As HDC
 Dim hPen As HPEN
 Dim hOldPen As HPEN
 
  hDC=GetDC(hWnd)

  hPen= CreatePen(PS_SOLID,0,penColor)
  SelectObject(hDC,hPen)
  hOldPen=SelectObject(hMemDC,hPen)

    MoveToEx(hMemDC,rc.left,rc.top,ByVal NULL)
    LineTo(hMemDC,rc.right,rc.bottom)
    SetPixel(hMemDC,rc.right,rc.bottom,penColor)
    MoveToEx(hDC,rc.left,rc.top,ByVal NULL)
    LineTo(hDC,rc.right,rc.bottom)
    SetPixel(hDC,rc.right,rc.bottom,penColor)

  ReleaseDC(hWnd,hDC)
  SelectObject(hMemDC,hOldPen)
  DeleteObject(hPen)

End Sub
 実行結果は、

 渦巻きの描画終了までのタイムを計ってみると、

まず、直し前のMainWnd上の描画では約「2分30秒」
(プロンプト画面を前面にしたときの描画では約「41秒」、これでも差は
歴然としています。)

 直しをした後の実行結果は、MainWndを前面にした状態で
「4秒」。

 (もっとも一回の描画で「Line」が描画される回数が増えてきたりする場合など
元々の"メモリビットマップに描いて、それから一気にビットマップ転送"の
利点も出てくるのではないかとも思います。)

 それでも、知っている方には高速化の基本の技術なのかもしれないと
思うのですが、自分は正直驚きました。
 とりあえず、これで直しをしていきたいと思います。

 それからkonisiさん、改めてレクありがとうございました。
またよろしくお願いします。

 その後の報告と、感想でした。

------------------------------------------------

 ただ、「BitBlt命令」は、その後も色々やってみたんですが
MainWndが晒されている面積の大きさによって遅くなったり、速くなったり、
まちまちで、どうにも掴めません。
 よくよく考えてみれば、このプログラム内のペイント・イベントでは

コード: 全て選択


'
'●ペイント・イベント
'
Sub MainWnd_Paint(hDC As HDC)
 BitBlt(hDC,0,0,clientRc.right,clientRc.bottom,hMemDC,0,0,SRCCOPY)
End Sub

※clientRc.right=クライアントエリアの幅
  clientRc.bottom=クライアントエリアの高さ
として、常にクライアントエリア全体を更新しているので
ウインドウの晒されている面積が大きくなろうが小さくなろうが、
まったく隠れてしまおうが、全部見えていようが
ビットマップ転送の速度は変わらない筈じゃないかとも
思うのですが、、どうなのでしょうか?
 今現状ではかなり遅いです。

レスありがとうございます。

by jacoby » 2006年8月12日(土) 02:52

 konisiさん、レスありがとうございます。

括弧でくくってAsで宣言
「x=(r+xo) As Long」
と書くんですね。
キャストの方法、教えていただいてありがとうございました。
prompt.sbpの中身も順次変えていきたいと思います。

 それから、
れはBitBlt(描画処理)があまりにも時間がかかるので体感できるほどの差になった。
BitBltをコメントアウトすると差はあるけど早すぎて体感できないくらいの速度。
ということだと思います。
恐らく、言われる通りだと思います。
メインウインドウが他のウインドウの重なりから離れて、
画面に多く晒されるほど、スピードは遅くなっていくようですから。

 ただそれにしてもpromptウインドウでは何故あれだけ高速に
表示されるのかがやはり疑問なんです。
promptウインドウだって、結局のとこ内部で「BitBlt」してビットマップを
表示してるのでは?と思ったりして。
 このままだと速度が気になるプログラムでは「MainWnd」を使いづらく、
promptウインドウを使わざるを得ないのかなと、悩んでいます。

警告について

by konisi » 2006年8月11日(金) 21:03

まず、90行目

コード: 全て選択

  x=r+xo
については、これはx,r,xoの型の定義が

コード: 全て選択

  Dim xo As Long, yo As Long '渦巻き中心座標
  Dim x As Long, y As Long   '描画地点(中心からの相対座標)
  Dim r As Double  '渦巻き円の半径初期値
となっている事から、r+xoの演算の答えはDouble型で、しかも代入先がLong型なので警告が出ています。
つまり「少数を含む可能性のある数値が少数を扱えない変数に代入されてますよ。」という意味で、「データが失われる可能性があります。」という警告が表示されています。
この類の警告を出さないようにする方法は大抵次の2通りで、変数rを宣言するときの型をLong型等の整数型にするか、あるいは

コード: 全て選択

    x=(r+xo) As Long
とキャストするという方法です。
103行目、104行目で明らかにDouble型が返る計算をしているので、キャストしましょう。

コード: 全て選択

  x=(r*Cos(o)+xo) As Long
  y=(r*Sin(o)+yo) As Long
他にはprompt.sbpから警告が出ていると思いますが、Long型で宣言されているhDC,hPen,hOldPen,hBrush,hOldBrush変数についてそれぞれ

コード: 全て選択

	Dim hDC As HDC
	Dim hPen As HPEN, hOldPen As VoidPtr
	Dim hBrush As HBRUSH, hOldBrush As VoidPtr
と書き直せば警告は出なくなると思います。
ちなみに、説明文中に「大抵」と書いたのは他に方法があることもあるんです。でも普通使えないので省きました。

Re: 描画速度の違いについて

by ノッチ » 2006年8月11日(金) 10:23

>  プロンプトウィンドウとメインウインドウにそれぞれ
> 同様にラインでテストパターン(渦巻き)を描いていくプログラムを
> 作ったのですが、実行時にプロンプトウインドウが
> メインウインドウより前面にあるときと、その逆に
> メインがプロンプトより前面にあるときで
> 描画速度にかなりの差が見られます。
> (プログラムソースは一番下に)

確か、Windowsはフォアグランドウィンドウに対してCPUパワーを多く割り当てる、
という記憶が。
ですのでWindowsの仕様だと思います。(レジストリで変更できたような)

処理に時間のかかるアプリを2つ同時に起動して片方をフォアグランドにしておくと
そちらが先に終了するはずです。


>  プロンプトが前面にあるときは描画スピードは
> 速く、メインを前に持ってきたときはその半分以下くらいに
> 描画スピードがガクっと遅くなります。
>  色々チェックをしてみたところ、メインウインドウのペイント・イベント
> の「BitBlt命令」がその速度の違いの元になっているように思えました。
> (ここをRem文にすると速度に変化は無くなりました)

これはBitBlt(描画処理)があまりにも時間がかかるので体感できるほどの差になった。
BitBltをコメントアウトすると差はあるけど早すぎて体感できないくらいの速度。
ということだと思います。

間違ってるかもしれませんが。

描画速度の違いについて

by jacoby » 2006年8月11日(金) 03:49

 ABの用意したプロンプトウインドウと、
 自分の作成したメインウインドウの描画スピード
の違いについて教えてください。

 プロンプトウィンドウとメインウインドウにそれぞれ
同様にラインでテストパターン(渦巻き)を描いていくプログラムを
作ったのですが、実行時にプロンプトウインドウが
メインウインドウより前面にあるときと、その逆に
メインがプロンプトより前面にあるときで
描画速度にかなりの差が見られます。
(プログラムソースは一番下に)

 プロンプトが前面にあるときは描画スピードは
速く、メインを前に持ってきたときはその半分以下くらいに
描画スピードがガクっと遅くなります。
 色々チェックをしてみたところ、メインウインドウのペイント・イベント
の「BitBlt命令」がその速度の違いの元になっているように思えました。
(ここをRem文にすると速度に変化は無くなりました)

コード: 全て選択


'
'●ペイント・イベント
'
Sub MainWnd_Paint(hDC As HDC)
 BitBlt(hDC,0,0,clientRc.right,clientRc.bottom,hMemDC,0,0,SRCCOPY)
End Sub
が、それにしてもあそこまで速度に差が出てくるのは
どうしてなのか理由が分かりません。
 もしか自分のプログラムにどこか不正なところが
あるのではないかと思っているのですが。
 原因をお知りの方がおられましたら、是非教えてください。

AB version 4.24
(OS)Windows Me

※下のプログラムを実行するとデバッグ実行時に
警告がズラズラと出てきます。
 一つのグループはx,y座標などの値をDoubleで計算し
画面表示のためLong型の変数に無理やり代入した時に
検出されるもの。
 もう一つのグループはどうも「prompt.sys」の内部で
起こっている現象のようで(ハンドル類をLongで定義している
といった種類のもの)、いずれも自分では
これらの警告を取ることは出来ませんでした。
 ただし、そのままでも実行そのものには影響は無いように
思います。

 プロジェクト名「UzumakiTest424」で製作。

ページトップ