Android Performance

Android Performance Optimization: Overdraw - Theory

Word count: 1.7kReading time: 10 min
2014/10/20
loading

It’s been a while since my last blog update. After joining a new company, I’ve been quite busy and haven’t been able to update the blog as frequently as before. However, the VPN I set up on this VPS is used daily and performs quite well. Recently, I’ve been focusing on Android performance-related topics, specifically Android performance optimization. I’ve realized how little I actually know about this area, so I’m starting from the application layer and working my way down, learning step by step. This series will document my learnings and summaries related to performance optimization.

First, let’s discuss GPU overdraw, which is often the most direct aspect developers encounter. This topic will be divided into two parts: Part 1 will cover the basic principles of GPU overdraw and provide optimization suggestions, while Part 2 will use practical examples to demonstrate general steps for optimizing GPU overdraw.

What is GPU Overdraw?

GPU Overdraw Concept: GPU overdraw occurs when a single pixel on the screen is drawn multiple times (more than once). For example, if a TextView has a background, the pixels displaying the text are drawn at least twice - once for the background and once for the text. GPU overdraw inevitably impacts performance to some extent. Device memory bandwidth is limited, and when overdraw causes an application to require more bandwidth than what’s available, performance degrades. Bandwidth limitations vary across different devices.

Causes of GPU Overdraw

  1. Too many overlapping Views: Multiple views occupying the same screen area
  2. Complex hierarchical stacking: Deep view hierarchies with unnecessary nesting
  3. Longer inflation times: XML layouts with excessive complexity

Impact of GPU Overdraw and Poor XML Layouts

  1. XML Parsing Overhead: Layout files are XML files. Inflating a layout file involves parsing XML, creating corresponding layout objects based on tag information, and establishing associations. More tags and attributes in the XML, along with deeper node tree depth, result in more conditional logic, function nesting, and recursion during parsing, thus consuming more time.

  2. Measurement and Drawing Costs: Inflation is just the first step in layout impact. For an interface to be displayed, after requestLayout(), a series of measure, layout, and draw operations must be executed. The execution time of each step is affected by the layout quality itself. The final display of the interface occurs only after all these operations are completed, so poor layout quality increases the time cost of each step, resulting in longer overall display times.

Basic Concepts and Detection Methods

Android provides three tools to help identify and resolve overdraw issues:

  1. Hierarchy Viewer - For analyzing view hierarchies
  2. Tracer for OpenGL - For GPU performance analysis
  3. Show GPU Overdraw - For visualizing overdraw areas (available in Developer Options)

GPU Overdraw Testing

Overdraw testing is primarily done manually and is the preferred method for discovering application overdraw. Enable “Show GPU Overdraw” in Developer Options:

  • On Meizu phones: Settings → Accessibility → Developer Tools → Hardware Accelerated Rendering → Debug GPU Overdraw → Show Overdraw Areas
  • Note: Meizu phones require enabling developer mode by entering *#*#6961#*#* in the phone dialer
  • PS: This feature is only available on Android 4.2 and above

Color Coding for Overdraw Visualization

GPU overdraw visualization uses the following color coding (from best to worst):

Color Meaning Overdraw Level
Blue Optimal 1x overdraw
Green Acceptable 2x overdraw
Light Red Warning 3x overdraw
Red Critical 4x+ overdraw

Acceptance Criteria

  • Control overdraw to 2x (green areas)
  • No 4x overdraw allowed (red areas)
  • No 3x overdraw (light red areas) covering more than 1/4 of the screen area

Optimization Tools

1. Lint Tool

The Lint tool is Android’s built-in code analysis tool that helps identify potential performance issues and optimization opportunities:

  • In Eclipse: Click to run, and suggestions appear in the bottom window
  • In Android Studio: Built-in Lint tool marks suboptimal areas in yellow
  • Command Line: Can be run via command line for automated checks

Key Benefits:

  • Provides excellent optimization suggestions for layouts
  • Identifies unreasonable or potentially risky code modules
  • Regular use helps maintain code quality

