-
Notifications
You must be signed in to change notification settings - Fork 395
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Precise, time period-independent timing for Windows game loop.
- Loading branch information
Showing
8 changed files
with
180 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
using System; | ||
using System.Runtime.InteropServices; | ||
using System.Threading; | ||
using TerraFX.Interop.Windows; | ||
|
||
namespace Robust.Shared.Timing; | ||
|
||
/// <summary> | ||
/// Helper for more precise sleeping functionality than <see cref="Thread.Sleep(int)"/>. | ||
/// </summary> | ||
internal abstract class PrecisionSleep : IDisposable | ||
{ | ||
/// <summary> | ||
/// Sleep for the specified amount of time. | ||
/// </summary> | ||
public abstract void Sleep(TimeSpan time); | ||
|
||
/// <summary> | ||
/// Create the most optimal optimization for the current platform. | ||
/// </summary> | ||
public static PrecisionSleep Create() | ||
{ | ||
// Check Windows 10 1803 | ||
if (OperatingSystem.IsWindows() && Environment.OSVersion.Version.Build >= 17134) | ||
return new PrecisionSleepWindowsHighResolution(); | ||
|
||
return new PrecisionSleepUniversal(); | ||
} | ||
|
||
public virtual void Dispose() | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Universal cross-platform implementation of <see cref="PrecisionSleep"/>. Not very precise! | ||
/// </summary> | ||
internal sealed class PrecisionSleepUniversal : PrecisionSleep | ||
{ | ||
public override void Sleep(TimeSpan time) | ||
{ | ||
Thread.Sleep(time); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// High-precision implementation of <see cref="PrecisionSleep"/> that is available since Windows 10 1803. | ||
/// </summary> | ||
internal sealed unsafe class PrecisionSleepWindowsHighResolution : PrecisionSleep | ||
{ | ||
private HANDLE _timerHandle; | ||
|
||
public PrecisionSleepWindowsHighResolution() | ||
{ | ||
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is only supported since Windows 10 1803 | ||
_timerHandle = Windows.CreateWaitableTimerExW( | ||
null, | ||
null, | ||
CREATE.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, | ||
Windows.TIMER_ALL_ACCESS); | ||
|
||
if (_timerHandle == HANDLE.NULL) | ||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); | ||
} | ||
|
||
public override void Sleep(TimeSpan time) | ||
{ | ||
LARGE_INTEGER due; | ||
Windows.GetSystemTimeAsFileTime((FILETIME*)(&due)); | ||
|
||
due.QuadPart += time.Ticks; | ||
|
||
var success = Windows.SetWaitableTimer( | ||
_timerHandle, | ||
&due, | ||
0, | ||
null, | ||
null, | ||
BOOL.FALSE | ||
); | ||
|
||
if (!success) | ||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); | ||
|
||
var waitResult = Windows.WaitForSingleObject(_timerHandle, Windows.INFINITE); | ||
if (waitResult == WAIT.WAIT_FAILED) | ||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); | ||
|
||
GC.KeepAlive(this); | ||
} | ||
|
||
private void DisposeCore() | ||
{ | ||
Windows.CloseHandle(_timerHandle); | ||
|
||
_timerHandle = default; | ||
} | ||
|
||
public override void Dispose() | ||
{ | ||
DisposeCore(); | ||
|
||
GC.SuppressFinalize(this); | ||
} | ||
|
||
~PrecisionSleepWindowsHighResolution() | ||
{ | ||
DisposeCore(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters