|
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
dlpb Advanced Cheater Reputation: 0
Joined: 11 Dec 2013 Posts: 78
|
Posted: Tue Sep 17, 2024 2:28 am Post subject: Stuttering game? Important - You need to call dwmflush() |
|
|
Hi, all
I lead a project to relocalize Final Fantasy VII and correct bugs in the game - see https://thereunion.live
and
https://www.eurogamer.net/why-would-someone-spend-five-years-retranslating-all-of-final-fantasy-7
As part of the on-going efforts to improve the game, I recently replaced the entire game loop with my own and created a proper frame limiter.
However, despite all my best efforts and tests, the game would still stutter in window mode. And I've noticed many other games and emulators do it too. It seems the reason behind it isn't as well known as it should be, so I'll be doing my best to update people.
The reason is DWM - Desktop Window Manager. It is forced in Windows 10 and 11. You cannot disable it without causing an even bigger problem.
If you are in window mode with vsync on, you need to be calling
https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmflush
immediately before SwapBuffers() - or the Directx equivalent.
This will force the sync to be in line with DWM. If you don't do this, you WILL get stuttering in window mode. In DirectX full screen Exclusive mode, DWM is disabled. With OpenGL, in my own tests, it seems to "disable" as long as you use a borderless window that exactly matches the desktop resolution, but I can't find any documentation online from Microsoft to confirm it.
Regardless, you will want to call dwmflush() whenever vsync is enabled (window mode or not). Do not call it when vsync is disabled, as it will cause vsync-like behaviour.
if using Opengl, it is sometimes beneficial to also call glFinish() after the SwapBuffer, but that depends.
The following is my code
main
Code: |
if (is_vsync && dwm_enabled)
DwmFlushFunc();
if (!SwapBuffers(hDC))
{
Log(1, "SwapBuffers failed.\n");
windows_error(0);
} |
Global var
Code: | bool_ dwm_enabled = false;
typedef HRESULT(WINAPI* pfnDwmFlush)();
pfnDwmFlush DwmFlushFunc = NULL; |
Code: | void CheckDwm() {
HMODULE hDwmapi = LoadLibrary("Dwmapi.dll");
bool_ dwm_bool = false;
dwm_enabled = false;
if (hDwmapi)
{
typedef HRESULT(WINAPI* pfnDwmIsCompositionEnabled)(BOOL*);
pfnDwmIsCompositionEnabled DwmIsCompositionEnabledFunc = (pfnDwmIsCompositionEnabled)GetProcAddress(hDwmapi, "DwmIsCompositionEnabled");
if (DwmIsCompositionEnabledFunc)
{
HRESULT hr = DwmIsCompositionEnabledFunc(&dwm_bool);
if (SUCCEEDED(hr) && dwm_bool)
{
DwmFlushFunc = (pfnDwmFlush)GetProcAddress(hDwmapi, "DwmFlush");
if (DwmFlushFunc)
{
Log(0, "Desktop Window Manager has been detected.\n");
dwm_enabled = true;
}
}
}
}
}
|
DELPHI CODE
Code: | var
dwm_enabled: boolean = False;
DwmFlushFunc: function: HRESULT; stdcall = nil; |
Code: | procedure CheckDwm;
var
hDwmapi: HMODULE;
hr: HRESULT;
DwmIsCompositionEnabledFunc: function(out pfEnabled: boolean): HRESULT; stdcall;
dwm_bool: boolean;
begin
hDwmapi := LoadLibrary('Dwmapi.dll');
dwm_enabled := False;
if hDwmapi <> 0 then
begin
@DwmIsCompositionEnabledFunc := GetProcAddress(hDwmapi, 'DwmIsCompositionEnabled');
if Assigned(DwmIsCompositionEnabledFunc) then
begin
hr := DwmIsCompositionEnabledFunc(dwm_bool);
if (Succeeded(hr) ) and (dwm_bool) then
begin
@DwmFlushFunc := GetProcAddress(hDwmapi, 'DwmFlush');
if Assigned(DwmFlushFunc) then
begin
// Replace this with your logging function or remove
Showmessage('Desktop Window Manager has been detected.'#13#10);
dwm_enabled := True;
end;
end;
end;
end;
end; |
|
|
Back to top |
|
|
atom0s Moderator Reputation: 202
Joined: 25 Jan 2006 Posts: 8546 Location: 127.0.0.1
|
|
Back to top |
|
|
dlpb Advanced Cheater Reputation: 0
Joined: 11 Dec 2013 Posts: 78
|
Posted: Wed Sep 18, 2024 4:59 pm Post subject: |
|
|
You'd be surprised how many people don't know about this - It took me ages to find some decent documentation. So I think it's worth posting it with full code so people can be aware. It's not enough to just post "dwmflush" like most are - that helps no one.
Esp the fact Opengl doesnt have an exclusive mode. And then other solutions like GLEW wrangler don't call dwmflush - so yeah I def think a post like this is a good idea.
Further to that, it does look like MS check fir a full screen borderless window when OPENGL is running, because it goes smooth without dwmflush. Is there a confirmation on this?
|
|
Back to top |
|
|
dlpb Advanced Cheater Reputation: 0
Joined: 11 Dec 2013 Posts: 78
|
Posted: Thu Sep 19, 2024 8:44 pm Post subject: |
|
|
https://devblogs.microsoft.com/directx/demystifying-full-screen-optimizations/
Here is an official statement that shows they turn it off when borderless window - so that would explain OpenGL not having issues in full screen.
"To get back this performance overhead, we enhanced the DWM to recognize when a game is running in a borderless full screen window with no other applications on the screen. "
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|