Deferred loading of resources.

TODO: deferred load of models, animations, dialog gfx
  TODO: work on deferred loading for spell stages
This commit is contained in:
makise-homura 2017-03-09 22:00:15 +03:00 committed by Andrei "Akari" Alexeyev
parent 55c56e9bd6
commit 6258bf5828
11 changed files with 127 additions and 12 deletions

View file

@ -26,7 +26,7 @@ void taisei_shutdown(void) {
printf("\nshutdown:\n");
free_all_refs();
free_resources();
free_resources(0);
audio_shutdown();
video_shutdown();
gamepad_shutdown();

View file

@ -37,6 +37,7 @@ static void register_handler(
ResourceNameFunc name,
ResourceFindFunc find,
ResourceCheckFunc check,
ResourceTransientFunc istransient,
size_t tablesize)
{
assert(type >= 0 && type < RES_NUMTYPES);
@ -48,6 +49,7 @@ static void register_handler(
h->name = name;
h->find = find;
h->check = check;
h->istransient = istransient;
h->mapping = hashtable_new_stringkeys(tablesize);
strcpy(h->subdir, subdir);
}
@ -163,31 +165,44 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
return res;
}
bool istransient_filepath(const char *path) {
char *fnstart = strrchr(path, '/');
if (fnstart == NULL) return false;
char *stgstart = strstr(path, "stage");
return fnstart && stgstart && (stgstart < fnstart);
}
bool istransient_filename(const char *path) {
char *fnstart = strrchr(path, '/');
if (fnstart == NULL) return false;
return strstr(fnstart, "stage");
}
void init_resources(void) {
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
register_handler(
RES_TEXTURE, TEX_PATH_PREFIX, load_texture, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, 227
RES_TEXTURE, TEX_PATH_PREFIX, load_texture, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, istransient_filepath, 227
);
register_handler(
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, 23
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, NULL, 23
);
register_handler(
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, 29
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, NULL, 29
);
register_handler(
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, 17
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, NULL, 17
);
register_handler(
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, 16
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, NULL, 16
);
register_handler(
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, 16
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, istransient_filename, 16
);
}
@ -234,7 +249,8 @@ static void recurse_dir(const char *path) {
} else for(int rtype = 0; rtype < RES_NUMTYPES; ++rtype) {
ResourceHandler *handler = get_handler(rtype);
if(handler->check(filepath)) {
// NULL transient handler treats this resource type as permanent
if((!handler->istransient || !handler->istransient(filepath)) && handler->check(filepath)) {
load_resource(handler, filepath, NULL, 0);
}
}
@ -292,7 +308,7 @@ void load_resources(void) {
init_fbo(&resources.fsec);
}
void free_resources(void) {
void free_resources(ResourceFlags flags) {
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
ResourceHandler *handler = get_handler(type);
@ -303,12 +319,20 @@ void free_resources(void) {
Resource *res;
for(HashtableIterator *i = hashtable_iter(handler->mapping); hashtable_iter_next(i, (void**)&name, (void**)&res);) {
if ((flags & RESF_TRANSIENT) && !(res->flags & RESF_TRANSIENT)) continue;
unload_resource(res);
printf("Unloaded %s '%s'\n", resource_type_names[type], name);
if (flags & RESF_TRANSIENT) hashtable_unset_deferred(handler->mapping, name);
}
hashtable_free(handler->mapping);
if (flags & RESF_TRANSIENT) {
hashtable_unset_deferred_now(handler->mapping);
}
else {
hashtable_free(handler->mapping);
}
}
if (flags & RESF_TRANSIENT) return;
delete_vbo(&_vbo);

View file

@ -34,7 +34,7 @@ typedef enum ResourceType {
typedef enum ResourceFlags {
RESF_REQUIRED = 1,
RESF_OVERRIDE = 2,
// RESF_PERMANENT = 4;
RESF_TRANSIENT = 4
} ResourceFlags;
// All paths are relative to the current working directory, which can assumed to be the resources directory,
@ -54,6 +54,9 @@ typedef char* (*ResourceFindFunc)(const char *name);
// Tells whether the resource handler should attempt to load a file, specified by a path.
typedef bool (*ResourceCheckFunc)(const char *path);
// Tells whether the resource specified by a path is transient.
typedef bool (*ResourceTransientFunc)(const char *path);
// Loads a resource at path and returns a pointer to it.
// Must return NULL and not crash the program on failure.
typedef void* (*ResourceLoadFunc)(const char *path);
@ -61,11 +64,18 @@ typedef void* (*ResourceLoadFunc)(const char *path);
// Unloads a resource, freeing all allocated to it memory.
typedef void (*ResourceUnloadFunc)(void *res);
// ResourceTransientFunc callback: resource treated as transient if its path contains "stage".
bool istransient_filepath(const char *path);
// ResourceTransientFunc callback: resource treated as transient if its filename contains "stage".
bool istransient_filename(const char *path);
typedef struct ResourceHandler {
ResourceType type;
ResourceNameFunc name;
ResourceFindFunc find;
ResourceCheckFunc check;
ResourceTransientFunc istransient;
ResourceLoadFunc load;
ResourceUnloadFunc unload;
Hashtable *mapping;
@ -97,7 +107,7 @@ extern Resources resources;
void init_resources(void);
void load_resources(void);
void free_resources(void);
void free_resources(ResourceFlags flags);
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags);
Resource* insert_resource(ResourceType type, const char *name, void *data, ResourceFlags flags, const char *source);

View file

@ -626,6 +626,8 @@ static void stage_free(void) {
free_boss(global.boss);
global.boss = NULL;
}
free_resources(RESF_TRANSIENT);
}
static void stage_finalize(void *arg) {
@ -691,6 +693,12 @@ void stage_loop(StageInfo *stage) {
stg->playpos = 0;
}
if (stage->procs->preload)
{
printf("Loading resources for stage:\n");
stage->procs->preload();
}
Enemy *e = global.plr.slaves, *tmp;
short power = global.plr.power;
global.plr.power = -1;

View file

@ -49,6 +49,7 @@ typedef struct StageProcs StageProcs;
struct StageProcs {
StageProc begin;
StageProc preload;
StageProc end;
StageProc draw;
StageProc event;

View file

@ -159,6 +159,14 @@ void stage1_start(void) {
bgcontext.cv[1] = 4;
}
void stage1_preload(void) {
get_resource(RES_BGM, "bgm_stage1", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage1boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage1/cirnobg", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage1/fog", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage1/snowlayer", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage1_end(void) {
free_stage3d(&bgcontext);
}
@ -180,6 +188,7 @@ ShaderRule stage1_shaders[] = { stage1_fog, NULL };
StageProcs stage1_procs = {
.begin = stage1_start,
.preload = stage1_preload,
.end = stage1_end,
.draw = stage1_draw,
.event = stage1_events,

View file

@ -173,6 +173,17 @@ void stage2_start(void) {
add_model(&bgcontext, stage2_bg_leaves_draw, stage2_bg_pos);
}
void stage2_preload(void) {
get_resource(RES_BGM, "bgm_stage2", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage2boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/border", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/leaves", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/roadgrass", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/roadstones", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/spellbg1", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/spellbg2", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage2_end(void) {
free_stage3d(&bgcontext);
}
@ -211,6 +222,7 @@ ShaderRule stage2_shaders[] = { stage2_fog, stage2_bloom, NULL };
StageProcs stage2_procs = {
.begin = stage2_start,
.preload = stage2_preload,
.end = stage2_end,
.draw = stage2_draw,
.event = stage2_events,

View file

@ -116,6 +116,16 @@ void stage3_start(void) {
// stgstate.fog_exp = 5.0;
}
void stage3_preload(void) {
get_resource(RES_BGM, "bgm_stage3", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage3boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage3/border", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage3/spellbg1", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage3/wspellbg", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage3/wspellclouds", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage3/wspellswarm", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage3_end(void) {
free_stage3d(&bgcontext);
}
@ -279,6 +289,7 @@ ShaderRule stage3_shaders[] = { stage3_fog, stage3_tunnel, NULL };
StageProcs stage3_procs = {
.begin = stage3_start,
.preload = stage3_preload,
.end = stage3_end,
.draw = stage3_draw,
.event = stage3_events,

View file

@ -208,6 +208,18 @@ void stage4_start(void) {
add_model(&bgcontext, stage4_corridor_draw, stage4_corridor_pos);
}
void stage4_preload(void) {
get_resource(RES_BGM, "bgm_stage4", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage4boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage2/border", RESF_REQUIRED | RESF_TRANSIENT); // Stage 2 is intentional!
get_resource(RES_TEXTURE, "stage4/kurumibg1", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage4/kurumibg2", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage4/lake", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage4/mansion", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage4/planks", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage4/wall", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage4_end(void) {
free_stage3d(&bgcontext);
}
@ -247,6 +259,7 @@ ShaderRule stage4_shaders[] = { stage4_fog, NULL };
StageProcs stage4_procs = {
.begin = stage4_start,
.preload = stage4_preload,
.end = stage4_end,
.draw = stage4_draw,
.event = stage4_events,

View file

@ -122,6 +122,16 @@ void stage5_start(void) {
stagedata.rad = 2800;
}
void stage5_preload(void) {
get_resource(RES_BGM, "bgm_stage5", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage5boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage5/noise", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage5/spell_bg", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage5/spell_clouds", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage5/spell_lightning", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage5/tower", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage5_end(void) {
free_stage3d(&bgcontext);
}
@ -143,6 +153,7 @@ ShaderRule stage5_shaders[] = { NULL };
StageProcs stage5_procs = {
.begin = stage5_start,
.preload = stage5_preload,
.end = stage5_end,
.draw = stage5_draw,
.event = stage5_events,

View file

@ -167,6 +167,21 @@ void stage6_start(void) {
}
void stage6_preload(void) {
get_resource(RES_BGM, "bgm_stage6", RESF_TRANSIENT);
get_resource(RES_BGM, "bgm_stage6boss", RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/baryon_connector", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/baryon", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/scythecircle", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/scythe", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/sky", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/spellbg_chalk", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/spellbg_classic", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/spellbg_modern", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/towertop", RESF_REQUIRED | RESF_TRANSIENT);
get_resource(RES_TEXTURE, "stage6/towerwall", RESF_REQUIRED | RESF_TRANSIENT);
}
void stage6_end(void) {
free_stage3d(&bgcontext);
}
@ -228,6 +243,7 @@ ShaderRule stage6_shaders[] = { NULL };
StageProcs stage6_procs = {
.begin = stage6_start,
.preload = stage6_preload,
.end = stage6_end,
.draw = stage6_draw,
.event = stage6_events,