Best Practice: Use the Lint tool frequently to check your application and address all suggestions.

Lint

2. Lint Tool Improvement Examples

From official documentation, here are common Lint suggestions for layout optimization:

Suggestion Description Benefit
Use compound drawables Replace LinearLayout with ImageView+TextView using a compound drawable Reduces view count
Merge root frame Replace root FrameLayout without background/padding with <merge> tag Reduces nesting
Useless leaf Remove layouts with no children or background Flattens hierarchy
Useless parent Remove intermediate layouts without siblings or background Reduces nesting
Deep layouts Avoid layouts with excessive nesting (>10 levels default) Improves performance

3. Hierarchy Viewer

Hierarchy Viewer is part of ADT tools (or Android Monitor) for analyzing view hierarchies:

  • Purpose: Quickly interpret view hierarchies and identify layout issues
  • Usage: Particularly useful for handling layout issues and performance problems
  • Limitation: By default, only works on non-encrypted devices (engineering phones, tablets, or emulators)

For Production Devices: To use Hierarchy Viewer on any phone, add ViewServer to your application.

How to Use:

  1. Connect to the device
  2. Open Hierarchy Viewer (located in tools/ directory or via hierarchyviewer command)
  3. Select the target process
  4. Click “Load View Hierarchy” to display the layout tree

Performance Indicators: Each view module shows three traffic lights representing Measure, Layout, and Draw performance.

Layout Optimization Best Practices

Following these conventional and effective layout principles can help create efficient and reusable UIs:

1. Layout Container Selection

Prefer RelativeLayout and LinearLayout, avoid AbsoluteLayout:

  • LinearLayout: Use for simple, linear arrangements. With the same layout hierarchy, LinearLayout performs slightly better than RelativeLayout.
  • RelativeLayout: Use for complex layouts. RelativeLayout can achieve layouts that would otherwise require LinearLayout nesting, reducing hierarchy depth.

2. Code Reuse and Lazy Loading

  • <include> tag: Extract reusable components and include them where needed
  • <ViewStub> tag: Load infrequently used layouts lazily
  • Dynamic Inflation: Better performance than setVisibility() for showing/hiding views. ViewStub is the optimal choice for this pattern.
  • <merge> tag: Reduce layout nesting levels by merging redundant parent layouts

3. Background Optimization

Remove Redundant Background Colors:

  • For layouts with multiple background colors, keep only the top layer’s color
  • For layouts using Selector as background (e.g., ListView items), set the normal state color to "@android:color/transparent"

Detection Method: Export HierarchyView diagram as PSD and analyze in Photoshop (see this video)

4. Performance Considerations

  • Avoid layout_weight in nested LinearLayouts: Each child component needs to be measured twice, incurring expensive system resources. This is particularly important in ListView and GridView where child components are repeatedly created.
  • Prefer wide and shallow layouts: Create layouts that are wide (more siblings) and shallow (fewer nesting levels) rather than narrow and deep, as reflected in Hierarchy Viewer’s Tree view.

Source Code References

For developers interested in understanding the implementation details, here are the relevant source code locations:

1. Overdraw Rendering Implementation

File: /frameworks/base/libs/hwui/OpenGLRenderer.cpp

This file contains the core implementation for rendering overdraw visualization:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void OpenGLRenderer::renderOverdraw() {
if (mCaches.debugOverdraw && getTargetFbo() == 0) {
const Rect* clip = &mTilingClip;

mCaches.enableScissor();
mCaches.setScissor(clip->left, mFirstSnapshot->height - clip->bottom,
clip->right - clip->left, clip->bottom - clip->top);

// 1x overdraw
mCaches.stencil.enableDebugTest(2);
drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);

// 2x overdraw
mCaches.stencil.enableDebugTest(3);
drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);

// 3x overdraw
mCaches.stencil.enableDebugTest(4);
drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);

// 4x overdraw and higher
mCaches.stencil.enableDebugTest(4, true);
drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);

mCaches.stencil.disable();
}
}

void OpenGLRenderer::countOverdraw() {
size_t count = mWidth * mHeight;
uint32_t* buffer = new uint32_t[count];
glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);

size_t total = 0;
for (size_t i = 0; i < count; i++) {
total += buffer[i] & 0xff;
}

mOverdraw = total / float(count);

delete[] buffer;
}

2. Overdraw Counter Implementation

File: Framework/base/core/java/android/view/HardwareRender.java

This file contains the implementation for displaying the overdraw counter value (Note: This feature was removed in Android 5.0):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
HardwareCanvas canvas, DisplayList displayList) {

if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
if (mDebugOverdrawLayer == null) {
mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
} else if (mDebugOverdrawLayer.getWidth() != mWidth ||
mDebugOverdrawLayer.getHeight() != mHeight) {
mDebugOverdrawLayer.resize(mWidth, mHeight);
}

if (!mDebugOverdrawLayer.isValid()) {
mDebugOverdraw = -1;
return;
}

HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
countOverdraw(layerCanvas);
final int restoreCount = layerCanvas.save();
layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
layerCanvas.restoreToCount(restoreCount);
mDebugOverdrawLayer.end(canvas);

float overdraw = getOverdraw(layerCanvas);
DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();

drawOverdrawCounter(canvas, overdraw, metrics.density);
}
}

private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
final String text = String.format("%.2fx", overdraw);
final Paint paint = setupPaint(density);
// HSBtoColor will clamp the values in the 0..1 range
paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));

canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
}

Reference Articles

Performance Optimization Guides

  1. Optimization Process - Case study on Android performance optimization
  2. Decompilation and Adding GPU Display - Technical deep dive into GPU display implementation

Official Android Documentation

  1. Optimizing Layouts - Official guide for layout optimization
  2. Reusing Layouts - Using <include> tag effectively
  3. Loading Layouts On-Demand - Lazy loading with ViewStub
  4. Smooth Scrolling - Performance tips for scrolling
  5. Hierarchy Viewer Tool - Official tool documentation
  6. Lint Tool Tips - Best practices for using Lint

About Me && Blog

Below is my personal introduction and related links. I look forward to exchanging ideas with fellow professionals in the field. When three people walk together, one is bound to be my teacher!

  1. Blogger’s Personal Introduction: Contains my WeChat and WeChat group links.
  2. Blog Content Navigation: A navigation guide for my blog content.
  3. Personally Curated and Collected Excellent Blog Articles - Must-Know Android Performance Optimization: Welcome to recommend and self-recommend (private message on WeChat is fine)
  4. Android Performance Optimization Knowledge Planet: Welcome to join, thank you for your support!

One person can walk faster, but a group of people can walk farther

WeChat Scan

CATALOG
  1. 1. What is GPU Overdraw?
  2. 2. Causes of GPU Overdraw
  3. 3. Impact of GPU Overdraw and Poor XML Layouts
  4. 4. Basic Concepts and Detection Methods
    1. 4.1. GPU Overdraw Testing
    2. 4.2. Color Coding for Overdraw Visualization
    3. 4.3. Acceptance Criteria
  5. 5. Optimization Tools
    1. 5.1. 1. Lint Tool
    2. 5.2. 2. Lint Tool Improvement Examples
    3. 5.3. 3. Hierarchy Viewer
  6. 6. Layout Optimization Best Practices
    1. 6.1. 1. Layout Container Selection
    2. 6.2. 2. Code Reuse and Lazy Loading
    3. 6.3. 3. Background Optimization
    4. 6.4. 4. Performance Considerations
  7. 7. Source Code References
    1. 7.1. 1. Overdraw Rendering Implementation
    2. 7.2. 2. Overdraw Counter Implementation
  8. 8. Reference Articles
    1. 8.1. Performance Optimization Guides
    2. 8.2. Official Android Documentation
  • About Me && Blog