mirror of
https://github.com/libretro/RetroArch
synced 2025-04-25 00:02:31 +00:00
(iOS/OSX) Total reimplementation of game loop - does away with
observer callback
This commit is contained in:
parent
2d0701b1f6
commit
75b6bd21c3
@ -185,14 +185,48 @@ static char** waiting_argv;
|
|||||||
waiting_argc = 0;
|
waiting_argc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) poll_iteration
|
||||||
|
{
|
||||||
|
NSEvent *event;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||||
|
|
||||||
|
[NSApp sendEvent: event];
|
||||||
|
}while(event != nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) do_iteration
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
while (ret != -1)
|
||||||
|
{
|
||||||
|
[self poll_iteration];
|
||||||
|
ret = rarch_main_iterate();
|
||||||
|
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
main_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) apple_start_iteration
|
||||||
|
{
|
||||||
|
[self performSelectorOnMainThread:@selector(do_iteration) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) apple_stop_iteration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
apple_start_iteration();
|
[self apple_start_iteration];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillResignActive:(NSNotification *)notification
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
apple_stop_iteration();
|
[self apple_stop_iteration];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#import <Availability.h>
|
#import <Availability.h>
|
||||||
#import "RetroArch_Apple.h"
|
#import "RetroArch_Apple.h"
|
||||||
#include "../../general.h"
|
#include "../../general.h"
|
||||||
|
#include "../../runloop.h"
|
||||||
|
#include "../../frontend/frontend.h"
|
||||||
|
|
||||||
/* Define compatibility symbols and categories. */
|
/* Define compatibility symbols and categories. */
|
||||||
|
|
||||||
@ -193,3 +195,4 @@ static void apple_gfx_ctx_update(void);
|
|||||||
#ifdef HAVE_LOCATION
|
#ifdef HAVE_LOCATION
|
||||||
#include "apple_location.c.inl"
|
#include "apple_location.c.inl"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -265,7 +265,44 @@ void notify_content_loaded(void) {
|
|||||||
|
|
||||||
apple_gamecontroller_init();
|
apple_gamecontroller_init();
|
||||||
|
|
||||||
apple_start_iteration();
|
[self apple_start_iteration];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
- (void) poll_iteration
|
||||||
|
{
|
||||||
|
UIEvent *event;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
event = [UIApplication nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||||
|
|
||||||
|
|
||||||
|
[UIApplication sendEvent: event];
|
||||||
|
}while(event != nil);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- (void) do_iteration
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
while (ret != -1)
|
||||||
|
{
|
||||||
|
//[self poll_iteration];
|
||||||
|
ret = rarch_main_iterate();
|
||||||
|
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
main_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) apple_start_iteration
|
||||||
|
{
|
||||||
|
[self performSelectorOnMainThread:@selector(do_iteration) withObject:nil waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) apple_stop_iteration
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||||
|
@ -28,147 +28,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//#define DEBUG_RUNLOOP
|
|
||||||
|
|
||||||
#ifdef DEBUG_RUNLOOP
|
|
||||||
#include "../../retroarch_logger.h"
|
|
||||||
|
|
||||||
#define CF_LOG(...) RARCH_LOG(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define CF_LOG(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void apple_start_iteration(void);
|
|
||||||
|
|
||||||
void apple_stop_iteration(void);
|
|
||||||
|
|
||||||
static CFRunLoopObserverRef iterate_observer = NULL;
|
|
||||||
|
|
||||||
static int do_ra_iteration(void)
|
|
||||||
{
|
|
||||||
int ret = rarch_main_iterate();
|
|
||||||
if (ret == -1)
|
|
||||||
main_exit(NULL);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_iteration(CFRunLoopObserverRef observer, CFRunLoopActivity activity,
|
|
||||||
void *info)
|
|
||||||
{
|
|
||||||
switch (activity)
|
|
||||||
{
|
|
||||||
case kCFRunLoopEntry:
|
|
||||||
CF_LOG("RUNLOOP ENTRY, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
case kCFRunLoopBeforeTimers:
|
|
||||||
CF_LOG("RUNLOOP BEFORE TIMERS, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
case kCFRunLoopAfterWaiting:
|
|
||||||
CF_LOG("RUNLOOP AFTER WAITING, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
case kCFRunLoopBeforeWaiting:
|
|
||||||
{
|
|
||||||
CF_LOG("RUNLOOP BEFORE WAITING, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
int ret = do_ra_iteration();
|
|
||||||
if (ret == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CFRunLoopWakeUp(CFRunLoopGetMain());
|
|
||||||
|
|
||||||
/* TODO/FIXME
|
|
||||||
I am almost positive that this is not necessary and is actually a
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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. :)
|
|
||||||
|
|
||||||
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_runloop.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 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.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case kCFRunLoopBeforeSources:
|
|
||||||
CF_LOG("RUNLOOP BEFORE SOURCES, frame: %d\n.", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
case kCFRunLoopExit:
|
|
||||||
CF_LOG("RUNLOOP EXIT, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
case kCFRunLoopAllActivities:
|
|
||||||
CF_LOG("RUNLOOP ALL ACTIVITIES, frame: %d.\n", g_runloop.frames.video.count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void apple_start_iteration(void)
|
|
||||||
{
|
|
||||||
if (iterate_observer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
iterate_observer =
|
|
||||||
CFRunLoopObserverCreate(0, kCFRunLoopBeforeWaiting,
|
|
||||||
true, 0, (CFRunLoopObserverCallBack)do_iteration, 0);
|
|
||||||
CFRunLoopAddObserver(CFRunLoopGetMain(), iterate_observer,
|
|
||||||
kCFRunLoopCommonModes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void apple_stop_iteration(void)
|
|
||||||
{
|
|
||||||
if (!iterate_observer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CFRunLoopObserverInvalidate(iterate_observer);
|
|
||||||
CFRelease(iterate_observer);
|
|
||||||
iterate_observer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void frontend_apple_get_environment_settings(int *argc, char *argv[],
|
static void frontend_apple_get_environment_settings(int *argc, char *argv[],
|
||||||
void *args, void *params_data)
|
void *args, void *params_data)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user