The Android Frame Pacing library, also known as Swappy, is part of the Android Game SDK. It helps OpenGL and Vulkan games achieve smooth rendering and correct frame pacing on Android.
Frame pacing is the synchronization of a game's logic and rendering loop with an OS's display subsystem and underlying display hardware. The Android display subsystem was designed to avoid certain visual artifacts, such as tearing. The display subsystem avoids tearing by doing the following:
- Buffering past frames internally
- Detecting late frame submissions
- Continuing to display the current frame when a late frame is detected
Inconsistent frame display times are caused by a game's render loop running at a different rate than what the native display hardware supports. Problems arise when a game's render loop runs too slowly for the underlying display hardware, leading to inconsistent display times. For example, when a game running at 30 fps attempts to render on a device that natively supports 60 fps, the game's render loop causes a repeated frame to remain on the screen for an extra 16 ms. This type of disconnect creates substantial inconsistencies in frame times such as 33 ms, 16 ms, 49 ms, and so on. Overly complex scenes further compound this problem because they cause missed frames to occur.
The Frame Pacing library performs these tasks:
- Compensates for stuttering due to short game frames.
- Adds presentation timestamps so that frames are presented on time, not early.
- Uses presentation timestamp extensions
EGL_ANDROID_presentation_time
andVK_GOOGLE_display_timing
.
- Uses sync fences for long frames that lead to stuttering and latency.
- Injects waits into the app. These allow the display pipeline to catch up, rather than allowing back pressure to build up.
- Uses sync fences (
EGL_KHR_fence_sync
andVkFence
).
- Chooses a refresh rate to provide flexibility and a smooth presentation, if your device supports multiple refresh rates.
- Provides stats for debugging and profiling using frame stats.
To learn how to configure the library to operate in different modes according to what you need, see Supported operating modes.
To implement using OpenGL renderer or Vulkan renderer, see
- Integrate Android Frame Pacing into your OpenGL renderer
- Integrate Android Frame Pacing into your Vulkan renderer
To read more, see Achieve proper frame pacing.
Frames per second throttling intervention
Frames per second (FPS) throttling intervention enables games to pace at an appropriate FPS using only platform side changes and without requiring any action on the developers' part.
The implementation of the FPS throttling intervention uses the following components:
GameManagerService
The
GameManagerService component maintains all per-user and
per-game information of game mode and game intervention. The FPS information is stored in the
GameManagerService with other intervention information, such as the resolution downscaling factor,
in a <PACKAGE_NAME, Interventions>
mapping for each user profile.
The FPS information is accessed when the game mode is changed or the intervention is updated. A
UID
is unique to each PACKAGE_NAME
and user, and can further be translated
into a <UID, Frame Rate>
pair to send to the SurfaceFlinger.
SurfaceFlinger
SurfaceFlinger component already supports throttling the FPS of an application as long as the frame rate is a divisor of the display refresh rate. In the event of a vsync, the SurfaceFlinger checks the validity of the vsync for the throttled application by verifying whether the vsync timestamp is in phase with the frame rate of the application. If the frame rate is not in phase with the vsync, then the SurfaceFlinger holds the frame until the frame rate and vsync are in phase.
The following figure describes the interaction between the GameManagerService and the SurfaceFlinger:
The SurfaceFinger maintains a <UID, Frame Rate>
pair mapping to set a new
frame rate throttling priority. The UID
is unique between users and games, so that each
user on a single device can have different settings of frame rate on the same game. To throttle the
frame rate of a game, the GameServiceManager calls the SurfaceFlinger to override the frame rate for
a UID. With this mechanism, the SurfaceFlinger updates the mapping whenever
the game mode is changed or the intervention is updated. The SurfaceFlinger handles the FPS change
by latching buffers accordingly.
To understand more about FPS throttling, see FPS throttling introduction.