From 13e6ed8fd529f62518abb1408e701da95a844693 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Jun 2020 22:26:59 +0200 Subject: [PATCH] ECS core imprevement -Adedd function to resize array to Mallocator -significant speed up for first time ID allocation by using resizeArray instead of makeArray -fix: onUpdate called with zero length arrays -call updateBlocks before updateEvents (it's more accurate behaviour) -some minore fixes -fixed meson.build for GDC --- meson.build | 4 +-- source/bubel/ecs/id_manager.d | 10 ++---- source/bubel/ecs/manager.d | 61 ++++++++++++++++++++--------------- source/bubel/ecs/std.d | 44 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 36 deletions(-) diff --git a/meson.build b/meson.build index 94b9c64..2a71fc7 100644 --- a/meson.build +++ b/meson.build @@ -52,8 +52,8 @@ endif if betterC_opt if comp_id == 'gcc' - args += ['-flto','-fno-druntime'] - link_args += ['-flto','-fno-druntime'] + args += ['-fno-druntime'] + link_args += ['-fno-druntime'] else args += '-betterC' link_args += '-betterC' diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index db15b26..86a611e 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -177,15 +177,9 @@ struct IDManager if (m_last_id > m_ids_array.length) { uint begin = cast(uint) m_ids_array.length; - Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16)); - memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); - Mallocator.dispose(m_ids_array); - m_ids_array = new_array; - uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); - memcpy(new_stack.ptr, m_free_stack.ptr, m_free_stack.length * uint.sizeof); - Mallocator.dispose(m_free_stack); - m_free_stack = new_stack; + m_ids_array = Mallocator.resizeArray(m_ids_array, begin + (m_blocks_count << 16)); + m_free_stack = Mallocator.resizeArray(m_free_stack, m_ids_array.length); foreach (block; m_blocks[0 .. m_blocks_count - 1]) { diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 19068cb..4c543ce 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -456,7 +456,7 @@ export struct EntityManager uint writable_dep = 1; } - static ComponentsCounts getComponentsCounts()() + static ComponentsCounts getComponentsCounts() { ComponentsCounts components_counts; @@ -679,7 +679,7 @@ export struct EntityManager } - static ComponentsIndices!component_counts getComponentsInfo()() + static ComponentsIndices!component_counts getComponentsInfo() { ComponentsIndices!component_counts components_info; @@ -786,7 +786,7 @@ export struct EntityManager enum ComponentsIndices!component_counts components_info = getComponentsInfo(); - static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) + static void genCompList(ref System system, ref HashMap!(char[], ushort) components_map) { foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -885,7 +885,7 @@ export struct EntityManager } } - static void fillInputData()(ref Sys.EntitiesData input_data, EntityInfo* info, + static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); @@ -907,7 +907,8 @@ export struct EntityManager }//*/ ///FIXME: should be "components_info.req()" but it's not compile with GCC - static foreach (iii, comp_info; components_info.m_req[0 .. components_info.m_req_counter]) + static foreach (iii, comp_info; components_info.m_req[0 + .. components_info.m_req_counter]) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)( @@ -915,7 +916,8 @@ export struct EntityManager .. entities_count]; } - static foreach (iii, comp_info; components_info.m_optional[0 .. components_info.m_optional_counter]) + static foreach (iii, comp_info; components_info.m_optional[0 + .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) @@ -929,7 +931,7 @@ export struct EntityManager } } - /*bool checkOnUpdateParams()() + /*bool checkOnUpdateParams() { bool ret = false; foreach (func; __traits(getOverloads, Sys, "onUpdate")) @@ -1006,26 +1008,29 @@ export struct EntityManager else entities_count = block.entities_count; - assert(entities_count <= block.entities_count - && offset <= block.entities_count); - - fillInputData(input_data, info, block, offset, entities_count, system); - - static if (hasMember!(Sys.EntitiesData, "thread_id")) + if (entities_count > 0) { - input_data.thread_id = cast(typeof(input_data.thread_id)) data - .thread_id; + assert(entities_count <= block.entities_count + && offset <= block.entities_count); + + fillInputData(input_data, info, block, offset, entities_count, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast( + typeof(input_data.thread_id)) data.thread_id; + } + + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( + input_data); } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - //s.onUpdate(input_data); - (cast(typeof(&__traits(getOverloads, s, - "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); - block = block.next_block; offset = 0; blocks--; @@ -1339,10 +1344,12 @@ export struct EntityManager export void callEntitiesFunction(Sys, T)(T func) { + //TODO: check if onUpdate function is good Sys* s; static assert(isDelegate!func, "Function must be delegate."); static assert(__traits(hasMember, Sys, "EntitiesData"), "Can't call function with system which hasn't EntitesData structure."); + ///TODO: make possibly to call function to group without system with onUpdate function static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), @@ -1353,6 +1360,8 @@ export struct EntityManager System* system = getSystem(Sys.system_id); assert(system != null, "System must be registered in EntityManager before any funcion can be called."); + if (!system.m_any_system_caller) + return; foreach (info; system.m_any_system_caller.infos) { @@ -3101,7 +3110,7 @@ export struct EntityManager swapData(); has_work = false; - // has_work |= updateBlocks(); + has_work |= updateBlocks(); // has_work |= changeEntities(); // has_work |= removeEntities(); has_work |= updateEvents(); diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index cac07b2..38ad0d8 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -152,6 +152,50 @@ else static struct Mallocator { + static T[] resizeArray(T)(T[] array, size_t length) nothrow @nogc + { + T[] ret; + + if(length > array.length) + { + ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; + static if (__traits(isPOD, T)) + { + __gshared immutable T init = T.init; + + foreach (i; array.length .. ret.length) + { + memcpy(&ret[i], &init, T.sizeof); + } + } + else + { + static import std.conv; + + foreach (i; array.length .. ret.length) + { + std.conv.emplace(&ret[i]); + } + } + } + else + { + static if (__traits(hasMember, T, "__xdtor")) + foreach (i; length .. array.length) + { + array[i].__xdtor(); + } + else static if (__traits(hasMember, T, "__dtor")) + foreach (i; length .. array.length) + { + array[i].__dtor(); + } + ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; + } + + return ret; + } + static T[] makeArray(T)(size_t length) nothrow @nogc { T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];