Making Your Game Go Fast by Asking Windows Nicely
anthropicstudios.com
anthropicstudios.com
Ugh. Few years ago I've built a gaming rig with i5-8400 and GTX1080 (both chosen for known workloads). Some games ran fine, but some were jerky af, and frametime monitor was zigzag-y all over the place. I thought that maybe 8400 was not a best choice despite my research and bought i7-8700 only to see that situation got much worse. After days of googling and discussions I found the issue: mobo bios had C1E state enabled. In short, it allows to drop the CPU frequency and voltage significantly when it's idling, but this technique isn't ready to operate 100+ times per second. After drawing a frame, CPU basically did nothing for a period of time (<10ms), which was enough to drop to C1E, but it can't get out of it quickly for some reason. And of course 8700 was much better at sucking at it, since it had more free time to fall asleep.
I understand that power saving is useful in general, but man, when Direct3D sees every other frame skipped, maybe it's time to turn the damn thing off for a while. Idk how a regular consumer could deal with it. You basically spend a little fortune on a rig, which then stutters worse than an average IGP because of some stupid misconfiguration.
As overclockers are aware, to achieve higher frequencies but keep CPU stable, one gonna need higher CPU voltage. Works other way too, lowing frequency allows to lower voltage, and that’s what mostly delivers the power saving from these low-power states.
These chips can’t adjust voltage instantly because wires inside them are rather thin, and there’s non-trivial capacity everywhere. This means CPUs can drop frequency instantly, then decrease the voltage over time. However, if they raise frequency instantly without first raising the voltage, the chip will glitch.
That’s AFAIK the main reason why increasing the clock frequency takes time. The chips first raise the voltage which takes time because capacity, and only then they can raise the frequency which is instant.
I use QuickCPU and max everything out. Yes it sounds like a sham but works wonders.
One thing that we noticed was that wakeups after wglSwapBuffers were just more jittery than wakeups after D3D9/D3D11 Present() with the same software on the same system. In windowed mode, this could be mitigated by blocking on DwmFlush() instead of wglSwapBuffers (it seems like GLFW does this too, but only in Vista and 7.)
The developer might also get some mileage from using ANGLE (a GLES 3.1 implementation on top of D3D11) or Microsoft's new GLon12.
[1]: https://mpv.io/
Doesn't help when your testers run Google Chrome all the time...
There are many technologies that work first or better until a certain time on Windows. For example (not necessarily HPC related) SMR drive support.
I actually was just looking this up, quite randomly. I think it is actually a soft no, in the sense that support is essentially non-existent now, but it is being worked on.
It appears to be an annoying situation where HDCP (high definition content protect, I think) content has some sort of encryption baked in that requires proprietary driver/hardware support. Since the main use case for HDR is watching movies, and we can't do that without the proprietary stuff, there's not a ton of incremental value for the community to get by working on it. But Intel, Nvidia, AMD, and Red Hat are all working on it.
https://www.phoronix.com/scan.php?page=news_item&px=Red-Hat-...
Also this recent version of libreelec
https://libreelec.tv/2021/11/03/libreelec-matrix-10-0-1/
advertises that they can process (decode?) 4k, 10 bit video, on a raspberry pi 4, but they apparently only 8 bit output is actually available. Not sure if this is a hardware or software limitation.
Anyway, the pieces are maybe coming together, just very slowly.
> This function is part of User32.lib, and is defined in winuser.h which is included in Windows.h.
This is one reason I think Windows is such a mess of an OS. (Look at the contents of C:\Windows and tell me it's not, if you can do so with a straight face!)
To make what ought to be a system call you have to load some DLL, sys, or lib file at a random (but fixed) path and call a function on it.
That combined with COM, and the registry, and I don't want to touch it with a ten-foot pole.
> combined with COM, and the registry
And yet GNOME has dconf and CORBA, because in order to do certain things you converge on the same solutions.
(Now, if you want a mess, the attempts to retrofit secure containers onto this with UWP definitely count!)
“Ought to be a system call” is a matter of opinion. Among OSes, Linux is an outlier in that it keeps its system call interface stable.
Many other OSes choose to provide a library with a stable interface through which system calls can (and, in some cases must. See https://lwn.net/Articles/806776/; discussed in https://news.ycombinator.com/item?id=21859612) be called. That allows them to change the system call ABI, for example to retire calls that have been superseded by other ones.
(ideally, IMO, that library should not be the C library. There should be two libraries, a “Kernel interface library” and a “C library”. That’s a different subject, though)
On x86 processors, you can achieve this at the kernel level by adding `idle=poll` to the kernel command line.
I've never played OP's game, so evidently a few games are out there doing this.
Why isn't there a function I can call that enforces full CPU power, but only while my application is running? I never wanted to change global system-level settings, but if that's the only affordance provided by the Win32 API, then so be it.
It's entirely reasonable for performance-critical applications (not just games!) to be able to request maximum available performance from the hardware without resorting to stupid tricks like the measures described in this story, launching threads that do nothing but run endless loops, and so forth.
I do agree with those who point out that this should be a user-controlled option. On the application side, this could be as simple as a checkbox labeled "Enable maximum performance while running" or something similar. Ideally, the OS would then switch back to the system-level performance setting when the application terminates, rather than leaving it up to the application to do the right thing and restore it explicitly.
This is the kind of thing I hate about "New Windows". Once upon a time MS used to strive for backward compatibility. These days every few years there's a new function you need to call. You can't get optimal behavior just by writing good code from the start. You need to do that, and also call the YesIKnowHowPixelsWork api call, and set <yesIAmCompetent>true</yesIAmCompetent> in your manifest to get what should be the default behavior. It's a mess.
For reference SetProcessDPIAware solidified over 15 years ago whereas 15 years prior to that there wasn't even a taskbar so of course it's going to be out of date from a UI API perspective but that's what's needed if you want to also support apps from 15 years ago well.
Func -> FuncEx -> FuncExN was a common pattern. (Which I like more than Func -> Funcness -> FuncnessContext, despite the lack of creativity!) Another one was tagging structures with their own length as the first member variable, so if a later SDK creates a newer version of the struct, the callee can tell the difference. eg https://docs.microsoft.com/en-us/windows/win32/seccrypto/cry...
ASSERT(SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2));
If ASSERT is a no-op in release mode then you're only getting your setting set here while in debug modeI had to do that couple times for Direct3D 11 or 12 apps with frontend written in WPF. Microsoft doesn't support exporting DWORD variables from .NET executables.
Technical info there: https://stackoverflow.com/a/40915100
(https://docs.nvidia.com/gameworks/content/technologies/deskt...)
> For any application without an existing application profile, there is a set of libraries which, when statically linked to a given application executable, will direct the Optimus driver to render the application using High Performance Graphics. As of Release 302, the current list of libraries are vcamp110.dll, vcamp110d.dll, nvapi.dll, nvapi64.dll, opencl.dll, nvcuda.dll, and cudart..
However, I don't really like that method. The app will fail to launch on computers without nVidia drivers, complaining about the missing DLL. For languages like C++ or Rust, the exported DWORD variable is the best way to go. The only reason I bothered with custom installer actions, that method wasn't available.
If you aren't scaling up text and UI elements based on the DPI then it doesn't really sound like your application is truly DPI aware to me. I don't see why that applies any differently to games versus any other kind of application.
If you want to see why, try mocking up a typical shooter HUD. Now try scaling up/down all the elements by 50% and see what happens. Feel free to play with the anchoring, etc. Chances are you're not gonna like what you see! Things get even more complicated when you consider that players with controllers often change their view distance when gaming and don't wanna reconfigure their display all the time.
The typical solution is to fix the UI scale to the window size, and keep the text large enough that it's readable at a large range of DPIs and viewing distances. If you can't get 100% there that way you'll typically add an in-game UI scale option. (The key difference between that and the built in UI scaling in Windows being that it's specific to the game, so you'll set it to something milder than you'd set the Windows option, and it will only affect the game so you don't have to keep changing it back and forth.)
[EDIT] I think I came up with a way to explain this that saves you the trouble of drawing it out yourself. The fundamental issue, view distance changes aside, is that games are balancing a third variable most apps don't have to: how much of the background--the actual game--is the UI occluding?
It is non-ideal for something like a traditional UI element where users may want to alter scaling settings to have more screen space if their monitor is close enough to their eyes, but for a game HUD that usually isn’t the desired effect anyway.
I think Microsoft made it this hard to enable the DPI-aware setting exactly because it forces developers to think about things like DPI. If everyone follows this guide and ignores it, then I predict that in a few years this setting will be ignored as well and a new DPI-awareness API will be released.
1. Please add options to conserve battery too. A FPS limiter would be good. Messing with the system power management when the user doesn't want to be tethered to a wall plug is Not Nice(tm).
2. When you do UI scaling, especially if you're young with 20/20 eyesight, please allow scaling beyond what you think is big enough.
For #2--my glasses prescription is so strong that I spent $330 on fancy lenses today in the hopes that they'll distort less around the edges. Wish me luck. (:
Using Vsync is actually conservative power wise. You can always smash the gpu by rendering frames as fast as possible. This a one way of reducing input latency in FPS shooters, using vsync guarantees one frame of latency on a fast GPU.
2. Agreed 100%. All too frequently the UI is too small on high dpi monitors (see CIV6), or unreadable when viewed from a distance when playing on a TV (see Witcher 3)
It depends on the game. What does Civ need 60 fps for? Not sure if they have a limiter because I'm not playing 6 due to some of their design decisions that tick me off.
On the other hand, I do keep my Minecraft limited to 30 fps.
I was surprised to find vertical blanking interval mentioned in the article as CRTs haven't been a common sight for years. Is it still a relevant concept when writing code for modern GPUs?
In any case, you want to know when the frame has been scanned out so you can swap the buffer to the next frame.