Upgrade to Pro — share decks privately, control downloads, hide ads and more …

For Butter or Worse

For Butter or Worse

Project Butter was an initiative to make the OS faster and more responsive in Android 4.1. This presentation explains some of the tools and techniques used by the Android team to achieve its goals.

Romain Guy

June 27, 2012
Tweet

More Decks by Romain Guy

Other Decks in Programming

Transcript

  1. Developers

    View Slide

  2. For Butter or Worse
    Smoothing Out Performance in Android UIs
    Chet Haase
    Romain Guy
    Android UI Toolkit Engineers

    View Slide

  3. Developers

    View Slide

  4. jank, noun
    1. Choppy performance
    “Swiping the home screen feels janky”
    2. Discontinuous, surprising experience
    “What's with the jank launching that app?”

    View Slide

  5. butter, tasty noun
    1. Smooth performance
    “Home screen swiping is very buttery”
    2. Fattening spread and cooking ingredient
    “America’s obesity problem is directly
    proportional to the deliciousness of butter”

    View Slide

  6. 2. Discontinuous, surprising experience
    “What's with the jank launching that app?”
    jank, noun
    1. Choppy performance
    “Swiping the home screen feels janky”
    This session will focus on the first kind of jank.

    View Slide

  7. Recipe
    • Butter for eating is made from cream
    • Butter for Android is made from
    - low latency
    - fast, consistent framerate
    Latency
    Event Display

    View Slide

  8. Recipe
    • Butter for eating is made from cream
    • Butter for Android is made from
    - low latency
    - fast, consistent framerate
    Latency
    Event Display

    View Slide

  9. Recipe
    • Butter for eating is made from cream
    • Butter for Android is made from
    - low latency
    - fast, consistent framerate
    Latency
    Event Display Event Display Event Display Event Display Event Display Event Display Event Display Event Display Event Display Event Display Event Display

    View Slide

  10. Input Latency
    Event
    Event
    Queue
    Event
    Event
    Event
    Event
    Process
    Events
    Draw

    View Slide

  11. Input Lag (What a drag)
    `

    View Slide

  12. Input Lag (What a drag)
    `

    View Slide

  13. Input Lag (What a drag)
    `

    View Slide

  14. Input Latency
    a
    a..c
    b
    User Input
    Time
    c d e f g h i j k l m n o p q r s t u v w x
    Dispatcher
    Activity Proc a..c Draw
    d...j
    Proc d..j Draw
    k..s

    View Slide

  15. Input Latency
    a
    a..c
    b
    User Input
    Time
    c d e f g h i j k l m n o p q r s t u v w x
    Dispatcher
    Activity Proc a..c Draw
    d...j
    Proc d..j Draw
    k..s
    Latency
    a
    d
    c
    j

    View Slide

  16. Event Streaming
    a b
    User Input
    Time
    c d e f g h i j k l m n o p q r s t u v w x
    Activity Proc a..f Draw Proc g..o Draw
    VSync VSync

    View Slide

  17. Event Streaming
    a b
    User Input
    Time
    c d e f g h i j k l m n o p q r s t u v w x
    Activity Proc a..f Draw Proc g..o Draw
    VSync VSync
    Latency
    a
    g
    f
    o

    View Slide

  18. Framerate
    Drawing
    Drawing faster is a good start

    View Slide

  19. Framerate
    Drawing
    Drawing faster is a good start

    View Slide

  20. Framerate
    But that's not quite all there is to it...
    Drawing
    Drawing faster is a good start

    View Slide

  21. Drawing: The Big Picture
    Event
    Set Property
    Value
    Invalidate
    Measure &
    Layout
    Prepare
    Draw
    Update
    DisplayList
    Draw
    DisplayList
    Swap
    Buffers
    Composite
    Windows
    Post
    Buffer
    Display
    List
    Dequeue
    Buffer
    Enqueue
    Buffer
    Activity
    SurfaceFlinger

    View Slide

  22. Something
    Happens
    Draw
    Display
    Activity
    SurfaceFlinger

    View Slide

  23. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Event
    Set Property
    Value
    Invalidate

    View Slide

  24. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Measure &
    Layout

    View Slide

  25. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Measure &
    Layout
    Prepare
    Draw
    Dequeue
    Buffer

    View Slide

  26. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Measure &
    Layout
    Prepare
    Draw
    Update
    DisplayList
    Display
    List
    Dequeue
    Buffer

    View Slide

  27. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Measure &
    Layout
    Prepare
    Draw
    Update
    DisplayList
    Draw
    DisplayList
    Display
    List
    Dequeue
    Buffer

    View Slide

  28. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Measure &
    Layout
    Prepare
    Draw
    Update
    DisplayList
    Draw
    DisplayList
    Swap
    Buffers
    Display
    List
    Dequeue
    Buffer
    Enqueue
    Buffer

    View Slide

  29. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Composite
    Windows
    Post
    Buffer

    View Slide

  30. Something
    Happens
    Draw Display
    Something
    Happens
    Draw Display
    Event
    Set Property
    Value
    Invalidate
    Measure &
    Layout
    Prepare
    Draw
    Update
    DisplayList
    Draw
    DisplayList
    Swap
    Buffers
    Composite
    Windows
    Post
    Buffer
    Display
    List
    Dequeue
    Buffer
    Enqueue
    Buffer
    Activity
    SurfaceFlinger

    View Slide

  31. VSync
    Synchronizing rendering with the display refresh
    60 fps
    Displays refresh at 60 Hz, allowing apps to render at 60fps
    VSync (vertical sync) is a way to synchronize the rendering sub-system
    with the refresh of the hardware display.

    View Slide

  32. In practice, the display refresh rate will be between 55 and 60 Hz. If
    your app does not hit 60 fps you might just be maxing out the device’s
    refresh rate. adb shell dumpsys SurfaceFlinger will tell you the exact
    refresh rate of your display.

    View Slide

  33. Android has always used vsync to avoid tearing. Tearing happens when
    swapping buffers does not happen at the vsync. When this occurs, you
    will see part of the screen showing the previous buffer and part of the
    screen showing the new buffer. This effect can be seen in many games
    on consoles for instance.
    Prior to Android 4.1 Jelly Bean, animations and drawing requests were
    however not vsync’d.

    View Slide

  34. Tearing
    Android has always used vsync to avoid tearing. Tearing happens when
    swapping buffers does not happen at the vsync. When this occurs, you
    will see part of the screen showing the previous buffer and part of the
    screen showing the new buffer. This effect can be seen in many games
    on consoles for instance.
    Prior to Android 4.1 Jelly Bean, animations and drawing requests were
    however not vsync’d.

    View Slide

  35. Getting the Pixels to the Screen
    Time
    CPU GPU Visible
    Update
    DisplayList
    Draw
    DisplayList Display

    View Slide

  36. Drawing without VSync
    1
    0
    1
    Time
    Display 1 1 2
    2
    2
    CPU
    GPU
    3
    VSync VSync VSync VSync
    3
    3
    4
    4

    View Slide

  37. Drawing without VSync
    1
    0
    1
    Time
    Display 1 1 2
    2
    2
    CPU
    GPU
    3
    VSync VSync VSync VSync
    3
    3
    4
    4
    Jank!

    View Slide

  38. Drawing with VSync
    1
    0
    1
    Time
    Display 1 2 3
    2
    2
    CPU
    GPU
    4
    VSync VSync VSync VSync
    3
    3
    4
    4

    View Slide

  39. Drawing with DisplayLists
    set property invalidate
    set property invalidate
    set property invalidate
    set property invalidate
    Update
    DisplayList
    Draw
    DisplayList
    Display
    List
    VSync

    View Slide

  40. Drawing with DisplayList Properties
    set property
    set property
    set property
    set property
    Draw
    DisplayList
    Display
    List
    VSync
    DLProps

    View Slide

  41. DisplayList Properties
    • Free with ViewPropertyAnimator
    • Or use ObjectAnimator with View properties
    - alpha
    - translationX/Y
    - scaleX/Y
    - rotation/X/Y

    View Slide

  42. 0
    1
    2
    3
    Time in ms
    Frame
    With DisplayList Properties Without DisplayList Properties
    Comparison of drawing the transition from launcher to the list of all
    apps with and without display list properties. You can see that display
    list properties cost almost nothing

    View Slide

  43. Parallel Processing and Double Buffering
    B
    A
    B
    Time
    Display
    VSync
    B A B
    A
    A
    B
    B
    A
    A
    CPU
    GPU
    A
    VSync VSync VSync

    View Slide

  44. Parallel Processing and Double Buffering
    B
    A
    B
    Time
    Display A B B
    A
    A
    CPU
    GPU
    A
    VSync VSync VSync VSync
    Jank!
    Jank!

    View Slide

  45. Parallel Processing and Double Buffering
    Triple
    B
    A
    B
    Time
    Display A B C
    C
    A
    CPU
    GPU C
    A B
    B
    A
    VSync VSync VSync VSync
    Jank!

    View Slide

  46. Window Composition
    Draw
    DisplayList
    Swap
    Buffers
    Composite
    Windows
    Post
    Buffer
    Activity
    SurfaceFlinger

    View Slide

  47. Window Composition
    GPU
    Draw
    DisplayList
    Swap
    Buffers
    Composite
    Windows
    Post
    Buffer
    Activity
    SurfaceFlinger
    Buffer
    Overlay
    Overlay
    Overlay
    FB
    FB
    FB
    Overlay

    View Slide

  48. android:sdk $ cd platform-tools/
    android:platform-tools $ adb shell 㾑
    dumpsys gfxinfo
    dumpsys gfxinfo is a useful tool to analyze hardware accelerated apps
    shows memory usage, number of views and, with the right setting,
    frame profiling data

    View Slide

  49. Must first be enabled
    Go to settings, then developer options

    View Slide

  50. Must first be enabled
    Go to settings, then developer options

    View Slide

  51. Must first be enabled
    Go to settings, then developer options

    View Slide

  52. In Settings > Developer options, enable Profile GPU rendering
    You must destroy your activity before you’ll see the results

    View Slide

  53. In Settings > Developer options, enable Profile GPU rendering
    You must destroy your activity before you’ll see the results

    View Slide

  54. Demo
    Demo doing a dumpsys on com.android.settings
    Shows the array of values: Draw = update display lists Process =
    execute display lists Execute = swap buffers
    Copy the array and paste it in a spreadsheet to visualize the data. You’ll
    see the last 128 frames at most. Every time you capture a series of
    value, the buffer is cleared.

    View Slide

  55. 0
    3
    6
    9
    12
    15
    Time in ms
    Frames
    Update display lists Process display lists Swap buffers
    Scrolling the main screen in Settings on a Nexus 7
    Everything is below 16ms. You can see processing the display lists is
    usually what takes time (turning Canvas commands into OpenGL
    primitives)

    View Slide

  56. android:sdk $ cd tools/systrace
    android:systrace $ ./systrace
    systrace is a new, system-wide, instrumentation tool
    Useful to see how your app interacts with the rest of the world
    It can be used for optimization work. For instance if performance looks
    bad from gfxinfo or gfxinfo looks good but perf is bad

    View Slide

  57. Find and click the Enable traces item

    View Slide

  58. Find and click the Enable traces item

    View Slide

  59. Find and click the Enable traces item

    View Slide

  60. Select the traces you want. Most of the time you’ll want to use Graphics
    and View together, but you should experiment with other traces

    View Slide

  61. Select the traces you want. Most of the time you’ll want to use Graphics
    and View together, but you should experiment with other traces

    View Slide

  62. Select the traces you want. Most of the time you’ll want to use Graphics
    and View together, but you should experiment with other traces

    View Slide

  63. Demo
    Let’s see how it works. Run systrace while scrolling settings, open the
    result and explain what we see: performTraversals/draw/etc.
    Open trace-slow.html and show what a bad app looks like and what to
    do with it. Go in traceview to see what the app does

    View Slide

  64. Captures 5 seconds
    A systrace will capture only 5 seconds of data. You’ll usually run it to
    analyze an animation, a scroll, etc. You can change this behavior with
    an argument (-t)

    View Slide

  65. Stand-alone HTML output
    The output is a stand-alone HTML file you can attach to bug reports,
    email to co-workers, etc.
    Open the help menu to see all the keys you can use. Most useful: WASD
    (just like in FPS games on PC) to move around and zoom in/out

    View Slide

  66. android:sdk $ cd platform-tools/
    android:platform-tools $ adb shell 㾑
    dumpsys SurfaceFlinger

    View Slide

  67. Demo

    View Slide

  68. type | ... | name
    ----------+ ... +-------
    OVERLAY | ... | com...SlowListActivity
    OVERLAY | ... | StatusBar
    OVERLAY | ... | NavigationBar
    Here’s a sample output. You’ll find this table at the end of the dump.
    You want as many windows as possible to go into overlays. Here we
    have 3 windows on screen and everything is composited with overlays,
    it’s great

    View Slide

  69. type | ... | name
    ----------+ ... +-------
    OVERLAY | ... | com...SlowListActivity
    OVERLAY | ... | StatusBar
    OVERLAY | ... | NavigationBar



    Here’s a sample output. You’ll find this table at the end of the dump.
    You want as many windows as possible to go into overlays. Here we
    have 3 windows on screen and everything is composited with overlays,
    it’s great

    View Slide

  70. type | ... | name
    ----------+ ... +------
    OVERLAY | ... | com...SlowListActivity
    FB | ... | PopupWindow:424d4cc8
    FB | ... | StatusBar
    FB | ... | NavigationBar
    In this case our application creates an extra window, the PopupWindow
    The windows now cannot all go in overlays and 3 of them must be
    flattened using GPU composition
    There is a cost: GPU has more work to do, burns fillrate/bandwidth, etc.
    You want to avoid this.

    View Slide

  71. type | ... | name
    ----------+ ... +------
    OVERLAY | ... | com...SlowListActivity
    FB | ... | PopupWindow:424d4cc8
    FB | ... | StatusBar
    FB | ... | NavigationBar




    In this case our application creates an extra window, the PopupWindow
    The windows now cannot all go in overlays and 3 of them must be
    flattened using GPU composition
    There is a cost: GPU has more work to do, burns fillrate/bandwidth, etc.
    You want to avoid this.

    View Slide

  72. Caveats
    The number of overlays depends on the device. The opacity of the
    window may impact whether it goes in an overlay or not. Always use
    dumpsys while the app is drawing, or shortly after it’s done. Android
    has an optimization to move everything to FB (GPU) after a short period
    of time (saves battery when the app doesn’t update)

    View Slide

  73. traceview
    We briefly talked about traceview, you can refer to the official
    documentation in the SDK
    It’s a tracing profiler that helps you see what’s going on in your app
    and how much time it takes
    It’s one of the most important tools at your disposal, and you can
    invoke it from ADT or DDMS

    View Slide

  74. HierarchyViewer
    HierarchyViewer is your best friend when it comes to optimizing your
    UI. Use it stand-alone or as part of ADT. It shows you the tree of views
    straight from your app. You can inspect numerous properties, capture
    partial screenshots, force layouts/repaints, export PSD files and much
    more. Custom properties are supported with an annotation.

    View Slide

  75. https://github.com/romainguy/ViewServer
    Note however that HierarchyViewer will not work out of the box on
    consumer devices. You must use an emulator, a userdebug or eng
    build, or use ViewServer.java available on github. Apache 2.0, easy to
    use and secure. We’re thinking of ways to integrate this directly into
    ADT.

    View Slide

  76. Tracer for OpenGL ES
    Our newest tool; helps you debug and profile GL apps. Can be useful
    for hardware accelerated apps to see exactly what’s going on behind
    the scenes. Shows you how many commands your app generates, how
    much overdraw they cause, etc. You can also see the time each
    command takes to execute. Note that the commands are grouped by
    view, making it easy to read.

    View Slide

  77. Allocation Tracker
    Allocation Tracker is part of DDMS and the easiest way to track down
    and remove unnecessary allocations from your app. Each allocation has
    a type, size and stack trace.
    Anecdote: as I was preparing this talk, I decided to take a screenshot of
    Allocation Tracker. This lead me to discover numerous unnecessary
    allocations caused by the GL rendering pipeline and that affected most
    apps.

    View Slide

  78. Tips & Tricks

    View Slide

  79. ✔ Consistent frame-rate
    ✔ Lower latency
    ✔ Faster display list drawing
    ✔ GPU-free window composition
    ✔ Faster display list updates
    Here are the various things you can improve by applying the following
    tips

    View Slide

  80. new
    Let me tell you how to use this keyword: don’t use it. Use DDMS’
    allocation tracker to ensure you allocate only what you need in
    performance sensitive code paths (onDraw, onMeasure, onLayout,
    touch events, Adapter.getView, etc.)

    View Slide

  81. new
    Let me tell you how to use this keyword: don’t use it. Use DDMS’
    allocation tracker to ensure you allocate only what you need in
    performance sensitive code paths (onDraw, onMeasure, onLayout,
    touch events, Adapter.getView, etc.)

    View Slide

  82. ✔ Consistent frame-rate

    View Slide

  83. public void bindView(View view, Context context, Cursor c) {
    BookViewHolder holder = (BookViewHolder) view.getTag();
    String bookId = c.getString(mInternalIdIndex);
    holder.bookId = bookId;
    holder.sortTitle = c.getString(mSortTitleIndex);
    final ShelvesActivity activity = mActivity;
    if (activity.getScrollState() == SCROLL_STATE_FLING ||
    activity.isPendingCoversUpdate()) {
    holder.title.setCompoundDrawablesWithIntrinsicBounds(
    null, null, null, mDefaultCover);
    holder.queryCover = true;
    } else {
    holder.title.setCompoundDrawablesWithIntrinsicBounds(
    null, null, null,
    ImageUtilities.getCachedCover(bookId, mDefaultCover));
    holder.queryCover = false;
    }
    final CharArrayBuffer buffer = holder.buffer;
    c.copyStringToBuffer(mTitleIndex, buffer);
    final int size = buffer.sizeCopied;
    if (size != 0) {
    holder.title.setText(buffer.data, 0, size);
    }
    }
    In performance sensitive code paths, do less work. Use caches, avoid I/
    O, don’t rescale images on the fly, use background tasks, etc. See Jeff
    Sharkey’s talk.

    View Slide

  84. // Do less!
    In performance sensitive code paths, do less work. Use caches, avoid I/
    O, don’t rescale images on the fly, use background tasks, etc. See Jeff
    Sharkey’s talk.

    View Slide

  85. ✔ Consistent frame-rate
    ✔ Lower latency

    View Slide

  86. android.view.Choreographer
    Choreographer is a new API, very simple, in Android 4.1 Jelly Bean. It
    lets you schedule callbacks on vsync. This is the API used internally by
    the framework to schedule animations, redraws, etc. This API is great if
    your app does its own animations; games for instance.

    View Slide

  87. // Invalidates at the next v-sync event
    myView.postInvalidateOnAnimation();
    Use this method when implementing animations in your view. This is
    how the UI toolkit animates scrolls and flings in ListView, ScrollView,
    etc. Can be invoked from any thread.

    View Slide

  88. callback = new Runnable() {
    public void run() {
    setupAndStartAnimation();
    }
    }
    myView.postOnAnimation(callback);
    Runs an arbitrary action at the next v-sync. Useful to start your custom
    animations

    View Slide

  89. callback = new Choreographer.FrameCallback() {
    public void doFrame(long frameTime) {
    render(frameTime);
    }
    };
    Choreographer c = Choreographer.getInstance();
    c.postFrameCallback(callback);
    If you write a game, you might not have a View, or you’re not using the
    UI thread, so use Choreographer direction. Simply create a
    FrameCallback and pass it to Choreographer. Note that there is one
    Choreographer instance per Looper thread. You can post a callback
    from any thread, but they will run on the Choreographer’s looper.
    The frametime in nanoseconds is very useful to synchronize animations
    on a single time-base. It’s the time at which the vsync event occurred.

    View Slide

  90. ✔ Consistent frame-rate
    ✔ Lower latency

    View Slide

  91. view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    Complex view should be animated with layers enabled. A layer is a GPU
    snapshot of your view, and it’s extremely efficient to render. For more
    information, please refer to our Google I/O 2011 talk called “Android
    Accelerated Rendering”, available on YouTube.

    View Slide

  92. view.animate().alpha(0).withLayer();
    Starting with Android 4.1 Jelly Bean, an easier way to use layers is to
    use the new withLayer() API on ViewPropertyAnimator. Easy to write,
    easy to read, very efficient.

    View Slide

  93. ✔ Consistent frame-rate
    ✔ Faster display list drawing

    View Slide


  94. CLIP PING
    Clipping is handled by the UI toolkit to ensure the system only draws
    what needs to be drawn. Usually you don’t have to do anything but if
    you have custom drawing code or custom views you should make sure
    you don’t draw more than what you really need. Here are a couple of
    things you can do to help.

    View Slide

  95. view.invalidate();
    Whenever you call View.invalidate() ensure you need to redraw the
    entire view. In many situations a partial invalidate is enough and will
    help performance. Simply specify the region of the view that needs to
    be redrawn. A great example of this is EditText and its blinking cursor.

    View Slide

  96. view.invalidate(left, top, right, bottom);
    Whenever you call View.invalidate() ensure you need to redraw the
    entire view. In many situations a partial invalidate is enough and will
    help performance. Simply specify the region of the view that needs to
    be redrawn. A great example of this is EditText and its blinking cursor.

    View Slide

  97. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    Calling invalidate() on a View will cause that entire View (and any view it
    intersects) to redraw. In this example, a complex view causes all of its
    children to redraw. Each display list must be executed.

    View Slide

  98. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    invalidate()
    Calling invalidate() on a View will cause that entire View (and any view it
    intersects) to redraw. In this example, a complex view causes all of its
    children to redraw. Each display list must be executed.

    View Slide

  99. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    invalidate()
    Draw display lists
    Calling invalidate() on a View will cause that entire View (and any view it
    intersects) to redraw. In this example, a complex view causes all of its
    children to redraw. Each display list must be executed.

    View Slide

  100. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList
    DisplayList
    DisplayList
    DisplayList DisplayList DisplayList
    DisplayList
    DisplayList
    invalidate()
    Draw display lists
    Calling invalidate() on a View will cause that entire View (and any view it
    intersects) to redraw. In this example, a complex view causes all of its
    children to redraw. Each display list must be executed.

    View Slide

  101. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    With invalidate(l, t, r, b) the rendering pipeline can cull (i.e. ignore)
    entire parts of the render tree. This leads to significant performance
    improvements when used properly.

    View Slide

  102. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    invalidate(l, t, r, b)
    With invalidate(l, t, r, b) the rendering pipeline can cull (i.e. ignore)
    entire parts of the render tree. This leads to significant performance
    improvements when used properly.

    View Slide

  103. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    invalidate(l, t, r, b)
    Draw display lists
    With invalidate(l, t, r, b) the rendering pipeline can cull (i.e. ignore)
    entire parts of the render tree. This leads to significant performance
    improvements when used properly.

    View Slide

  104. DisplayList
    DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList DisplayList
    DisplayList
    DisplayList
    DisplayList
    DisplayList
    invalidate(l, t, r, b)
    Draw display lists
    With invalidate(l, t, r, b) the rendering pipeline can cull (i.e. ignore)
    entire parts of the render tree. This leads to significant performance
    improvements when used properly.

    View Slide

  105. ✔ Faster display list drawing

    View Slide

  106. In developer settings, use “Show GPU view updates” to enable a tool
    that flashes the region of the screen you invalidate. This is very useful
    to ensure you only invalidate what’s needed.

    View Slide

  107. In developer settings, use “Show GPU view updates” to enable a tool
    that flashes the region of the screen you invalidate. This is very useful
    to ensure you only invalidate what’s needed.

    View Slide

  108. Don’t draw invisible items
    invalidate(l,t,r,b) is useful to tell the system what parts of the screen to
    redraw. It is equally important to never draw pieces of the UI that will
    never be visible to the user. In this section we’ll focus on a real-world
    example, using the Google application, new in Android 4.1 Jelly Bean.
    When the app shows you suggestion cards, they can appear stacked. If
    you use standard views, overdraw will occur.

    View Slide

  109. Let’s concentrate on two of the cards to see how they are implemented.

    View Slide

  110. Let’s concentrate on two of the cards to see how they are implemented.

    View Slide

  111. Let’s concentrate on two of the cards to see how they are implemented.

    View Slide

  112. If you just stack the two cards using regular Views, here is how they will
    be drawn. First the bottom view, then the top one. There is quite a lot
    of overdraw happening here, highlighted in red. What can we do to get
    rid of that overdraw?

    View Slide

  113. If you just stack the two cards using regular Views, here is how they will
    be drawn. First the bottom view, then the top one. There is quite a lot
    of overdraw happening here, highlighted in red. What can we do to get
    rid of that overdraw?

    View Slide

  114. If you just stack the two cards using regular Views, here is how they will
    be drawn. First the bottom view, then the top one. There is quite a lot
    of overdraw happening here, highlighted in red. What can we do to get
    rid of that overdraw?

    View Slide

  115. If you just stack the two cards using regular Views, here is how they will
    be drawn. First the bottom view, then the top one. There is quite a lot
    of overdraw happening here, highlighted in red. What can we do to get
    rid of that overdraw?

    View Slide

  116. @Override
    public void onDraw(Canvas c) {
    c.save();
    if (stacked) {
    c.clipRect(headerLeft, headerTop,
    headerRight, headerBottom);
    }
    drawHeader(c);
    drawContent(c);
    c.restore();
    }
    The trick is to set the clip rect to include only the “header” of the
    stacked card. This way the content won’t be drawn at all.

    View Slide

  117. Here’s what the render pass looks like now that we properly clip the
    content of the bottom card. No more wasted cycles on drawing hidden
    content.

    View Slide

  118. clipRect
    Here’s what the render pass looks like now that we properly clip the
    content of the bottom card. No more wasted cycles on drawing hidden
    content.

    View Slide

  119. clipRect
    Here’s what the render pass looks like now that we properly clip the
    content of the bottom card. No more wasted cycles on drawing hidden
    content.

    View Slide

  120. clipRect
    Here’s what the render pass looks like now that we properly clip the
    content of the bottom card. No more wasted cycles on drawing hidden
    content.

    View Slide

  121. ✔ Faster display list drawing
    Properly clipping your custom views will help reduce the time spent
    drawing display lists. But we can do better.

    View Slide

  122. private void drawContent(Canvas c) {
    for (Item item : itemsList) {
    if (!c.quickReject(item.l, item.t, item.r, item.b,
    Canvas.EdgeType.BW)) {
    item.draw(c);
    }
    }
    }
    If quickReject() returns true, then the specified rectangle is outside of
    the current clip region. Which means whatever you draw within the
    bounds of the specified rectangle will not show up on screen. In this
    case you can simply avoid calling your drawing code. This is what the
    UI toolkit does automatically with views.

    View Slide

  123. ✔ Faster display list drawing
    ✔ Faster display list updates
    Any piece of code you can avoid running is a win for performance and
    quickReject can help you.

    View Slide

  124. Dim layer
    The dim layer is a special layer on Android, managed by the window
    manager and SurfaceFlinger. Any window can request the dim layer to
    draw attention to the foreground. It helps the user by giving context
    (you are still performing the same task) but removes distractions.

    View Slide

  125. getWindow().addFlags(
    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    Requesting a dim layer is very easy. Just set the appropriate flag on
    your activity’s or dialog’s window. You can also change the dim
    amount.

    View Slide

  126. type | ... | name
    ----------+ ... +------
    OVERLAY | ... | com...MyActivity
    FB | ... | DimAnimator
    FB | ... | StatusBar
    FB | ... | NavigationBar
    Using a dim layer will unfortunately introduce a new surface that
    SurfaceFlinger must composite. This is usually enough to make apps
    fall out of the optimized all-overlays case. In addition, the dim layer is
    *always* composited by the GPU. Even if there are enough overlays
    available to do the composition, the dim layer will force a GPU
    composition.

    View Slide

  127. type | ... | name
    ----------+ ... +------
    OVERLAY | ... | com...MyActivity
    FB | ... | DimAnimator
    FB | ... | StatusBar
    FB | ... | NavigationBar




    Using a dim layer will unfortunately introduce a new surface that
    SurfaceFlinger must composite. This is usually enough to make apps
    fall out of the optimized all-overlays case. In addition, the dim layer is
    *always* composited by the GPU. Even if there are enough overlays
    available to do the composition, the dim layer will force a GPU
    composition.

    View Slide

  128. getWindow().addFlags(
    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    If you need the extra resources, use a background drawable instead.
    This is what Android 4.1 Jelly Bean does in the quick contact window to
    ensure the opening animation is smooth, with a consistent frame-rate.

    View Slide

  129. getWindow().addFlags(
    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    getWindow().setBackground(
    new ColorDrawable(0x7f000000));
    If you need the extra resources, use a background drawable instead.
    This is what Android 4.1 Jelly Bean does in the quick contact window to
    ensure the opening animation is smooth, with a consistent frame-rate.

    View Slide

  130. ✔ Faster display list drawing
    ✔ GPU-free window composition
    If you avoid using the dim layer, you can avoid spending GPU resources
    compositing the special dim layer. This will help improve the time spent
    drawing display lists. The fewer layers that need to be composited, the
    better.

    View Slide

  131. Users love butter

    View Slide

  132. Users love butter
    Spread the word

    View Slide

  133. For More Information
    Google I/O 2011
    Parleys.com
    Accelerated Android Rendering
    Various Android GUI performance talks

    View Slide

  134. Q&A
    +Chet Haase
    +Romain Guy
    @chethaase
    @romainguy

    View Slide

  135. Developers

    View Slide