refactor: global thread/vsync into nsobject (raylibcontroller)
This commit is contained in:
parent
bfbfeeb654
commit
d9c8a09f19
|
|
@ -36,17 +36,141 @@ typedef struct IOSBridgeState {
|
||||||
int renderHeight;
|
int renderHeight;
|
||||||
float scaleX;
|
float scaleX;
|
||||||
float scaleY;
|
float scaleY;
|
||||||
bool raylibStarted;
|
|
||||||
bool shuttingDown;
|
bool shuttingDown;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
} IOSBridgeState;
|
} IOSBridgeState;
|
||||||
|
|
||||||
static IOSBridgeState ios = {0};
|
static IOSBridgeState ios = {0};
|
||||||
|
|
||||||
static dispatch_queue_t raylibQueue = nil;
|
@interface RaylibController : NSObject
|
||||||
static CADisplayLink *displayLink = nil;
|
|
||||||
static dispatch_semaphore_t frameSem = nil;
|
+ (instancetype)sharedController;
|
||||||
static int64_t vsyncCount = 0;
|
|
||||||
|
- (void)startInternal;
|
||||||
|
|
||||||
|
- (void)startDisplayLink:(float)minFPS;
|
||||||
|
|
||||||
|
- (void)stopDisplayLink;
|
||||||
|
|
||||||
|
- (void)waitForVSync;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation RaylibController {
|
||||||
|
CADisplayLink *_displayLink;
|
||||||
|
dispatch_semaphore_t _frameSemaphore;
|
||||||
|
dispatch_queue_t _raylibQueue;
|
||||||
|
int64_t _vsyncCount;
|
||||||
|
int64_t _lastConsumedVsync;
|
||||||
|
float _minimumFPS;
|
||||||
|
BOOL _raylibStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedController {
|
||||||
|
static RaylibController *instance = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[self alloc] init];
|
||||||
|
});
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_frameSemaphore = dispatch_semaphore_create(0);
|
||||||
|
_raylibQueue =
|
||||||
|
dispatch_queue_create("com.raylib.engine", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_vsyncCount = 0;
|
||||||
|
_lastConsumedVsync = 0;
|
||||||
|
_raylibStarted = NO;
|
||||||
|
_minimumFPS = 60.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startInternal {
|
||||||
|
if (_raylibStarted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_raylibStarted = YES;
|
||||||
|
|
||||||
|
dispatch_async(_raylibQueue, ^{
|
||||||
|
[[NSThread currentThread] setName:@"com.raylib.engine"];
|
||||||
|
|
||||||
|
// NSLog(@"[raylib][IOS] raylib thread: %@", [NSThread currentThread].name);
|
||||||
|
|
||||||
|
raylib_main(ios.argc, ios.argv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startDisplayLink:(float)minFPS {
|
||||||
|
if (![NSThread isMainThread]) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self startDisplayLink:_minimumFPS];
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_minimumFPS = minFPS;
|
||||||
|
|
||||||
|
if (_displayLink != nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_displayLink =
|
||||||
|
[CADisplayLink displayLinkWithTarget:self
|
||||||
|
selector:@selector(onDisplayFrame:)];
|
||||||
|
|
||||||
|
NSInteger maxFPS = [UIScreen mainScreen].maximumFramesPerSecond;
|
||||||
|
|
||||||
|
// Use the display native refresh rate
|
||||||
|
_displayLink.preferredFrameRateRange =
|
||||||
|
CAFrameRateRangeMake(_minimumFPS, maxFPS, maxFPS);
|
||||||
|
|
||||||
|
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop]
|
||||||
|
forMode:NSRunLoopCommonModes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)onDisplayFrame:(CADisplayLink *)link {
|
||||||
|
(void)link;
|
||||||
|
|
||||||
|
__atomic_fetch_add(&_vsyncCount, 1, __ATOMIC_RELEASE);
|
||||||
|
dispatch_semaphore_signal(_frameSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopDisplayLink {
|
||||||
|
if (![NSThread isMainThread]) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self stopDisplayLink];
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_displayLink == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_displayLink invalidate];
|
||||||
|
_displayLink = nil;
|
||||||
|
|
||||||
|
dispatch_semaphore_signal(_frameSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)waitForVSync {
|
||||||
|
int64_t current = __atomic_load_n(&_vsyncCount, __ATOMIC_ACQUIRE);
|
||||||
|
|
||||||
|
while ((current - _lastConsumedVsync) < 1 && !ios.shuttingDown) {
|
||||||
|
dispatch_semaphore_wait(_frameSemaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
current = __atomic_load_n(&_vsyncCount, __ATOMIC_ACQUIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastConsumedVsync = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface RaylibGLView : UIView
|
@interface RaylibGLView : UIView
|
||||||
@end
|
@end
|
||||||
|
|
@ -130,55 +254,8 @@ static int64_t vsyncCount = 0;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface RaylibDisplayLinkTarget : NSObject
|
|
||||||
+ (void)startDisplayLink;
|
|
||||||
+ (void)onDisplayFrame:(CADisplayLink *)link;
|
|
||||||
+ (void)stopDisplayLink;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RaylibDisplayLinkTarget
|
|
||||||
|
|
||||||
+ (void)startDisplayLink {
|
|
||||||
if (displayLink != nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
frameSem = dispatch_semaphore_create(0);
|
|
||||||
vsyncCount = 0;
|
|
||||||
|
|
||||||
displayLink =
|
|
||||||
[CADisplayLink displayLinkWithTarget:[self class]
|
|
||||||
selector:@selector(onDisplayFrame:)];
|
|
||||||
|
|
||||||
NSInteger maxFPS = [UIScreen mainScreen].maximumFramesPerSecond;
|
|
||||||
|
|
||||||
// Use the display native refresh rate
|
|
||||||
displayLink.preferredFrameRateRange =
|
|
||||||
CAFrameRateRangeMake(60.0f, maxFPS, maxFPS);
|
|
||||||
|
|
||||||
[displayLink addToRunLoop:[NSRunLoop mainRunLoop]
|
|
||||||
forMode:NSRunLoopCommonModes];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)onDisplayFrame:(CADisplayLink *)link {
|
|
||||||
(void)link;
|
|
||||||
__atomic_fetch_add(&vsyncCount, 1, __ATOMIC_RELEASE);
|
|
||||||
dispatch_semaphore_signal(frameSem);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)stopDisplayLink {
|
|
||||||
if (displayLink == nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[displayLink invalidate];
|
|
||||||
displayLink = nil;
|
|
||||||
|
|
||||||
dispatch_semaphore_signal(frameSem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
static void shutdown_internal(void) {
|
static void shutdown_internal(void) {
|
||||||
[RaylibDisplayLinkTarget stopDisplayLink];
|
[[RaylibController sharedController] stopDisplayLink];
|
||||||
|
|
||||||
if (ios.context != nil) {
|
if (ios.context != nil) {
|
||||||
[EAGLContext setCurrentContext:ios.context];
|
[EAGLContext setCurrentContext:ios.context];
|
||||||
|
|
@ -223,24 +300,6 @@ void ios_close_platform(void) {
|
||||||
@property(strong, nonatomic) UIWindow *window;
|
@property(strong, nonatomic) UIWindow *window;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static void ios_start_raylib_main(void) {
|
|
||||||
if (ios.raylibStarted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ios.raylibStarted = true;
|
|
||||||
|
|
||||||
raylibQueue =
|
|
||||||
dispatch_queue_create("com.raylib.engine", DISPATCH_QUEUE_SERIAL);
|
|
||||||
|
|
||||||
dispatch_async(raylibQueue, ^{
|
|
||||||
[[NSThread currentThread] setName:@"com.raylib.engine"];
|
|
||||||
|
|
||||||
// NSLog(@"[raylib][IOS] raylib thread: %@", [NSThread currentThread].name);
|
|
||||||
|
|
||||||
raylib_main(ios.argc, ios.argv);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation RaylibAppDelegate
|
@implementation RaylibAppDelegate
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application
|
- (BOOL)application:(UIApplication *)application
|
||||||
|
|
@ -304,9 +363,9 @@ static void ios_start_raylib_main(void) {
|
||||||
self.window.rootViewController = ios.viewController;
|
self.window.rootViewController = ios.viewController;
|
||||||
[self.window makeKeyAndVisible];
|
[self.window makeKeyAndVisible];
|
||||||
|
|
||||||
[RaylibDisplayLinkTarget startDisplayLink];
|
[[RaylibController sharedController] startDisplayLink:60.0f];
|
||||||
|
|
||||||
ios_start_raylib_main();
|
[[RaylibController sharedController] startInternal];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sceneDidBecomeActive:(UIScene *)scene {
|
- (void)sceneDidBecomeActive:(UIScene *)scene {
|
||||||
|
|
@ -482,16 +541,9 @@ void ios_present_frame(void) {
|
||||||
err = glGetError();
|
err = glGetError();
|
||||||
if (err != GL_NO_ERROR)
|
if (err != GL_NO_ERROR)
|
||||||
NSLog(@"[raylib][IOS] glGetError after present: 0x%04X", err);
|
NSLog(@"[raylib][IOS] glGetError after present: 0x%04X", err);
|
||||||
if (frameSem != nil && !ios.shuttingDown) {
|
|
||||||
static int64_t lastVsync = 0;
|
|
||||||
int64_t current = __atomic_load_n(&vsyncCount, __ATOMIC_ACQUIRE);
|
|
||||||
|
|
||||||
while ((current - lastVsync) < 1 && !ios.shuttingDown) {
|
if (!ios.shuttingDown) {
|
||||||
dispatch_semaphore_wait(frameSem, DISPATCH_TIME_FOREVER);
|
[[RaylibController sharedController] waitForVSync];
|
||||||
current = __atomic_load_n(&vsyncCount, __ATOMIC_ACQUIRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastVsync = current;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user