-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improving Windows OpenGL VSync in windowed mode #5797
Comments
If it helps, here's a workaround using DwmFlush conservatively that I implemented for my own code. It's only had a lot of testing on my own system though, so maybe there are corner cases it doesn't handle. https://github.com/love2d/love/blob/5175b0d1b599ea4c7b929f6b4282dd379fa116b8/src/modules/window/sdl/Window.cpp#L1018 |
Ah yeah I did come by the LOVE2D issue while I was googling around for this. Figured we ought to implement this upstream if possible though. For what it's worth here is the GLFW logic. Some things to note:
|
Did some more testing. I did state that It's probably not possible for SDL to transparently make use of this though. Apps could theoretically use |
Could it be because you are forced to use this awful roundabout?
That seems a recipe for disaster (or if not any confusion)
Guy in ppy/osu#8165 (comment) reported it was working indeed. Nvidia mentions some "minor memory and performance overhead" in their latest drivers that are basically enabling this for every program (well, at least optimus laptops.. note: don't use any newer than 526.47 if you want to keep results comparable to your previous ones), but if "functionally" results were strictly better you'd really need some hefty hit to justify the native solution IMHO. |
dGPU is wired to HDMI port, iGPU is to internal monitor. Realistically though I don't think there's a good fix here other than "stop using WGL for present on Windows". Either IHVs don't care to make it usable or Microsoft makes it impossible to correctly integrate with the display stack. Even Vulkan isn't comparable to DXGI on this kind of present stuff. |
Indeed, after reading the hell out of this, I'm starting to sway in that direction too. I have been wondering for years and years and years why would It's unbelievable how shittily documented this fact is (hell, even just figuring out that that when you are windowed-composited you shouldn't buffer requires digging the Mines of Moria), but I guess that the quick guidance was always "just call So.. uh, yeah? Long story short I think we should play nice with the Windows compositor by having buffers like it properly expects. It also made me realize that there exist two totally opposite aims that any one application could want to achieve. |
as discussed in #10160 |
We are scoping work for the SDL 3.2.0 release, so please let us know if this is a showstopper for you. |
If this is something that could even be implemented and ship next year, okay, it's not so damning. |
microsoft is kind of neglecting opengl/wgl stuff more and more as time goes on and they really really want you to be using DXGI for windowing, apparently its even worse in windows 11 than it was in windows 10, having the openGL context be on top of a DXGI context seems like the most compatible way to do opengl things going into the future, and the type of platform specific code I would really like to not have to do myself. Its not a showstopper but it might be in the future... (it is important though) |
Microsoft can't neglect "more" something that they did never care for to begin with (and I'm not sure I can blame them too much if it took like 10 years from when DWM became mandatory, for somebody to figure this out in the open in the first place). And of course-ish if the compositor speaks language X it's not exactly like it is its fault for hiccups to happen when applications want to talk in Y. Maybe this is more on GPU vendors, to never have put much of a thought until very recently (probably forced by HDR reasons). |
I'm trying to move my app from GLFW to SDL2 and one of the first things I noticed is that OpenGL vsync stutters a lot on SDL2.
The problem here appears to be that
SwapBuffers(HDC)
synchronizes to the monitor instead of to DWM (Windows' desktop compositor). While the frame timings are an extremely solid 16.666~ms, It does not line up with when DWM needs the frame to be able to composit it to the screen.GLFW calls
DwmFlush()
before runningSwapBuffers(HDC)
if they detect DWM is running, and this seems to work pretty solidly: frame timing graph isn't as smooth as before, but there is no stutter. Also requires some juggling withwglSwapInterval()
since we have to report 0 when we detect DWM isn't running... Ugh. It's also not clear to me how this API is supposed to work with multi-monitor scenarios (DWM is supposed1 to be able to run multiple monitors with different refresh rate smoothly)To elaborate on frame times with
DwmFlush()
: they don't seem significantly worse thanIDXGISwapchain::Present()
, which also does not stutter. If I load my system (by just recompiling my project) the frame times do get less smooth (that is, my program is woken up at less consistent intervals), but the frames are still presented at a solid 60 Hz. Because of the inconsistent frame times this would still mess up any game loop relying on delta time though, unless my game's game loop just sucks. I wonder if there is a more accurate way to get timing info to avoid this? Also of course if your game is CPU intensive, "losing 2ms this frame and getting 2ms extra next frame" could probably be a dealbreaker to cause dropped frames.Some potentially relevant info I found online:
Reliable windowed vsync with OpenGL on Windows? - StackOverflow: contains a lot of testing. In the comments they mention they found
DwmFlush()
to be the most reliable (when called afterSwapBuffers()
, in contrast to what GLFW does). They also mention an API calledD3DKMTWaitForVerticalBlankEvent
and an issue on the Chromium bug tracker investigating this stuff:Issue 467617: How to dramatically improve Chrome's requestAnimationFrame VSYNC accuracy in Windows: the aforementioned Chromium issue. It mentions the
DwmFlush()
timing inconsistency up above. A lot of the discussion revolves aroundD3DKMTWaitForVerticalBlankEvent
, which is intended to be a driver API to do vsync. The suspicious thing is that, from what I can gather, this API sits below DWM and therefore would not be useful for syncing to DWM itself again, so you have the exact same problem. I'm really not sure what to make of this issue. What I especially do not get is why they don't just vsync withIDXGISwapchain::Present()
? (reminder, browsers use ANGLE so they use D3D underneath). They mention having to turn off ANGLE vsync because DWM already does vsync. This makes no sense to me since, as far as I can tell,IDXGISwapchain::Present()
works fine with vsync even if DWM is running. Now this probably isn't too relevant to SDL2 since, well, OpenGL not D3D, but it still confuses the hell out of me.For what it's worth, the relevant testing from me here was done on an Optimus system with an nvidia GPU and Intel iGPU.
Footnotes
DWM smoothly working with different refresh rates per monitor doesn't really seem to work for me. My setup is an Optimus laptop with the primary monitor being 75 Hz attached to the dGPU over HDMI, while the internal display is at 60 Hz. I cannot get Windows to vsync programs on the laptop monitor at 60 Hz and the primary monitor at 75 Hz at all (even using DXGI to present etc)... I just put the primary monitor at 60 Hz because those extra 15 Hz aren't worth my secondary monitor stuttering like mad. ↩
The text was updated successfully, but these errors were encountered: