Consoles: Make Quit Game more stable

This commit is contained in:
UnknownShadow200 2024-06-20 22:14:42 +10:00
parent 5d31caf57b
commit f3326f4f17
4 changed files with 49 additions and 43 deletions

View File

@ -400,7 +400,7 @@ static void LoadPlugins(void) {
static void LoadPlugins(void) { } static void LoadPlugins(void) { }
#endif #endif
static void Game_Free(void* obj); static void Game_PendingClose(void* obj) { gameRunning = false; }
static void Game_Load(void) { static void Game_Load(void) {
struct IGameComponent* comp; struct IGameComponent* comp;
Game_UpdateDimensions(); Game_UpdateDimensions();
@ -415,7 +415,7 @@ static void Game_Load(void) {
Event_Register_(&WorldEvents.NewMap, NULL, HandleOnNewMap); Event_Register_(&WorldEvents.NewMap, NULL, HandleOnNewMap);
Event_Register_(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded); Event_Register_(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded);
Event_Register_(&WindowEvents.Resized, NULL, Game_OnResize); Event_Register_(&WindowEvents.Resized, NULL, Game_OnResize);
Event_Register_(&WindowEvents.Closing, NULL, Game_Free); Event_Register_(&WindowEvents.Closing, NULL, Game_PendingClose);
Event_Register_(&WindowEvents.InactiveChanged, NULL, HandleInactiveChanged); Event_Register_(&WindowEvents.InactiveChanged, NULL, HandleInactiveChanged);
Game_AddComponent(&World_Component); Game_AddComponent(&World_Component);
@ -647,10 +647,18 @@ static void DrawSplitscreen(float delta, float t, int i, int x, int y, int w, in
} }
#endif #endif
static CC_INLINE void Game_RenderFrame(double delta) { static CC_INLINE void Game_RenderFrame(void) {
struct ScheduledTask entTask; struct ScheduledTask entTask;
float t; float t;
cc_uint64 render = Stopwatch_Measure();
double delta = Stopwatch_ElapsedMicroseconds(Game_FrameStart, render) / (1000.0 * 1000.0);
Window_ProcessEvents(delta);
if (delta > 5.0) delta = 5.0; /* avoid large delta with suspended process */
if (delta <= 0.0) return;
Game_FrameStart = render;
/* TODO: Should other tasks get called back too? */ /* TODO: Should other tasks get called back too? */
/* Might not be such a good idea for the http_clearcache, */ /* Might not be such a good idea for the http_clearcache, */
/* don't really want all skins getting lost */ /* don't really want all skins getting lost */
@ -722,7 +730,7 @@ static CC_INLINE void Game_RenderFrame(double delta) {
Gfx_EndFrame(); Gfx_EndFrame();
} }
static void Game_Free(void* obj) { static void Game_Free(void) {
struct IGameComponent* comp; struct IGameComponent* comp;
/* Most components will call OnContextLost in their Free functions */ /* Most components will call OnContextLost in their Free functions */
/* Set to false so components will always free managed textures too */ /* Set to false so components will always free managed textures too */
@ -730,7 +738,8 @@ static void Game_Free(void* obj) {
Event_UnregisterAll(); Event_UnregisterAll();
tasksCount = 0; tasksCount = 0;
for (comp = comps_head; comp; comp = comp->next) { for (comp = comps_head; comp; comp = comp->next)
{
if (comp->Free) comp->Free(); if (comp->Free) comp->Free();
} }
@ -741,25 +750,17 @@ static void Game_Free(void* obj) {
Window_DisableRawMouse(); Window_DisableRawMouse();
} }
#define Game_DoFrameBody() \
render = Stopwatch_Measure();\
delta = Stopwatch_ElapsedMicroseconds(Game_FrameStart, render) / (1000.0 * 1000.0);\
\
Window_ProcessEvents(delta);\
if (!gameRunning) return;\
\
if (delta > 5.0) delta = 5.0; /* avoid large delta with suspended process */ \
if (delta > 0.0) { Game_FrameStart = render; Game_RenderFrame(delta); }
#ifdef CC_BUILD_WEB #ifdef CC_BUILD_WEB
void Game_DoFrame(void) { void Game_DoFrame(void) {
cc_uint64 render; if (gameRunning) {
double delta; Game_RenderFrame();
Game_DoFrameBody() } else if (tasksCount) {
Game_Free();
Window_Free();
}
} }
static void Game_RunLoop(void) { static void Game_RunLoop(void) {
Game_FrameStart = Stopwatch_Measure();
/* Window_Web.c sets Game_DoFrame as the main loop callback function */ /* Window_Web.c sets Game_DoFrame as the main loop callback function */
/* (i.e. web browser is in charge of calling Game_DoFrame, not us) */ /* (i.e. web browser is in charge of calling Game_DoFrame, not us) */
} }
@ -777,11 +778,11 @@ cc_bool Game_ShouldClose(void) {
} }
#else #else
static void Game_RunLoop(void) { static void Game_RunLoop(void) {
cc_uint64 render; while (gameRunning)
double delta; {
Game_RenderFrame();
Game_FrameStart = Stopwatch_Measure(); }
for (;;) { Game_DoFrameBody() } Game_Free();
} }
#endif #endif
@ -793,5 +794,7 @@ void Game_Run(int width, int height, const cc_string* title) {
Game_Load(); Game_Load();
Event_RaiseVoid(&WindowEvents.Resized); Event_RaiseVoid(&WindowEvents.Resized);
Game_FrameStart = Stopwatch_Measure();
Game_RunLoop(); Game_RunLoop();
} }

View File

@ -14,6 +14,7 @@ extern void* Window_XFB;
static void* xfbs[2]; static void* xfbs[2];
static int curFB; static int curFB;
static GfxResourceID white_square; static GfxResourceID white_square;
static GXTexRegionCallback regionCB;
// https://wiibrew.org/wiki/Developer_tips // https://wiibrew.org/wiki/Developer_tips
// https://devkitpro.org/wiki/libogc/GX // https://devkitpro.org/wiki/libogc/GX
@ -44,6 +45,9 @@ static void InitGX(void) {
xfbs[0] = Window_XFB; xfbs[0] = Window_XFB;
xfbs[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(mode)); xfbs[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(mode));
regionCB = GX_SetTexRegionCallback(NULL);
GX_SetTexRegionCallback(regionCB);
} }
void Gfx_Create(void) { void Gfx_Create(void) {
@ -173,7 +177,8 @@ void Gfx_BindTexture(GfxResourceID texId) {
CCTexture* tex = (CCTexture*)texId; CCTexture* tex = (CCTexture*)texId;
if (!tex) tex = white_square; if (!tex) tex = white_square;
GX_LoadTexObj(&tex->obj, GX_TEXMAP0); GXTexRegion* reg = regionCB(&tex->obj, GX_TEXMAP0);
GX_LoadTexObjPreloaded(&tex->obj, reg, GX_TEXMAP0);
} }

View File

@ -413,7 +413,15 @@ void Window_Init(void) {
interop_ForceTouchPageLayout(); interop_ForceTouchPageLayout();
} }
void Window_Free(void) { } void Window_Free(void) {
/* If the game is closed while in fullscreen, the last rendered frame stays */
/* shown in fullscreen, but the game can't be interacted with anymore */
Window_ExitFullscreen();
Window_SetSize(0, 0);
UnhookEvents();
emscripten_cancel_main_loop();
}
extern void interop_InitContainer(void); extern void interop_InitContainer(void);
static void DoCreateWindow(void) { static void DoCreateWindow(void) {
@ -525,15 +533,6 @@ void Window_SetSize(int width, int height) {
void Window_RequestClose(void) { void Window_RequestClose(void) {
Window_Main.Exists = false; Window_Main.Exists = false;
Event_RaiseVoid(&WindowEvents.Closing); Event_RaiseVoid(&WindowEvents.Closing);
/* If the game is closed while in fullscreen, the last rendered frame stays */
/* shown in fullscreen, but the game can't be interacted with anymore */
Window_ExitFullscreen();
Window_SetSize(0, 0);
UnhookEvents();
/* Game_DoFrame doesn't do anything when WindowExists.False is false, */
/* but it's still better to cancel main loop to minimise resource usage */
emscripten_cancel_main_loop();
} }
extern void interop_RequestCanvasResize(void); extern void interop_RequestCanvasResize(void);

View File

@ -19,6 +19,13 @@ typedef struct {
#define ALIGNED_VECTOR_CHUNK_SIZE 256u #define ALIGNED_VECTOR_CHUNK_SIZE 256u
#define av_assert(x) \
do {\
if(!(x)) {\
fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\
exit(1);\
}\
} while(0); \
#define ROUND_TO_CHUNK_SIZE(v) \ #define ROUND_TO_CHUNK_SIZE(v) \
((((v) + ALIGNED_VECTOR_CHUNK_SIZE - 1) / ALIGNED_VECTOR_CHUNK_SIZE) * ALIGNED_VECTOR_CHUNK_SIZE) ((((v) + ALIGNED_VECTOR_CHUNK_SIZE - 1) / ALIGNED_VECTOR_CHUNK_SIZE) * ALIGNED_VECTOR_CHUNK_SIZE)
@ -52,14 +59,6 @@ AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t ele
return vector->data + original_byte_size; return vector->data + original_byte_size;
} }
#define av_assert(x) \
do {\
if(!(x)) {\
fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\
exit(1);\
}\
} while(0); \
/* Resizes the array and returns a pointer to the first new element (if upsizing) or NULL (if downsizing) */ /* Resizes the array and returns a pointer to the first new element (if upsizing) or NULL (if downsizing) */
AV_FORCE_INLINE void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count) { AV_FORCE_INLINE void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count) {
void* ret = NULL; void* ret = NULL;