GetTickCountによるwaitとFPS

前回のプログラムでは、CPUの許す限り動くので
処理の速さが一定ではありませんでした。そこで今回は
なるべく一定時間で処理を行うようにします。

・GetTickCountによるwait処理

GetTickCount関数は、windowsCEが起動してからの
経過した時間をミリ秒単位で返してくれます。
これにより、一定時間立つまでは
処理を留めることができるようになる、というわけです。

では以下に処理の一例を書いていきます。
(前回のラインアート風プログラムを使っています)

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void Point_Move(HWND) ;

//ループ用wait変数
DWORD dWait;

グローバル変数として、時間を格納する変数dWait を宣言します。

     dWait=GetTickCount();

     //ループ処理
     while (TRUE)
          {
          //キューにメッセージがあればいつもの処理
          if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
               ・・・

WinMain内で、メッセージループに入る前に GetTickCount 関数で時間を取得します。

//座標の移動
void Point_Move(HWND hwnd)
{
     //20ms経過してなければ戻る
     if(dWait+20>GetTickCount())
          return ;
     dWait=GetTickCount();
               ・・・

自作関数内に入ったときの時間をGetTickCount()で取得し、
前回取得していたdWaitがその値より20m秒大きければ
(まだ時間が20m秒経過していなければ)、メインループに戻ります。
逆に、超えていればdWaitにGetTickCount()を格納し処理を続行します。

では以上を踏まえたソースを実行してみましょう。

ウェイトを置く

これにより、比較的一定な間隔で処理を制御できるようになりました。
とはいえ、もちろん1回のループが20msよりも遅ければ成り立ちませんが。
(CE以外のwindowsではtimeGetTimeという、GetTickCountより正確に
時間を測れるものがあるのですが、CEには見当たらないようでした)

DWORD GetTickCount( void );
・WindowsCEが起動してからの時間を1/1000秒単位で返します。

戻り値 WindowsCEが起動してから経過したミリ秒の数が返ります。

ソースの表示

・FPSを測定する

今度は、この関数を利用してFrame Per Second(FPS)、
いわゆるフレームレート(1秒間に画面に描画する回数)っぽいものを測ってみましょう。
といっても、本当は描画処理と計算処理は分けるべきなので
正確にはFPSとは言い難いですが、まぁ計算にかかる時間なんてものは
描画処理に比べると微々たる物なので、ここではよしとします。しましょう。

上のソースに追加していきます。

//ループ用wait変数
DWORD dWait;
//FPS用変数
DWORD dFPS;
//FPSを格納・右は一秒ごとに変動
int iFPS1,iFPS2;

3つのグローバル変数を使います。
dFPSは、起動してからの時間を取得します。
iFPS1はプログラムが一周するごとに数をカウントします。
iFPS2はその数値を表示するため、一時保存します。(fpsとして描画するのはこの値)

     dWait=GetTickCount();
     dFPS=GetTickCount();

     //ループ処理
     while (TRUE)
          {

メッセージループに入る前に、dFPSに起動してからの時間を格納します。

void Point_Move(HWND hwnd)
{
     //20ms経過してなければ戻る
     if(dWait+20>GetTickCount())
          return ;
     dWait=GetTickCount();

     //FPS+1
     iFPS1++;
     //1000m秒経過していれば
     if(dFPS+999<GetTickCount())
     {
          iFPS2=iFPS1; iFPS1=0;
          dFPS=GetTickCount();
     }

この関数が呼ばれる度に、iFPS1(ループの回数)をインクリメントします。
dFPSが前回取得した時間から1000ms過ぎていれば
iFPS2にiFPS1の値を格納して0に戻り、dFPSは再び時間を取得します。

以上の処理を含めたものを実行してみます。

FPS:19

左上に表示されているFPS値は、iFPS2の値です。
FPS値についてですが、キャプチャが起動していない状態では20/s、
Waitを外すと22~23 となりましたが、どちらにしろかなり遅いですね^^;
アニメーションだと1秒間に24回、コンシューマーゲームだと
1秒間に30~60回画面を書き換えるらしいのですが
museaで全画面を描画し直すそうとすると、1秒間にせいぜい20回程度・・・

まぁ、そのあたりはいわゆるプログラマとしての腕の見せ所というやつでしょうね。
例えば、馬鹿正直に全画面を描画しなおす必要はないわけですし。
そういったいろんなところを改良すれば、それなりには速くすることが出来るでしょう。

FPS:180

ちなみに300MHzの現役windowsマシン(つД`)では、同じ処理(wait抜き)で804fpsも出ました。
もっとも、こちらでも640x480あたりにすれば遅くなるでしょうが。

ソースの表示

2005/6/5


戻る