C#でWIN32API step9 FPSを測定する
step8:ここまでのまとめ(その1)
今回から何回かに亘って描画処理をしてみることにします。.NET Frameworkには描画処理のためにSystem.Drawing
名前空間が用意されていますが、この連載記事では敢えてWIN32APIを使用します。
最初にFPSを測定するようにしておきましょう。
メッセージループの処理を少し変更するだけです。
GetMessage
関数を直接使わず、PeekMessage
関数でキュー上のメッセージの有無を調べて、メッセージが存在する場合にだけGetMessage
関数を呼び出します。メッセージが存在しない場合は、カウンタと表示の処理を行った後InvalidateRect
関数により再描画を実施し、最後に暫くの間眠ります。まだ文字描画について解説していないので、FPS値はコンソール画面に表示するようにしました。
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int counter = 0;
WIN32.Window.MSG msg = new WIN32.Window.MSG();
while (true)
{
if (WIN32.Window.PeekMessage(out msg, IntPtr.Zero, 0, 0, WIN32.Window.PM.PM_NOREMOVE))
{
if (!WIN32.Window.GetMessage(out msg, IntPtr.Zero, 0, 0))
break;
WIN32.Window.TranslateMessage(ref msg);
WIN32.Window.DispatchMessage(ref msg);
}
else
{
counter++;
if (stopwatch.ElapsedMilliseconds > 1000)
{
Console.WriteLine(counter.ToString());
stopwatch.Reset();
stopwatch.Start();
counter = 0;
}
WIN32.Window.InvalidateRect(hWnd, IntPtr.Zero, false);
WIN32.Window.UpdateWindow(hWnd);
Thread.Sleep(1);
}
}
Stopwatch
クラスやThread.Sleep
メソッドを使用せず、敢えて対応するWIN32APIであるQueryPerformanceFrequency
関数/QueryPerformanceCounter
関数とSleep
関数を使用する場合は以下のようになります。
int counter = 0;
long frequency = 0, time1 = 0, time2 = 0;
WIN32.Common.QueryPerformanceFrequency(out frequency);
WIN32.Common.QueryPerformanceCounter(out time1);
WIN32.Window.MSG msg = new WIN32.Window.MSG();
while (true)
{
if (WIN32.Window.PeekMessage(out msg, IntPtr.Zero, 0, 0, WIN32.Window.PM.PM_NOREMOVE))
{
if (!WIN32.Window.GetMessage(out msg, IntPtr.Zero, 0, 0))
break;
WIN32.Window.TranslateMessage(ref msg);
WIN32.Window.DispatchMessage(ref msg);
}
else
{
counter++;
WIN32.Common.QueryPerformanceCounter(out time2);
if ((time2 - time1) / frequency >= 1)
{
Console.WriteLine(counter.ToString());
WIN32.Common.QueryPerformanceCounter(out time1);
counter = 0;
}
WIN32.Window.InvalidateRect(hWnd, IntPtr.Zero, false);
WIN32.Window.UpdateWindow(hWnd);
WIN32.Common.Sleep(1);
}
}
こちらが、P/I用のコードです(前回からの追加部分)。
using System;
using System.Runtime.InteropServices;
namespace Anttn.WIN32
{
public static class Common
{
(省略)
[DllImport("kernel32.dll")]
public static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("kernel32.dll")]
public static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("kernel32.dll")]
public static extern void Sleep(uint dwMilliseconds);
(省略)
}
}
using System;
using System.Runtime.InteropServices;
namespace Anttn.WIN32
{
public static partial class Window
{
(省略)
[DllImport("user32.dll")]
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PM wRemoveMsg);
[DllImport("user32.dll")]
public static extern bool InvalidateRect(IntPtr hWnd, IntPtr rect, bool bErase);
(省略)
[Flags]
public enum PM : uint
{
PM_NOREMOVE = 0x0000,
PM_REMOVE = 0x0001,
PM_NOYIELD = 0x0002,
PM_QS_INPUT = QS.QS_INPUT << 16,
PM_QS_POSTMESSAGE = (QS.QS_POSTMESSAGE | QS.QS_HOTKEY | QS.QS_TIMER) << 16,
PM_QS_PAINT = QS.QS_PAINT << 16,
PM_QS_SENDMESSAGE = QS.QS_SENDMESSAGE << 16
}
(省略)
}
}
当方の環境では900FPS程度になりました。

スポンサーリンク