120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
RonanZero
Citizen
Posts: 90
Joined: Mon Oct 20, 2014 3:33 am

120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by RonanZero »

I've successfully connected a 120/144hz (it supports both, but I usually use 120) monitor to my mac and set it to 120hz in system preferences. It generally works perfect on most programs (no jitter), but in my Love2D game when using window.vsync it tries to sync to 60 for some reason instead of 120, and the timer for that is also very inaccurate resulting in very laggy/jittery/stuttering motion. That means it's not true vsync, just a crappy timer, which seems almost like it could be a deliberate, hardcoded 60hz framerate limiter (part of SDL maybe?)

It works fine when I use the same monitor (120hz + LOVE) on a windows PC. And it also gives smooth, non-jittery, tear-free 60hz movement in LOVE when I set the monitor to 60hz mode on mac. However even though LOVE tries to sync to 60hz, it does correctly report 120hz in the window flags which is odd. Could this be an SDL/OpenGL bug on macOS, considering the somewhat uncommon situation of mac+120hz+LOVE+vsync? I doubt this is a bug in mac, that would be pretty ridiculous.

EDIT: Okay, I did more testing... here's what's actually happening: with vsync *off* @120hz it tries to sync to 65 FPS (which explains the jittering), with vsync *on* @120hz it tries to sync to 62 FPS! (which produces slightly less jittering than vsync *off* (65 FPS), but still jittery)
while true do end;
User avatar
slime
Solid Snayke
Posts: 3133
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: 120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by slime »

RonanZero wrote: Wed Dec 27, 2017 7:55 pmThat means it's not true vsync, just a crappy timer, which seems almost like it could be a deliberate, hardcoded 60hz framerate limiter (part of SDL maybe?)
SDL just sets the NSOpenGLContext swap interval (number of monitor refreshes per frame) to 1 when you use vsync, it doesn't have any hard-coded limiter.
RonanZero wrote: Wed Dec 27, 2017 7:55 pmCould this be an SDL/OpenGL bug on macOS, considering the somewhat uncommon situation of mac+120hz+LOVE+vsync? I doubt this is a bug in mac, that would be pretty ridiculous.
Have you tested other non-love games in macOS? Are you running your love game in fullscreen mode?
RonanZero wrote: Wed Dec 27, 2017 7:55 pmI did more testing... here's what's actually happening: with vsync *off* @120hz it tries to sync to 65 FPS (which explains the jittering), with vsync *on* @120hz it tries to sync to 62 FPS! (which produces slightly less jittering than vsync *off* (65 FPS), but still jittery)
Do you get a lot more than 65 fps when vsync is off on a 60hz monitor of a similar resolution? If not, you probably need to optimize your game to get the framerate you expect.

The way vsync works is it forces the game framerate to be the lowest possible multiple of the monitor's refresh rate. Ideally that multiple will be 1, which means 120 hz == 120 frames. If the game can't produce 120 frames per second, vsync will drop it down to the next multiple (2), which means the game will produce a frame every 2 monitor refreshes - i.e. ~60 FPS for a 120 hz monitor.
User avatar
RonanZero
Citizen
Posts: 90
Joined: Mon Oct 20, 2014 3:33 am

Re: 120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by RonanZero »

slime wrote:Have you tested other non-love games in macOS?
Yes. See bottom of post.
slime wrote:Are you running your love game in fullscreen mode?
No, but that probably wouldn't make a difference since mac uses borderless full screen (I think? Usually?)
slime wrote:Do you get a lot more than 65 fps when vsync is off on a 60hz monitor of a similar resolution? If not, you probably need to optimize your game to get the framerate you expect.
Even with 60hz monitor mode, LOVE with vsync set to off still vsyncs (perfectly) to 60hz. My game isn't very demanding, I should be able to get a ton of FPS. It doesn't slow down much more if at all when I add a ton (50+) of more enemies on screen for example.

Here are some stats from more extensive testing:

Half-Life macOS (OpenGL)
....60hz mode
........Vsync OFF
............Uncapped; very high framerate.
........Vsync ON
............Caps itself at 60fps, no jitter. true vsync
....120hz mode
........Vsync OFF
............Uncapped; very high framerate.
........Vsync ON
............Caps itself at 120fps, no jitter. true vsync(?): fluctuates between 119-121, but probably just a cl_showfps error
LOVE macOS (OpenGL)
....60hz mode
........Vsync OFF
............Caps itself at 60fps, no jitter. true vsync(?)
........Vsync ON
............Caps itself at 60fps, no jitter. true vsync
....120hz mode
........Vsync OFF
............Cap unknown, fluctuates between 60-64fps, usually at 62fps, slightly more noticeable jitter
........Vsync ON
............Cap unknown, fluctuates between 61-65fps, usually at 64fps, noticeable jitter

