From 458eff5f4d0752a6c666bdd61b9abeb37772351c Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 4 Oct 2014 14:14:45 +0200 Subject: [PATCH] Both the 'pause' state and the 'menu' state return 1 - so that we can signal to the Apple upper-layer function that we want to run CFRunLoopWakeUp --- frontend/frontend.c | 9 ++- frontend/platform/platform_apple.c | 103 ++++++++++++------------ frontend/platform/platform_emscripten.c | 4 +- retroarch.c | 18 +++-- 4 files changed, 70 insertions(+), 64 deletions(-) diff --git a/frontend/frontend.c b/frontend/frontend.c index 3bce076d06..f793e90e1d 100644 --- a/frontend/frontend.c +++ b/frontend/frontend.c @@ -56,7 +56,9 @@ int main_entry_decide(signature(), args_type() args) { - if (rarch_main_iterate() == -1) + int ret = rarch_main_iterate(); + + if (ret == -1) { if (g_extern.core_shutdown_initiated && g_settings.load_dummy_on_core_shutdown) @@ -66,13 +68,12 @@ int main_entry_decide(signature(), args_type() args) g_extern.core_shutdown_initiated = false; return 0; } - return 1; } if (driver.frontend_ctx && driver.frontend_ctx->process_events) driver.frontend_ctx->process_events(args); - return 0; + return ret; } void main_exit(args_type() args) @@ -241,7 +242,7 @@ returntype main_entry(signature()) #endif #if defined(HAVE_MAIN_LOOP) - while (!main_entry_decide(signature_expand(), args)); + while (main_entry_decide(signature_expand(), args) != -1); main_exit(args); #endif diff --git a/frontend/platform/platform_apple.c b/frontend/platform/platform_apple.c index 1d4009a99d..3c9dfd0edc 100644 --- a/frontend/platform/platform_apple.c +++ b/frontend/platform/platform_apple.c @@ -28,73 +28,74 @@ static CFRunLoopObserverRef iterate_observer; static void do_iteration(void) { - if (main_entry_decide(0, NULL, NULL)) + int ret = main_entry_decide(0, NULL, NULL); + + if (ret == -1) { main_exit(NULL); return; } + if (ret) + CFRunLoopWakeUp(CFRunLoopGetMain()); + /* TODO/FIXME - I am almost positive that this is not necessary and is actually a - bad thing. + I am almost positive that this is not necessary and is actually a + bad thing. - 1st. Why it is bad thing. + 1st. Why it is bad thing. - This wakes up the main event loop immediately and the main loop - has only one observer, which is this function. In other words, - this causes the function to be called immediately. I did an - experiment where I saved the time before calling this and then - reported the difference between it and the start of - do_iteration, and as expected it was about 0. As a result, when - we remove this, idle performance (i.e. displaying the RetroArch - menu) is 0% CPU as desired. + This wakes up the main event loop immediately and the main loop + has only one observer, which is this function. In other words, + this causes the function to be called immediately. I did an + experiment where I saved the time before calling this and then + reported the difference between it and the start of + do_iteration, and as expected it was about 0. As a result, when + we remove this, idle performance (i.e. displaying the RetroArch + menu) is 0% CPU as desired. - 2nd. Why it is not necessary. + 2nd. Why it is not necessary. - The event loop will wake up itself when there is input to the - process. This includes touch events, keyboard, bluetooth, - etc. Thus, it will be woken up and without any intervention so - that we can process that event. + The event loop will wake up itself when there is input to the + process. This includes touch events, keyboard, bluetooth, + etc. Thus, it will be woken up and without any intervention so + that we can process that event. - Nota bene. Why this analysis might be wrong (and what to do about it). + Nota bene. Why this analysis might be wrong (and what to do about it). - If RA is not idle and is running a core, then I believe it is - designed to expect to be called in a busy loop like this because - it implements its own frame timer to ensure that the emulation - simulation isn't too fast. In that case, this change would only - allow emulation to run when there was input, which would make - all games turn-based. :) + If RA is not idle and is running a core, then I believe it is + designed to expect to be called in a busy loop like this because + it implements its own frame timer to ensure that the emulation + simulation isn't too fast. In that case, this change would only + allow emulation to run when there was input, which would make + all games turn-based. :) - There are two good ways to fix this and still have the desired - 0% CPU idle behavior. + There are two good ways to fix this and still have the desired + 0% CPU idle behavior. - Approach 1: Change main_entry_decide from returning a boolean - (two-values) that are interpreted as CONTINUE and QUIT. Into - returning a char-sized enum with three values that are - interpreted as QUIT, WAIT, and AGAIN, such that QUIT calls - main_exit, WAIT doesn't wake up the loop, and AGAIN does. It - would then return AGAIN when a core was active. An ugly way to - get the same effect is to look have this code just look at - g_extern.is_menu and use the WAIT behavior in that case. + Approach 1: Change main_entry_decide from returning a boolean + (two-values) that are interpreted as CONTINUE and QUIT. Into + returning a char-sized enum with three values that are + interpreted as QUIT, WAIT, and AGAIN, such that QUIT calls + main_exit, WAIT doesn't wake up the loop, and AGAIN does. It + would then return AGAIN when a core was active. An ugly way to + get the same effect is to look have this code just look at + g_extern.is_menu and use the WAIT behavior in that case. - Approach 2: Instead of signalling outside of RA whether a core - is running, instead externalize the frame time that is inside - retroarch. change main_entry_decide to return a value in - [-1,MAX_INT] where -1 is interpreted as QUIT, [0,MAX_INT) is - interpreted as the amount of time to wait until continuing, and - MAX_INT is interpreted as WAIT. This could be more robust - because we'd be exposing the scheduling behavior of RA to iOS, - which might be good in other platforms as well. + Approach 2: Instead of signalling outside of RA whether a core + is running, instead externalize the frame time that is inside + retroarch. change main_entry_decide to return a value in + [-1,MAX_INT] where -1 is interpreted as QUIT, [0,MAX_INT) is + interpreted as the amount of time to wait until continuing, and + MAX_INT is interpreted as WAIT. This could be more robust + because we'd be exposing the scheduling behavior of RA to iOS, + which might be good in other platforms as well. - Approach 1 is the simplest and essentially just pushes down - these requirements to rarch_main_iterate. I have gone with the - "ugly way" first because it is the most expedient and - safe. Other eyeballs should decide if it isn't necessary. - */ -#if 0 - if ( ! g_extern.is_menu ) - CFRunLoopWakeUp(CFRunLoopGetMain()); -#endif + Approach 1 is the simplest and essentially just pushes down + these requirements to rarch_main_iterate. I have gone with the + "ugly way" first because it is the most expedient and + safe. Other eyeballs should decide if it isn't necessary. + */ } void apple_start_iteration(void) diff --git a/frontend/platform/platform_emscripten.c b/frontend/platform/platform_emscripten.c index 138906e552..9b3a68f965 100644 --- a/frontend/platform/platform_emscripten.c +++ b/frontend/platform/platform_emscripten.c @@ -27,7 +27,9 @@ static void emscripten_mainloop(void) { - if (main_entry_decide(0, NULL, NULL)) + int ret = main_entry_decide(0, NULL, NULL) + + if (ret == -1) { main_exit(NULL); exit(0); diff --git a/retroarch.c b/retroarch.c index 40e0974a55..496b5d844e 100644 --- a/retroarch.c +++ b/retroarch.c @@ -3220,17 +3220,20 @@ static inline int time_to_exit(retro_input_t input) } /* Returns: - * 0 - Successful iteration. - * -1 - Quit out of iteration loop. + * 0 - Successful iteration. + * 1 - Forcibly wake up the loop. + * -1 - Quit out of iteration loop. */ + int rarch_main_iterate(void) { unsigned i; + retro_input_t trigger_input; + int ret = 0; static retro_input_t last_input = 0; - retro_input_t old_input, trigger_input; + retro_input_t old_input = last_input; retro_input_t input = input_keys_pressed(); - old_input = last_input; last_input = input; if (driver.flushing_input) @@ -3258,6 +3261,7 @@ int rarch_main_iterate(void) if (!menu_iterate(input, old_input, trigger_input)) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); + ret = 1; goto success; } #endif @@ -3274,9 +3278,7 @@ int rarch_main_iterate(void) driver.retro_ctx.poll_cb(); rarch_sleep(10); - /* TODO - maybe change this from 0 to something else - * to signal that RetroArch is currently paused. */ - return 0; + return 1; } #if defined(HAVE_THREADS) @@ -3338,7 +3340,7 @@ success: if (g_settings.fastforward_ratio_throttle_enable) limit_frame_time(); - return 0; + return ret; } void rarch_main_deinit(void)