-
Limit FPS with injected clr app
First of all: Yes nowdays you can use CVar maxfpsbk to limit the framerate in WoW however Im not really interested in capping the FPS for a purpose but rather want to find out the best technique to do it.
Right now I got an injected clr executable running in WoW.
Obviously one EndScene call means one frame. So FPS depends on how often EndScene can get executed in a second.
If we want to cap at 60 FPS:
1000/60 = 16,66666666666667 => Time between each rendered frame should be around 16666666ns
Logic is easy:
If the time passing by between the last rendered frame and the current frame takes less than 16 ms we sleep til we reach 16 ms.
Now I redirected EndScene to a c# function which will do the logic:
Code:
private static int LastFrameTick = 0;
private static int TimeBetweenFrame = 0;
private static int WaitTilNextFrame = 0;
private static int EndSceneHook(IntPtr parDevice)
{
int ret = (int)_endSceneHook.CallOriginal(parDevice);
if (LastFrameTick != 0)
{
TimeBetweenFrame = (Environment.TickCount - LastFrameTick);
if (TimeBetweenFrame < 15)
{
WaitTilNextFrame = Environment.TickCount + (15 - TimeBetweenFrame);
while (Environment.TickCount < WaitTilNextFrame) ;
}
}
LastFrameTick = Environment.TickCount;
return ret;
}
Well I am pretty happy with the result but I am wondering if there are ways to be more accurate. Since .net cant work with ns (atleast I read it cant) we cant really work with 16,66666666666667 so we have to decide between 16ms (62.5 fps) and 17ms (58.8 fps) not accounting that the detour itself also affects the outcome.
Can someone recommend a better way to be more accurate?
Last edited by Corthezz; 11-03-2015 at 03:28 PM.
Check my blog: https://zzuks.blogspot.com
-
Post Thanks / Like - 1 Thanks
HI5 (1 members gave Thanks to Corthezz for this useful post)
-
Contributor
Correct me if I'm wrong, but i was under the impression that dx9 endscene isnt *always* called once per frame, but in some cases multiple times per rendered frame.
-
Originally Posted by
danwins
Correct me if I'm wrong, but i was under the impression that dx9 endscene isnt *always* called once per frame, but in some cases multiple times per rendered frame.
Atleast in 1.12.1 WoW EndScene is called once each mainthread loop. Im not to experienced with DirectX
.
Check my blog: https://zzuks.blogspot.com
-
Contributor
I didn't mean wow but rather, in general. its just something I've stumbled upon in other games.
it generally causes issues with things like ESP drawing,
-
Sorry for derailing.. it's just a related topic and people posting here know more than I do about it.
Can anyone explain to me as some one newer to this stuff what the obsession is with hooking EndScene and running their code in each frame?
Outside of visual tools that render things to the screen like radar's and esp, is it really needed or even ideal? I really prefer to run as much code as I possible can on my end, just so my code is the least dependent on other factors I don't control as possible.
For code I desire to be called frequently at specified interval, I use this class mostly:
https://github.com/lolp1/MemorySharp...ols/Updater.cs
Then, to actually run any code that interacting with game functions that I want thread-safety from, I use the code Jadd posted and just invoke it when ever.
ntoskrnl | Hooking Threads without Detours or Patches
If you're curious about the blog like I was, here is an example easier to look at than a single-page blog:
https://github.com/lolp1/MemorySharp/tree/master/Hooks
Is there anything wrong with this, or am I totally missing something that explains why there is one million topics and discussions about hooking endscene at the ultimate end-all?
Last edited by lolp1; 11-03-2015 at 06:52 PM.
-
Active Member
Originally Posted by
lolp1
Sorry for derailing.. it's just a related topic and people posting here know more than I do about it.
Can anyone explain to me as some one newer to this stuff what the obsession is with hooking EndScene and running their code in each frame?
Outside of visual tools that render things to the screen like radar's and esp, is it really needed or even ideal? I really prefer to run as much code as I possible can on my end, just so my code is the least dependent on other factors I don't control as possible.
For code I desire to be called frequently at specified interval, I use this class mostly:
https://github.com/lolp1/MemorySharp...ols/Updater.cs
Then, to actually run any code that interacting with game functions that I want thread-safety from, I use the code Jadd posted and just invoke it when ever.
ntoskrnl | Hooking Threads without Detours or Patches
If you're curious about the blog like I was, here is an example easier to look at than a single-page blog:
https://github.com/lolp1/MemorySharp/tree/master/Hooks
Is there anything wrong with this, or am I totally missing something that explains why there is one million topics and discussions about hooking endscene at the ultimate end-all?
Imagine following situation:
You're hooking a function (not EndScene) because it gets called way more often, right? Now what happens if a function, which generates the underlying object geometry for e.g. TraceLine calls exactly this function during the generation? You would have an incomplete, or in worst case a corrupt, state. An incomplete list is not always a matter, but could result in inconsistent behaviour like detecting objects upon the first call, even though they're not "there" during the first call because this object has not been processed yet.
To sum it up: EndScene guarantees a finite state, because it gets called as soon as every single background-task to process the changed data (because of movement, time, server-packets, events etc...) between each frame.has been finished.
A programmer should generally prefer consistency over speed: Calling some code a little bit faster may be great, but speed should not be the point which decides whether your program works or not. A consistent state on the other hand is very important: You will always have to debug errors and thus spend a lot of time to find out reasons your code is crashing or behaving in a strange manner. Now imagine you're spending 12 hours in a row just to find out that the function you're hooking corrupts the state of the data you're accessing.
EndScene will "never" leave data in a corrupt state and you will avoid a lot of possible problems.
-
(....)To sum it up: EndScene guarantees a finite state, because it gets called as soon as every single background-task to process the changed data (because of movement, time, server-packets, events etc...) between each frame.has been finished.
This I understand. What I don't understand is why hooking EndScene is a solution for this. If you're not rendering stuff like a radar, the EndScene hook seems like massive overkill to provide safety. I'm fairly sure the example Jadd posted in his blog that I linked above provides 100% thread safety just as EndScene does.
For example, in my project I apply the WndProc hook, which runs on the same thread as EndScene. Then, when I want to execute code or access any data/function I assume to be not thread-safe, I have my 'tick' event fire a PostMessage with WM_USER+1 as the message and then intercept that message in the hook call back and it's handled there. This seems to let me execute code inside the main thread on any tick event I desire, and still be safe.
A programmer should generally prefer consistency over speed.
I think so too, especially when using something like C#. I'm not really sure how speed is hurt by using methods other than hooking EndScene to run misc code.
-
Originally Posted by
danwins
Correct me if I'm wrong, but i was under the impression that dx9 endscene isnt *always* called once per frame, but in some cases multiple times per rendered frame.
EndScene finalizes the scene and occurs once per frame, so yes, EndScene is a viable place to count frames.
Originally Posted by
danwins
I didn't mean wow but rather, in general. its just something I've stumbled upon in other games.
it generally causes issues with things like ESP drawing,
The issue is most likely that a different device or swap-chain is calling EndScene, in which case you should compare the device and/or swap-chain to a list you're maintaining. That way you can get your framerate for all outputs.
Originally Posted by
Frosttall
Imagine following situation:
You're hooking a function (not EndScene) because it gets called way more often, right? Now what happens if a function, which generates the underlying object geometry for e.g. TraceLine calls exactly this function during the generation? You would have an incomplete, or in worst case a corrupt, state. An incomplete list is not always a matter, but could result in inconsistent behaviour like detecting objects upon the first call, even though they're not "there" during the first call because this object has not been processed yet.
What in the name of **** are you talking about? Use a timer? Use a WndProc callback for a custom window message?
Originally Posted by
Frosttall
To sum it up: EndScene guarantees a finite state, because it gets called as soon as every single background-task to process the changed data (because of movement, time, server-packets, events etc...) between each frame.has been finished.
EndScene isn't all that reliable. What happens when you minimize your game? You have no choice but to wait for the game to be shown again. And what happens when we're running on one computer at 500fps and on another at 5fps? It's inconsistent, not to mention slower.
Edit: Sorry OP, totally ignored your question. P/Invoke QueryPerformanceCounter if you want to do timing in microseconds. I believe System.Diagnostics.Stopwatch also uses QPC for timing so it's also quite precise if you would prefer to use that.
Last edited by Jadd; 11-04-2015 at 03:37 AM.
-
Post Thanks / Like - 1 Thanks
HI5 (1 members gave Thanks to Jadd for this useful post)
-
Adding up to Jadds post this guy is pretty interesting.
Edit: Actually pretty funny. In the start post published snippet provides a cap at 64 FPS while the example below caps at 160 FPS while it technically should do the same:
Code:
private static double LastFrameTick = 0;
private static double TimeBetweenFrame = 0;
private static double WaitTilNextFrame = 0;
private static double CapAt = 16.66;
private static int EndSceneHook(IntPtr parDevice)
{
int ret = (int)_endSceneHook.CallOriginal(parDevice);
if (LastFrameTick != 0)
{
TimeBetweenFrame = (QueryPerformanceCounter() - LastFrameTick);
if (TimeBetweenFrame < CapAt)
{
WaitTilNextFrame = QueryPerformanceCounter() + (CapAt - TimeBetweenFrame);
while (QueryPerformanceCounter() <= WaitTilNextFrame) ;
}
}
LastFrameTick = QueryPerformanceCounter();
return ret;
}
private static double QueryPerformanceCounter()
{
long tmp;
WinImports.QueryPerformanceCounter(out tmp);
return tmp / (double)1000;
}
Last edited by Corthezz; 11-04-2015 at 05:51 AM.
Check my blog: https://zzuks.blogspot.com
-
Elite User
Originally Posted by
Jadd
EndScene finalizes the scene and occurs once per frame, so yes, EndScene is a viable place to count frames.
Actually it's perfectly valid to have multiple BeginScene/EndScene calls per frame. Its almost always better to use Present instead of EndScene.
For example my injected UI framework hooks Present and calls a new BeginScene/EndScene pair.
This would obviously mess with anyone elses hooks on EndScene because he'd see multiple calls as soon as mine is loaded.
-
Out of curiosity Corthezz, what exactly is the need of having such precise timing for fps in a game?
-
Originally Posted by
lolp1
Out of curiosity Corthezz, what exactly is the need of having such precise timing for fps in a game?
In vanilla WoW click2move is affected by the framerate. If you have a framerate which is above 80 it will just initial a never ending walk in the direction your character is facing.
When I was using my bot privately this wasnt a problem since my monitor is 60hz anyway and I can easily cap the FPS using vSync but now since its public it should also support 120 hz monitors 
The timing is not that important. I am just curious if it possible to create an external framecapper that can limit FPS to the exact value specified.
Oh and btw: I am really curious if it is possible to fix CTM for FPS higher than 80 but havnt found the time to really look into it ... probably another "fun" exercise with no real benefit.
Check my blog: https://zzuks.blogspot.com
-
Active Member
Might be my 11pm rambling but calling EndScene then looping seems like it steals processing time from the next frame.
Also use Present.
-
Elite User
Originally Posted by
Corthezz
Adding up to Jadds post
this guy is pretty interesting.
Edit: Actually pretty funny. In the start post published snippet provides a cap at 64 FPS while the example below caps at 160 FPS while it technically should do the same:
Code:
private static double LastFrameTick = 0;
private static double TimeBetweenFrame = 0;
private static double WaitTilNextFrame = 0;
private static double CapAt = 16.66;
private static int EndSceneHook(IntPtr parDevice)
{
int ret = (int)_endSceneHook.CallOriginal(parDevice);
if (LastFrameTick != 0)
{
TimeBetweenFrame = (QueryPerformanceCounter() - LastFrameTick);
if (TimeBetweenFrame < CapAt)
{
WaitTilNextFrame = QueryPerformanceCounter() + (CapAt - TimeBetweenFrame);
while (QueryPerformanceCounter() <= WaitTilNextFrame) ;
}
}
LastFrameTick = QueryPerformanceCounter();
return ret;
}
private static double QueryPerformanceCounter()
{
long tmp;
WinImports.QueryPerformanceCounter(out tmp);
return tmp / (double)1000;
}
You are not taking the frequency of the timer into account in this snippet. QPC has way higher precision than milliseconds on modern PCs.
If you want to control the FPS more precisely you can accumulate the errors and correct for the error in future ticks. This will allow you to achieve a perfect average FPS in the long run.
[16:15:41] Cypher: caus the CPU is a dick
[16:16:07] kynox: CPU is mad
[16:16:15] Cypher: CPU is all like
[16:16:16] Cypher: whatever, i do what i want