BenjaTK / Gaea

Procedural generation add-on for Godot 4.
https://benjatk.github.io/Gaea/
MIT License
1.13k stars 55 forks source link

Using the "Terrain" option for TilemapTileInfo causes horrible lag. #169

Open cullumi opened 2 months ago

cullumi commented 2 months ago

This issue is likely due to the _set_terrain function inside of tile_map_gaea_renderer.gd.

Our set_cells_terrain_connect calls are updating the connections over an entire chunk's worth of tiles all at once. This likely has performance implications and should be spread out over time (for example, connecting only 3x3 groups of neighbors, then repeating in separate thread_safe calls over the entire chunk).

I plan to make a PR for this issue soon, just wanted to document my findings in the meantime.

cullumi commented 2 months ago

Observations

After further investigation, the issue isn't as simple to address as I thought it would be:

What's this mean for us?

A consequence of these two observations is that it seems like no amount of thread_safe calls made in the TilemapGaeaRenderer seem to make much difference in our lag problem-- perhaps because one expensive call is just immediately followed by another expensive call, which all lead to a big huge physics update of some sort.

Possible Solutions

We have some options for addressing these limitations:

GeminiSquishGames commented 2 months ago

Maybe someone could help make a C# version for a larger scale, but usually making small chunks and only when you need them helps with GDScript performance-based generation, which probably would be better done at runtime rather than in the editor to generate things on the fly as the player is exploring. C# can be way faster for this type of procgen, either way, though it means your addon users would have to use the mono build of Godot. Unless you do a GDExtention in C++ then you have way more flexibility with performance and it should work with any build.

When you say thread safety doesn't seem to help, that says to me that it's doing it's job and preventing parallel processes from accessing the data that you may want to be doing in parallel for speed, maybe. Typically, I would toss the thread safety for the first pass for full-speed parallel calculations of chunks and then do my seam fixing and other clean-up in a second pass. Take this with a grain of salt as I have not familiarized myself with your code and am likely missing something.

cullumi commented 1 month ago

When you say thread safety doesn't seem to help,

To clarify, the thread_safe calls I mentioned are being used to call non-thread-safe code in parts of the code that can optionally be run from a thread so as to not block the main thread (see How to optimize your generators). The functions called this way are almost exclusively built-in Godot engine methods for setting tiles and such (implemented in C++).

That being said...

Typically, I would toss the thread safety

I think you might be on to something here. I'm playing around with just forgoing the thread_safe call entirely (seeing as the bulk of the auto-tiling work is independently exclusive even when multiple chunks are loaded in parallel), and I'm seeing some promising results!

Maybe someone could help make a C# version for a larger scale

I get where you're coming from, but at the end of the day, this issue seems to be more of an implementation bottle-neck than a language bottle-neck.