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
This commit is contained in:
twinaphex 2014-10-04 14:14:45 +02:00
parent 291f4579a2
commit 458eff5f4d
4 changed files with 70 additions and 64 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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)