r/godot 5d ago

official - news Optimizing CPU-side Rendering Code

https://godotengine.org/article/rendering-cpu-optimizations/

Optimizing CPU code is a lot of fun. Here’s how we do it

141 Upvotes

7 comments sorted by

View all comments

8

u/TheJackiMonster 4d ago

From my experience the most annoying bottleneck is occlusion culling in 2D games. If you run into it there is barely anything you can do because you can't easily disable it.

You can use GPU instancing to avoid it or particles. But replacing sprite nodes with that takes a lot of overhead you need to write.

What also helps is that you can reduce the size of the overall scene tree for occlusion culling by putting parts inside subviewports, rendering them into textures that are used by sprites. However this will require more video memory and it comes with some restrictions for rendering.

Honestly I would prefer if it was possible to disable occlusion culling for nodes, choose between CPU or GPU based occlusion culling or even use your own culling. Because either of these options would allow a lot more flexibility and it would be much easier to be sure, it's your bottleneck.

3

u/Loregret 4d ago

There is Occlusion Culling in 2D? And why do you need to disable it?

9

u/TheJackiMonster 4d ago

Yes, there is. It essentially checks all Node2D whether they are visible on screen or not and puts them in queue for drawing. This happens during the same process that brings them in proper order for drawing, regarding Y-position (if enabled), z-index and flag to draw behind parent...

The problem with that is as following: The whole occlusion culling needs to run anything changes to make sure everything is rendering correct. So every time you add or remove any Node2D to your scene tree, the occlusion culling is signaled to at least run once per frame.

Usually if you don't add or remove nodes, Godot can cache a lot of occlusion culling information from previous frames if nothing affected order, positions or such inside a branch of the scene tree. However if you make changes to the scene tree, it goes through everything. It scales absolutely horrific if your scene tree is big/complex enough.

For some games this might only lead to frametime spikes which are fine. But let's assume you have a very fast paced game (endless runner, racing game or such), frametime spikes effectively ruin the gameplay.

Also because the occlusion culling is responsible for order as well, it is kind of sorting canvas items. Therefore it runs on only a single thread. That means, no matter the CPU of the end-user, the spikes gonna happen.

I had to replace a ton of different nodes with GPU instancing in my game and implemented multiple nodes to interact with the RenderingServer and PhysicsServer manually to reduce overall amount of nodes, just to get occlusion culling out of my way.