EcsRx / ecsrx

A reactive take on the ECS pattern for .net game developers
MIT License
520 stars 36 forks source link

quick and dirty fix to be able to pin unmanaged component pool in memory (break IComponent<> covariance) #18

Closed Doraku closed 3 years ago

Doraku commented 4 years ago

removed IComponentPool<out T> covariance so a lot of stuff break because of

        public void AddComponents(IReadOnlyList<IComponent> components)
        {
            var componentTypeIds = new int[components.Count];
            for (var i = 0; i < components.Count; i++)
            {
                var componentTypeId = ComponentTypeLookup.GetComponentType(components[i].GetType());
                var allocationId = ComponentDatabase.Allocate(componentTypeId);
                InternalComponentAllocations[componentTypeId] = allocationId;
                ComponentDatabase.Set(componentTypeId, allocationId, components[i]);
                componentTypeIds[i] = componentTypeId;
            }

            _onComponentsAdded.OnNext(componentTypeIds);
        }

in Entity.cs (can't down cast to IComponentPool<IComponent> anymore). It should be fixable but I think I have done enough non trivial changes here and it might not be a road you want to take ^^"

grofit commented 4 years ago

This would allow me to pin the whole pool though right, and im not sure if I want to pin everything as you may only want to pin a few parts of that array, I need to do some more research into this when I get the time as if indexes will still allow for prefetching (I am doubtful) then maybe thats a lesser pain to go with, it also removes a lot of the unmanaged requirements.

There is also some hope for ref structs being possible here as there is some traction on the other issue mentioned. I will see if I can get a few hours to do a deeper dive on this and if pinning all the component arrays doesn't carry much overhead and we can allow bool/chars and other value but non blittable types in there then this may be a viable approach.

Either way thank you so much for your efforts on this.

Doraku commented 4 years ago

Yes, you can't pin just a part of an array (because the full array has to be contiguous in memory), or you could use a linked list of array segments but this seems like a nightmare to handle. Personally I tried the indices pre-fetched method but I was not impressed by the result (my component pools are kinda like yours, entity id > component index > component value, so to replace it with enumeration index > component index > component value didn't change much), Currently I am looking into sorting my set of entities and their components position by the entity ids so that the cpu always move forward into the memory instead of jumping around.

The only throw back with pinning the array would be memory fragmentation because the GC can't compact everything BUT, for a game in c# we try really hard to not produce garbage once running anyway so it's probably no that bad.

grofit commented 3 years ago

I am gonna mark this as closed but if you want to discuss it some more at a future point feel free to re-open, or raise an issue around it.