Unstable FPS in Vsync mode

Hi guys. I’m making Vampire Survivors clone as my first project in Defold.

Everything works quite well, even with 1000 enemies rushing toward the player, as long as Vsync is disabled.

Let me share some more about the scene and settings:

  • All 1000 enemies have one animated sprite, dynamic collision object and script, that pushes them toward the player.
  • There are 18 drawcalls in each frame.
  • Physics engine is 2D type, with fixed timestep set to 30.
  • Apart from enemies, there are GUI, tiled map with 6000 tiles and the player.
  • Resolution: 1600x900, framerate of my display is 60Hz.

And the illustrative graphic:

I had issue with ustable FPS and have been exprimenting for quite long time with different types of collision objects (kinematic/trigger) and handling collsiion in lua, various physic timestamps etc, however nothing really helped, I couldn’t achieve stable 60 FPS for more that 100 enemies touching each other.

I decided to untick the Vsync in Display setting and I was stunned… 500 fps (with min: 400, max 800) just happend with basic dynamic collisions. It more than enough for me, however it’s strange that with Vsync enabled the FPS is unstable.

Summary of different settings and achieved FPS:

  1. Update freq: 0, Vsyns: DISABLED – FPS: min: 400, avg 560, max 800.
  2. Update freq: 30, Vsyns: DISABLED – FPS: min: 29.8, avg 30.0, max 30.1.
  3. Update freq: 60, Vsyns: DISABLED – FPS: min: 59.7, avg 60.0, max 60.3.
  4. Update freq: 120, Vsyns: DISABLED – FPS: min: 105, avg 110, max 115.
  5. Update freq: 0, Vsyns: ENABLED – FPS: min: 27, avg 59, max 64.
  6. Update freq: 30, Vsyns: ENABLED – FPS: min: 29.9, avg 30.0, max 30.01.
  7. Update freq: 60, Vsyns: ENABLED – FPS: min: 59.2, avg 60.0, max 60.5.
  8. Update freq: 120, Vsyns: ENABLED – FPS: min: 13, avg 58, max 63.

As you can see above, the theoretical max FPS is quite high and stable. Also it is possible to maintain 60 FPS with update frequency set to 60 and no Vsync.

Is anybody have clue why there is sudden drop in stability, when Vsync is enabled and update frequency is higher than display framerate? The FPS drops are still present even when the amount of enemies is reduced to 250.

1 Like

This was flagged recently

I’m using Windows and it’s not working exactly as pointed in this issue.
Rather I have just some random frame drops, but only in Vsync mode without update frequency set below refresh rate of my display. With update frequency set to 60 everything works perfectly smooth.

Hi there, I am facing exactly the same problem and been trying for days. I can easily have 1000 enemys with dynamic sphere collision moving towards the player (barebones script) with about 1600 fps (no vsync, fixed update rate of physics at 30 Hz), but as soon as I switch on vysnc, the framerate drops below 60 Hz occasionally and the game is stuttering.
I am on Windows too.
This is the same if I run the game from Defold or if I bundle a release for windows.
I love Defold from toying with it for a week now, but something is off here.

Thanks, so much for any help!

Nobody out there to help? Or is this a known issue that Defold cannot reach stable FPS? I tried everything, collision handling and all other scripts are now in seperate frames. Garbage collection on or off, no difference. Here two screenshots without Vsync about 1000 fps however, drops to 1% low (Nvidia Frameview) of 170 fps, but with Vsync drops to much below 60 fps … Help, please … I really like Defold otherwise. Great project.


@coroner-gss Thanks for digging this up.

Yeah, still same for me. In my game prototype I how more than 1000 FPS with fixed framerate and vsync disabled, stable 60 FPS with fixed update but with vsync and fixed fps disabled there are framerate drops.

For now I just dont use vsync at all and just set fixed 60 FPS.

When developing video games you should measure frame time, not FPS. Let’s leave the measurement of FPS and 1%, 0.1% etc to game journalists.

Next to the question of your game cycle and why it seems to work better with vsync disabled. Let’s imagine that use fixed timestep is enabled for physics, with vsync enabled on a 60hz monitor and with 30hz fixed update:

frame number | what is happening in the frame
1 | update, fixed update, render
2 | update, render
3 | update, fixed update, render
4 | update, render
5 | update, fixed update, render
6 | update, render
...

Without vsync:

