トップページ > 記事閲覧
ScreenFlipの処理時間につきまして
名前:dotdot 日時: 2026/09/29 21:04

C#(.NET10)です。自作アプリのFPSが安定しない原因を調査しています(突然カクっと画面がカタつく ことがちょいちょいある)。いろいろ削っていき、とりあえずシンプルなコードで測定してみました。 画面クリア ⇒ 一行表示 ⇒ ScreenFlip というだけのループで試してみました。 using DxLibDLL; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; class Program { [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")] public static extern int timeBeginPeriod(int uPeriod); [DllImport("winmm.dll", EntryPoint = "timeEndPeriod")] public static extern int timeEndPeriod(int uPeriod); private static readonly string MutexName = "MyDxLib_App_2026"; private static Mutex _mutex; static void Main() { _mutex = new Mutex(true, MutexName, out bool createdNew); if (!createdNew) { _mutex.Dispose(); return; } Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // .NET10用 timeBeginPeriod(1); // 1ms精度 DX.ChangeWindowMode(DX.TRUE); DX.SetGraphMode(1920, 1080, 32); DX.SetAlwaysRunFlag(DX.TRUE); // 常時稼働 DX.SetEnableXAudioFlag(DX.TRUE); DX.SetWindowSizeExtendRate(1.0); DX.SetMultiThreadFlag(DX.TRUE); DX.SetZBufferBitDepth(24); DX.SetCreateDrawValidGraphZBufferBitDepth(24); DX.SetFullSceneAntiAliasingMode(4, 2); DX.SetDrawValidMultiSample(4, 2); DX.SetCreateSoundIgnoreLoopAreaInfo(DX.TRUE); DX.SetBackgroundColor(16, 16, 52); DX.SetFontCacheCharNum(3072); DX.SetWaitVSyncFlag(DX.FALSE); // VSync待たない if (DX.DxLib_Init() == -1) return; DX.SetDrawMode(DX.DX_DRAWMODE_BILINEAR); DX.SetDrawScreen(DX.DX_SCREEN_BACK); long t0 = Stopwatch.GetTimestamp() / 10, lMax = 0; int nNGCount = 0; while (DX.ProcessMessage() == 0) { DX.ClearDrawScreen(); if (DX.CheckHitKey(DX.KEY_INPUT_ESCAPE) == 1) break; DX.DrawString(20, 20, $"Quit To ESC: 5msec以上{nNGCount}回発生: 最大値{lMax}: FPS{DX.GetFPS()}", DX.GetColor(255, 255, 255)); long t1 = Stopwatch.GetTimestamp() / 10; if (DX.ScreenFlip() != 0) break; long t2 = Stopwatch.GetTimestamp() / 10; if (t2 - t1 > lMax) lMax = t2 - t1; if (t2 - t1 >= 3000) nNGCount++; // 3msec以上でカウント if (t2 - t0 >= 60 * 1000 * 1000) break; // 60秒で抜ける // ここの行 } long t3 = Stopwatch.GetTimestamp() / 10; // ここでSTOPして数値を確認 DX.DxLib_End(); _mutex.ReleaseMutex(); _mutex.Dispose(); timeEndPeriod(1); } } ScreenFlip自体の処理時間を測定してみました。上記の「// ここの行」のところを変えて、 60秒間で「ScreenFlipが3msec以上かかった回数と、かかった時間の最大値」を数回 測定して平均してみたところ  ウェイト 発生回数 最大時間 FPS  -----------------------------------------------------  行なし(ノーウェイト) 0回 1msec  9000〜  Thread.Sleep(1) 25回 5msec  500弱  Thread.Sleep(16) 140回 7msec  60弱  Thread.Sleep(33) 50回 5msec  30弱 のようになりました。 ここまで書いて別のことを試しました。GeForce4070SUPERなのですが、 NVIDIAコントロールパネルで電源管理モードを 標準 ⇒ パフォーマンス優先 に変更すると Sleep(1)も(16)も発生回数0回、最大時間1msec程度になりました。 ・ループ中にSleepがあるとScreenFlipの処理時間が変わる ・GPUの電源設定でこれまた変わる ということでしょうか?
メンテ

Page: 1 |

Re: ScreenFlipの処理時間につきまして ( No.1 )
名前:管理人 日時:2026/10/01 00:36

> ・ループ中にSleepがあるとScreenFlipの処理時間が変わる > ・GPUの電源設定でこれまた変わる >  > ということでしょうか? NVIDIAコントロールパネルの設定で変化したとなりますと 恐らく計測の通り( Sleepがあると何故かScreenFlipの時間が変わる、GPUの電源設定でも変わる )なのだと思います ( 因みにDXライブラリのプログラム的にはそちらの2つの要素で処理時間が変わるような処理にはなっていません ) ただ、こちらの挙動に関しては恐らくデバイス依存だと思いますので、 NVIDIAではないAMD系やIntel系のGPUでも同様の結果になるかは不明です 尚、私の環境( GeForce RTX 5080 )では結果は以下の通りで、回数はかなり少なかったです  ウェイト 発生回数  ---------------------------------  行なし(ノーウェイト) 0回  Thread.Sleep(1) 1回  Thread.Sleep(16) 7回  Thread.Sleep(33) 1回 また、一番回数の多いThread.Sleep(16)で2回、3回と繰り返し試した所、3回目は1回、 4回目、5回目は0となりました メモリキャッシュや他の要因が絡んでいるのかもしれませんが、原因については不明です ただ、時間経過と共に発生回数は減っていくのではないかと思います
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存