Skip to content

Commit

Permalink
More accurate frame limiting by using spinlocks.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeFisto94 committed Apr 14, 2024
1 parent 7acd838 commit 715e1a7
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 16 deletions.
35 changes: 19 additions & 16 deletions D3D9/D3D9FrameLimiter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using Andraste.Shared.Lifecycle;
using SharpDX.Direct3D9;

Expand All @@ -23,35 +25,35 @@ public class D3D9FrameLimiter : IManager
public float TargetFPS { get; set; } = 60f;

private float MsPerFrame => 1000f / TargetFPS;

/// <summary>
/// The timestamp since the last Present()/PresentEx()/EndScene() call
/// The time since the last Present()/PresentEx()/EndScene() call
/// </summary>
DateTime _lastFrame;

public D3D9FrameLimiter(D3D9HookManager d3d9)
{
_d3d9 = d3d9;
}
private readonly Stopwatch _stopwatch;

[DllImport("winmm.dll")]
private static extern uint timeBeginPeriod(uint uPeriod);
[DllImport("winmm.dll")]
private static extern uint timeEndPeriod(uint uPeriod);

public D3D9FrameLimiter(D3D9HookManager d3d9)
{
_stopwatch = new Stopwatch();
_d3d9 = d3d9;
}

// ReSharper disable once InconsistentNaming
public D3D9FrameLimiter(D3D9HookManager d3d9, float targetFPS)
public D3D9FrameLimiter(D3D9HookManager d3d9, float targetFPS) : this(d3d9)
{
_d3d9 = d3d9;
TargetFPS = targetFPS;
}

public void Load()
{
// TODO: Query min timer resolution which may not be 1
timeBeginPeriod(1);
_lastFrame = DateTime.Now;
// TODO: Support different callbacks: Present, PresentEx and EndScene
_stopwatch.Start();
// TODO: Support different callbacks: Present, PresentEx and EndScene [actually EndScene is probably not right]
_d3d9.Present += D3d9OnPresent;
Loaded = true;
}
Expand All @@ -70,12 +72,13 @@ private void D3d9OnPresent(Device deviceptr, ref Rectangle? sourcerect, ref Rect
return;
}

var ms = (DateTime.Now - _lastFrame).TotalMilliseconds;
if (ms < MsPerFrame)
var sw = new SpinWait();
while (_stopwatch.Elapsed.TotalMilliseconds < MsPerFrame)
{
System.Threading.Thread.Sleep((int)(MsPerFrame - ms));
sw.SpinOnce();
}
_lastFrame = DateTime.Now;

_stopwatch.Restart();
}
}
}
1 change: 1 addition & 0 deletions D3D9/D3D9HookManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Andraste.Payload.D3D9
/// Hook various DirectX 9 Functions and provide safe event handlers
/// as well as a way to manually hook other functions.
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class D3D9HookManager : IManager
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
Expand Down

0 comments on commit 715e1a7

Please sign in to comment.