Results 1 to 3 of 3

Thread: Stuttering game? Important - You need to call dwmflush()

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1

    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-...inal-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/wi...wmapi-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;

  2. #2
    Ahh good to know, thanks for sharing. Will add this to my code base.

  3. #3
    https://devblogs.microsoft.com/direc...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 windowwith no other applications on the screen. "

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •