Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 1 | page.title=Hardware Acceleration |
| 2 | parent.title=Graphics |
| 3 | parent.link=index.html |
| 4 | @jd:body |
| 5 | |
| 6 | |
| 7 | <div id="qv-wrapper"> |
| 8 | <div id="qv"> |
| 9 | <h2>In this document</h2> |
| 10 | |
| 11 | <ol> |
| 12 | <li><a href="#controlling">Controlling Hardware Acceleration</a></li> |
| 13 | <li><a href="#determining">Determining if a View is Hardware Accelerated</a></li> |
| 14 | <li><a href="#model">Android Drawing Models</a> |
| 15 | |
| 16 | <ol> |
| 17 | <li><a href="#software-model">Software-based drawing model</a></li> |
| 18 | <li><a href="#hardware-model">Hardware accelerated drawing model</a></li> |
| 19 | </ol> |
| 20 | </li> |
| 21 | |
| 22 | <li> |
| 23 | <a href="#unsupported">Unsupported Drawing Operations</a> |
| 24 | </li> |
| 25 | |
| 26 | |
| 27 | |
| 28 | <li> |
| 29 | <a href="#layers">View Layers</a> |
| 30 | |
| 31 | <ol> |
| 32 | <li><a href="#layers-anims">View Layers and Animations</a></li> |
| 33 | </ol> |
| 34 | </li> |
| 35 | |
| 36 | <li><a href="#tips">Tips and Tricks</a></li> |
| 37 | </ol> |
| 38 | |
| 39 | <h2>See also</h2> |
| 40 | |
| 41 | <ol> |
| 42 | <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL with the Framework |
| 43 | APIs</a></li> |
| 44 | |
Robert Ly | 02c9388 | 2012-02-22 11:15:53 -0800 | [diff] [blame] | 45 | <li><a href="{@docRoot}guide/topics/renderscript/index.html">Renderscript</a></li> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 46 | </ol> |
| 47 | </div> |
| 48 | </div> |
| 49 | |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 50 | <p>Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline supports hardware |
| 51 | acceleration, meaning that all drawing operations that are performed on a {@link |
| 52 | android.view.View}'s canvas use the GPU. Because of the increased resources required to enable |
| 53 | hardware acceleration, your app will consume more RAM.</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 54 | |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 55 | <p>Hardware acceleration is enabled by default if your Target API level is >=14, but can also |
| 56 | be explicitly enabled. If your application uses only standard views and {@link |
| 57 | android.graphics.drawable.Drawable}s, turning it on globally should not cause any adverse drawing |
| 58 | effects. However, because hardware acceleration is not supported for all of the 2D drawing |
| 59 | operations, turning it on might affect some of your custom views or drawing calls. Problems |
| 60 | usually manifest themselves as invisible elements, exceptions, or wrongly rendered pixels. To |
| 61 | remedy this, Android gives you the option to enable or disable hardware acceleration at multiple |
| 62 | levels. See <a href="#controlling">Controlling Hardware Acceleration</a>.</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 63 | |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 64 | <p>If your application performs custom drawing, test your application on actual hardware devices |
| 65 | with hardware acceleration turned on to find any problems. The <a |
| 66 | href="#drawing-support">Unsupported drawing operations</a> section describes known issues with |
| 67 | hardware acceleration and how to work around them.</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 68 | |
| 69 | <h2 id="controlling">Controlling Hardware Acceleration</h2> |
| 70 | <p>You can control hardware acceleration at the following levels:</p> |
| 71 | <ul> |
| 72 | <li>Application</li> |
| 73 | |
| 74 | <li>Activity</li> |
| 75 | |
| 76 | <li>Window</li> |
| 77 | |
| 78 | <li>View</li> |
| 79 | </ul> |
| 80 | |
| 81 | <h4>Application level</h4> |
| 82 | <p>In your Android manifest file, add the following attribute to the |
| 83 | <a href="{@docRoot}guide/topics/manifest/application-element.html"> |
| 84 | <code><application></code></a> tag to enable hardware acceleration for your entire |
| 85 | application:</p> |
| 86 | |
| 87 | <pre> |
| 88 | <application android:hardwareAccelerated="true" ...> |
| 89 | </pre> |
| 90 | |
| 91 | <h4>Activity level</h4> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 92 | <p>If your application does not behave properly with hardware acceleration turned on globally, you |
| 93 | can control it for individual activities as well. To enable or disable hardware acceleration at |
| 94 | the activity level, you can use the <code>android:hardwareAccelerated</code> attribute for |
| 95 | the <a href="{@docRoot}guide/topics/manifest/activity-element.html"> |
| 96 | <code><activity></code></a> element. The following example enables hardware acceleration for |
| 97 | the entire application but disables it for one activity:</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 98 | |
| 99 | <pre> |
| 100 | <application android:hardwareAccelerated="true"> |
| 101 | <activity ... /> |
| 102 | <activity android:hardwareAccelerated="false" /> |
| 103 | </application> |
| 104 | </pre> |
| 105 | |
| 106 | <h4>Window level</h4> |
| 107 | <p>If you need even more fine-grained control, you can enable hardware acceleration for a given |
| 108 | window with the following code:</p> |
| 109 | |
| 110 | <pre> |
| 111 | getWindow().setFlags( |
| 112 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, |
| 113 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); |
| 114 | |
| 115 | </pre> |
| 116 | |
| 117 | <p class="note"><strong>Note</strong>: You currently cannot disable hardware acceleration at |
| 118 | the window level.</p> |
| 119 | |
| 120 | <h4>View level</h4> |
| 121 | |
| 122 | <p>You can disable hardware acceleration for an individual view at runtime with the |
| 123 | following code:</p> |
| 124 | |
| 125 | <pre> |
| 126 | myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); |
| 127 | </pre> |
| 128 | |
| 129 | <p class="note"><strong>Note</strong>: You currently cannot enable hardware acceleration at |
| 130 | the view level. View layers have other functions besides disabling hardware acceleration. See <a |
| 131 | href="#layers">View layers</a> for more information about their uses.</p> |
| 132 | |
| 133 | <h2 id="determining">Determining if a View is Hardware Accelerated</h2> |
| 134 | |
| 135 | <p>It is sometimes useful for an application to know whether it is currently hardware |
| 136 | accelerated, especially for things such as custom views. This is particularly useful if your |
| 137 | application does a lot of custom drawing and not all operations are properly supported by the new |
| 138 | rendering pipeline.</p> |
| 139 | |
| 140 | <p>There are two different ways to check whether the application is hardware accelerated:</p> |
| 141 | |
| 142 | <ul> |
| 143 | <li>{@link android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} returns |
| 144 | <code>true</code> if the {@link android.view.View} is attached to a hardware accelerated |
| 145 | window.</li> |
| 146 | |
| 147 | <li>{@link android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()} |
| 148 | returns <code>true</code> if the {@link android.graphics.Canvas} is hardware accelerated</li> |
| 149 | </ul> |
| 150 | |
| 151 | <p>If you must do this check in your drawing code, use {@link |
| 152 | android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()} instead of {@link |
| 153 | android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} when possible. When a view |
| 154 | is attached to a hardware accelerated window, it can still be drawn using a non-hardware |
| 155 | accelerated Canvas. This happens, for instance, when drawing a view into a bitmap for caching |
| 156 | purposes.</p> |
| 157 | |
| 158 | |
| 159 | <h2 id="model">Android Drawing Models</h2> |
| 160 | |
| 161 | <p>When hardware acceleration is enabled, the Android framework utilizes a new drawing model that |
| 162 | utilizes <em>display lists</em> to render your application to the screen. To fully understand |
| 163 | display lists and how they might affect your application, it is useful to understand how Android |
| 164 | draws views without hardware acceleration as well. The following sections describe the |
| 165 | software-based and hardware-accelerated drawing models.</p> |
| 166 | |
| 167 | <h3>Software-based drawing model</h3> |
| 168 | <p>In the software drawing model, views are drawn with the following two steps:</p> |
| 169 | <ol> |
| 170 | <li>Invalidate the hierarchy</li> |
| 171 | |
| 172 | <li>Draw the hierarchy</li> |
| 173 | </ol> |
| 174 | |
| 175 | <p>Whenever an application needs to update a part of its UI, it invokes {@link |
| 176 | android.view.View#invalidate invalidate()} (or one of its variants) on any view that has changed |
| 177 | content. The invalidation messages are propagated all the way up the view hierarchy to compute |
| 178 | the regions of the screen that need to be redrawn (the dirty region). The Android system then |
| 179 | draws any view in the hierarchy that intersects with the dirty region. Unfortunately, there are |
| 180 | two drawbacks to this drawing model:</p> |
| 181 | <ul> |
| 182 | <li>First, this model requires execution of a lot of code on every draw pass. For example, if |
| 183 | your application calls {@link android.view.View#invalidate invalidate()} on a button and that |
| 184 | button sits on top of another view, the Android system redraws the view even though it hasn't |
| 185 | changed.</li> |
| 186 | <li>The second issue is that the drawing model can hide bugs in your application. Since the |
| 187 | Android system redraws views when they intersect the dirty region, a view whose content you |
| 188 | changed might be redrawn even though {@link android.view.View#invalidate invalidate()} was not |
| 189 | called on it. When this happens, you are relying on another view being invalidated to obtain the |
| 190 | proper behavior. This behavior can change every time you modify your application. Because of |
| 191 | this, you should always call {@link android.view.View#invalidate invalidate()} on your custom |
| 192 | views whenever you modify data or state that affects the view’s drawing code.</li> |
| 193 | </ul> |
| 194 | |
| 195 | <p class="note"><strong>Note</strong>: Android views automatically call {@link |
| 196 | android.view.View#invalidate invalidate()} when their properties change, such as the background |
| 197 | color or the text in a {@link android.widget.TextView}.</p> |
| 198 | |
| 199 | <h3>Hardware accelerated drawing model</h3> |
| 200 | <p>The Android system still uses {@link android.view.View#invalidate invalidate()} and {@link |
| 201 | android.view.View#draw draw()} to request screen updates and to render views, but handles the |
| 202 | actual drawing differently. Instead of executing the drawing commands immediately, the Android |
| 203 | system records them inside display lists, which contain the output of the view hierarchy’s |
| 204 | drawing code. Another optimization is that the Android system only needs to record and update |
| 205 | display lists for views marked dirty by an {@link android.view.View#invalidate invalidate()} |
| 206 | call. Views that have not been invalidated can be redrawn simply by re-issuing the previously |
| 207 | recorded display list. The new drawing model contains three stages:</p> |
| 208 | |
| 209 | <ol> |
| 210 | <li>Invalidate the hierarchy</li> |
| 211 | |
| 212 | <li>Record and update display lists</li> |
| 213 | |
| 214 | <li>Draw the display lists</li> |
| 215 | </ol> |
| 216 | |
| 217 | <p>With this model, you cannot rely on a view intersecting the dirty region to have its {@link |
| 218 | android.view.View#draw draw()} method executed. To ensure that the Android system records a |
| 219 | view’s display list, you must call {@link android.view.View#invalidate invalidate()}. Forgetting |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 220 | to do so causes a view to look the same even after it has been changed.</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 221 | |
| 222 | <p>Using display lists also benefits animation performance because setting specific properties, |
| 223 | such as alpha or rotation, does not require invalidating the targeted view (it is done |
| 224 | automatically). This optimization also applies to views with display lists (any view when your |
| 225 | application is hardware accelerated.) For example, assume there is a {@link |
| 226 | android.widget.LinearLayout} that contains a {@link android.widget.ListView} above a {@link |
| 227 | android.widget.Button}. The display list for the {@link android.widget.LinearLayout} looks like |
| 228 | this:</p> |
| 229 | |
| 230 | <ul> |
| 231 | <li>DrawDisplayList(ListView)</li> |
| 232 | |
| 233 | <li>DrawDisplayList(Button)</li> |
| 234 | </ul> |
| 235 | |
| 236 | <p>Assume now that you want to change the {@link android.widget.ListView}'s opacity. After |
| 237 | invoking <code>setAlpha(0.5f)</code> on the {@link android.widget.ListView}, the display list now |
| 238 | contains this:</p> |
| 239 | |
| 240 | <ul> |
| 241 | <li>SaveLayerAlpha(0.5)</li> |
| 242 | |
| 243 | <li>DrawDisplayList(ListView)</li> |
| 244 | |
| 245 | <li>Restore</li> |
| 246 | |
| 247 | <li>DrawDisplayList(Button)</li> |
| 248 | </ul> |
| 249 | |
| 250 | <p>The complex drawing code of {@link android.widget.ListView} was not executed. Instead, the |
| 251 | system only updated the display list of the much simpler {@link android.widget.LinearLayout}. In |
| 252 | an application without hardware acceleration enabled, the drawing code of both the list and its |
| 253 | parent are executed again.</p> |
| 254 | |
| 255 | <h2 id="unsupported">Unsupported Drawing Operations</h2> |
| 256 | |
| 257 | <p>When hardware accelerated, the 2D rendering pipeline supports the most commonly used {@link |
| 258 | android.graphics.Canvas} drawing operations as well as many less-used operations. All of the |
| 259 | drawing operations that are used to render applications that ship with Android, default widgets |
| 260 | and layouts, and common advanced visual effects such as reflections and tiled textures are |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 261 | supported.</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 262 | |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 263 | <p>The following table describes the support level of various operations across API levels:</p> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 264 | |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 265 | <style type="text/css"> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 266 | .tblGenFixed, .tblGeneric{font-size:15px}.tblGenFixed td {padding:0 3px;letter-spacing:0;word-spacing:0;background-color:#fff;z-index:1;border-top:0px none;border-left:0px none;border-bottom:1px solid #CCC;border-right:1px solid #CCC;} .dn {display:none} .tblGenFixed td.s0 {background-color:white;border-top:1px solid #CCC;border-left:1px solid #CCC;} .tblGenFixed td.s1 {background-color:#434343;color:#ffffff;text-align:center;border-top:1px solid #CCC;} .tblGenFixed td.s2 {background-color:#d9d9d9;color:#000000;text-align:center;} .tblGenFixed td.s3 {background-color:white;color:#000000;text-align:center;} .tblGenFixed td.s5 {background-color:#434343;color:#ffffff;text-align:left;border-left:1px solid #CCC;} .tblGenFixed td.s10 {background-color:white;font-family:courier new,monospace;color:#000000;text-align:right;border-left:1px solid #CCC;} .tblGenFixed td.g_pos {background-color:#d9d9d9;color:#6aa84f;text-align:center;} .tblGenFixed td.g_neg {background-color:#d9d9d9;color:#980000;text-align:center;} .tblGenFixed td.w_pos {background-color:white;color:#6aa84f;text-align:center;} .tblGenFixed td.w_neg {background-color:white;color:#980000;text-align:center;} |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 267 | </style> |
| 268 | <table border="0" cellpadding="0" cellspacing="0" class="tblGenFixed" id="tblMain"> |
| 269 | <tbody> |
| 270 | <tr class="rShim"> |
| 271 | <td class="rShim" style="width:380px;"></td> |
| 272 | <td class="rShim" style="width:120px;"></td> |
| 273 | <td class="rShim" style="width:120px;"></td> |
| 274 | <td class="rShim" style="width:120px;"></td> |
| 275 | <td class="rShim" style="width:120px;"></td> |
| 276 | </tr> |
| 277 | <tr> |
| 278 | <td rowspan="2" class="s0"></td> |
| 279 | <td colspan="4" class="s1">API level</td> |
| 280 | </tr> |
| 281 | <tr> |
| 282 | <td style="display:none;"></td> |
| 283 | <td class="s2">< 16</td> |
| 284 | <td class="s3">16</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 285 | <td class="s2">17</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 286 | <td class="s3">18</td> |
| 287 | </tr> |
| 288 | <tr> |
| 289 | <td colspan="5" class="s5">Canvas</td> |
| 290 | </tr> |
| 291 | <tr> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 292 | <td class="s10">drawBitmapMesh() (colors array)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 293 | <td class="g_neg">✗</td> |
| 294 | <td class="w_neg">✗</td> |
| 295 | <td class="g_neg">✗</td> |
| 296 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 297 | </tr> |
| 298 | <tr> |
| 299 | <td class="s10">drawPicture()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 300 | <td class="g_neg">✗</td> |
| 301 | <td class="w_neg">✗</td> |
| 302 | <td class="g_neg">✗</td> |
| 303 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 304 | </tr> |
| 305 | <tr> |
| 306 | <td class="s10">drawPosText()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 307 | <td class="g_neg">✗</td> |
| 308 | <td class="w_pos">✓</td> |
| 309 | <td class="g_pos">✓</td> |
| 310 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 311 | </tr> |
| 312 | <tr> |
| 313 | <td class="s10">drawTextOnPath()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 314 | <td class="g_neg">✗</td> |
| 315 | <td class="w_pos">✓</td> |
| 316 | <td class="g_pos">✓</td> |
| 317 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 318 | </tr> |
| 319 | <tr> |
| 320 | <td class="s10">drawVertices()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 321 | <td class="g_neg">✗</td> |
| 322 | <td class="w_neg">✗</td> |
| 323 | <td class="g_neg">✗</td> |
| 324 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 325 | </tr> |
| 326 | <tr> |
| 327 | <td class="s10">setDrawFilter()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 328 | <td class="g_neg">✗</td> |
| 329 | <td class="w_pos">✓</td> |
| 330 | <td class="g_pos">✓</td> |
| 331 | <td class="w_pos">✓</td> |
| 332 | </tr> |
| 333 | <tr> |
| 334 | <td class="s10">clipPath()</td> |
| 335 | <td class="g_neg">✗</td> |
| 336 | <td class="w_neg">✗</td> |
| 337 | <td class="g_neg">✗</td> |
| 338 | <td class="w_pos">✓</td> |
| 339 | </tr> |
| 340 | <tr> |
| 341 | <td class="s10">clipRegion()</td> |
| 342 | <td class="g_neg">✗</td> |
| 343 | <td class="w_neg">✗</td> |
| 344 | <td class="g_neg">✗</td> |
| 345 | <td class="w_pos">✓</td> |
| 346 | </tr> |
| 347 | <tr> |
| 348 | <td class="s10">clipRect(Region.Op.XOR)</td> |
| 349 | <td class="g_neg">✗</td> |
| 350 | <td class="w_neg">✗</td> |
| 351 | <td class="g_neg">✗</td> |
| 352 | <td class="w_pos">✓</td> |
| 353 | </tr> |
| 354 | <tr> |
| 355 | <td class="s10">clipRect(Region.Op.Difference)</td> |
| 356 | <td class="g_neg">✗</td> |
| 357 | <td class="w_neg">✗</td> |
| 358 | <td class="g_neg">✗</td> |
| 359 | <td class="w_pos">✓</td> |
| 360 | </tr> |
| 361 | <tr> |
| 362 | <td class="s10">clipRect(Region.Op.ReverseDifference)</td> |
| 363 | <td class="g_neg">✗</td> |
| 364 | <td class="w_neg">✗</td> |
| 365 | <td class="g_neg">✗</td> |
| 366 | <td class="w_pos">✓</td> |
| 367 | </tr> |
| 368 | <tr> |
| 369 | <td class="s10">clipRect() with rotation/perspective</td> |
| 370 | <td class="g_neg">✗</td> |
| 371 | <td class="w_neg">✗</td> |
| 372 | <td class="g_neg">✗</td> |
| 373 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 374 | </tr> |
| 375 | <tr> |
| 376 | <td colspan="5" class="s5">Paint</td> |
| 377 | </tr> |
| 378 | <tr> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 379 | <td class="s10">setAntiAlias() (for text)</td> |
| 380 | <td class="g_neg">✗</td> |
| 381 | <td class="w_neg">✗</td> |
| 382 | <td class="g_neg">✗</td> |
| 383 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 384 | </tr> |
| 385 | <tr> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 386 | <td class="s10">setAntiAlias() (for lines)</td> |
| 387 | <td class="g_neg">✗</td> |
| 388 | <td class="w_pos">✓</td> |
| 389 | <td class="g_pos">✓</td> |
| 390 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 391 | </tr> |
| 392 | <tr> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 393 | <td class="s10">setFilterBitmap()</td> |
| 394 | <td class="g_neg">✗</td> |
| 395 | <td class="w_neg">✗</td> |
| 396 | <td class="g_pos">✓</td> |
| 397 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 398 | </tr> |
| 399 | <tr> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 400 | <td class="s10">setLinearText()</td> |
| 401 | <td class="g_neg">✗</td> |
| 402 | <td class="w_neg">✗</td> |
| 403 | <td class="g_neg">✗</td> |
| 404 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 405 | </tr> |
| 406 | <tr> |
| 407 | <td class="s10">setMaskFilter()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 408 | <td class="g_neg">✗</td> |
| 409 | <td class="w_neg">✗</td> |
| 410 | <td class="g_neg">✗</td> |
| 411 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 412 | </tr> |
| 413 | <tr> |
| 414 | <td class="s10">setPathEffect() (for lines)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 415 | <td class="g_neg">✗</td> |
| 416 | <td class="w_neg">✗</td> |
| 417 | <td class="g_neg">✗</td> |
| 418 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 419 | </tr> |
| 420 | <tr> |
| 421 | <td class="s10">setRasterizer()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 422 | <td class="g_neg">✗</td> |
| 423 | <td class="w_neg">✗</td> |
| 424 | <td class="g_neg">✗</td> |
| 425 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 426 | </tr> |
| 427 | <tr> |
| 428 | <td class="s10">setShadowLayer() (other than text)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 429 | <td class="g_neg">✗</td> |
| 430 | <td class="w_neg">✗</td> |
| 431 | <td class="g_neg">✗</td> |
| 432 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 433 | </tr> |
| 434 | <tr> |
| 435 | <td class="s10">setStrokeCap() (for lines)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 436 | <td class="g_neg">✗</td> |
| 437 | <td class="w_neg">✗</td> |
| 438 | <td class="g_neg">✗</td> |
| 439 | <td class="w_pos">✓</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 440 | </tr> |
| 441 | <tr> |
| 442 | <td class="s10">setStrokeCap() (for points)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 443 | <td class="g_neg">✗</td> |
| 444 | <td class="w_neg">✗</td> |
| 445 | <td class="g_neg">✗</td> |
| 446 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 447 | </tr> |
| 448 | <tr> |
| 449 | <td class="s10">setSubpixelText()</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 450 | <td class="g_neg">✗</td> |
| 451 | <td class="w_neg">✗</td> |
| 452 | <td class="g_neg">✗</td> |
| 453 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 454 | </tr> |
| 455 | <tr> |
| 456 | <td colspan="5" class="s5">Xfermode</td> |
| 457 | </tr> |
| 458 | <tr> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 459 | <td class="s10">AvoidXfermode</td> |
| 460 | <td class="g_neg">✗</td> |
| 461 | <td class="w_neg">✗</td> |
| 462 | <td class="g_neg">✗</td> |
| 463 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 464 | </tr> |
| 465 | <tr> |
| 466 | <td class="s10">PixelXorXfermode</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 467 | <td class="g_neg">✗</td> |
| 468 | <td class="w_neg">✗</td> |
| 469 | <td class="g_neg">✗</td> |
| 470 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 471 | </tr> |
| 472 | <tr> |
| 473 | <td class="s10">PorterDuff.Mode.DARKEN (framebuffer)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 474 | <td class="g_neg">✗</td> |
| 475 | <td class="w_neg">✗</td> |
| 476 | <td class="g_neg">✗</td> |
| 477 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 478 | </tr> |
| 479 | <tr> |
| 480 | <td class="s10">PorterDuff.Mode.LIGHTEN (framebuffer)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 481 | <td class="g_neg">✗</td> |
| 482 | <td class="w_neg">✗</td> |
| 483 | <td class="g_neg">✗</td> |
| 484 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 485 | </tr> |
| 486 | <tr> |
| 487 | <td class="s10">PorterDuff.Mode.OVERLAY (framebuffer)</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 488 | <td class="g_neg">✗</td> |
| 489 | <td class="w_neg">✗</td> |
| 490 | <td class="g_neg">✗</td> |
| 491 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 492 | </tr> |
| 493 | <tr> |
| 494 | <td colspan="5" class="s5">Shader</td> |
| 495 | </tr> |
| 496 | <tr> |
| 497 | <td class="s10">ComposeShader inside ComposeShader</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 498 | <td class="g_neg">✗</td> |
| 499 | <td class="w_neg">✗</td> |
| 500 | <td class="g_neg">✗</td> |
| 501 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 502 | </tr> |
| 503 | <tr> |
| 504 | <td class="s10">Same type shaders inside ComposeShader</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 505 | <td class="g_neg">✗</td> |
| 506 | <td class="w_neg">✗</td> |
| 507 | <td class="g_neg">✗</td> |
| 508 | <td class="w_neg">✗</td> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 509 | </tr> |
Romain Guy | bbb4e03 | 2013-03-19 10:31:38 -0700 | [diff] [blame] | 510 | <tr> |
| 511 | <td class="s10">Local matrix on ComposeShader</td> |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 512 | <td class="g_neg">✗</td> |
| 513 | <td class="w_neg">✗</td> |
| 514 | <td class="g_neg">✗</td> |
| 515 | <td class="w_pos">✓</td> |
Romain Guy | bbb4e03 | 2013-03-19 10:31:38 -0700 | [diff] [blame] | 516 | </tr> |
Romain Guy | 9ff7d16 | 2013-02-26 14:49:35 -0800 | [diff] [blame] | 517 | </tbody> |
| 518 | </table> |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 519 | |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 520 | <h3 id="scaling">Canvas Scaling</h3> |
| 521 | |
| 522 | <p>The hardware accelerated 2D rendering pipeline was built first to support unscaled drawing, |
| 523 | with some drawing operations degrading quality significantly at higher scale values. These |
| 524 | operations are implemented as textures drawn at scale 1.0, transformed by the GPU. In API level |
| 525 | <17, using these operations will result in scaling artifacts increasing with scale.</p> |
| 526 | |
| 527 | The following table shows when implementation was changed to correctly handle large scales: |
| 528 | |
| 529 | <table border="0" cellpadding="0" cellspacing="0" class="tblGenFixed" id="tblMain"> |
| 530 | <tbody> |
| 531 | <tr class="rShim"> |
| 532 | <td class="rShim" style="width:380px;"></td> |
| 533 | <td class="rShim" style="width:120px;"></td> |
| 534 | <td class="rShim" style="width:120px;"></td> |
| 535 | <td class="rShim" style="width:120px;"></td> |
| 536 | </tr> |
| 537 | <tr> |
| 538 | <td rowspan="2" class="s0"></td> |
| 539 | <td colspan="4" class="s1">API level</td> |
| 540 | </tr> |
| 541 | <tr> |
| 542 | <td style="display:none;"></td> |
| 543 | <td class="s2">< 17</td> |
| 544 | <td class="s3">17</td> |
| 545 | <td class="s2">18</td> |
| 546 | </tr> |
| 547 | <tr> |
| 548 | <td colspan="5" class="s5">Support for large scale factors</td> |
| 549 | </tr> |
| 550 | <tr> |
| 551 | <td class="s10">drawText()</td> |
| 552 | <td class="g_neg">✗</td> |
| 553 | <td class="w_neg">✗</td> |
| 554 | <td class="g_pos">✓</td> |
| 555 | </tr> |
| 556 | <tr> |
| 557 | <td class="s10">drawPosText()</td> |
| 558 | <td class="g_neg">✗</td> |
| 559 | <td class="w_neg">✗</td> |
| 560 | <td class="g_neg">✗</td> |
| 561 | </tr> |
| 562 | <tr> |
| 563 | <td class="s10">drawTextOnPath()</td> |
| 564 | <td class="g_neg">✗</td> |
| 565 | <td class="w_neg">✗</td> |
| 566 | <td class="g_neg">✗</td> |
| 567 | </tr> |
| 568 | <tr> |
| 569 | <td class="s10">Simple Shapes*</td> |
| 570 | <td class="g_neg">✗</td> |
| 571 | <td class="w_pos">✓</td> |
| 572 | <td class="g_pos">✓</td> |
| 573 | </tr> |
| 574 | <tr> |
| 575 | <td class="s10">Complex Shapes*</td> |
| 576 | <td class="g_neg">✗</td> |
| 577 | <td class="w_neg">✗</td> |
| 578 | <td class="g_neg">✗</td> |
| 579 | </tr> |
| 580 | <tr> |
| 581 | <td class="s10">drawPath()</td> |
| 582 | <td class="g_neg">✗</td> |
| 583 | <td class="w_neg">✗</td> |
| 584 | <td class="g_neg">✗</td> |
| 585 | </tr> |
| 586 | <tr> |
| 587 | <td class="s10">Shadow layer</td> |
| 588 | <td class="g_neg">✗</td> |
| 589 | <td class="w_neg">✗</td> |
| 590 | <td class="g_neg">✗</td> |
| 591 | </tr> |
| 592 | </tbody> |
| 593 | </table> |
| 594 | |
| 595 | <p class="note"><strong>Note</strong>: 'Simple' shapes are <code>drawRect()</code>, |
| 596 | <code>drawCircle()</code>, <code>drawOval()</code>, <code>drawRoundRect()</code>, and |
| 597 | <code>drawArc()</code> (with useCenter=false) commands issued with a Paint that doesn't have a |
| 598 | PathEffect, and doesn't contain non-default joins (via <code>setStrokeJoin()</code> / |
| 599 | <code>setStrokeMiter()</code>). Other instances of those draw commands fall under 'Complex,' in |
| 600 | the above chart.</p> |
| 601 | |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 602 | <p>If your application is affected by any of these missing features or limitations, you can turn |
Chris Craik | 0f7ade7 | 2013-04-19 16:07:23 -0700 | [diff] [blame] | 603 | off hardware acceleration for just the affected portion of your application by calling {@link |
| 604 | android.view.View#setLayerType setLayerType(View.LAYER_TYPE_SOFTWARE, null)}. This way, you can |
| 605 | still take advantage of hardware acceleration everywhere else. See <a |
| 606 | href="#controlling">Controlling Hardware Acceleration</a> for more information on how to enable |
| 607 | and disable hardware acceleration at different levels in your application. |
Robert Ly | ce8af06 | 2011-09-15 15:18:09 -0700 | [diff] [blame] | 608 | |
| 609 | <h2 id="layers">View Layers</h2> |
| 610 | |
| 611 | <p>In all versions of Android, views have had the ability to render into off-screen buffers, |
| 612 | either by using a view's drawing cache, or by using {@link android.graphics.Canvas#saveLayer |
| 613 | Canvas.saveLayer()}. Off-screen buffers, or layers, have several uses. You can use them to get |
| 614 | better performance when animating complex views or to apply composition effects. For instance, |
| 615 | you can implement fade effects using <code>Canvas.saveLayer()</code> to temporarily render a view |
| 616 | into a layer and then composite it back on screen with an opacity factor.</p> |
| 617 | |
| 618 | <p>Beginning in Android 3.0 (API level 11), you have more control on how and when to use layers |
| 619 | with the {@link android.view.View#setLayerType View.setLayerType()} method. This API takes two |
| 620 | parameters: the type of layer you want to use and an optional {@link android.graphics.Paint} |
| 621 | object that describes how the layer should be composited. You can use the {@link |
| 622 | android.graphics.Paint} parameter to apply color filters, special blending modes, or opacity to a |
| 623 | layer. A view can use one of three layer types:</p> |
| 624 | |
| 625 | <ul> |
| 626 | <li>{@link android.view.View#LAYER_TYPE_NONE}: The view is rendered normally and is not backed |
| 627 | by an off-screen buffer. This is the default behavior.</li> |
| 628 | |
| 629 | <li>{@link android.view.View#LAYER_TYPE_HARDWARE}: The view is rendered in hardware into a |
| 630 | hardware texture if the application is hardware accelerated. If the application is not hardware |
| 631 | accelerated, this layer type behaves the same as {@link |
| 632 | android.view.View#LAYER_TYPE_SOFTWARE}.</li> |
| 633 | |
| 634 | <li>{@link android.view.View#LAYER_TYPE_SOFTWARE}: The view is rendered in software into a |
| 635 | bitmap.</li> |
| 636 | </ul> |
| 637 | |
| 638 | <p>The type of layer you use depends on your goal:</p> |
| 639 | |
| 640 | <ul> |
| 641 | <li><strong>Performance</strong>: Use a hardware layer type to render a view into a hardware |
| 642 | texture. Once a view is rendered into a layer, its drawing code does not have to be executed |
| 643 | until the view calls {@link android.view.View#invalidate invalidate()}. Some animations, such as |
| 644 | alpha animations, can then be applied directly onto the layer, which is very efficient |
| 645 | for the GPU to do.</li> |
| 646 | |
| 647 | <li><strong>Visual effects</strong>: Use a hardware or software layer type and a {@link |
| 648 | android.graphics.Paint} to apply special visual treatments to a view. For instance, you can |
| 649 | draw a view in black and white using a {@link |
| 650 | android.graphics.ColorMatrixColorFilter}.</li> |
| 651 | |
| 652 | <li><strong>Compatibility</strong>: Use a software layer type to force a view to be rendered in |
| 653 | software. If a view that is hardware accelerated (for instance, if your whole |
| 654 | application is hardware acclerated), is having rendering problems, this is an easy way to work |
| 655 | around limitations of the hardware rendering |
| 656 | pipeline.</li> |
| 657 | </ul> |
| 658 | |
| 659 | <h3 id="layers-anims">View layers and animations</h3> |
| 660 | |
| 661 | <p>Hardware layers can deliver faster and smoother animations when your application |
| 662 | is hardware accelerated. Running an animation at 60 frames per second is not always possible when |
| 663 | animating complex views that issue a lot of drawing operations. This can be alleviated by |
| 664 | using hardware layers to render the view to a hardware texture. The hardware texture can |
| 665 | then be used to animate the view, eliminating the need for the view to constantly redraw itself |
| 666 | when it is being animated. The view is not redrawn unless you change the view's |
| 667 | properties, which calls {@link android.view.View#invalidate invalidate()}, or if you call {@link |
| 668 | android.view.View#invalidate invalidate()} manually. If you are running an animation in |
| 669 | your application and do not obtain the smooth results you want, consider enabling hardware layers on |
| 670 | your animated views.</p> |
| 671 | |
| 672 | <p>When a view is backed by a hardware layer, some of its properties are handled by the way the |
| 673 | layer is composited on screen. Setting these properties will be efficient because they do not |
| 674 | require the view to be invalidated and redrawn. The following list of properties affect the way |
| 675 | the layer is composited. Calling the setter for any of these properties results in optimal |
| 676 | invalidation and no redrawing of the targeted view:</p> |
| 677 | |
| 678 | <ul> |
| 679 | <li><code>alpha</code>: Changes the layer's opacity</li> |
| 680 | |
| 681 | <li><code>x</code>, <code>y</code>, <code>translationX</code>, <code>translationY</code>: |
| 682 | Changes the layer's position</li> |
| 683 | |
| 684 | <li><code>scaleX</code>, <code>scaleY</code>: Changes the layer's size</li> |
| 685 | |
| 686 | <li><code>rotation</code>, <code>rotationX</code>, <code>rotationY</code>: Changes the |
| 687 | layer's orientation in 3D space</li> |
| 688 | |
| 689 | <li><code>pivotX</code>, <code>pivotY</code>: Changes the layer's transformations origin</li> |
| 690 | </ul> |
| 691 | |
| 692 | <p>These properties are the names used when animating a view with an {@link |
| 693 | android.animation.ObjectAnimator}. If you want to access these properties, call the appropriate |
| 694 | setter or getter. For instance, to modify the alpha property, call {@link |
| 695 | android.view.View#setAlpha setAlpha()}. The following code snippet shows the most efficient way |
| 696 | to rotate a viewiew in 3D around the Y-axis:</p> |
| 697 | <pre> |
| 698 | view.setLayerType(View.LAYER_TYPE_HARDWARE, null); |
| 699 | ObjectAnimator.ofFloat(view, "rotationY", 180).start(); |
| 700 | </pre> |
| 701 | |
| 702 | <p>Because hardware layers consume video memory, it is highly recommended that you enable them |
| 703 | only for the duration of the animation and then disable them after the animation is done. You |
| 704 | can accomplish this using animation listeners:</p> |
| 705 | <pre> |
| 706 | View.setLayerType(View.LAYER_TYPE_HARDWARE, null); |
| 707 | ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); |
| 708 | animator.addListener(new AnimatorListenerAdapter() { |
| 709 | @Override |
| 710 | public void onAnimationEnd(Animator animation) { |
| 711 | view.setLayerType(View.LAYER_TYPE_NONE, null); |
| 712 | } |
| 713 | }); |
| 714 | animator.start(); |
| 715 | </pre> |
| 716 | |
| 717 | <p>For more information on property animation, see <a href= |
| 718 | "{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a>.</p> |
| 719 | |
| 720 | <h2 id="tips">Tips and Tricks</h2> |
| 721 | |
| 722 | <p>Switching to hardware accelerated 2D graphics can instantly increase performance, but you |
| 723 | should still design your application to use the GPU effectively by following these |
| 724 | recommendations:</p> |
| 725 | |
| 726 | <dl> |
| 727 | <dt><strong>Reduce the number of views in your application</strong></dt> |
| 728 | |
| 729 | <dd>The more views the system has to draw, the slower it will be. This applies to the software |
| 730 | rendering pipeline as well. Reducing views is one of the easiest ways to optimize your UI.</dd> |
| 731 | |
| 732 | <dt><strong>Avoid overdraw</strong></dt> |
| 733 | |
| 734 | <dd>Do not draw too many layers on top of each other. Remove any views that are completely |
| 735 | obscured by other opaque views on top of it. If you need to draw several layers blended on top |
| 736 | of each other, consider merging them into a single layer. A good rule of thumb with current |
| 737 | hardware is to not draw more than 2.5 times the number of pixels on screen per frame |
| 738 | (transparent pixels in a bitmap count!).</dd> |
| 739 | |
| 740 | <dt><strong>Don't create render objects in draw methods</strong></dt> |
| 741 | |
| 742 | <dd>A common mistake is to create a new {@link android.graphics.Paint} or a new {@link |
| 743 | android.graphics.Path} every time a rendering method is invoked. This forces the garbage |
| 744 | collector to run more often and also bypasses caches and optimizations in the hardware |
| 745 | pipeline.</dd> |
| 746 | |
| 747 | <dt><strong>Don't modify shapes too often</strong></dt> |
| 748 | |
| 749 | <dd>Complex shapes, paths, and circles for instance, are rendered using texture masks. Every |
| 750 | time you create or modify a path, the hardware pipeline creates a new mask, which can be |
| 751 | expensive.</dd> |
| 752 | |
| 753 | <dt><strong>Don't modify bitmaps too often</strong></dt> |
| 754 | |
| 755 | <dd>Every time you change the content of a bitmap, it is uploaded again as a GPU texture the |
| 756 | next time you draw it.</dd> |
| 757 | |
| 758 | <dt><strong>Use alpha with care</strong></dt> |
| 759 | |
| 760 | <dd>When you make a view translucent using {@link android.view.View#setAlpha setAlpha()}, |
| 761 | {@link android.view.animation.AlphaAnimation}, or {@link android.animation.ObjectAnimator}, it |
| 762 | is rendered in an off-screen buffer which doubles the required fill-rate. When applying alpha |
| 763 | on very large views, consider setting the view's layer type to |
| 764 | <code>LAYER_TYPE_HARDWARE</code>.</dd> |
| 765 | </dl> |