frame number | what is happening in the frame
1 | update, fixed update, render
2 | update, render
3 | update, render
4 | update, render
5 | update, render
6 | update, render
7 | update, render
8 | update, render
9 | update, render
10 | update, fixed update, render
11 | update, render
...

So when measuring FPS, it will appear to you that with vsync disabled, their minimum values are higher, as there are simply more of them per second on average.

But periodic lags in the game will not disappear anywhere, because physics updates require a huge amount of time on such a large number of objects. Plus, if you put a script on each object, it will work as it does now.

7 Likes

I agree that frame time is the key for smoothness, however at least in my experience there is something wrong going on with the vsync. I respectfully disagree that is seems to work better with vsync disabled. Every time the update frequency is higher than my screen frequency I experience huge issues with smoothes, not just “a little bit worse 0.1%”.

My screen have 60 Hz refresh rate.
When I run my proto with update frequency set to 0 and vsync disabled framerate never drops below 200 FPS. When there are less enemies even 600 FPS can be achieved.

With update frequency set to 60 and vsync disabled, FPS sometimes drops to 55-56, however everything is smooth in general and pleasant to play.
With update frequency set to 60 FPS and vsync enabled still everything is still fine.
With vsync enabled and update frequency set to 0 or 120, there are 60 FPS with small amount of enemies but huge drops when there is more enemies. Bascilly unplayable.

Is there any preditable reason for issues with update frequency higher than vsync frequency?

Hi there, I already had a look at the frametime extensively. Just posted fps with the nvidia tool because you can see the issue quite good there.
I do not need to “leave anything to game journalists”, I came here because I have anoying stutters. This is also not the first game engine I am working with, I have over 30 years experience.

My code only runs a fixed update frame every 30 Hz (doing nothing except being in sync with the physics update at 30 Hz and setting a timer state) which takes about 3-4 ms (for physics) and following this one other interleaved “duty” frame with about 4 ms for game logic and go.animate() for smooth motion. All other frames inbetween without Vsync basically do nothing (except the engine runs go.animate), thus giving 1000+ fps on average. Nevertheless, without issues, the 1% low fps should thus be about 250 Hz (=1/4 ms).
However, there are some frames inbetween which take longer.

This problem is bigger at 60 Hz Vsync when my code executes interleaved two 30 Hz physics and 30 Hz game update, with (like above) 4 ms frame time each. So this should be super stable 60 Hz (=16.67 ms), with 12 ms overhead per frame, however, this is not the case, there are always longer intermittent frames … so you never get stable 60 Hz.

BTW I also ran 144 Hz with Vsync which gives me 1% drops to 120 Hz, still feeling some stuttering much less pronounced than at 60 Hz of course.
These numbers tell you that it is not my game (which in theory should give stable 250 Hz).

1 Like

It would be really great if you could post small real examples or a repo-case.

I made a quick equivalent of what I saw on the pictures above and so far everything is fine, it runs smoothly (source code). It demonstrates 1000 collision objects, 2D physics; the objects are moving towards the center.

No vsync, 144hz monitor, OpenGL

Vsync, 144hz monitor, OpenGL

image

And just to check that the empty project works okay too -

Empty project, vsync, OpenGL

image

Empty project, vsync, Vulkan

image

3 Likes

Hi there, thanks so much! Just adding

if (socket.gettime() - self.fpsclock) > 0.018 then
	print(socket.gettime() - self.fpsclock)
end
self.fpsclock = socket.gettime()

in fixed_update and initializing self.fpsclock in init already shows occasional random increases to 33 ms on my system. You do not recognize this in the example because nothing is moving in the end, but if you would now move with the camera around it would stutter.

I am not sure, in your example it might in fact be the physics collision that increases its runtime randomly in time, for me it seems to be the script.

BTW, sporadic fps drops also already occur with 100 objects … for me

Curious how this is for you

I keep worrying about your question, i.e. it’s like an unsolved case. Have you tried running your project on version 1.9.2 and newer? The point is that this version of Defold on Windows uses GLFW 3.4 instead of 2.7. The important point of this GLFW update is that vertical synchronization has been fixed (there is a lot of discussion of this issue on StackOverflow and in the GLFW Github issues).

2 Likes

Hi, I will happily check this with newer versions of Defold, both with my prototype and demo from you. I will update you in couple of days, thank you for your interest in this topic.

1 Like

A lot of work has been done in 1.9.6 to fix DT jumps. Hopefully that should fix your issues:

3 Likes

Hi guys,

