stageobjects,objectpool: simplify and reimplement on top of arenas
All pools now allocate from the same arena that is initialized once with 8MB of initial space and never deallocated, only reset between stages.
This commit is contained in:
parent
66e5a886f0
commit
df6b97caf7
16 changed files with 147 additions and 345 deletions
|
@ -186,13 +186,6 @@ option(
|
|||
description : 'Build the no-op audio backend (silence); you want this on!'
|
||||
)
|
||||
|
||||
option(
|
||||
'objpools',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
description : 'Pre-allocate memory for game objects (disable for debugging only)'
|
||||
)
|
||||
|
||||
option(
|
||||
'use_libcrypto',
|
||||
type : 'feature',
|
||||
|
|
|
@ -38,7 +38,7 @@ static void calc_spell_bonus(Attack *a, SpellBonus *bonus);
|
|||
DECLARE_TASK(boss_particles, { BoxedBoss boss; });
|
||||
|
||||
Boss *create_boss(char *name, char *ani, cmplx pos) {
|
||||
Boss *boss = objpool_acquire(stage_object_pools.bosses);
|
||||
Boss *boss = objpool_acquire(&stage_object_pools.bosses);
|
||||
|
||||
boss->name = strdup(name);
|
||||
boss->pos = pos;
|
||||
|
@ -1364,7 +1364,7 @@ void free_boss(Boss *boss) {
|
|||
boss_set_portrait(boss, NULL, NULL, NULL);
|
||||
aniplayer_free(&boss->ani);
|
||||
mem_free(boss->name);
|
||||
objpool_release(stage_object_pools.bosses, boss);
|
||||
objpool_release(&stage_object_pools.bosses, boss);
|
||||
}
|
||||
|
||||
static void boss_schedule_next_attack(Boss *b, Attack *a) {
|
||||
|
|
|
@ -88,7 +88,7 @@ Enemy *create_enemy_p(EnemyList *enemies, cmplx pos, float hp, EnemyVisualRule v
|
|||
log_fatal("Tried to spawn an enemy while in drawing code");
|
||||
}
|
||||
|
||||
Enemy *e = alist_append(enemies, (Enemy*)objpool_acquire(stage_object_pools.enemies));
|
||||
Enemy *e = alist_append(enemies, (Enemy*)objpool_acquire(&stage_object_pools.enemies));
|
||||
e->moving = false;
|
||||
e->dir = 0;
|
||||
e->birthtime = global.frames;
|
||||
|
@ -167,7 +167,7 @@ static void *_delete_enemy(ListAnchor *enemies, List* enemy, void *arg) {
|
|||
|
||||
COEVENT_CANCEL_ARRAY(e->events);
|
||||
ent_unregister(&e->ent);
|
||||
objpool_release(stage_object_pools.enemies, alist_unlink(enemies, enemy));
|
||||
objpool_release(&stage_object_pools.enemies, alist_unlink(enemies, enemy));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ Item* create_item(cmplx pos, cmplx v, ItemType type) {
|
|||
type = ITEM_SURGE;
|
||||
}
|
||||
|
||||
Item *i = (Item*)objpool_acquire(stage_object_pools.items);
|
||||
Item *i = objpool_acquire(&stage_object_pools.items);
|
||||
alist_append(&global.items, i);
|
||||
|
||||
i->pos = pos;
|
||||
|
@ -137,7 +137,7 @@ Item* create_item(cmplx pos, cmplx v, ItemType type) {
|
|||
|
||||
void delete_item(Item *item) {
|
||||
ent_unregister(&item->ent);
|
||||
objpool_release(stage_object_pools.items, alist_unlink(&global.items, item));
|
||||
objpool_release(&stage_object_pools.items, alist_unlink(&global.items, item));
|
||||
}
|
||||
|
||||
Item *create_clear_item(cmplx pos, uint clear_flags) {
|
||||
|
|
|
@ -43,7 +43,7 @@ Laser *create_laser(
|
|||
LaserPosRule prule,
|
||||
cmplx a0, cmplx a1, cmplx a2, cmplx a3
|
||||
) {
|
||||
Laser *l = objpool_acquire(stage_object_pools.lasers);
|
||||
Laser *l = objpool_acquire(&stage_object_pools.lasers);
|
||||
alist_push(&global.lasers, l);
|
||||
|
||||
l->birthtime = global.frames;
|
||||
|
@ -98,7 +98,7 @@ void laserline_set_posdir(Laser *l, cmplx pos, cmplx dir) {
|
|||
static void *_delete_laser(ListAnchor *lasers, List *laser, void *arg) {
|
||||
Laser *l = (Laser*)laser;
|
||||
ent_unregister(&l->ent);
|
||||
objpool_release(stage_object_pools.lasers, alist_unlink(lasers, laser));
|
||||
objpool_release(&stage_object_pools.lasers, alist_unlink(lasers, laser));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ static void taisei_shutdown(void) {
|
|||
|
||||
progress_unload();
|
||||
|
||||
stage_objpools_shutdown();
|
||||
gamemode_shutdown();
|
||||
shutdown_resources();
|
||||
taskmgr_global_shutdown();
|
||||
|
|
|
@ -78,6 +78,7 @@ taisei_src = files(
|
|||
'log.c',
|
||||
'main.c',
|
||||
'move.c',
|
||||
'objectpool.c',
|
||||
'player.c',
|
||||
'plrmodes.c',
|
||||
'portrait.c',
|
||||
|
@ -106,16 +107,6 @@ if is_developer_build
|
|||
)
|
||||
endif
|
||||
|
||||
if get_option('objpools')
|
||||
taisei_src += files(
|
||||
'objectpool.c',
|
||||
)
|
||||
else
|
||||
taisei_src += files(
|
||||
'objectpool_fake.c',
|
||||
)
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'nx'
|
||||
taisei_src += files(
|
||||
'arch_switch.c',
|
||||
|
|
210
src/objectpool.c
210
src/objectpool.c
|
@ -11,204 +11,48 @@
|
|||
#include "objectpool.h"
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#include "memory/arena.h"
|
||||
|
||||
typedef struct ObjHeader {
|
||||
alignas(alignof(max_align_t)) struct ObjHeader *next;
|
||||
} ObjHeader;
|
||||
|
||||
struct ObjectPool {
|
||||
char *tag;
|
||||
size_t size_of_object;
|
||||
size_t max_objects;
|
||||
#ifdef OBJPOOL_TRACK_STATS
|
||||
size_t usage;
|
||||
size_t peak_usage;
|
||||
#endif
|
||||
size_t num_extents;
|
||||
char **extents;
|
||||
ObjHeader *free_objects;
|
||||
char objects[];
|
||||
};
|
||||
|
||||
INLINE attr_returns_max_aligned
|
||||
ObjHeader *obj_ptr(ObjectPool *pool, char *objects, size_t idx) {
|
||||
return CASTPTR_ASSUME_ALIGNED(objects + idx * pool->size_of_object, ObjHeader);
|
||||
}
|
||||
|
||||
static void objpool_register_objects(ObjectPool *pool, char *objects) {
|
||||
for(size_t i = 0; i < pool->max_objects; ++i) {
|
||||
ObjHeader *o = obj_ptr(pool, objects, i);
|
||||
o->next = pool->free_objects;
|
||||
pool->free_objects = o;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectPool *objpool_alloc(size_t obj_size, size_t max_objects, const char *tag) {
|
||||
// TODO: overflow handling
|
||||
|
||||
auto pool = ALLOC_FLEX(ObjectPool, obj_size * max_objects);
|
||||
pool->size_of_object = obj_size;
|
||||
pool->max_objects = max_objects;
|
||||
pool->tag = strdup(tag);
|
||||
|
||||
objpool_register_objects(pool, pool->objects);
|
||||
|
||||
log_debug("[%s] Allocated pool for %zu objects, %zu bytes each",
|
||||
pool->tag,
|
||||
pool->max_objects,
|
||||
pool->size_of_object
|
||||
);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static char *objpool_add_extent(ObjectPool *pool) {
|
||||
pool->extents = mem_realloc(pool->extents, (++pool->num_extents) * sizeof(*pool->extents));
|
||||
char *extent = pool->extents[pool->num_extents - 1] = mem_alloc_array(pool->max_objects, pool->size_of_object);
|
||||
objpool_register_objects(pool, extent);
|
||||
return extent;
|
||||
}
|
||||
|
||||
static char* objpool_fmt_size(ObjectPool *pool) {
|
||||
switch(pool->num_extents) {
|
||||
case 0:
|
||||
return strfmt("%zu objects, %zu bytes each",
|
||||
pool->max_objects,
|
||||
pool->size_of_object
|
||||
);
|
||||
|
||||
case 1:
|
||||
return strfmt("%zu objects, %zu bytes each, with 1 extent",
|
||||
pool->max_objects * 2,
|
||||
pool->size_of_object
|
||||
);
|
||||
|
||||
default:
|
||||
return strfmt("%zu objects, %zu bytes each, with %zu extents",
|
||||
pool->max_objects * (1 + pool->num_extents),
|
||||
pool->size_of_object,
|
||||
pool->num_extents
|
||||
);
|
||||
}
|
||||
void objpool_init(
|
||||
ObjectPool *pool,
|
||||
const char *tag,
|
||||
MemArena *arena,
|
||||
size_t obj_size,
|
||||
size_t obj_align
|
||||
) {
|
||||
*pool = (ObjectPool) {
|
||||
.arena = arena,
|
||||
.obj_size = obj_size,
|
||||
.obj_align = obj_align,
|
||||
.tag = tag,
|
||||
};
|
||||
}
|
||||
|
||||
void *objpool_acquire(ObjectPool *pool) {
|
||||
ObjHeader *obj = pool->free_objects;
|
||||
|
||||
if(obj) {
|
||||
acquired:
|
||||
assert(pool->num_used < pool->num_allocated);
|
||||
pool->free_objects = obj->next;
|
||||
memset(obj, 0, pool->size_of_object);
|
||||
|
||||
#ifdef OBJPOOL_TRACK_STATS
|
||||
if(++pool->usage > pool->peak_usage) {
|
||||
pool->peak_usage = pool->usage;
|
||||
}
|
||||
#endif
|
||||
|
||||
return obj;
|
||||
} else {
|
||||
assert(pool->num_used == pool->num_allocated);
|
||||
obj = marena_alloc_aligned(pool->arena, pool->obj_size, pool->obj_align);
|
||||
++pool->num_allocated;
|
||||
}
|
||||
|
||||
char *tmp = objpool_fmt_size(pool);
|
||||
log_debug("[%s] Object pool exhausted (%s), extending",
|
||||
pool->tag,
|
||||
tmp
|
||||
);
|
||||
mem_free(tmp);
|
||||
memset(obj, 0, pool->obj_size);
|
||||
++pool->num_used;
|
||||
|
||||
objpool_add_extent(pool);
|
||||
obj = pool->free_objects;
|
||||
assert(obj != NULL);
|
||||
goto acquired;
|
||||
assert(pool->num_used <= pool->num_allocated);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void objpool_release(ObjectPool *pool, void *object) {
|
||||
objpool_memtest(pool, object);
|
||||
ObjHeader *obj = object;
|
||||
obj->next = pool->free_objects;
|
||||
pool->free_objects = obj;
|
||||
#ifdef OBJPOOL_TRACK_STATS
|
||||
pool->usage--;
|
||||
#endif
|
||||
|
||||
--pool->num_used;
|
||||
assert(pool->num_used >= 0);
|
||||
assert(pool->num_used <= pool->num_allocated);
|
||||
}
|
||||
|
||||
void objpool_free(ObjectPool *pool) {
|
||||
#ifdef OBJPOOL_TRACK_STATS
|
||||
if(pool->usage != 0) {
|
||||
log_warn("[%s] %zu objects still in use", pool->tag, pool->usage);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(size_t i = 0; i < pool->num_extents; ++i) {
|
||||
mem_free(pool->extents[i]);
|
||||
}
|
||||
|
||||
mem_free(pool->extents);
|
||||
mem_free(pool->tag);
|
||||
mem_free(pool);
|
||||
}
|
||||
|
||||
size_t objpool_object_size(ObjectPool *pool) {
|
||||
return pool->size_of_object;
|
||||
}
|
||||
|
||||
void objpool_get_stats(ObjectPool *pool, ObjectPoolStats *stats) {
|
||||
stats->tag = pool->tag;
|
||||
stats->capacity = pool->max_objects * (1 + pool->num_extents);
|
||||
#ifdef OBJPOOL_TRACK_STATS
|
||||
stats->usage = pool->usage;
|
||||
stats->peak_usage = pool->peak_usage;
|
||||
#else
|
||||
stats->usage = 0;
|
||||
stats->peak_usage = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
attr_unused
|
||||
static bool objpool_object_in_subpool(ObjectPool *pool, ObjHeader *object, char *objects) {
|
||||
char *objofs = (char*)object;
|
||||
char *minofs = objects;
|
||||
char *maxofs = objects + (pool->max_objects - 1) * pool->size_of_object;
|
||||
|
||||
if(objofs < minofs || objofs > maxofs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ptrdiff_t misalign = (ptrdiff_t)(objofs - objects) % pool->size_of_object;
|
||||
|
||||
if(misalign) {
|
||||
log_fatal("[%s] Object pointer %p is misaligned by %zi",
|
||||
pool->tag,
|
||||
(void*)objofs,
|
||||
(ssize_t)misalign
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
attr_unused
|
||||
static bool objpool_object_in_pool(ObjectPool *pool, ObjHeader *object) {
|
||||
if(objpool_object_in_subpool(pool, object, pool->objects)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < pool->num_extents; ++i) {
|
||||
if(objpool_object_in_subpool(pool, object, pool->extents[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef OBJPOOL_DEBUG
|
||||
void objpool_memtest(ObjectPool *pool, void *object) {
|
||||
if(!objpool_object_in_pool(pool, object)) {
|
||||
log_fatal("[%s] Object pointer %p does not belong to this pool",
|
||||
pool->tag,
|
||||
object
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,40 +10,35 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define OBJPOOL_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef OBJPOOL_DEBUG
|
||||
#define OBJPOOL_TRACK_STATS
|
||||
#define IF_OBJPOOL_DEBUG(code) code
|
||||
#else
|
||||
#define IF_OBJPOOL_DEBUG(code)
|
||||
#endif
|
||||
#include "memory/arena.h"
|
||||
|
||||
typedef struct ObjectPool ObjectPool;
|
||||
typedef struct ObjectPoolStats ObjectPoolStats;
|
||||
|
||||
struct ObjectPoolStats {
|
||||
typedef struct ObjHeader {
|
||||
alignas(alignof(max_align_t)) struct ObjHeader *next;
|
||||
} ObjHeader;
|
||||
|
||||
struct ObjectPool {
|
||||
MemArena *arena;
|
||||
ObjHeader *free_objects;
|
||||
const char *tag;
|
||||
size_t capacity;
|
||||
size_t usage;
|
||||
size_t peak_usage;
|
||||
size_t obj_size;
|
||||
size_t obj_align;
|
||||
int num_allocated;
|
||||
int num_used;
|
||||
};
|
||||
|
||||
#define OBJPOOL_ALLOC(typename,max_objects) objpool_alloc(sizeof(typename), max_objects, #typename)
|
||||
#define OBJPOOL_ACQUIRE(pool, type) CASTPTR_ASSUME_ALIGNED(objpool_acquire(pool), type)
|
||||
void objpool_init(
|
||||
ObjectPool *pool,
|
||||
const char *tag,
|
||||
MemArena *arena,
|
||||
size_t obj_size,
|
||||
size_t obj_align
|
||||
) attr_nonnull(1, 2, 3);
|
||||
|
||||
ObjectPool *objpool_alloc(size_t obj_size, size_t max_objects, const char *tag) attr_returns_allocated attr_nonnull(3);
|
||||
void objpool_free(ObjectPool *pool) attr_nonnull(1);
|
||||
void *objpool_acquire(ObjectPool *pool) attr_returns_allocated attr_hot attr_nonnull(1);
|
||||
void objpool_release(ObjectPool *pool, void *object) attr_hot attr_nonnull(1, 2);
|
||||
void objpool_get_stats(ObjectPool *pool, ObjectPoolStats *stats) attr_nonnull(1, 2);
|
||||
size_t objpool_object_size(ObjectPool *pool) attr_nonnull(1);
|
||||
void *objpool_acquire(ObjectPool *pool)
|
||||
attr_returns_allocated attr_hot attr_nonnull(1);
|
||||
|
||||
#ifdef OBJPOOL_DEBUG
|
||||
void objpool_memtest(ObjectPool *pool, void *object) attr_nonnull(1, 2);
|
||||
#else
|
||||
#define objpool_memtest(pool, object) ((void)(pool), (void)(object))
|
||||
#endif
|
||||
void objpool_release(ObjectPool *pool, void *object)
|
||||
attr_hot attr_nonnull(1, 2);
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "objectpool.h"
|
||||
#include "util.h"
|
||||
|
||||
struct ObjectPool {
|
||||
size_t size_of_object;
|
||||
};
|
||||
|
||||
ObjectPool *objpool_alloc(size_t obj_size, size_t max_objects, const char *tag) {
|
||||
return ALLOC(ObjectPool, { .size_of_object = obj_size });
|
||||
}
|
||||
|
||||
void *objpool_acquire(ObjectPool *pool) {
|
||||
return mem_alloc(pool->size_of_object);
|
||||
}
|
||||
|
||||
void objpool_release(ObjectPool *pool, void *object) {
|
||||
mem_free(object);
|
||||
}
|
||||
|
||||
void objpool_free(ObjectPool *pool) {
|
||||
mem_free(pool);
|
||||
}
|
||||
|
||||
void objpool_get_stats(ObjectPool *pool, ObjectPoolStats *stats) {
|
||||
memset(stats, 0, sizeof(ObjectPoolStats));
|
||||
stats->tag = "<N/A>";
|
||||
}
|
||||
|
||||
size_t objpool_object_size(ObjectPool *pool) {
|
||||
return pool->size_of_object;
|
||||
}
|
||||
|
||||
#ifdef OBJPOOL_DEBUG
|
||||
void objpool_memtest(ObjectPool *pool, void *object) {
|
||||
}
|
||||
#endif
|
|
@ -234,7 +234,7 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
log_fatal("Tried to spawn a projectile while in drawing code");
|
||||
}
|
||||
|
||||
Projectile *p = (Projectile*)objpool_acquire(stage_object_pools.projectiles);
|
||||
Projectile *p = objpool_acquire(&stage_object_pools.projectiles);
|
||||
|
||||
p->birthtime = global.frames;
|
||||
p->pos = p->pos0 = p->prevpos = args->pos;
|
||||
|
@ -313,7 +313,7 @@ static void delete_projectile(ProjectileList *projlist, Projectile *p, ProjColli
|
|||
signal_event_with_collision_result(p, &p->events.killed, col);
|
||||
COEVENT_CANCEL_ARRAY(p->events);
|
||||
ent_unregister(&p->ent);
|
||||
objpool_release(stage_object_pools.projectiles, alist_unlink(projlist, p));
|
||||
objpool_release(&stage_object_pools.projectiles, alist_unlink(projlist, p));
|
||||
}
|
||||
|
||||
static void *foreach_delete_projectile(ListAnchor *projlist, List *proj, void *arg) {
|
||||
|
|
|
@ -1050,7 +1050,7 @@ static void _stage_enter(
|
|||
global.stage = stage;
|
||||
|
||||
ent_init();
|
||||
stage_objpools_alloc();
|
||||
stage_objpools_init();
|
||||
stage_draw_pre_init();
|
||||
stage_preload();
|
||||
stage_draw_init();
|
||||
|
@ -1172,7 +1172,6 @@ void stage_end_loop(void *ctx) {
|
|||
player_free(&global.plr);
|
||||
ent_shutdown();
|
||||
rng_make_active(&global.rand_visual);
|
||||
stage_objpools_free();
|
||||
stop_all_sfx();
|
||||
|
||||
taisei_commit_persistent_data();
|
||||
|
|
|
@ -1174,22 +1174,43 @@ static void stage_draw_hud_scores(float ypos_hiscore, float ypos_score, char *bu
|
|||
}
|
||||
|
||||
static void stage_draw_hud_objpool_stats(float x, float y, float width) {
|
||||
ObjectPool **last = &stage_object_pools.first + (sizeof(StageObjectPools)/sizeof(ObjectPool*) - 1);
|
||||
char buf[128];
|
||||
auto objpools = STAGE_OBJPOOLS_AS_ARRAYPTR;
|
||||
MemArena *arena = (*objpools)[0].arena;
|
||||
|
||||
Font *font = res_font("monotiny");
|
||||
|
||||
ShaderProgram *sh_prev = r_shader_current();
|
||||
r_shader("text_default");
|
||||
for(ObjectPool **pool = &stage_object_pools.first; pool <= last; ++pool) {
|
||||
ObjectPoolStats stats;
|
||||
char buf[32];
|
||||
objpool_get_stats(*pool, &stats);
|
||||
r_shader("text_hud");
|
||||
|
||||
snprintf(buf, sizeof(buf), "%zu | %5zu", stats.usage, stats.peak_usage);
|
||||
// draw_text(ALIGN_LEFT | AL_Flag_NoAdjust, (int)x, (int)y, stats.tag, font);
|
||||
// draw_text(ALIGN_RIGHT | AL_Flag_NoAdjust, (int)(x + width), (int)y, buf, font);
|
||||
// y += stringheight(buf, font) * 1.1;
|
||||
float lineskip = font_get_lineskip(font);
|
||||
|
||||
text_draw(stats.tag, &(TextParams) {
|
||||
text_draw("Arena memory:", &(TextParams) {
|
||||
.pos = { x, y },
|
||||
.font_ptr = font,
|
||||
.align = ALIGN_LEFT,
|
||||
});
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"%zukb | %5zukb",
|
||||
arena->total_used / 1024,
|
||||
arena->total_allocated / 1024
|
||||
);
|
||||
|
||||
text_draw(buf, &(TextParams) {
|
||||
.pos = { x + width, y },
|
||||
.font_ptr = font,
|
||||
.align = ALIGN_RIGHT,
|
||||
});
|
||||
|
||||
y += lineskip * 1.5;
|
||||
|
||||
for(int i = 0; i < ARRAY_SIZE(*objpools); ++i) {
|
||||
ObjectPool *p = &(*objpools)[i];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u | %7u", p->num_used, p->num_allocated);
|
||||
|
||||
text_draw(p->tag, &(TextParams) {
|
||||
.pos = { x, y },
|
||||
.font_ptr = font,
|
||||
.align = ALIGN_LEFT,
|
||||
|
@ -1201,8 +1222,9 @@ static void stage_draw_hud_objpool_stats(float x, float y, float width) {
|
|||
.align = ALIGN_RIGHT,
|
||||
});
|
||||
|
||||
y += font_get_lineskip(font);
|
||||
y += lineskip;
|
||||
}
|
||||
|
||||
r_shader_ptr(sh_prev);
|
||||
}
|
||||
|
||||
|
@ -1273,10 +1295,6 @@ static void stage_draw_hud_text(struct labels_s* labels) {
|
|||
draw_label("Graze:", labels->y.graze, labels, &stagedraw.hud_text.color.label_graze);
|
||||
r_mat_mv_pop();
|
||||
|
||||
if(stagedraw.objpool_stats) {
|
||||
stage_draw_hud_objpool_stats(0, 390, HUD_EFFECTIVE_WIDTH);
|
||||
}
|
||||
|
||||
// Score/Hi-Score values
|
||||
stage_draw_hud_scores(labels->y.hiscore, labels->y.score, buf, sizeof(buf));
|
||||
|
||||
|
@ -1443,6 +1461,10 @@ static void stage_draw_hud_text(struct labels_s* labels) {
|
|||
.color = RGB(1.0, 0.5, 0.2),
|
||||
});
|
||||
}
|
||||
|
||||
if(stagedraw.objpool_stats) {
|
||||
stage_draw_hud_objpool_stats(0, 440, HUD_EFFECTIVE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
void stage_draw_bottom_text(void) {
|
||||
|
|
|
@ -17,37 +17,33 @@
|
|||
#include "boss.h"
|
||||
#include "aniplayer.h"
|
||||
|
||||
#define MAX_projectiles 2048
|
||||
#define MAX_items MAX_projectiles
|
||||
#define MAX_enemies 64
|
||||
#define MAX_lasers 64
|
||||
#define MAX_stagetext 1024
|
||||
#define MAX_bosses 1
|
||||
|
||||
#define OBJECT_POOLS \
|
||||
OBJECT_POOL(Projectile, projectiles) \
|
||||
OBJECT_POOL(Item, items) \
|
||||
OBJECT_POOL(Enemy, enemies) \
|
||||
OBJECT_POOL(Laser, lasers) \
|
||||
OBJECT_POOL(StageText, stagetext) \
|
||||
OBJECT_POOL(Boss, bosses) \
|
||||
#define INIT_ARENA_SIZE (8 << 20)
|
||||
|
||||
StageObjectPools stage_object_pools;
|
||||
|
||||
void stage_objpools_alloc(void) {
|
||||
stage_object_pools = (StageObjectPools){
|
||||
#define OBJECT_POOL(type,field) \
|
||||
.field = OBJPOOL_ALLOC(type, MAX_##field),
|
||||
static struct {
|
||||
MemArena arena;
|
||||
} stgobjs;
|
||||
|
||||
void stage_objpools_init(void) {
|
||||
if(!stgobjs.arena.pages.first) {
|
||||
marena_init(&stgobjs.arena, INIT_ARENA_SIZE - sizeof(MemArenaPage));
|
||||
} else {
|
||||
marena_reset(&stgobjs.arena);
|
||||
}
|
||||
|
||||
#define OBJECT_POOL(type, field) \
|
||||
objpool_init( \
|
||||
&stage_object_pools.field, \
|
||||
#type, \
|
||||
&stgobjs.arena, \
|
||||
sizeof(type), \
|
||||
alignof(type));
|
||||
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
};
|
||||
}
|
||||
|
||||
void stage_objpools_free(void) {
|
||||
#define OBJECT_POOL(type,field) \
|
||||
objpool_free(stage_object_pools.field);
|
||||
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
}
|
||||
|
||||
void stage_objpools_shutdown(void) {
|
||||
marena_deinit(&stgobjs.arena);
|
||||
}
|
||||
|
|
|
@ -11,22 +11,29 @@
|
|||
|
||||
#include "objectpool.h"
|
||||
|
||||
typedef struct StageObjectPools {
|
||||
union {
|
||||
struct {
|
||||
ObjectPool *projectiles; // includes particles as well
|
||||
ObjectPool *items;
|
||||
ObjectPool *enemies;
|
||||
ObjectPool *lasers;
|
||||
ObjectPool *stagetext;
|
||||
ObjectPool *bosses;
|
||||
};
|
||||
#define OBJECT_POOLS \
|
||||
OBJECT_POOL(Projectile, projectiles) \
|
||||
OBJECT_POOL(Item, items) \
|
||||
OBJECT_POOL(Enemy, enemies) \
|
||||
OBJECT_POOL(Laser, lasers) \
|
||||
OBJECT_POOL(StageText, stagetext) \
|
||||
OBJECT_POOL(Boss, bosses) \
|
||||
|
||||
ObjectPool *first;
|
||||
};
|
||||
typedef struct StageObjectPools {
|
||||
#define OBJECT_POOL(type, field) \
|
||||
ObjectPool field;
|
||||
|
||||
OBJECT_POOLS
|
||||
#undef OBJECT_POOL
|
||||
} StageObjectPools;
|
||||
|
||||
extern StageObjectPools stage_object_pools;
|
||||
|
||||
void stage_objpools_alloc(void);
|
||||
void stage_objpools_free(void);
|
||||
#define STAGE_OBJPOOLS_AS_ARRAYPTR \
|
||||
(ObjectPool (*)[sizeof(stage_object_pools) / sizeof(ObjectPool)])&stage_object_pools
|
||||
|
||||
// Can be called many times to reinitialize the pools while reusing allocated arena memory.
|
||||
void stage_objpools_init(void);
|
||||
|
||||
// Frees the arena
|
||||
void stage_objpools_shutdown(void);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
static StageText *textlist = NULL;
|
||||
|
||||
StageText* stagetext_add(const char *text, cmplx pos, Alignment align, Font *font, const Color *clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
|
||||
StageText *t = (StageText*)objpool_acquire(stage_object_pools.stagetext);
|
||||
StageText *t = objpool_acquire(&stage_object_pools.stagetext);
|
||||
list_append(&textlist, t);
|
||||
|
||||
if(text != NULL) {
|
||||
|
@ -48,7 +48,7 @@ StageText* stagetext_add_numeric(int n, cmplx pos, Alignment align, Font *font,
|
|||
}
|
||||
|
||||
static void* stagetext_delete(List **dest, List *txt, void *arg) {
|
||||
objpool_release(stage_object_pools.stagetext, list_unlink(dest, txt));
|
||||
objpool_release(&stage_object_pools.stagetext, list_unlink(dest, txt));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue