diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index d2272dd..2894f61 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -10,7 +10,15 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) private uint block_size; private uint blocks_in_allocation; + struct BlockPointers + { + void*[32] blocks; + uint numberof = 0; + BlockPointers* next_pointers = null; + } + void* next_block = null; + BlockPointers* pointers = null; void* getBlock() nothrow @nogc { @@ -31,6 +39,16 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) { next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( block_size * blocks_in_allocation, block_size); + + if(pointers is null)pointers = Mallocator.instance.make!BlockPointers; + if(pointers.numberof >= 32) + { + BlockPointers* new_pointers = Mallocator.instance.make!BlockPointers; + new_pointers.next_pointers = pointers; + pointers = new_pointers; + } + pointers.blocks[pointers.numberof++] = next_block; + foreach (i; 0 .. blocks_in_allocation - 1) { void** pointer = cast(void**)(next_block + i * block_size); @@ -40,4 +58,18 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) next_block + (blocks_in_allocation - 1) * block_size); *pointer = null; } + + void freeMemory() nothrow @nogc + { + while(pointers) + { + foreach(i;0..pointers.numberof) + { + AlignedMallocator.instance.dispose(pointers.blocks[i]); + } + BlockPointers* next_pointers = pointers.next_pointers; + Mallocator.instance.dispose(pointers); + pointers = next_pointers; + } + } } diff --git a/source/ecs/core.d b/source/ecs/core.d index 8f34fc0..64dceba 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -8,7 +8,8 @@ static struct ECS mixin template System(uint jobs_count = 32) { __gshared ushort system_id; - EntityManager.Job[] _ecs_jobs; + uint __ecs_jobs_count = jobs_count; + /*EntityManager.Job[] _ecs_jobs; void __ecsInitialize() nothrow @nogc { @@ -16,6 +17,13 @@ static struct ECS import std.experimental.allocator; _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); } + + void __ecsDeinitialize() nothrow @nogc + { + import std.experimental.allocator.mallocator; + import std.experimental.allocator; + Mallocator.instance.dispose(_ecs_jobs); + }*/ } mixin template Component() diff --git a/source/ecs/events.d b/source/ecs/events.d index ca9bade..47d9415 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -175,15 +175,7 @@ struct EventManager void allocateData(uint threads_count) nothrow @nogc { - if(events) - { - foreach(ref event;events) - { - Mallocator.instance.dispose(event.blocks); - Mallocator.instance.dispose(event.first_blocks); - } - Mallocator.instance.dispose(events); - } + disposeData(); events = Mallocator.instance.makeArray!EventData(gEM.events.length); foreach(i,ref event;events) { @@ -196,8 +188,44 @@ struct EventManager } } + private void disposeData() nothrow @nogc + { + if(events) + { + foreach(ref event;events) + { + foreach(first_block; event.first_blocks) + { + EventBlock* block = first_block; + EventBlock* next_block; + if(block)next_block = first_block.next; + while(block) + { + Mallocator.instance.dispose(block); + block = next_block; + if(block)next_block = block.next; + } + } + + Mallocator.instance.dispose(event.blocks); + Mallocator.instance.dispose(event.first_blocks); + } + Mallocator.instance.dispose(events); + } + allocator.freeMemory(); + } + + ~this() nothrow @nogc + { + disposeData(); + /*foreach(i,ref event;events) + { + EventBlock* block = event.first_blocks; + }*/ + } + ///Single page size. Must be power of two. - enum events_block_size = 1 << 12; + enum events_block_size = 1 << 14; ///Number of pages in block. enum events_blocks_in_allocation = 128; diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 07566d3..3ee7f1c 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -154,6 +154,24 @@ begin: add_mutex = Mallocator.instance.make!Mutex(); } + void deinitialize() @trusted @nogc + { + if(m_ids_array)Mallocator.instance.dispose(m_ids_array); + if(m_free_stack)Mallocator.instance.dispose(m_free_stack); + if(m_blocks) + { + foreach(ref block;m_blocks) + { + if(block.data)block.free(); + } + Mallocator.instance.dispose(m_blocks); + } + if(add_mutex) + { + Mallocator.instance.dispose(cast(void*)add_mutex); //workaround for compiler bug + } + } + void optimize() nothrow @nogc { if(m_stack_top < -1)m_stack_top = -1; @@ -176,7 +194,7 @@ begin: begin += 65536; } memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); - foreach(block;m_blocks[1..m_blocks_count])block.free(); + foreach(ref block;m_blocks[1..m_blocks_count])block.free(); m_blocks_count = 1; } } @@ -193,9 +211,10 @@ begin: { assert(data !is null); Mallocator.instance.dispose(data); + data = null; } - Data[] data; //65536 + Data[] data = null; //65536 } private static struct Data diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 12dfa7c..0a7017d 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -36,7 +36,17 @@ export class EntityManager export static void initialize(uint threads_count) { if (instance is null) + { instance = Mallocator.instance.make!EntityManager(threads_count); + + with(instance) + { + UpdatePass* pass = Mallocator.instance.make!UpdatePass; + pass.name = Mallocator.instance.makeArray("update"); + passes.add(pass); + passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + } + } } export static void destroy() @@ -44,19 +54,58 @@ export class EntityManager if (instance is null) return; - foreach (ref system; instance.systems) + with(instance) { - system.disable(); - } + foreach (ref system; systems) + { + system.disable(); + if (system.m_destroy) + (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - foreach (ref system; instance.systems) - { - if (system.m_destroy) - (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); + if(system.jobs)Mallocator.instance.dispose(system.jobs); + if(system.m_read_only_components)Mallocator.instance.dispose(system.m_read_only_components); + if(system.m_modified_components)Mallocator.instance.dispose(system.m_modified_components); + if(system.m_components)Mallocator.instance.dispose(system.m_components); + if(system.m_excluded_components)Mallocator.instance.dispose(system.m_excluded_components); + if(system.m_optional_components)Mallocator.instance.dispose(system.m_optional_components); + if(system.name)Mallocator.instance.dispose(system.name); + if(system.m_event_callers)Mallocator.instance.dispose(system.m_event_callers); + + if(system.m_system_pointer)Mallocator.instance.dispose(system.m_system_pointer); + } + + foreach(EntityInfo* info;&entities_infos.byValue) + { + //if(info.components)Mallocator.instance.dispose(info.components); + + Mallocator.instance.dispose(info); + } + + foreach(UpdatePass* pass; passes) + { + Mallocator.instance.dispose(pass); + } + passes.clear(); + + foreach(ComponentInfo info; components) + { + if(info.init_data)Mallocator.instance.dispose(info.init_data); + } + + foreach(EventInfo info; events) + { + if(info.callers)Mallocator.instance.dispose(info.callers); + } + + foreach(name; &components_map.byKey) + { + if(name)Mallocator.instance.dispose(name); + } } Mallocator.instance.dispose(instance); instance = null; + } /************************************************************************************************************************ @@ -198,12 +247,16 @@ export class EntityManager entity_block_alloc_mutex = Mallocator.instance.make!Mutex; //event_manager = EventManager(this); //event_manager.manager = this; + } - UpdatePass* pass = Mallocator.instance.make!UpdatePass; - pass.name = Mallocator.instance.makeArray("update"); - passes.add(pass); + ~this() + { + id_manager.deinitialize(); - passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + if(threads)Mallocator.instance.dispose(threads); + if(entity_block_alloc_mutex)Mallocator.instance.dispose(entity_block_alloc_mutex); + + allocator.freeMemory(); } /************************************************************************************************************************ @@ -451,7 +504,7 @@ export class EntityManager enum ComponentsIndices components_info = getComponentsInfo(); - static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) + static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) { foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -661,12 +714,13 @@ export class EntityManager system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; - (cast(Sys*) system.m_system_pointer).__ecsInitialize(); - system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; + //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); + //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; + system.jobs = Mallocator.instance.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); genCompList(system, components_map); - ushort sys_id = systems_map.get(Sys.stringof, ushort.max); + ushort sys_id = systems_map.get(cast(char[])Sys.stringof, ushort.max); if (sys_id < systems.length) { system.enable(); @@ -761,7 +815,7 @@ export class EntityManager info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - ushort comp_id = components_map.get(Comp.stringof, ushort.max); + ushort comp_id = components_map.get(cast(char[])Comp.stringof, ushort.max); if (comp_id < components.length) { Comp.component_id = comp_id; @@ -771,7 +825,7 @@ export class EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - const(char)[] name = Mallocator.instance.makeArray(Comp.stringof); + char[] name = Mallocator.instance.makeArray(Comp.stringof); components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -2362,6 +2416,17 @@ export class EntityManager } } + ~this() + { + if(components)Mallocator.instance.dispose(components); + if(deltas)Mallocator.instance.dispose(deltas); + if(tmpl_deltas)Mallocator.instance.dispose(tmpl_deltas); + if(systems)Mallocator.instance.dispose(systems); + if(add_listeners)Mallocator.instance.dispose(add_listeners); + if(remove_listeners)Mallocator.instance.dispose(remove_listeners); + if(change_listeners)Mallocator.instance.dispose(change_listeners); + } + ///entity components ushort[] components; @@ -2498,6 +2563,9 @@ export class EntityManager if (dependencies) { Mallocator.instance.dispose(dependencies); + } + if(exclusion) + { Mallocator.instance.dispose(exclusion); } if (job_group.dependencies) @@ -2526,10 +2594,13 @@ export class EntityManager assert(name); if (name) Mallocator.instance.dispose(name); + foreach(caller; system_callers) + { + Mallocator.instance.dispose(caller); + } + system_callers.clear(); } - export size_t __xtoHash(); - char[] name; Vector!(SystemCaller*) system_callers; } @@ -2558,8 +2629,8 @@ export class EntityManager uint delegate() m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(const(char)[], ushort) systems_map; - HashMap!(const(char)[], ushort) components_map; + HashMap!(char[], ushort) systems_map; + HashMap!(char[], ushort) components_map; HashMap!(const(char)[], ushort) events_map; HashMap!(const(char)[], ushort) passes_map; Vector!System systems; @@ -2578,6 +2649,15 @@ export class EntityManager uint allocated = 0; } + ~this() + { + foreach(block;blocks) + { + Mallocator.instance.dispose(block); + } + blocks.clear(); + } + Vector!(Block*) blocks; uint id; diff --git a/source/ecs/system.d b/source/ecs/system.d index 765c380..e033147 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -97,7 +97,7 @@ package: int m_pass; ///system name - const(char)[] name; + char[] name; ///required components ushort[] m_components; diff --git a/tests/tests.d b/tests/tests.d index 4f68da4..03fcc97 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -141,18 +141,20 @@ struct ChangeTestSystem { //printf("Entity added! ID: "); foreach (i; 0 .. data.length) - printf("Entity added! ID: %u\n",data.entites[i].id.id); - //writeln("Entity added! ID: ", data.entites[i].id.id); + printf("Entity added! ID: %u\n",data.entites[i].id); + //writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { - writeln("Entity removed! ID: ", data.entites[0].id); + //writeln("Entity removed! ID: ", data.entites[0].id); + printf("Entity removed! ID: %u\n",data.entites[0].id); } void onChangeEntity(EntitiesData data) { - writeln("Entity changed! ID: ", data.entites[0].id); + //writeln("Entity changed! ID: ", data.entites[0].id); + printf("Entity changed! ID: %u\n",data.entites[0].id); } bool onBegin() @@ -538,6 +540,7 @@ int main() //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000] + scope(exit)Mallocator.instance.dispose(idss); foreach (i; 0 .. 200) { @@ -568,7 +571,7 @@ int main() //foreach(j; 0..1_000)gEM.addEntity(tmpl); gEM.beginRegister(); - gEM.registerSystem!TestSystem2(0); + //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); //gEM.generateDependencies(); @@ -674,13 +677,16 @@ int main() gEM.removeComponents!(TestComp4)(entity.id); - gEM.commit(); + gEM.commit();//*/ writeEntityComponents(gEM.getEntity(entity.id)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); + gEM.freeTemplate(tmpl2); EntityManager.destroy(); + + return 0; }