it took me longer than expected to revisit this topic, but I wanted to be accurate about the measurments and differences between Defold verions.

It’s gonna be long post, so TL:DR:

  1. Problem seems to be fixed in 1.9.6.
  2. But 1.9.6 breaks camera in many demos.
  3. Also max FPS seems to be about 5% lower in 1.9.6 in comparision to 1.9.0 and 1.7.0, but it may be measurements issue.

Setup

Firstly, I did some changes to my demo:

  1. I was averaging the FPS by counting ticks over 100 ms. Now I get raw fps just by 1/dt.
  2. I cut out many unused things.
  3. Now I display current FPS, worst from past 3s and worst from past 10s.
  4. I have new SSD drive and fresh Windows installation.

Due to that I had to redone all tests, to make them comparable.

I tested 3 versions:

  • 1.7.0 - I believe this is the version I’ve been using when created this issue,
  • 1.9.0 - Just had it downloaded some time ago to test new tiles features,
  • 1.9.6 - To check the newest stable version.

Results

The problem seems to be fixed somewhere between 1.9.0 and 1.9.6. The are currently no FPS drops when Vsync is enabled and update frequency is set to 0.

In the table below you can see all results that I gathered:


The bolded columns interest me the most.

There seems to be slight performance drop when comes to 1.9.6, but it may be just result of fixing bugs related to dt, since my logic of FPS counting is dead simple:

function update(self, dt)
self.fps = 1 / dt

local scorenode = gui.get_node("fps")
gui.set_text(scorenode, string.format("FPS: %.2f", self.fps))

if self.fps < self.fps_min3 then
	self.fps_min3 = self.fps
	local scorenode = gui.get_node("fps_min3")
	gui.set_text(scorenode, string.format("FPS MIN (3s): %.2f", self.fps_min3))
end
if self.fps < self.fps_min10 then
	self.fps_min10 = self.fps
	local scorenode = gui.get_node("fps_min10")
	gui.set_text(scorenode, string.format("FPS MIN (10s): %.2f", self.fps_min10))
end
end

local function fps_min_rst3(self)
	self.fps_min3 = 10000
end

local function fps_min_rst10(self)
 	self.fps_min10 = 10000
end

fps_min3 and fps_min10 is resetted each 3 and 10 s respectively.
For FPS AVG I was counting all the frames over 3.33s time period (200 frames in 60 FPS).

Camera issue

One thing that I notice is different camera behaviour. It act the same in versions 1.7.0, 1.8.0 beta and 1.9.0. I can just run any of my project or demo and everything looks the same. When I run some projects in 1.9.6 almost always camera is broken.

In this project camera was offseted and super zoomed. I fixed by adjusting some parameters and now zoom is the same for 1.7.0 and 1.9.6 but there is still issue with new method of camera position setting. In 1.9.6 position of camera GO is center of visible area, while in older versions it was left bottom corner. I found two entries about camera between releases 1.9.0 and 1.9.6, but none of them mentions it.

1.9.2 – " Frame the camera to the very first visible object added to the scene view It may be confusing when a visible object is added to an empty scene, but nothing is visible because the camera is too zoomed in. After this fix, the very first visible object added to a scene will be framed to ensure it is visible."

1.9.6 – " NEW : (#9847) ‘Camera components should have precedence in the default render script’ by Jhonnyg The default render script has been updated to take camera components into account […]"

I think new changes are brilliant, since it was really bothering me to offset camera by half of screen dimensions, but maybe it was a bit rushed, since not only my projects but also the offical examples are now broken:

Ending

I want to thanks for everyone involved in this topic and for your improvments to the engine. My issue is resolved in my opinion, but if I can provide you more data for further analysis, just let me know what you need.

3 Likes

This is for the editor, not runtime. SO, it’s not related

Could you pls provide a list of public projects where you found that camera is broken? That would be really helpful, thank you!

2 Likes

Sure. From Defold examples Magic Link, Ocean Commotion and Examples are working properly.

There are problems with:

  • Alien World
  • Sample runner
  • War Battles

Details

Alien World 1.9.6 not working:


Alien World 1.9.0 seems to be ok:

Sample runner 1.9.6:
Editor shows error during project loading:


but can build the game:

However it differs from expected:

Defold 1.7.0 and 1.9.0 display same error as 1.9.6 but editor immediately closes, therefore 1.9.6 is actually better.

And War Battles as mentioned:

1 Like

I’ve updated the three projects to be compatible with Defold 1.9.6

6 Likes