v2.3 puts hierarchies on steroids!

Flecs v2.3 (and v2.2) is out!

Sander Mertens

--

I blog-skipped v2.2, so there’s a lot to catch up on :-)

First of all, Flecs is an Entity Component System (ECS). If you don’t know what an ECS is, check out the FAQ.

Much has happened since the last update, and not all of it in code! The Flecs community has grown rapidly and now has more than 300 people on the Discord with many more outside of it (welcome everyone 👋). Flecs has also been adopted by a bunch of new ambitious and exciting projects in gaming, government and AI!

Flecs is also increasingly finding a home with Unreal projects as the C99/C++11 codebase has been proven easy to integrate with Unreal Engine. Don’t take my word for it though, as two projects have written a few kind words about their experiences with Flecs and Unreal (for which many thanks! 🙏):

Additionally, vblanco ported his Unreal SpaceBattle project to Flecs:

Okay, let’s get to the good stuff. Both v2.2 and v2.3 were big Flecs releases that improved stability, added lots of new features and increased performance in a few major ways. Let’s go over the highlights!

Component toggling (v2.3)

Flecs, just like Unity DOTS, Our Machinery, Bevy and Legion, uses a so called “archetype storage”. Without getting into details (see this blog post for more info), archetypes are great for quickly iterating and mutating large numbers of entities, but the performance of adding/removing components degrades as entities have more components. This overhead won’t be noticeable for many, if not most applications, but there are scenario’s where it is useful to rapidly add and remove components.

To support this use case v2.3 introduces “component toggling”, which lets an application enable / disable components by flipping bits. This offers similar functionality as add/remove, but with a very fast, constant time operation. Disabled components are automatically skipped by queries. This impacts iteration performance a little bit, but an efficient bitset-based iterator has been implemented to minimize overhead and still allow for vectorization. The best part is that if an entity doesn’t use component toggling, there is no performance impact at all!

The API for enabling/disabling components is super easy:

e.enable<Position>();
e.disable<Position>();

Click here for the C example.

Click here for the C++ example.

New staging implementation (v2.2)

Flecs staging is the mechanism that allows an application to use the API safely while iterating component arrays and/or from multiple threads. v2.2 introduced a new staging implementation that is based on a command queue which is much faster and more flexible than the previous implementation. The best part about this improvement is that it doesn’t change the API at all, applications will simply perform better after upgrading to v2.2!

While the previous staging implementation was only enabled while iterating components in a system, the new staging implementation can be used outside of systems as well. Applications can now use defer_begin() and defer_end() operations to indicate when API commands should be queued and when they should be merged. This is super useful for when mutating component arrays while an application is iterating, for example, a query.

Future versions will add features that provide full control over the command queue so that queues can be used to spread commands out over multiple frames (to reduce spikes), synchronize commands over the network, discard commands when they’re no longer required and much more!

Dramatically improved table creation performance (v2.3)

(Yes, dramatically. I’m not exaggerating.)

Tables are the primary storage containers for component data. While applications generally have many more entities than tables, certain Flecs features, such as hierarchies, rely heavily on tables. Flecs v2.3 introduced a number of changes that improved table creation performance by two orders of magnitude, and table reduced memory footprint by a factor 60. Those numbers sound incredible, so let’s unpack this.

When Flecs creates a new table, it must make sure that the table does not already exist. Previous to v2.3, this was implemented by iterating and checking all existing tables. This quadratic approach could cause noticeable slowdowns when an application created for example large hierarchies. In v2.3 this quadratic algorithm has been replaced with a hashmap which provides near constant-time performance. Where Flecs v2.2 would struggle with creating thousands of tables, v2.3 can easily create 1 million tables without breaking into sweat.

Being able to create so many tables so fast exposed another problem: tables used up quite a lot of memory. It took some investigation and detours to find out why. It turned out that the Flecs hashmap, which is used to store edges in the table graph, was a big RAM spender. After that was addressed, the memory overhead of a table dropped on average by a factor 60!

These improvements enable much larger scenes to be expressed with Flecs. I figured I should put it to the test too, which is when this happened:

Each turret is its own multi-entity hierarchy

New statistics API (v2.3)

Flecs has always made a point about exposing as much data as possible about what’s going on internally. Without it, an ECS can easily become somewhat of a black box, especially for big projects. Version 2.3 steps up this effort with a new statistics API that exposes more data, and is much easier to use. The API can be used to directly monitor statistics over time and exposes more information about the underlying storage and API usage. Two dashboards have been built with it that monitor application- and system performance:

The best part is that these dashboards work with any Flecs application by simply importing the right Flecs modules!

Click here for the dashboard module.

Improved entity lifecycle management (v2.2)

Generating new entity ids is not only faster than before, but also much more powerful. Since v2.2 entity lifecycle tracking has been implemented by adding a 16-bit generation count to each entity. In plain English this means that Flecs can detect whether an entity handle is still valid after deleting & recycling the same entity id 65 thousand times.

Direct access API (v2.3)

Don’t you sometimes wish you could do X, but the API of a framework doesn’t have a dedicated function for it? Flecs v2.3 introduces a new API for power users that provides direct access to the underlying table storage. The API is more verbose than the regular API, but allows for the construction of custom operations that are just as fast as the built-in Flecs ones.

Some of the things that can be efficiently implemented by the direct access API are multi-component initialization, copying/moving data between worlds, mutating table columns directly, instantiating components without needing an entity, … Use your imagination!

Click here for a code example.

V3

Okay, this is strictly not related to the v2.2 and v2.3 releases, but it’s still fun to talk about: the Flecs v3 project has started in earnest! It will take a while before its release, but some exciting features have already been implemented such as a hybrid sparse/archetype storage, an improved model for entity relationships and lots of big performance improvements. Expect to see more updates this year.

If you’d like to track v3 development, check the v3 branch: https://github.com/SanderMertens/flecs/tree/v3

And much, much more…

Of course this is only the tip of the iceberg. For the full v2.2 and v2.3 change logs click here for the Flecs releases page. Some noteworthy things to call out:

  • Warning-less compilation on all big platforms for most compiler settings
  • Added sanitizer build to CI
  • Added a godbolt-powered “try online” badge
  • Added lots of inline documentation
  • Sorting has been implemented for shared components
  • Improved prefab workflow that enables automatic overriding
  • New and improved API and storage approach for singletons
  • Improved support for tags in C++ (detection of empty structs)
  • Improved performance of ecs_delete() and ecs_get()
  • Improved portability of POSIX platform abstraction example
  • Changed the Github logo to match dark mode :-)

Thanks for making it to the end! If you’ve enjoyed working with Flecs, consider giving it a star or becoming a sponsor:

If you liked what you read and are hungry for more, definitely join Discord:

That’s all! Until 2.4 (or 2.5) 👋.

--

--

Sander Mertens

Author of Flecs, an Entity Component System for C and C++