Frame pacing

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.
  • 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 and VkFence).
  • 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

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:

Interaction between the GameManagerService and the SurfaceFlinger

Figure 1. Interaction between the GameServiceManager and 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.