An app may draw the same pixel more than once within a single frame, an event called overdraw. Overdraw is usually unnecessary, and best eliminated. It manifests itself as a performance problem by wasting GPU time to render pixels that don't contribute to what the user sees on the screen.
This document explains overdraw: what it is, how to diagnose it, and actions you can take to eliminate or mitigate it.
Overdraw refers to the system's drawing a pixel on the screen multiple times in a single frame of rendering. For example, if we have a bunch of stacked UI cards, each card hides a portion of the one below it.
However, the system still needs to draw even the hidden portions of the cards in the stack. This is because stacked cards are rendered according to the painter's algorithm: that is, in back-to-front order. This sequence of rendering allows the system to apply proper alpha blending to translucent objects such as shadows.
Finding Overdraw Problems
The platform offers several tools to help you determine if overdraw is affecting your app's performance. These tools are available right on the device, and accessible by turning on Developer Settings under Settings. For more information about device developer settings, see Run Apps on a Hardware Device.
Debug GPU overdraw tool
The Debug GPU Overdraw tool uses color-coding to show the number of times your app draws each pixel on the screen. The higher this count, the more likely it is that overdraw affects your app's performance.
Profile GPU rendering tool
The Profile GPU Rendering tool displays, as a scrolling histogram, the time each stage of the rendering pipeline takes to display a single frame. The Process part of each bar, indicated in orange, shows when the system is swapping buffers; this metric provides important clues about overdraw.
On less performant GPUs, available fill-rate (the speed at which the GPU can fill the frame buffer) can be quite low. As the number of pixels required to draw a frame increases, the GPU may take longer to process new commands, and ask the rest of the system to wait until it can catch up. The Process bar shows that this spike happens as the GPU gets overwhelmed trying to draw pixels as fast as possible. Issues other than raw numbers of pixels may also cause this metric to spike. For example, if the Debug GPU Overdraw tool shows heavy overdraw and Process spikes, there's likely an issue with overdraw.
Note: The Profile GPU Rendering tool does not work with apps that use the NDK. This is because the system pushes framework messages to the background whenever OpenGL takes a full-screen context. In such cases, you may find a profiling tool provided by the GPU manufacturer helpful.
There are several strategies you can pursue to reduce or eliminate overdraw:
- Removing unneeded backgrounds in layouts.
- Flattening the view hierarchy.
- Reducing transparency.
This section provides information about each of these approaches.
Removing unneeded backgrounds in layouts
By default, a layout does not have a background, which means it does not render anything directly by itself. When layouts do have backgrounds, however, they may contribute to overdraw.
Removing unnecessary backgrounds is a quick way of improving rendering performance. An unnecessary background may never be visible because it's completely covered by everything else the app is drawing on top of that view. For example, the system may entirely cover up a parent's background when it draws child views on top of it.
To find out why you're overdrawing, walk through the hierarchy in the Hierarchy Viewer tool. As you do so, look out for any backgrounds you can eliminate because they are not visible to the user. Cases where many containers share a common background color offer another opportunity to eliminate unneeded backgrounds: You can set the window background to the main background color of your app, and leave all of the containers above it with no background values defined.
Flattening view hierarchy
Modern layouts make it easy to stack and layer views to produce beautiful design. However, doing so can degrade performance by resulting in overdraw, especially in scenarios where each stacked view object is opaque, requiring the drawing of both seen and unseen pixels to the screen.
If you encounter this sort of issue, you may be able to improve performance by optimizing your view hierarchy to reduce the number of overlapping UI objects. For more information about how to accomplish this, see Optimizing View Hierarchies.
Rendering of transparent pixels on screen, known as alpha rendering, is a key
contributor to overdraw. Unlike standard overdraw,
in which the system completely hides existing drawn pixels by drawing
opaque pixels on top of them, transparent
objects require existing pixels to be drawn first, so that the right blending
equation can occur. Visual effects like transparent animations, fade-outs, and
drop shadows all involve some sort of transparency, and can therefore contribute
significantly to overdraw. You can improve overdraw in these situations by
reducing the number of transparent objects you render. For example, you can get
gray text by drawing black text in a
TextView with a
translucent alpha value set on it. But you can get the same effect with far
better performance by simply drawing the text in gray.
To learn more about performance costs that transparency imposes throughout the entire drawing pipeline, watch the video Hidden Costs of Transparency.