Skip to content

Commit bfcb06e

Browse files
committed
added code to Set/Get FPS Limit without the use of VSync
also changed following defaults VSync by default is now set to false. FPSLimit by default is set to 60 FPS. See SimpleExample to see how to get/set FPS.
1 parent 2743223 commit bfcb06e

3 files changed

Lines changed: 82 additions & 5 deletions

File tree

ClickableTransparentOverlay/Overlay.cs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public abstract class Overlay : IDisposable
5252
private Thread renderThread;
5353
private volatile CancellationTokenSource cancellationTokenSource;
5454
private volatile bool overlayIsReady;
55+
private int fpslimit;
5556

5657
private Dictionary<string, (IntPtr Handle, uint Width, uint Height)> loadedTexturesPtrs;
5758

@@ -150,7 +151,8 @@ public Overlay(string windowTitle, bool DPIAware, int windowWidth, int windowHei
150151
{
151152
this.initialWindowWidth = windowWidth;
152153
this.initialWindowHeight = windowHeight;
153-
this.VSync = true;
154+
this.VSync = false;
155+
this.FPSLimit = 60;
154156
this._disposedValue = false;
155157
this.overlayIsReady = false;
156158
this.title = windowTitle;
@@ -311,9 +313,38 @@ public unsafe bool ReplaceFont(FontHelper.FontLoadDelegate fontLoadDelegate)
311313

312314
/// <summary>
313315
/// Enable or disable the vsync on the overlay.
316+
/// You can either use the <see cref="FPSLimit"/> or <see cref="VSync"/>.
317+
/// VSync will be given the preference if both are set.
314318
/// </summary>
315319
public bool VSync;
316320

321+
/// <summary>
322+
/// Gets or sets the FPS Limits of the overlay.
323+
/// You can either use the <see cref="FPSLimit"/> or <see cref="VSync"/>.
324+
/// VSync will be given the preference if both are set.
325+
/// </summary>
326+
public int FPSLimit
327+
{
328+
get => this.fpslimit;
329+
set
330+
{
331+
if (value == 0)
332+
{
333+
this.fpslimit = value;
334+
_ = Winmm.MM_EndPeriod(1);
335+
}
336+
else if (value > 0)
337+
{
338+
this.fpslimit = value;
339+
_ = Winmm.MM_BeginPeriod(1);
340+
}
341+
else
342+
{
343+
// ignore negative values.
344+
}
345+
}
346+
}
347+
317348
/// <summary>
318349
/// Gets or sets the position of the overlay window.
319350
/// </summary>
@@ -444,6 +475,11 @@ protected virtual void Dispose(bool disposing)
444475

445476
if (disposing)
446477
{
478+
if (this.FPSLimit > 0)
479+
{
480+
Winmm.MM_EndPeriod(1);
481+
}
482+
447483
this.renderThread?.Join();
448484
foreach(var key in this.loadedTexturesPtrs.Keys.ToArray())
449485
{
@@ -491,22 +527,35 @@ protected virtual Task PostInitialized()
491527
private void RunInfiniteLoop(CancellationToken token)
492528
{
493529
var stopwatch = Stopwatch.StartNew();
494-
float deltaTime = 0f;
530+
var currentTimeSec = 0f;
495531
var clearColor = new Color4(0.0f);
532+
var delayMs = 0f;
533+
var sleepTimeMs = 0;
496534
while (!token.IsCancellationRequested)
497535
{
498-
deltaTime = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency;
536+
currentTimeSec = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency;
499537
stopwatch.Restart();
500538
this.window.PumpEvents();
501539
Utils.SetOverlayClickable(this.window.Handle, this.inputhandler.Update());
502-
this.renderer.Update(deltaTime, () => { Render(); });
540+
this.renderer.Update(currentTimeSec, () => { Render(); });
503541
this.deviceContext.OMSetRenderTargets(renderView);
504542
this.deviceContext.ClearRenderTargetView(renderView, clearColor);
505543
this.renderer.Render();
506544
if (VSync)
507545
{
508546
this.swapChain.Present(1, PresentFlags.None); // Present with vsync
509547
}
548+
else if (this.FPSLimit > 0)
549+
{
550+
this.swapChain.Present(0, PresentFlags.None);
551+
delayMs = 1000f / this.FPSLimit;
552+
currentTimeSec = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency;
553+
sleepTimeMs = (int)(delayMs - (currentTimeSec * 1000));
554+
if (sleepTimeMs > 0)
555+
{
556+
Thread.Sleep(sleepTimeMs);
557+
}
558+
}
510559
else
511560
{
512561
this.swapChain.Present(0, PresentFlags.None); // Present without vsync
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace ClickableTransparentOverlay.Win32
2+
{
3+
using System;
4+
using System.Runtime.InteropServices;
5+
6+
internal static class Winmm
7+
{
8+
public const string LibraryName = "winmm.dll";
9+
10+
[DllImport(LibraryName, EntryPoint = "timeBeginPeriod")]
11+
public static extern uint MM_BeginPeriod(uint uMilliseconds);
12+
13+
[DllImport(LibraryName, EntryPoint = "timeEndPeriod")]
14+
public static extern uint MM_EndPeriod(uint uMilliseconds);
15+
}
16+
}

Examples/SimpleExample/SampleOverlay.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,32 @@
77
internal class SampleOverlay : Overlay
88
{
99
private bool wantKeepDemoWindow = true;
10+
private int FPSHelper;
1011

1112
public SampleOverlay() : base(3840, 2160)
1213
{
14+
this.FPSHelper = this.FPSLimit;
1315
}
1416

1517
protected override Task PostInitialized()
1618
{
17-
this.VSync = false;
1819
return Task.CompletedTask;
1920
}
2021

2122
protected override void Render()
2223
{
2324
ImGui.ShowDemoWindow(ref wantKeepDemoWindow);
25+
26+
if (ImGui.Begin("FPS Changer"))
27+
{
28+
if (ImGui.InputInt("Set FPS", ref FPSHelper))
29+
{
30+
this.FPSLimit = this.FPSHelper;
31+
}
32+
33+
ImGui.End();
34+
}
35+
2436
if (!this.wantKeepDemoWindow)
2537
{
2638
this.Close();

0 commit comments

Comments
 (0)