Tuning Main Loop Performance
Setting Up Desired Frame-Rate
Unity iOS allows you to tweak how many times per second your application will try to execute its rendering loop. By default it is 30 times per second. By lowering this number, your application will save more battery power but will render fewer frames per second. By increasing this value, rendering will be prioritized over other activities such as touch input and accelerometer processing. You will need to experiment with the frame-rate selection and determine for yourself the impact it has on your specific game.
If your application is computational or rendering heavy and can maintain say only 15 frames per second, then setting desired frame rate over 15 wouldn't make any sense. First you have to optimize your application, then increase desired frame-rate.
To set the desired frame-rate, open your XCode project generated by Unity iOS, and select the AppController.mm
file. Locate and change #define kFPS 30
to a desired value, for example: #define kFPS 60
.
Choosing the Best Rendering Loop
The Apple standard way of using System Timer for scheduling rendering is perfect for non-performance critical applications which favours battery life and scrupulous correct events processing over rendering performance. However, some games might prefer frame-rate over battery life. Therefore, Unity provides alternate methods which allows you to run in a tighter rendering loop:
- System Timer - approach usually suggested by Apple. Uses NSTimer to schedule rendering. Has worst performance, but guarantees to process all input events.
- Thread - separate thread is used to schedule rendering. Provides good performance improvement comparing with System Timer approach, but sometimes could miss touch or accelerometer events. This approach is easiest to setup.
- Event Pump - uses CFRunLoop object to dispatch events. Provides good performance improvement comparing with System Timer approach. Allows you to explicitly define how much time operating system should spend on processing touch and accelerometer events. Care must be taken however as lack of time will result in lost touch or accelerometer events.
Unity uses a thread-based rendering loop for devices with operating system older than version 3.1 by default.
Setting up System Timer Based Main Loop
Open the XCode project generated by Unity iOS. Select the AppController.mm
file, locate and uncomment #define MAIN_LOOP_TYPE NSTIMER_BASED_LOOP
, make sure both defines for other main loop types are removed or commented out:
#define MAIN_LOOP_TYPE NSTIMER_BASED_LOOP //#define MAIN_LOOP_TYPE THREAD_BASED_LOOP //#define MAIN_LOOP_TYPE EVENT_PUMP_BASED_LOOP
If you want to prioritize rendering over input processing with the System Timer based approach you have to locate and change #define kThrottleFPS 2.0
in AppController.mm
file (for example, to #define kThrottleFPS 4.0
). Increasing this number will give higher priority to rendering. The result of changing this value might differ for different applications, so it's best to try it for yourself and see the impact on your specific case.
Setting up Thread Based Main Loop
Open the XCode project generated by Unity iOS. Select the AppController.mm
file, locate and uncomment #define MAIN_LOOP_TYPE THREAD_BASED_LOOP
, and make sure both defines for other main loop types are removed or commented out:
//#define MAIN_LOOP_TYPE NSTIMER_BASED_LOOP #define MAIN_LOOP_TYPE THREAD_BASED_LOOP //#define MAIN_LOOP_TYPE EVENT_PUMP_BASED_LOOP
Setting up Event Pump Based Main Loop
Open the XCode project generated by Unity iOS. Select the AppController.mm
file, locate and uncomment #define MAIN_LOOP_TYPE EVENT_PUMP_BASED_LOOP
, and make sure both defines for other main loop types are removed or commented out:
//#define MAIN_LOOP_TYPE NSTIMER_BASED_LOOP //#define MAIN_LOOP_TYPE THREAD_BASED_LOOP #define MAIN_LOOP_TYPE EVENT_PUMP_BASED_LOOP
If you chose the Event Pump based rendering loop, then you have to carefully tweak the kMillisecondsPerFrameToProcessEvents
constant to achieve the desired responsiveness. The kMillisecondsPerFrameToProcessEvents
constant allows you to specify exactly how much time (in milliseconds) you will allow the OS to process events. If you allocate insufficient time for this task, then touch or accelerometer events might be lost resulting in a fast, but less responsive application.
To specify the amount of time (in milliseconds) that the OS will spend processing events, you have to locate and change #define kMillisecondsPerFrameToProcessEvents 7.0
in AppController.mm
file, for example to #define kMillisecondsPerFrameToProcessEvents 3.0
Display Link Support
Although CADisplayLink was introduced in the iOS3.1 and theoretically should be a preferable approach for scheduling rendering, some developers reported occasional input lag on 1st generation of devices with OS 3.1 installed. If you wish to enable CADisplayLink support for your application, then you will have to open the XCode project generated by Unity iOS, select the AppController.mm
file, and locate and change #define USE_DISPLAY_LINK_IF_AVAILABLE 0
into #define USE_DISPLAY_LINK_IF_AVAILABLE 1
Tuning Accelerometer Processing Frequency
A high frequency of accelerometer input processing might have a negative impact on overall performance of your game. By default an iOS Unity application will query the accelerometer input 60 times per second. You might discover an additional performance improvement by lowering the accelerometer frequency or even setting it to 0, if your game is not using the accelerometer at all.
To specify desired processing frequency for the accelerometer you will have to open the Unity generated XCode project, select the AppController.mm file and change #define kAccelerometerFrequency 60
to a different value, for example: define kAccelerometerFrequency 10