Last active
June 27, 2025 23:23
-
-
Save SanderMertens/00cfd8480650d9979109ff465d516f32 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <prefab_storage_tests.h> | |
#include <stdio.h> | |
ECS_COMPONENT_DECLARE(Position); | |
ECS_COMPONENT_DECLARE(Rotation); | |
ECS_COMPONENT_DECLARE(Velocity); | |
ECS_COMPONENT_DECLARE(Transform); | |
ECS_COMPONENT_DECLARE(TransformRef); | |
ECS_COMPONENT_DECLARE(Parent); | |
ECS_COMPONENT_DECLARE(Children); | |
typedef struct Position { | |
float x, y, z; | |
} Position; | |
typedef struct Velocity { | |
float x, y, z; | |
} Velocity; | |
typedef struct Rotation { | |
float x, y, z; | |
} Rotation; | |
typedef struct Transform { | |
mat4 value; | |
} Transform; | |
typedef struct TransformRef { | |
ecs_ref_t value; | |
} TransformRef; | |
typedef struct Parent { | |
ecs_entity_t value; | |
} Parent; | |
typedef struct Children { | |
ecs_entity_t *value; | |
int32_t count; | |
int32_t size; | |
} Children; | |
void Children_reserve(Children *c, int32_t count) { | |
assert(c->size == 0); | |
c->size = count; | |
c->count = 0; | |
c->value = ecs_os_malloc_n(ecs_entity_t, count); | |
} | |
void Children_append(Children *c) { | |
if (c->size == c->count) { | |
if (!c->size) { | |
c->size = 1; | |
} else { | |
c->size *= 2; | |
} | |
c->value = ecs_os_realloc_n(c->value, ecs_entity_t, c->size); | |
} | |
c->count ++; | |
} | |
typedef struct FlattenedSoA { | |
Position *p; | |
Rotation *r; | |
Transform *t; | |
int32_t count, size; | |
} FlattenedSoA; | |
void FlattenedSoA_reserve(FlattenedSoA *f, int32_t count) { | |
assert(f->size == 0); | |
f->size = count; | |
f->count = 0; | |
f->p = ecs_os_malloc_n(Position, count); | |
f->r = ecs_os_malloc_n(Rotation, count); | |
f->t = ecs_os_malloc_n(Transform, count); | |
} | |
void FlattenedSoA_append(FlattenedSoA *f) { | |
if (f->size == f->count) { | |
if (!f->size) { | |
f->size = 1; | |
} else { | |
f->size *= 2; | |
} | |
f->p = ecs_os_realloc_n(f->p, Position, f->size); | |
f->r = ecs_os_realloc_n(f->r, Rotation, f->size); | |
f->t = ecs_os_realloc_n(f->t, Transform, f->size); | |
} | |
f->count ++; | |
} | |
typedef struct FlattenedAoSElem { | |
Position p; | |
Rotation r; | |
Transform t; | |
} FlattenedAoSElem; | |
typedef struct FlattenedAoS { | |
FlattenedAoSElem *v; | |
int32_t count, size; | |
} FlattenedAoS; | |
void FlattenedAoS_reserve(FlattenedAoS *f, int32_t count) { | |
assert(f->size == 0); | |
f->size = count; | |
f->count = 0; | |
f->v = ecs_os_malloc_n(FlattenedAoSElem, count); | |
} | |
void FlattenedAoS_append(FlattenedAoS *f) { | |
if (f->size == f->count) { | |
if (!f->size) { | |
f->size = 1; | |
} else { | |
f->size *= 2; | |
} | |
f->v = ecs_os_realloc_n(f->v, FlattenedAoSElem, f->size); | |
} | |
f->count ++; | |
} | |
int InstanceCount = 20000; | |
int ChildCount = 20; | |
int ChildFragmentationCount = 4; | |
int ChildrenWithGrandChildren = 10; | |
int GrandChildCount = 2; | |
int QuerySampleCount = 20; | |
void fragmenting_dfs(ecs_world_t *world, ecs_entity_t parent, Transform *pt) { | |
ecs_query_t *q = ecs_query(world, { | |
.terms = { | |
{ ecs_childof(parent) }, | |
{ ecs_id(Position) }, | |
{ ecs_id(Rotation) }, | |
{ ecs_id(Transform) } | |
} | |
}); | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 1); | |
Rotation *r = ecs_field(&it, Rotation, 2); | |
Transform *t = ecs_field(&it, Transform, 3); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
if (ecs_table_has_traversable(it.table)) { | |
for (int i = 0; i < it.count; i ++) { | |
fragmenting_dfs(world, it.entities[i], &t[i]); | |
} | |
} | |
} | |
ecs_query_fini(q); | |
} | |
void fragmenting() { | |
ecs_world_t *world = ecs_init(); | |
ECS_COMPONENT_DEFINE(world, Position); | |
ECS_COMPONENT_DEFINE(world, Rotation); | |
ECS_COMPONENT_DEFINE(world, Velocity); | |
ECS_COMPONENT_DEFINE(world, Transform); | |
ECS_COMPONENT_DEFINE(world, TransformRef); | |
ECS_COMPONENT_DEFINE(world, Parent); | |
ECS_COMPONENT_DEFINE(world, Children); | |
ecs_query_t *q_move = ecs_query(world, { | |
.expr = "Position, Velocity", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, ?Transform(cascade)", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q_roots = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, !(ChildOf, *)", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
int child_fragment_ids[ChildFragmentationCount]; | |
for (int i = 0; i < ChildFragmentationCount; i ++) { | |
child_fragment_ids[i] = ecs_new(world); | |
} | |
ecs_time_t t; ecs_time_measure(&t); | |
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform) | |
}, 4); | |
for (int i = 0; i < InstanceCount; i ++) { | |
ecs_entity_t inst = ecs_new_w_table(world, table); | |
ecs_set(world, inst, Position, {i, i, i}); | |
ecs_set(world, inst, Rotation, {0, 0, 0}); | |
ecs_set(world, inst, Velocity, {0, 0, 0}); | |
ecs_table_t *child_table = | |
ecs_table_add_id(world, table, ecs_pair(EcsChildOf, inst)); | |
for (int c = 0; c < ChildCount; c ++) { | |
ecs_entity_t child = ecs_new_w_table(world, child_table); | |
ecs_set(world, child, Position, {c, c, c}); | |
ecs_set(world, child, Rotation, {0, 0, 0}); | |
ecs_set(world, child, Velocity, {0, 0, 0}); | |
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]); | |
if (c < ChildrenWithGrandChildren) { | |
for (int gc = 0; gc < GrandChildCount; gc ++) { | |
ecs_entity_t grandchild = ecs_new_w_table(world, table); | |
ecs_add_pair(world, grandchild, EcsChildOf, child); | |
ecs_set(world, grandchild, Position, {c, c, c}); | |
ecs_set(world, grandchild, Rotation, {0, 0, 0}); | |
ecs_set(world, grandchild, Velocity, {0, 0, 0}); | |
} | |
} | |
} | |
} | |
printf("create: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
Transform *pt = ecs_field(&it, Transform, 3); | |
if (!pt) { | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} else { | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} | |
} | |
} | |
printf("transform (bfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_roots); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
for (int i = 0; i < it.count; i ++) { | |
fragmenting_dfs(world, it.entities[i], &t[i]); | |
} | |
} | |
} | |
printf("transform (dfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_move); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Velocity *v = ecs_field(&it, Velocity, 1); | |
for (int i = 0; i < it.count; i ++) { | |
p[i].x += v[i].x; | |
p[i].y += v[i].y; | |
p[i].z += v[i].z; | |
} | |
} | |
} | |
printf("move: %.3f\n", ecs_time_measure(&t)); | |
ecs_fini(world); | |
} | |
void child_tables_dfs(ecs_world_t *world, ecs_entity_t parent, Transform *pt, Children *parent_children) { | |
for (int i = 0; i < parent_children->count; i ++) { | |
ecs_entity_t child = parent_children->value[i]; | |
Position *p = ecs_get_mut(world, child, Position); | |
Rotation *r = ecs_get_mut(world, child, Rotation); | |
Transform *t = ecs_get_mut(world, child, Transform); | |
glm_translate_to(pt->value, *(vec3*)p, t->value); | |
glm_rotate(t->value, r->x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t->value, r->y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t->value, r->z, (vec3){0.0, 0.0, 1.0}); | |
Children *children = ecs_get_mut(world, child, Children); | |
if (children) { | |
child_tables_dfs(world, child, t, children); | |
} | |
} | |
} | |
void child_tables() { | |
ecs_world_t *world = ecs_init(); | |
ECS_COMPONENT_DEFINE(world, Position); | |
ECS_COMPONENT_DEFINE(world, Rotation); | |
ECS_COMPONENT_DEFINE(world, Velocity); | |
ECS_COMPONENT_DEFINE(world, Transform); | |
ECS_COMPONENT_DEFINE(world, TransformRef); | |
ECS_COMPONENT_DEFINE(world, Parent); | |
ECS_COMPONENT_DEFINE(world, Children); | |
ECS_ENTITY(world, Depth, Exclusive); | |
ECS_TAG(world, Depth0); | |
ECS_TAG(world, Depth1); | |
ECS_TAG(world, Depth2); | |
ecs_entity_t child_kinds[ChildCount + GrandChildCount]; | |
for (int i = 0; i < ChildCount + GrandChildCount; i ++) { | |
child_kinds[i] = ecs_new(world); | |
} | |
int child_fragment_ids[ChildFragmentationCount]; | |
for (int i = 0; i < ChildFragmentationCount; i ++) { | |
child_fragment_ids[i] = ecs_new(world); | |
} | |
ecs_query_t *q_move = ecs_query(world, { | |
.expr = "Position, Velocity", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, ?Parent", | |
.group_by = Depth | |
}); | |
ecs_query_t *q_roots = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, ?Children, !Parent", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_time_t t; ecs_time_measure(&t); | |
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_pair(Depth, Depth0) | |
}, 6); | |
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth1) | |
}, 6); | |
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2) | |
}, 6); | |
for (int i = 0; i < InstanceCount; i ++) { | |
ecs_entity_t inst = ecs_new_w_table(world, table); | |
ecs_set(world, inst, Position, {i, i, i}); | |
ecs_set(world, inst, Rotation, {0, 0, 0}); | |
ecs_set(world, inst, Velocity, {0, 0, 0}); | |
Children *children = ecs_get_mut(world, inst, Children); | |
ecs_os_zeromem(children); | |
Children_reserve(children, ChildCount); | |
for (int c = 0; c < ChildCount; c ++) { | |
ecs_entity_t child = ecs_new_w_table(world, child_table); | |
ecs_set(world, child, Parent, {inst}); | |
ecs_set(world, child, Position, {c, c, c}); | |
ecs_set(world, child, Rotation, {0, 0, 0}); | |
ecs_set(world, child, Velocity, {0, 0, 0}); | |
ecs_add_id(world, child, child_kinds[c]); | |
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]); | |
Children_append(children); | |
children->value[children->count - 1] = child; | |
if (c < ChildrenWithGrandChildren) { | |
Children *gchildren = ecs_ensure(world, child, Children); | |
ecs_os_zeromem(gchildren); | |
Children_reserve(gchildren, GrandChildCount); | |
for (int gc = 0; gc < GrandChildCount; gc ++) { | |
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table); | |
ecs_set(world, grandchild, Parent, {child}); | |
ecs_set(world, grandchild, Position, {c, c, c}); | |
ecs_set(world, grandchild, Rotation, {0, 0, 0}); | |
ecs_set(world, grandchild, Velocity, {0, 0, 0}); | |
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]); | |
Children_append(gchildren); | |
gchildren->value[gchildren->count - 1] = grandchild; | |
} | |
} | |
} | |
} | |
printf("create: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
Parent *parent = ecs_field(&it, Parent, 3); | |
if (!parent) { | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} else { | |
for (int i = 0; i < it.count; i ++) { | |
Transform *pt = ecs_get_mut(world, parent[i].value, Transform); | |
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} | |
} | |
} | |
printf("transform (bfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_roots); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
Children *children = ecs_field(&it, Children, 3); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
if (children) { | |
for (int i = 0; i < it.count; i ++) { | |
child_tables_dfs(world, it.entities[i], &t[i], children); | |
} | |
} | |
} | |
} | |
printf("transform (dfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_move); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Velocity *v = ecs_field(&it, Velocity, 1); | |
for (int i = 0; i < it.count; i ++) { | |
p[i].x += v[i].x; | |
p[i].y += v[i].y; | |
p[i].z += v[i].z; | |
} | |
} | |
} | |
printf("move: %.3f\n", ecs_time_measure(&t)); | |
ecs_fini(world); | |
} | |
void child_tables_w_ref() { | |
ecs_world_t *world = ecs_init(); | |
ECS_COMPONENT_DEFINE(world, Position); | |
ECS_COMPONENT_DEFINE(world, Rotation); | |
ECS_COMPONENT_DEFINE(world, Velocity); | |
ECS_COMPONENT_DEFINE(world, Transform); | |
ECS_COMPONENT_DEFINE(world, TransformRef); | |
ECS_COMPONENT_DEFINE(world, Parent); | |
ECS_COMPONENT_DEFINE(world, Children); | |
ECS_TAG(world, Depth); | |
ECS_TAG(world, Depth0); | |
ECS_TAG(world, Depth1); | |
ECS_TAG(world, Depth2); | |
ecs_entity_t child_kinds[ChildCount + GrandChildCount]; | |
for (int i = 0; i < ChildCount + GrandChildCount; i ++) { | |
child_kinds[i] = ecs_new(world); | |
} | |
int child_fragment_ids[ChildFragmentationCount]; | |
for (int i = 0; i < ChildFragmentationCount; i ++) { | |
child_fragment_ids[i] = ecs_new(world); | |
} | |
ecs_query_t *q_move = ecs_query(world, { | |
.expr = "Position, Velocity", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, ?TransformRef", | |
.group_by = Depth | |
}); | |
ecs_query_t *q_roots = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, ?Children, !Parent", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_time_t t; ecs_time_measure(&t); | |
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_pair(Depth, Depth0) | |
}, 6); | |
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(TransformRef), ecs_id(Parent), ecs_pair(Depth, Depth1) | |
}, 7); | |
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(TransformRef), ecs_id(Parent), ecs_pair(Depth, Depth2) | |
}, 7); | |
for (int i = 0; i < InstanceCount; i ++) { | |
ecs_entity_t inst = ecs_new_w_table(world, table); | |
ecs_set(world, inst, Position, {i, i, i}); | |
ecs_set(world, inst, Rotation, {0, 0, 0}); | |
ecs_set(world, inst, Velocity, {0, 0, 0}); | |
Children *children = ecs_get_mut(world, inst, Children); | |
ecs_os_zeromem(children); | |
Children_reserve(children, ChildCount); | |
ecs_ref_t tr = ecs_ref_init(world, inst, Transform); | |
for (int c = 0; c < ChildCount; c ++) { | |
ecs_entity_t child = ecs_new_w_table(world, child_table); | |
ecs_set(world, child, Parent, {inst}); | |
ecs_set(world, child, Position, {c, c, c}); | |
ecs_set(world, child, Rotation, {0, 0, 0}); | |
ecs_set(world, child, Velocity, {0, 0, 0}); | |
ecs_set(world, child, TransformRef, {tr}); | |
ecs_add_id(world, child, child_kinds[c]); | |
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]); | |
ecs_ref_t tr_child = ecs_ref_init(world, inst, Transform); | |
Children_append(children); | |
children->value[children->count - 1] = child; | |
if (c < ChildrenWithGrandChildren) { | |
Children *gchildren = ecs_ensure(world, child, Children); | |
ecs_os_zeromem(gchildren); | |
Children_reserve(gchildren, GrandChildCount); | |
for (int gc = 0; gc < GrandChildCount; gc ++) { | |
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table); | |
ecs_set(world, grandchild, Parent, {child}); | |
ecs_set(world, grandchild, Position, {c, c, c}); | |
ecs_set(world, grandchild, Rotation, {0, 0, 0}); | |
ecs_set(world, grandchild, Velocity, {0, 0, 0}); | |
ecs_set(world, grandchild, TransformRef, {tr_child}); | |
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]); | |
Children_append(gchildren); | |
gchildren->value[gchildren->count - 1] = grandchild; | |
} | |
} | |
} | |
} | |
printf("create: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
TransformRef *pt_ref = ecs_field(&it, TransformRef, 3); | |
if (!pt_ref) { | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} else { | |
for (int i = 0; i < it.count; i ++) { | |
Transform *pt = ecs_ref_get(world, &pt_ref->value, Transform); | |
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} | |
} | |
} | |
printf("transform (bfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_roots); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
Children *children = ecs_field(&it, Children, 3); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
if (children) { | |
for (int i = 0; i < it.count; i ++) { | |
child_tables_dfs(world, it.entities[i], &t[i], children); | |
} | |
} | |
} | |
} | |
printf("transform (dfs): %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_move); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Velocity *v = ecs_field(&it, Velocity, 1); | |
for (int i = 0; i < it.count; i ++) { | |
p[i].x += v[i].x; | |
p[i].y += v[i].y; | |
p[i].z += v[i].z; | |
} | |
} | |
} | |
printf("move: %.3f\n", ecs_time_measure(&t)); | |
ecs_fini(world); | |
} | |
void child_tables_flattened_soa() { | |
ecs_world_t *world = ecs_init(); | |
ECS_COMPONENT(world, Position); | |
ECS_COMPONENT(world, Rotation); | |
ECS_COMPONENT(world, Velocity); | |
ECS_COMPONENT(world, Transform); | |
ECS_COMPONENT(world, Parent); | |
ECS_COMPONENT(world, Children); | |
ECS_COMPONENT(world, FlattenedSoA); | |
ECS_TAG(world, Depth); | |
ECS_TAG(world, Depth0); | |
ECS_TAG(world, Depth1); | |
ECS_TAG(world, Depth2); | |
ecs_entity_t child_kinds[ChildCount + GrandChildCount]; | |
for (int i = 0; i < ChildCount + GrandChildCount; i ++) { | |
child_kinds[i] = ecs_new(world); | |
} | |
int child_fragment_ids[ChildFragmentationCount]; | |
for (int i = 0; i < ChildFragmentationCount; i ++) { | |
child_fragment_ids[i] = ecs_new(world); | |
} | |
ecs_query_t *q_move = ecs_query(world, { | |
.expr = "Position, Velocity", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, FlattenedSoA", | |
.group_by = Depth | |
}); | |
ecs_time_t t; ecs_time_measure(&t); | |
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_id(FlattenedSoA), ecs_pair(Depth, Depth0) | |
}, 6); | |
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth1) | |
}, 6); | |
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2) | |
}, 6); | |
for (int i = 0; i < InstanceCount; i ++) { | |
ecs_entity_t inst = ecs_new_w_table(world, table); | |
ecs_set(world, inst, Position, {i, i, i}); | |
ecs_set(world, inst, Rotation, {0, 0, 0}); | |
ecs_set(world, inst, Velocity, {0, 0, 0}); | |
Children *children = ecs_get_mut(world, inst, Children); | |
ecs_os_zeromem(children); | |
Children_reserve(children, ChildCount); | |
FlattenedSoA *f = ecs_get_mut(world, inst, FlattenedSoA); | |
ecs_os_zeromem(f); | |
FlattenedSoA_reserve(f, ChildCount); | |
for (int c = 0; c < ChildCount; c ++) { | |
ecs_entity_t child = ecs_new_w_table(world, child_table); | |
ecs_set(world, child, Parent, {inst}); | |
ecs_set(world, child, Position, {c, c, c}); | |
ecs_set(world, child, Rotation, {0, 0, 0}); | |
ecs_set(world, child, Velocity, {0, 0, 0}); | |
ecs_add_id(world, child, child_kinds[c]); | |
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]); | |
Children_append(children); | |
children->value[children->count - 1] = child; | |
FlattenedSoA_append(f); | |
f->p[f->count - 1] = (Position){i, i, i}; | |
f->r[f->count - 1] = (Rotation){0, 0, 0}; | |
if (c < ChildrenWithGrandChildren) { | |
Children *gchildren = ecs_ensure(world, child, Children); | |
ecs_os_zeromem(gchildren); | |
Children_reserve(gchildren, GrandChildCount); | |
for (int gc = 0; gc < GrandChildCount; gc ++) { | |
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table); | |
ecs_set(world, child, Parent, {child}); | |
ecs_set(world, grandchild, Position, {c, c, c}); | |
ecs_set(world, grandchild, Rotation, {0, 0, 0}); | |
ecs_set(world, grandchild, Velocity, {0, 0, 0}); | |
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]); | |
Children_append(gchildren); | |
gchildren->value[gchildren->count - 1] = grandchild; | |
FlattenedSoA_append(f); | |
f->p[f->count - 1] = (Position){i, i, i}; | |
f->r[f->count - 1] = (Rotation){0, 0, 0}; | |
} | |
} | |
} | |
} | |
printf("create: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
FlattenedSoA *f = ecs_field(&it, FlattenedSoA, 3); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
for (int i = 0; i < it.count; i ++) { | |
for (int c = 0; c < f->count; c ++) { | |
glm_translate_to(t[i].value, *(vec3*)&f[i].p[c], f[i].t[c].value); | |
glm_rotate(f[i].t[c].value, f[i].r[c].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(f[i].t[c].value, f[i].r[c].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(f[i].t[c].value, f[i].r[c].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} | |
} | |
} | |
printf("transform: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_move); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Velocity *v = ecs_field(&it, Velocity, 1); | |
for (int i = 0; i < it.count; i ++) { | |
p[i].x += v[i].x; | |
p[i].y += v[i].y; | |
p[i].z += v[i].z; | |
} | |
} | |
} | |
printf("move: %.3f\n", ecs_time_measure(&t)); | |
ecs_fini(world); | |
} | |
void child_tables_flattened_aos() { | |
ecs_world_t *world = ecs_init(); | |
ECS_COMPONENT(world, Position); | |
ECS_COMPONENT(world, Rotation); | |
ECS_COMPONENT(world, Velocity); | |
ECS_COMPONENT(world, Transform); | |
ECS_COMPONENT(world, Parent); | |
ECS_COMPONENT(world, Children); | |
ECS_COMPONENT(world, FlattenedAoS); | |
ECS_TAG(world, Depth); | |
ECS_TAG(world, Depth0); | |
ECS_TAG(world, Depth1); | |
ECS_TAG(world, Depth2); | |
ecs_entity_t child_kinds[ChildCount + GrandChildCount]; | |
for (int i = 0; i < ChildCount + GrandChildCount; i ++) { | |
child_kinds[i] = ecs_new(world); | |
} | |
int child_fragment_ids[ChildFragmentationCount]; | |
for (int i = 0; i < ChildFragmentationCount; i ++) { | |
child_fragment_ids[i] = ecs_new(world); | |
} | |
ecs_query_t *q_move = ecs_query(world, { | |
.expr = "Position, Velocity", | |
.cache_kind = EcsQueryCacheAuto | |
}); | |
ecs_query_t *q = ecs_query(world, { | |
.expr = "Position, Rotation, Transform, FlattenedAoS", | |
.group_by = Depth | |
}); | |
ecs_time_t t; ecs_time_measure(&t); | |
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_id(FlattenedAoS), ecs_pair(Depth, Depth0) | |
}, 6); | |
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_id(Children), ecs_pair(Depth, Depth1) | |
}, 6); | |
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){ | |
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2) | |
}, 6); | |
for (int i = 0; i < InstanceCount; i ++) { | |
ecs_entity_t inst = ecs_new_w_table(world, table); | |
ecs_set(world, inst, Position, {i, i, i}); | |
ecs_set(world, inst, Rotation, {0, 0, 0}); | |
ecs_set(world, inst, Velocity, {0, 0, 0}); | |
ecs_add_pair(world, inst, Depth, Depth0); | |
Children *children = ecs_get_mut(world, inst, Children); | |
ecs_os_zeromem(children); | |
Children_reserve(children, ChildCount); | |
FlattenedAoS *f = ecs_get_mut(world, inst, FlattenedAoS); | |
ecs_os_zeromem(f); | |
FlattenedAoS_reserve(f, ChildCount); | |
for (int c = 0; c < ChildCount; c ++) { | |
ecs_entity_t child = ecs_new_w_table(world, child_table); | |
ecs_set(world, child, Parent, {inst}); | |
ecs_set(world, child, Position, {c, c, c}); | |
ecs_set(world, child, Rotation, {0, 0, 0}); | |
ecs_set(world, child, Velocity, {0, 0, 0}); | |
ecs_add_id(world, child, child_kinds[c]); | |
ecs_add_pair(world, child, Depth, Depth1); | |
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]); | |
Children_append(children); | |
children->value[children->count - 1] = child; | |
FlattenedAoS_append(f); | |
f->v[f->count - 1].p = (Position){i, i, i}; | |
f->v[f->count - 1].r = (Rotation){0, 0, 0}; | |
if (c < ChildrenWithGrandChildren) { | |
Children *gchildren = ecs_ensure(world, child, Children); | |
ecs_os_zeromem(gchildren); | |
Children_reserve(gchildren, GrandChildCount); | |
for (int gc = 0; gc < GrandChildCount; gc ++) { | |
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table); | |
ecs_set(world, child, Parent, {child}); | |
ecs_set(world, grandchild, Position, {c, c, c}); | |
ecs_set(world, grandchild, Rotation, {0, 0, 0}); | |
ecs_set(world, grandchild, Velocity, {0, 0, 0}); | |
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]); | |
Children_append(gchildren); | |
gchildren->value[gchildren->count - 1] = grandchild; | |
FlattenedAoS_append(f); | |
f->v[f->count - 1].p = (Position){i, i, i}; | |
f->v[f->count - 1].r = (Rotation){0, 0, 0}; | |
} | |
} | |
} | |
} | |
printf("create: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Rotation *r = ecs_field(&it, Rotation, 1); | |
Transform *t = ecs_field(&it, Transform, 2); | |
FlattenedAoS *f = ecs_field(&it, FlattenedAoS, 3); | |
for (int i = 0; i < it.count; i ++) { | |
glm_translate_make(t[i].value, *(vec3*)&p[i]); | |
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0}); | |
} | |
for (int i = 0; i < it.count; i ++) { | |
for (int c = 0; c < f->count; c ++) { | |
glm_translate_to(t[i].value, *(vec3*)&f[i].v[c].p, f[i].v[c].t.value); | |
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.x, (vec3){1.0, 0.0, 0.0}); | |
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.y, (vec3){0.0, 1.0, 0.0}); | |
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.z, (vec3){0.0, 0.0, 1.0}); | |
} | |
} | |
} | |
} | |
printf("transform: %.3f\n", ecs_time_measure(&t)); | |
for (int x = 0; x < QuerySampleCount; x ++) { | |
ecs_iter_t it = ecs_query_iter(world, q_move); | |
while (ecs_query_next(&it)) { | |
Position *p = ecs_field(&it, Position, 0); | |
Velocity *v = ecs_field(&it, Velocity, 1); | |
for (int i = 0; i < it.count; i ++) { | |
p[i].x += v[i].x; | |
p[i].y += v[i].y; | |
p[i].z += v[i].z; | |
} | |
} | |
} | |
printf("move: %.3f\n", ecs_time_measure(&t)); | |
ecs_fini(world); | |
} | |
int main(int argc, char *argv[]) { | |
printf("Instances: %d, Children: %d, ChildrenWithGrandChildren: %d, GrandChildren: %d, ChildTables: %d\n", | |
InstanceCount, ChildCount, ChildrenWithGrandChildren, GrandChildCount, ChildFragmentationCount); | |
printf("\nFragmenting:\n===\n"); | |
fragmenting(); | |
printf("\nChild tables (get_mut<Transform>()):\n===\n"); | |
child_tables(); | |
printf("\nChild tables (ref_get<Transform>()):\n===\n"); | |
child_tables_w_ref(); | |
printf("\nChild tables (flattened SoA transform):\n===\n"); | |
child_tables_flattened_soa(); | |
printf("\nChild tables (flattened AoS transform):\n===\n"); | |
child_tables_flattened_aos(); | |
} | |
// Instances: 20000, Children: 20, ChildrenWithGrandChildren: 10, GrandChildren: 2, ChildTables: 4 | |
// Fragmenting: | |
// === | |
// create: 0.586 | |
// transform (bfs): 0.474 | |
// transform (dfs): 2.914 | |
// move: 0.157 | |
// Child tables (get_mut<Transform>()): | |
// === | |
// create: 0.102 | |
// transform (bfs): 0.172 | |
// transform (dfs): 0.316 | |
// move: 0.004 | |
// Child tables (ref_get<Transform>()): | |
// === | |
// create: 0.119 | |
// transform (bfs): 0.129 | |
// transform (dfs): 0.359 | |
// move: 0.004 | |
// Child tables (flattened SoA transform): | |
// === | |
// create: 0.115 | |
// transform: 0.122 | |
// move: 0.004 | |
// Child tables (flattened AoS transform): | |
// === | |
// create: 0.119 | |
// transform: 0.110 | |
// move: 0.004 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment