Replies: 3 comments
-
|
Sure, I can try and answer these questions. A lot of the system and query code is source generated, so it can be a bit messy to follow. Whats a fetch:Systems in this ECS arent directly related to querying the entity-component part but instead allows for creating systems one level above that. The Fetch is how the system pulls data out of the World and into the systems. Two main types of fetch are setup to pull data out of world, As long as a type implementing The This setup is pretty similar to how Bevy does it. Command buffer priorityCommands are sorted based on the command type, and there is no sorting between commands of the same type. Priority is controlled by the command itself so use of NativeArrayI've had some different ideas around this and right now there is no purpose for it. I had some ideas around keeping all chunks in contiguous memory and allowing more efficient moves. Having the ability to easily couple with queries implemented in native libraries was also another reason for it. It's most likely better to handle the chunks with managed memory the way it works now. Each By pinned here do you mean for the GC? if so the memory is allocated via the NativeMemory class which allocates it in the unmanaged memory block so it doesnt need to be pinned as it's never moved after allocation. Managed componentsThis hasn't been a priority as the goal was to ensure that blittable data can be queried and iterated fast. It's also something I'd like to avoid doing as it forces me to write queries over simple data. The way managed data is stored on components is via an asset Hope this answered your questions. Feel free to ask more, and provide insights from learnings you've made creating Fennecs. |
Beta Was this translation helpful? Give feedback.
-
|
Awesome, thank you for the detailed infos. :) I like how fennecs turned out, it was always intended as a drop-in ECS to use with other engines and works like a charm. But it's also got its rough edeges and many limitations, so I want to flesh it out more. (also, my fingers are itching to try dabbling with a pure C# engine) Some maybe relevant learnings & thoughts:MethodImplOptions.AggressiveInlining hardly ever helpsSo far RyuJIT has always inlined everything fine, and AggressiveInlining won't magically make it inline otherwise. (there's various inlining profiler/analyzers that can tell you why a function wasn't inlined) MethodImplOptions.AggressiveOptimization usually hurtsIt turns off Tiered PGO, which is responsible for the majority of performance gains I see in systems and streams ('queries'). I recommend avoiding it, it's a misnomer from the past. 64-bit Entities carry a surprising memory bandwidth costEspecially when enumerating them to a runner's ("system's") code. It's so bad that for instance in a system that despawns Entities when they go out of bounds, the Entity parameter passed to the system code makes up 40% of the total memory bandwidth used when looking at Therefore, I'm refactoring living Entity IDs to be a 32 bit Another approach could be an Entity-Chunk-accessor parameter. Sadly, passing in a Also potentially frees up an entire cache prefetch lane. 🤔 When to discard Archetypes is a hard decision for both users and the libraryDiscarding an empty archetype and freeing its memory is a difficult decision (all queries need to be modified, and not even one tick later, new entities might want to migrate into that archetype). My current Storage in Archetypes is a big contiguous array; I want to switch that to chunks because then empty archetypes lose most of their memory requirements. I tried some sort of "if the archetype is still empty after X world catchups, GC it", or having the user call Managed Components are awesome (to coexist with unmanaged ones)They are just inutitive and useful; e.g. keeping a pointer to mesh data, image references, etc. in a component is just too good. It also enables intuitive "shared" components. Managed components don't negatively affect the performance of unmanaged ones. With chunked storage even migrating (many) entites from one archetype to another doesn't even suffer the managed reference copy overhead.
|
Beta Was this translation helpful? Give feedback.
-
|
That was an interesting read, thanks for the information. This will surely come in handy whenever I do another pass over the ECS. Didn't know about the Chunks is something that works very well for allowing fast and cheap resize of archetype storage. Another benefit is that it could be easier to ensure alignment so that cache and memory lookups are more efficient, but that might be negligible when compared to one contiguous array. I havent looked at any multi-threading support yet as I want to ensure WASM support. It will be interesting to see if there is any benefit to unmanaged memory there, but the runtime is getting so good at optimizing so who knows. With your use of vector intrinsics and SIMD related optimizations, how ergonomic do you find that in use? Is there a lot of manual work to select exactly what data you want to iterate with. Say you have a Transform with a Position, Scale and Rotation and a Rigidbody with Velocity. How would an iteration adding the Velocity to Position look like when using Fennecs? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Dear Maintainer, if you have a little bit of time, I'd love to learn more about the internals. :) I'm generally familiar with ECS (maintaining one myself), but not quite familiar with Bevy.
The code looks well structured but has few comments explaining the ECS API/Architecture and its goals. Understandable, for sure, given it's so fresh. 💙
What's a "Fetch"?
This appears to be a core concept of pollus's ECS, but it's hard for me to glimpse from the code what it really represents.
It seems to be some sort of Archetype access registry?
What's
bool Commands.needsSort/ Command Buffer "Priority"?What's being sorted (the command buffers or commands?) The sorting seems to operate by some kind of priority based sorting, what are these priorities?
What are System Parameters?
e.g. in
SystemBuilder Create<TSystemParam>and inWhy are Entities stored in a bespoke
Pollus.Collections.NativeArray<Entity>?I can understand why it's useful for certain components that need to get passed on to native functions (I - perhaps incorrectly - tend to prefer
Memory<T>overSpan<byte>for that), but the Entity?How are the native arrays pinned / protected against modification, e.g. when Entities move out of a chunk?
Why are components stored in
NativeArray<byte>?Same question, almost, but more along the lines "does that mean managed components are impossible?"
Thank you very much in advance if you find the time, if not, no hard feelings if you close the issue.
Beta Was this translation helpful? Give feedback.
All reactions