Skip to content

[Bug]: MacOS Windowed mode not respecting VSync option #1486

Description

@zhulov3rz

Is there an existing issue for this?

  • I have searched the existing issues

Contact Details

Just reply to the issue

Version Info

Latest available release

What operating system are you seeing the problem on?

macOS

Bug Behavior

Vsync is not being turned off when in windowed mode specifically on MacOS. Toggling vsync in settings doesn't actually change the underlying behavior, resulting in worse than ideal performance.

Frame presentation remains synchronized to the monitor refresh rate, and capturing process samples with Activity Monitor shows most frame time blocked in CGLFlushDrawable().

Expected Behavior

VSync should only be on when the setting is enabled.

Reproduction Steps

  1. Run the game in Windowed mode on MacOS
  2. Ensure framerate cap is higher than monitor refresh rate
  3. Toggle VSync on and off through any way you prefer
  4. Notice in all cases that the FPS never exceeds the monitor refresh rate both in the menu and in game

Anything else?

So I actually went to compile a build with the fix since frame pacing with vsync on has been causing lag spikes.

The issue can be resolved by modifying LowLevelWindow_MacOSX.mm.

I'm not very familiar with rendering code so I got AI to write the patch, but after compiling with these changes it at least solves the problem and restores uncapped FPS with VSync off. It has not been tested for any backward compatibility or regressions. I'll leave it here just to give people who actually know what they're doing (unlike me) an idea where to look at.

diff --git a/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm b/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm
index da558de569..ea434f4c93 100644
--- a/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm
+++ b/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm
@@ -182,6 +182,20 @@ static NSOpenGLContext *CreateOGLContext( GLContextType type, int iColorSize, in
 	return context;
 }

+static void SetSwapInterval( NSOpenGLContext *context, bool vsync )
+{
+	CGLContextObj cglContext = [context CGLContextObj];
+	GLint interval = vsync ? 1 : 0;
+	const CGLError setError = CGLSetParameter( cglContext, kCGLCPSwapInterval, &interval );
+
+	if( setError != kCGLNoError )
+	{
+		Locator::getLogger()->warn(
+		  "CGLSetParameter(kCGLCPSwapInterval) failed: {} ({})",
+		  static_cast<int>(setError), CGLErrorString(setError));
+	}
+}
+

  class RenderTarget_MacOSX : public RenderTarget
  {
@@ -390,8 +404,12 @@ std::string LowLevelWindow_MacOSX::TryVideoMode( const VideoModeParams& p, bool&
 		});
 		[m_Context makeCurrentContext];
 		m_CurrentParams.windowed = true;
+		if( bChangeVsync )
+		{
+			SetSwapInterval( m_Context, p.vsync );
+			m_CurrentParams.vsync = p.vsync;
+		}
 		SetActualParamsFromMode( CGDisplayCurrentMode(kCGDirectMainDisplay) );
-		m_CurrentParams.vsync = p.vsync; // hack

 		return std::string();
 	}
@@ -432,8 +450,7 @@ std::string LowLevelWindow_MacOSX::TryVideoMode( const VideoModeParams& p, bool&

 	if( bChangeVsync )
 	{
-		GLint swap = p.vsync ? 1 : 0;
-		[m_Context setValues:&swap forParameter:NSOpenGLCPSwapInterval];
+		SetSwapInterval( m_Context, p.vsync );
 		m_CurrentParams.vsync = p.vsync;
 	}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions