Loading IOS game assets in the background.
In a previous blog post I commented on how my game ran fine in the simulator but crashed after about 20 seconds on a device not connected to XCode. The cause of this was that it failed to launch in time so IOS killed it.
Application Specific Information:
Raiblin.DecadeEngine failed to launch in time
Elapsed total CPU time (seconds): 21.310 (user 21.310, system 0.000), 53% CPU
Elapsed application CPU time (seconds): 19.936, 50% CPU
Blocking the main thread anywhere (in viewDidLoad or in the first frame of glkView) caused this exception. It is also not possible to load the assets on a background thread from C++.
The apple developer document on Concurrency and OpenGL ES states
Each thread in iOS has a single current OpenGL ES rendering context. Every time your application calls an OpenGL ES function, OpenGL ES implicitly looks up the context associated with the current thread and modifies the state or objects associated with that context.
OpenGL ES is not reentrant. If you modify the same context from multiple threads simultaneously, the results are unpredictable. Your application might crash or it might render improperly.
Thankfully Objective C does present us a way to use a background thread but use the main threads OpenGL context.
In viewDidLoad I perform a selector in the background, passing the current OpenGL context as the object parameter.
[self performSelectorInBackground:@selector(loadGameWithContext:) withObject:[EAGLContext currentContext]]
Before doing anything in the background selector, set the current context to be the main threads context.
-(void) loadGameWithContext:(EAGLContext*) main_context
_game = unique_ptr<Woof>(new Woof());
_loaded = YES;
One thing to note is that while calling OpenGL functions on the background selector you should not also call them on the main thread. As stated above, “If you modify the same context from multiple threads simultaneously, the results are unpredictable.” My app usually crashed when 2 or more threads were calling the OpenGL API.
The result of using this code means that my game now starts successfully on all devices I’ve tested on, but since I cannot do any rendering on the main thread while the background is loading my assets I have a black screen for about 25 seconds. I can either load a static image which I display before loading starts and it remains for the duration of loading, or I can break my loading into multiple steps, allowing the main thread to update the display between selectors with perhaps a progress bar etc…