Created
January 19, 2022 22:55
-
-
Save danmaas/4f3341b75a147d0c3ffc588a0f4c9b92 to your computer and use it in GitHub Desktop.
expo-gl 11.0.3 patch / concurrency and background rendering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/node_modules/expo-gl/ios/EXGL/EXGLContext.mm b/node_modules/expo-gl/ios/EXGL/EXGLContext.mm | |
index 0a904ab..2bd2fdf 100644 | |
--- a/node_modules/expo-gl/ios/EXGL/EXGLContext.mm | |
+++ b/node_modules/expo-gl/ios/EXGL/EXGLContext.mm | |
@@ -18,6 +18,7 @@ @interface EXGLContext () | |
@property (nonatomic, strong) dispatch_queue_t glQueue; | |
@property (nonatomic, weak) EXModuleRegistry *moduleRegistry; | |
@property (nonatomic, weak) EXGLObjectManager *objectManager; | |
+@property (atomic) BOOL appIsBackground; // tracks the app's foreground/background state | |
@end | |
@@ -32,6 +33,7 @@ - (instancetype)initWithDelegate:(id<EXGLContextDelegate>)delegate andModuleRegi | |
_objectManager = (EXGLObjectManager *)[_moduleRegistry getExportedModuleOfClass:[EXGLObjectManager class]]; | |
_glQueue = dispatch_queue_create("host.exp.gl", DISPATCH_QUEUE_SERIAL); | |
_eaglCtx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3] ?: [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; | |
+ _appIsBackground = NO; | |
} | |
return self; | |
} | |
@@ -48,6 +50,11 @@ - (EAGLContext *)createSharedEAGLContext | |
- (void)runInEAGLContext:(EAGLContext*)context callback:(void(^)(void))callback | |
{ | |
+ if (_appIsBackground) { | |
+ // iOS does not allow calls to OpenGL when the app is in background | |
+ return; | |
+ } | |
+ | |
[EAGLContext setCurrentContext:context]; | |
callback(); | |
glFlush(); | |
@@ -86,6 +93,16 @@ - (void)initialize:(void(^)(BOOL))callback | |
self->_contextId = UEXGLContextCreate(jsRuntimePtr); | |
[self->_objectManager saveContext:self]; | |
+ // listen for foreground/background transitions | |
+ [[NSNotificationCenter defaultCenter] addObserver:self | |
+ selector:@selector(onApplicationDidBecomeActive:) | |
+ name:UIApplicationDidBecomeActiveNotification | |
+ object:nil]; | |
+ [[NSNotificationCenter defaultCenter] addObserver:self | |
+ selector:@selector(onApplicationWillResignActive:) | |
+ name:UIApplicationWillResignActiveNotification | |
+ object:nil]; | |
+ | |
UEXGLContextSetFlushMethodObjc(self->_contextId, ^{ | |
[self flush]; | |
}); | |
@@ -112,6 +129,21 @@ - (void)flush | |
}]; | |
} | |
+- (void) onApplicationWillResignActive:(NSNotification *) note | |
+{ | |
+ // flush all pending GL activity, wait for completion, and then set the appIsBackground flag | |
+ [self runAsync:^{ | |
+ glFinish(); | |
+ self->_appIsBackground = YES; | |
+ }]; | |
+} | |
+ | |
+- (void) onApplicationDidBecomeActive:(NSNotification *) note { | |
+ // unset the appIsBackground flag so that rendering can resume | |
+ _appIsBackground = NO; | |
+ // [self flush]; | |
+} | |
+ | |
- (void)destroy | |
{ | |
[self runAsync:^{ | |
@@ -119,6 +151,10 @@ - (void)destroy | |
[self.delegate glContextWillDestroy:self]; | |
} | |
+ // stop listening for foreground/background transitions | |
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; | |
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; | |
+ | |
// Flush all the stuff | |
UEXGLContextFlush(self->_contextId); | |
diff --git a/node_modules/expo-gl/ios/EXGL/EXGLView.mm b/node_modules/expo-gl/ios/EXGL/EXGLView.mm | |
index e7ca617..324e148 100644 | |
--- a/node_modules/expo-gl/ios/EXGL/EXGLView.mm | |
+++ b/node_modules/expo-gl/ios/EXGL/EXGLView.mm | |
@@ -235,6 +235,8 @@ - (void)removeFromSuperview | |
- (void)draw | |
{ | |
+ @synchronized(self) { // DJM | |
+ | |
// exglCtxId may be unset if we get here (on the UI thread) before UEXGLContextCreate(...) is | |
// called on the JS thread to create the EXGL context and save its id (see EXGLContext.initializeContextWithBridge method). | |
// In this case no GL work has been sent yet so we skip this frame. | |
@@ -248,7 +250,7 @@ - (void)draw | |
// This happens exactly at `gl.endFrameEXP()` in the queue | |
if (_viewColorbuffer != 0 && !_renderbufferPresented) { | |
// bind renderbuffer and present it on the layer | |
- [_glContext runInEAGLContext:_uiEaglCtx callback:^{ | |
+ [_glContext runAsync:^{ | |
glBindRenderbuffer(GL_RENDERBUFFER, self->_viewColorbuffer); | |
[self->_uiEaglCtx presentRenderbuffer:GL_RENDERBUFFER]; | |
}]; | |
@@ -257,12 +259,14 @@ - (void)draw | |
_renderbufferPresented = YES; | |
} | |
} | |
+ } // @synchronized(self) | |
} | |
// [GL thread] blits framebuffers and then sets a flag that informs UI thread | |
// about presenting the new content of the renderbuffer on the next draw call | |
- (void)blitFramebuffers | |
{ | |
+ @synchronized(self) { // DJM | |
if (_glContext.isInitialized && _viewFramebuffer != 0 && _viewColorbuffer != 0) { | |
// Save surrounding framebuffer | |
GLint prevFramebuffer; | |
@@ -290,6 +294,7 @@ - (void)blitFramebuffers | |
// mark renderbuffer as not presented | |
_renderbufferPresented = NO; | |
} | |
+ } // @synchronized(self) | |
} | |
#pragma mark - EXGLContextDelegate |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment