integrate task scheduling into the stage loop

This commit is contained in:
Andrei Alexeyev 2019-07-23 04:33:52 +03:00
parent 5b0b676c0e
commit 76aef22e23
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
5 changed files with 69 additions and 53 deletions

View file

@ -44,10 +44,6 @@ struct CoTask {
uint32_t unique_id;
};
struct CoSched {
LIST_ANCHOR(CoTask) tasks, pending_tasks;
};
static LIST_ANCHOR(CoTask) task_pool;
static size_t num_tasks_allocated;
static size_t num_tasks_in_use;
@ -283,9 +279,8 @@ void coevent_cancel(CoEvent* evt) {
evt->subscribers = NULL;
}
CoSched *cosched_new(void) {
CoSched *sched = calloc(1, sizeof(*sched));
return sched;
void cosched_init(CoSched *sched) {
memset(sched, 0, sizeof(*sched));
}
CoTask *cosched_new_task(CoSched *sched, CoTaskFunc func, void *arg) {
@ -319,7 +314,7 @@ uint cosched_run_tasks(CoSched *sched) {
return ran;
}
void cosched_free(CoSched *sched) {
void cosched_finish(CoSched *sched) {
for(CoTask *t = sched->pending_tasks.first, *next; t; t = next) {
next = t->next;
cotask_free(t);
@ -329,6 +324,8 @@ void cosched_free(CoSched *sched) {
next = t->next;
cotask_free(t);
}
memset(sched, 0, sizeof(*sched));
}
void coroutines_init(void) {

View file

@ -43,6 +43,10 @@ typedef struct CoEvent {
uint8_t num_subscribers_allocated;
} CoEvent;
struct CoSched {
LIST_ANCHOR(CoTask) tasks, pending_tasks;
};
void coroutines_init(void);
void coroutines_shutdown(void);
@ -65,10 +69,10 @@ void coevent_signal(CoEvent *evt);
void coevent_signal_once(CoEvent *evt);
void coevent_cancel(CoEvent *evt);
CoSched *cosched_new(void);
void cosched_init(CoSched *sched);
CoTask *cosched_new_task(CoSched *sched, CoTaskFunc func, void *arg); // creates and runs the task, schedules it for resume on cosched_run_tasks if it's still alive
uint cosched_run_tasks(CoSched *sched); // returns number of tasks ran
void cosched_free(CoSched *sched);
void cosched_finish(CoSched *sched);
static inline attr_must_inline void cosched_set_invoke_target(CoSched *sched) { _cosched_global = sched; }

View file

@ -677,10 +677,11 @@ bool stage_is_cleared(void) {
typedef struct StageFrameState {
StageInfo *stage;
int transition_delay;
uint16_t last_replay_fps;
CallChain cc;
CoSched sched;
int transition_delay;
int logic_calls;
uint16_t last_replay_fps;
#ifdef DEBUG
bool skip_to_dialog;
@ -728,6 +729,22 @@ static void stage_give_clear_bonus(const StageInfo *stage, StageClearBonus *bonu
player_add_points(&global.plr, bonus->total, global.plr.pos);
}
inline bool stage_should_yield(void) {
return (global.boss && !boss_is_fleeing(global.boss)) || dialog_is_active(global.dialog);
}
void stage_yield(void) {
do {
cotask_yield(NULL);
} while(stage_should_yield());
}
void stage_wait(int delay) {
while(delay-- > 0) {
stage_yield();
}
}
static LogicFrameAction stage_logic_frame(void *arg) {
StageFrameState *fstate = arg;
StageInfo *stage = fstate->stage;
@ -757,7 +774,9 @@ static LogicFrameAction stage_logic_frame(void *arg) {
((global.replaymode == REPLAY_PLAY) ? replay_input : stage_input)();
if(global.gameover != GAMEOVER_TRANSITIONING) {
if((!global.boss || boss_is_fleeing(global.boss)) && !dialog_is_active(global.dialog)) {
cosched_run_tasks(&fstate->sched);
if(!stage_should_yield()) {
stage->procs->event();
}
@ -839,16 +858,28 @@ static RenderFrameAction stage_render_frame(void *arg) {
static void stage_end_loop(void *ctx);
static void stage_stub_proc(void) { }
void stage_enter(StageInfo *stage, CallChain next) {
assert(stage);
assert(stage->procs);
assert(stage->procs->preload);
assert(stage->procs->begin);
assert(stage->procs->end);
assert(stage->procs->draw);
assert(stage->procs->event);
assert(stage->procs->update);
assert(stage->procs->shader_rules);
#define STUB_PROC(proc, stub) do {\
if(!stage->procs->proc) { \
stage->procs->proc = stub; \
log_debug(#proc " proc is missing"); \
} \
} while(0)
static const ShaderRule shader_rules_stub[1] = { NULL };
STUB_PROC(preload, stage_stub_proc);
STUB_PROC(begin, stage_stub_proc);
STUB_PROC(end, stage_stub_proc);
STUB_PROC(draw, stage_stub_proc);
STUB_PROC(event, stage_stub_proc);
STUB_PROC(update, stage_stub_proc);
STUB_PROC(shader_rules, (ShaderRule*)shader_rules_stub);
if(global.gameover == GAMEOVER_WIN) {
global.gameover = 0;
@ -910,14 +941,9 @@ void stage_enter(StageInfo *stage, CallChain next) {
stg->playpos = 0;
}
stage->procs->begin();
player_stage_post_init(&global.plr);
if(global.stage->type != STAGE_SPELL) {
display_stage_title(stage);
}
StageFrameState *fstate = calloc(1 , sizeof(*fstate));
cosched_init(&fstate->sched);
cosched_set_invoke_target(&fstate->sched);
fstate->stage = stage;
fstate->cc = next;
@ -925,6 +951,13 @@ void stage_enter(StageInfo *stage, CallChain next) {
fstate->skip_to_dialog = env_get_int("TAISEI_SKIP_TO_DIALOG", 0);
#endif
stage->procs->begin();
player_stage_post_init(&global.plr);
if(global.stage->type != STAGE_SPELL) {
display_stage_title(stage);
}
eventloop_enter(fstate, stage_logic_frame, stage_render_frame, stage_end_loop, FPS);
}
@ -944,6 +977,7 @@ void stage_end_loop(void* ctx) {
stage_draw_shutdown();
stage_free();
player_free(&global.plr);
cosched_finish(&s->sched);
tsrand_switch(&global.rand_visual);
free_all_refs();
ent_shutdown();

View file

@ -149,6 +149,10 @@ bool stage_is_cleared(void);
void stage_unlock_bgm(const char *bgm);
bool stage_should_yield(void);
void stage_yield(void);
void stage_wait(int delay);
#include "stages/stage1.h"
#include "stages/stage2.h"
#include "stages/stage3.h"

View file

@ -13,10 +13,6 @@
#include "global.h"
#include "common_tasks.h"
static CoSched *cotest_sched;
static void cotest_stub_proc(void) { }
TASK(laserproj_death, { Projectile *p; }) {
spawn_projectile_clear_effect(ARGS.p);
}
@ -144,40 +140,21 @@ TASK_FINALIZER(test_enemy) {
TASK(stage_main, { int ignored; }) {
YIELD;
WAIT(30);
stage_wait(30);
log_debug("test 1! %i", global.timer);
WAIT(60);
stage_wait(60);
log_debug("test 2! %i", global.timer);
for(;;) {
INVOKE_TASK_DELAYED(60, test_enemy, 9000, CMPLX(VIEWPORT_W, VIEWPORT_H) * 0.5, 3*I);
WAIT(1000);
stage_wait(1000);
}
}
static void cotest_begin(void) {
cotest_sched = cosched_new();
cosched_set_invoke_target(cotest_sched);
INVOKE_TASK(stage_main, 0);
}
static void cotest_end(void) {
cosched_free(cotest_sched);
}
static void cotest_events(void) {
if(!global.gameover && !cosched_run_tasks(cotest_sched)) {
log_debug("over!");
stage_finish(GAMEOVER_SCORESCREEN);
}
}
StageProcs corotest_procs = {
.begin = cotest_begin,
.preload = cotest_stub_proc,
.end = cotest_end,
.draw = cotest_stub_proc,
.update = cotest_stub_proc,
.event = cotest_events,
.shader_rules = (ShaderRule[]) { NULL },
};