|
|
|
|
|
by jeremiep
3944 days ago
|
|
You arguably don't need that many data structures in a game engine, almost everything is tightly packed in linear arrays. Even hash-maps are frowned upon. The single most used structure I've seen in engines is the plain old array because of cache locality. Everything is pre-sorted, pre-looked-up and pre-crunched so the main use-case is a straightforward linear traversal with as little branches as possible. Also templates can greatly affect compilation times which are already horrible on projects of such magnitude. On the last AAA game I worked on we had very tight memory constraints and running about a dozen threads. Almost all of them used the minimum stack size except for the main thread. There were still a lot of stack allocations, but only for very small temporary objects and when the call stack was known to be shallow. Using megabytes for stack sizes would consume a noticeable percentage of the available memory which was direly needed elsewhere. I've seen one game using shared_ptr and it was far from being great. There's a big overhead to it when compared to custom allocators. You can't easily optimize for cache locality with shared_ptr (as far as I know!) and working around enable_shared_from_this can be a real pain. With custom allocators you can easily optimize according to the use-cases. Finally, templates are required to know their type at compile time, which for things like allocators is just not possible in many cases. For example, we used a bump-the-pointer allocator for a frame's temporary values which could be of any type but still needed cache locality. We also used a fixed-size allocator when avoiding memory fragmentation was more important than cache locality. Both would be impossible to do on anything but void*. |
|
I haven't taken the time to dig into seeing how these techniques will translate to Rust(obviously unsafe).