Hacker News new | ask | show | jobs
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*.

1 comments

Ah man, fond memories of game dev. That's the way you write high performance C/C++.

I haven't taken the time to dig into seeing how these techniques will translate to Rust(obviously unsafe).

I haven't tried Rust yet, but they all easily translate into D!

I've lost count of the number of times I've thought to myself "I wish C++ has this D feature." A lot of them are being added now but the interesting ones (concepts!) are still years away and some (inout functions!) are nowhere in sight.

And then there's templates, mixins, auto this, compile-time reflection, and so much more. Its far from perfect (nothing is) but constantly improving and rather productive. Of course also being a user of Clojure (and Emacs-LISP) I sometimes miss something like defmacro, which I can almost get with mixins and templates but often not as elegantly. On the other hand, I write shell scripts in D all the time and not in Clojure!