Keep in mind my does nothing to limit the framerate on mac except set t.window.vsync (as well as it works perfect on 120hz windows pc). But I'll keep messing with the code and system settings/conf.lua in case I missed something stupid.

EDIT: Okay, what... it is something in my game that's causing it...?

I was calling love.window.setMode to scale the game. But that's only part of the issue.

I've managed to trace it down to this (without the line i commented about it runs perfectly):

Code: Select all


function tile.get_quad(p, l)
	local world = getWorld();
	local tile_width, tile_height = world.tile.layer[l].image:getWidth()/16,world.tile.layer[l].image:getHeight()/16;
	if (world.tile.layer == nil) then
		love.event.quit();
	end
	if (world.tile.layer[l].quads == nil) then
		love.event.quit();
	end
	if (world.tile.layer[l].quads[1][1] == nil) then
		love.event.quit();
	end
	if (world.tile.layer[l].quads == nil) then
		love.event.quit();
	end
	return world.tile.layer[l].quads[math.ceil(p/(tile_height+1))][((p-1) % tile_width)+1];
end

...

local lx = 0;
	for l, _v in pairs(self.tile.level) do
		for k, v in pairs(_v.t) do
			for kk, vv in pairs(v) do
				local tile_width, tile_height = self.tile.layer[1].image:getWidth()/16,self.tile.layer[1].image:getHeight()/16;
				local zx = self.tile.layer[1].quads[math.ceil(vv/(tile_height+1))];
				if (zx ~= nil) then 
					-- THE FOLLOWING LINE OF CODE causes a weirdly consistent framerate limit... what?????!!!!!!!!!!!!!!!!!!!!!!1
					-- commenting it out allows vsync to work as it should
					love.graphics.draw(self.tile.layer[l].image, tile.get_quad(vv, 1), (kk-1)*16, (k-1)*16); -- this one
				end
			end
		end
		lx = lx + 1;
	end
I didn't think there was any possibility it could be a performance problem because the game runs *extremely fast* on comparable windows pcs, and the amount of enemies on screen (I'm talking even 50+) barely made a couple of FPS dent even on mac. And if that wasn't enough the framerate (with performance issue) is freakishly consistent almost like an inaccurate timer. I guess I have some optimizing to do
Last edited by RonanZero on Thu Dec 28, 2017 1:14 am, edited 2 times in total.
while true do end;
User avatar
slime
Solid Snayke
Posts: 3133
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: 120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by slime »

RonanZero wrote: Thu Dec 28, 2017 12:43 am
slime wrote:Are you running your love game in fullscreen mode?
No, but that probably wouldn't make a difference since mac uses borderless full screen (I think? Usually?)
macOS (and most other modern operating systems) optimize borderless fullscreen opengl windows to skip compositing when possible. You should try it.
RonanZero wrote: Thu Dec 28, 2017 12:43 am But I'll keep messing with the code and system settings/conf.lua in case I missed something stupid
Keep in mind any call to love.window.setMode will enable vsync by default, unless you explicitly set vsync=false in the table you pass in.
User avatar
RonanZero
Citizen
Posts: 90
Joined: Mon Oct 20, 2014 3:33 am

Re: 120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by RonanZero »

slime wrote: Thu Dec 28, 2017 1:10 am Keep in mind any call to love.window.setMode will enable vsync by default, unless you explicitly set vsync=false in the table you pass in.
I've updated my post. That was half of the issue
while true do end;
User avatar
slime
Solid Snayke
Posts: 3133
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: 120hz monitor on macOS, LOVE(?) tries to sync to 62 or 65 FPS instead of 120.

Post by slime »

Your code is producing a lot of draw calls per frame, so it's probably as I described above (reduced performance is pushing vsync down to one frame every other monitor refresh). I recommend using one or more SpriteBatch objects which drastically reduce draw calls (even if you have to clear and re-add everything every frame), especially if you combine them with texture atlases / sprite sheets.

nvidia drivers on Windows are known for optimizing / amortizing the cost of a draw call a lot, but most other drivers aren't able to so much.

You can use love.graphics.getStats to track how many draw calls are in a given frame. Generally they should be in the dozens or low hundreds on mobile, and in the single-digit thousands tops (preferably lower) on desktops.
Post Reply

Who is online

Users browsing this forum: No registered users and 193 guests