hardware-accel.jd revision 5ff9df658230d49e42c43586997a02d8e4dd417e
1page.title=Hardware Acceleration 2parent.title=Graphics 3parent.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 45 <li><a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a></li> 46 </ol> 47 </div> 48 </div> 49 50 <p>Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline is designed to 51 better support hardware acceleration. Hardware acceleration carries out all drawing operations 52 that are performed on a {@link android.view.View}'s canvas using the GPU.</p> 53 54 <p>The easiest way to enable hardware acceleration is to turn it on 55 globally for your entire application. If your application uses only standard views and {@link 56 android.graphics.drawable.Drawable}s, turning it on globally should not cause any adverse 57 effects. However, because hardware acceleration is not supported for all of the 2D drawing 58 operations, turning it on might affect some of your applications that use custom views or drawing 59 calls. Problems usually manifest themselves as invisible elements, exceptions, or wrongly 60 rendered pixels. To remedy this, Android gives you the option to enable or disable hardware 61 acceleration at the following levels:</p> 62 63 <ul> 64 <li>Application</li> 65 66 <li>Activity</li> 67 68 <li>Window</li> 69 70 <li>View</li> 71 </ul> 72 73 <p>If your application performs custom drawing, test your application on actual hardware 74devices with hardware acceleration turned on to find any problems. The <a 75href="#drawing-support">Unsupported drawing operations</a> section describes known issues with 76drawing operations that cannot be hardware accelerated and how to work around them.</p> 77 78 79 <h2 id="controlling">Controlling Hardware Acceleration</h2> 80 <p>You can control hardware acceleration at the following levels:</p> 81 <ul> 82 <li>Application</li> 83 84 <li>Activity</li> 85 86 <li>Window</li> 87 88 <li>View</li> 89 </ul> 90 91 <h4>Application level</h4> 92 <p>In your Android manifest file, add the following attribute to the 93 <a href="{@docRoot}guide/topics/manifest/application-element.html"> 94 <code><application></code></a> tag to enable hardware acceleration for your entire 95 application:</p> 96 97<pre> 98<application android:hardwareAccelerated="true" ...> 99</pre> 100 101 <h4>Activity level</h4> 102 <p>If your application does not behave properly with hardware acceleration turned on globally, 103 you can control it for individual activities as well. To enable or disable hardware acceleration 104 at the activity level, you can use the <code>android:hardwareAccelerated</code> 105 attribute for the <a href="{@docRoot}guide/topics/manifest/activity-element.html"> 106 <code><activity></code></a> element. The following example enables hardware acceleration 107for the entire application but disables it for one activity:</p> 108 109<pre> 110<application android:hardwareAccelerated="true"> 111 <activity ... /> 112 <activity android:hardwareAccelerated="false" /> 113</application> 114</pre> 115 116 <h4>Window level</h4> 117 <p>If you need even more fine-grained control, you can enable hardware acceleration for a given 118 window with the following code:</p> 119 120<pre> 121getWindow().setFlags( 122 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 123 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 124 125</pre> 126 127<p class="note"><strong>Note</strong>: You currently cannot disable hardware acceleration at 128the window level.</p> 129 130 <h4>View level</h4> 131 132 <p>You can disable hardware acceleration for an individual view at runtime with the 133following code:</p> 134 135<pre> 136myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 137</pre> 138 139<p class="note"><strong>Note</strong>: You currently cannot enable hardware acceleration at 140the view level. View layers have other functions besides disabling hardware acceleration. See <a 141href="#layers">View layers</a> for more information about their uses.</p> 142 143 <h2 id="determining">Determining if a View is Hardware Accelerated</h2> 144 145 <p>It is sometimes useful for an application to know whether it is currently hardware 146 accelerated, especially for things such as custom views. This is particularly useful if your 147 application does a lot of custom drawing and not all operations are properly supported by the new 148 rendering pipeline.</p> 149 150 <p>There are two different ways to check whether the application is hardware accelerated:</p> 151 152 <ul> 153 <li>{@link android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} returns 154 <code>true</code> if the {@link android.view.View} is attached to a hardware accelerated 155 window.</li> 156 157 <li>{@link android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()} 158 returns <code>true</code> if the {@link android.graphics.Canvas} is hardware accelerated</li> 159 </ul> 160 161 <p>If you must do this check in your drawing code, use {@link 162 android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()} instead of {@link 163 android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} when possible. When a view 164 is attached to a hardware accelerated window, it can still be drawn using a non-hardware 165 accelerated Canvas. This happens, for instance, when drawing a view into a bitmap for caching 166 purposes.</p> 167 168 169 <h2 id="model">Android Drawing Models</h2> 170 171 <p>When hardware acceleration is enabled, the Android framework utilizes a new drawing model that 172 utilizes <em>display lists</em> to render your application to the screen. To fully understand 173 display lists and how they might affect your application, it is useful to understand how Android 174 draws views without hardware acceleration as well. The following sections describe the 175 software-based and hardware-accelerated drawing models.</p> 176 177<h3>Software-based drawing model</h3> 178<p>In the software drawing model, views are drawn with the following two steps:</p> 179 <ol> 180 <li>Invalidate the hierarchy</li> 181 182 <li>Draw the hierarchy</li> 183 </ol> 184 185 <p>Whenever an application needs to update a part of its UI, it invokes {@link 186 android.view.View#invalidate invalidate()} (or one of its variants) on any view that has changed 187 content. The invalidation messages are propagated all the way up the view hierarchy to compute 188 the regions of the screen that need to be redrawn (the dirty region). The Android system then 189 draws any view in the hierarchy that intersects with the dirty region. Unfortunately, there are 190 two drawbacks to this drawing model:</p> 191 <ul> 192 <li>First, this model requires execution of a lot of code on every draw pass. For example, if 193your application calls {@link android.view.View#invalidate invalidate()} on a button and that 194button sits on top of another view, the Android system redraws the view even though it hasn't 195changed.</li> 196 <li>The second issue is that the drawing model can hide bugs in your application. Since the 197 Android system redraws views when they intersect the dirty region, a view whose content you 198 changed might be redrawn even though {@link android.view.View#invalidate invalidate()} was not 199 called on it. When this happens, you are relying on another view being invalidated to obtain the 200 proper behavior. This behavior can change every time you modify your application. Because of 201 this, you should always call {@link android.view.View#invalidate invalidate()} on your custom 202 views whenever you modify data or state that affects the view’s drawing code.</li> 203</ul> 204 205 <p class="note"><strong>Note</strong>: Android views automatically call {@link 206 android.view.View#invalidate invalidate()} when their properties change, such as the background 207 color or the text in a {@link android.widget.TextView}.</p> 208 209 <h3>Hardware accelerated drawing model</h3> 210 <p>The Android system still uses {@link android.view.View#invalidate invalidate()} and {@link 211 android.view.View#draw draw()} to request screen updates and to render views, but handles the 212 actual drawing differently. Instead of executing the drawing commands immediately, the Android 213 system records them inside display lists, which contain the output of the view hierarchy’s 214 drawing code. Another optimization is that the Android system only needs to record and update 215 display lists for views marked dirty by an {@link android.view.View#invalidate invalidate()} 216 call. Views that have not been invalidated can be redrawn simply by re-issuing the previously 217 recorded display list. The new drawing model contains three stages:</p> 218 219 <ol> 220 <li>Invalidate the hierarchy</li> 221 222 <li>Record and update display lists</li> 223 224 <li>Draw the display lists</li> 225 </ol> 226 227 <p>With this model, you cannot rely on a view intersecting the dirty region to have its {@link 228 android.view.View#draw draw()} method executed. To ensure that the Android system records a 229 view’s display list, you must call {@link android.view.View#invalidate invalidate()}. Forgetting 230 to do so causes a view to look the same even after changing it, which is an easier bug to find if 231 it happens.</p> 232 233 <p>Using display lists also benefits animation performance because setting specific properties, 234 such as alpha or rotation, does not require invalidating the targeted view (it is done 235 automatically). This optimization also applies to views with display lists (any view when your 236 application is hardware accelerated.) For example, assume there is a {@link 237 android.widget.LinearLayout} that contains a {@link android.widget.ListView} above a {@link 238 android.widget.Button}. The display list for the {@link android.widget.LinearLayout} looks like 239 this:</p> 240 241 <ul> 242 <li>DrawDisplayList(ListView)</li> 243 244 <li>DrawDisplayList(Button)</li> 245 </ul> 246 247 <p>Assume now that you want to change the {@link android.widget.ListView}'s opacity. After 248 invoking <code>setAlpha(0.5f)</code> on the {@link android.widget.ListView}, the display list now 249 contains this:</p> 250 251 <ul> 252 <li>SaveLayerAlpha(0.5)</li> 253 254 <li>DrawDisplayList(ListView)</li> 255 256 <li>Restore</li> 257 258 <li>DrawDisplayList(Button)</li> 259 </ul> 260 261 <p>The complex drawing code of {@link android.widget.ListView} was not executed. Instead, the 262 system only updated the display list of the much simpler {@link android.widget.LinearLayout}. In 263 an application without hardware acceleration enabled, the drawing code of both the list and its 264 parent are executed again.</p> 265 266 <h2 id="unsupported">Unsupported Drawing Operations</h2> 267 268 <p>When hardware accelerated, the 2D rendering pipeline supports the most commonly used {@link 269 android.graphics.Canvas} drawing operations as well as many less-used operations. All of the 270 drawing operations that are used to render applications that ship with Android, default widgets 271 and layouts, and common advanced visual effects such as reflections and tiled textures are 272 supported. The following list describes known operations that are <strong>not supported</strong> 273 with hardware acceleration:</p> 274 275 <ul> 276 <li> 277 <strong>Canvas</strong> 278 279 <ul> 280 <li>{@link android.graphics.Canvas#clipPath clipPath()}</li> 281 282 <li>{@link android.graphics.Canvas#clipRegion clipRegion()}</li> 283 284 <li>{@link android.graphics.Canvas#drawPicture drawPicture()}</li> 285 286 <li>{@link android.graphics.Canvas#drawTextOnPath drawTextOnPath()}</li> 287 288 <li>{@link android.graphics.Canvas#drawVertices drawVertices()}</li> 289 </ul> 290 </li> 291 292 <li> 293 <strong>Paint</strong> 294 295 <ul> 296 <li>{@link android.graphics.Paint#setLinearText setLinearText()}</li> 297 298 <li>{@link android.graphics.Paint#setMaskFilter setMaskFilter()}</li> 299 300 <li>{@link android.graphics.Paint#setRasterizer setRasterizer()}</li> 301 </ul> 302 </li> 303 304 <li> 305 <strong>Xfermodes</strong> 306 307 <ul> 308 <li>{@link android.graphics.AvoidXfermode AvoidXfermode}</li> 309 310 <li>{@link android.graphics.PixelXorXfermode PixelXorXfermode}</li> 311 </ul> 312 </li> 313 </ul> 314 315 <p>In addition, some operations behave differently with hardware acceleration enabled:</p> 316 317 <ul> 318 <li> 319 <strong>Canvas</strong> 320 321 <ul> 322 <li>{@link android.graphics.Canvas#clipRect clipRect()}: <code>XOR</code>, 323 <code>Difference</code> and <code>ReverseDifference</code> clip modes are ignored. 3D 324 transforms do not apply to the clip rectangle</li> 325 326 <li>{@link android.graphics.Canvas#drawBitmapMesh drawBitmapMesh()}: colors array is 327 ignored</li> 328 </ul> 329 </li> 330 331 <li> 332 <strong>Paint</strong> 333 334 <ul> 335 <li>{@link android.graphics.Paint#setDither setDither()}: ignored</li> 336 337 <li>{@link android.graphics.Paint#setFilterBitmap setFilterBitmap()}: filtering is always 338 on</li> 339 340 <li>{@link android.graphics.Paint#setShadowLayer setShadowLayer()}: works with text 341 only</li> 342 </ul> 343 </li> 344 345 <li> 346 <strong>PorterDuffXfermode</strong> 347 348 <ul> 349 <li>{@link android.graphics.PorterDuff.Mode#DARKEN PorterDuff.Mode.DARKEN} will 350 be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending 351 against the framebuffer.</li> 352 353 <li>{@link android.graphics.PorterDuff.Mode#LIGHTEN PorterDuff.Mode.LIGHTEN} will 354 be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending 355 against the framebuffer.</li> 356 357 <li>{@link android.graphics.PorterDuff.Mode#OVERLAY PorterDuff.Mode.OVERLAY} will 358 be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending 359 against the framebuffer.</li> 360 </ul> 361 </li> 362 363 <li> 364 <strong>ComposeShader</strong> 365 366 <ul> 367 <li>{@link android.graphics.ComposeShader} can only contain shaders of different types (a 368 {@link android.graphics.BitmapShader} and a {@link android.graphics.LinearGradient} for 369 instance, but not two instances of {@link android.graphics.BitmapShader} )</li> 370 371 <li>{@link android.graphics.ComposeShader} cannot contain a {@link 372 android.graphics.ComposeShader}</li> 373 </ul> 374 </li> 375 </ul> 376 377 <p>If your application is affected by any of these missing features or limitations, you can turn 378 off hardware acceleration for just the affected portion of your application by calling 379 {@link android.view.View#setLayerType setLayerType(View.LAYER_TYPE_SOFTWARE, null)}. This way, 380you can still take advantage of hardware acceleratin everywhere else. See <a 381href="#controlling">Controlling Hardware Acceleration</a> for more information on how to enable and 382disable hardware acceleration at different levels in your application. 383 384 385 386 <h2 id="layers">View Layers</h2> 387 388 <p>In all versions of Android, views have had the ability to render into off-screen buffers, 389either by using a view's drawing cache, or by using {@link android.graphics.Canvas#saveLayer 390 Canvas.saveLayer()}. Off-screen buffers, or layers, have several uses. You can use them to get 391 better performance when animating complex views or to apply composition effects. For instance, 392 you can implement fade effects using <code>Canvas.saveLayer()</code> to temporarily render a view 393 into a layer and then composite it back on screen with an opacity factor.</p> 394 395 <p>Beginning in Android 3.0 (API level 11), you have more control on how and when to use layers 396 with the {@link android.view.View#setLayerType View.setLayerType()} method. This API takes two 397 parameters: the type of layer you want to use and an optional {@link android.graphics.Paint} 398 object that describes how the layer should be composited. You can use the {@link 399 android.graphics.Paint} parameter to apply color filters, special blending modes, or opacity to a 400 layer. A view can use one of three layer types:</p> 401 402 <ul> 403 <li>{@link android.view.View#LAYER_TYPE_NONE}: The view is rendered normally and is not backed 404 by an off-screen buffer. This is the default behavior.</li> 405 406 <li>{@link android.view.View#LAYER_TYPE_HARDWARE}: The view is rendered in hardware into a 407 hardware texture if the application is hardware accelerated. If the application is not hardware 408 accelerated, this layer type behaves the same as {@link 409 android.view.View#LAYER_TYPE_SOFTWARE}.</li> 410 411 <li>{@link android.view.View#LAYER_TYPE_SOFTWARE}: The view is rendered in software into a 412 bitmap.</li> 413 </ul> 414 415 <p>The type of layer you use depends on your goal:</p> 416 417 <ul> 418 <li><strong>Performance</strong>: Use a hardware layer type to render a view into a hardware 419 texture. Once a view is rendered into a layer, its drawing code does not have to be executed 420 until the view calls {@link android.view.View#invalidate invalidate()}. Some animations, such as 421 alpha animations, can then be applied directly onto the layer, which is very efficient 422 for the GPU to do.</li> 423 424 <li><strong>Visual effects</strong>: Use a hardware or software layer type and a {@link 425 android.graphics.Paint} to apply special visual treatments to a view. For instance, you can 426 draw a view in black and white using a {@link 427 android.graphics.ColorMatrixColorFilter}.</li> 428 429 <li><strong>Compatibility</strong>: Use a software layer type to force a view to be rendered in 430 software. If a view that is hardware accelerated (for instance, if your whole 431 application is hardware acclerated), is having rendering problems, this is an easy way to work 432around limitations of the hardware rendering 433 pipeline.</li> 434 </ul> 435 436 <h3 id="layers-anims">View layers and animations</h3> 437 438 <p>Hardware layers can deliver faster and smoother animations when your application 439is hardware accelerated. Running an animation at 60 frames per second is not always possible when 440animating complex views that issue a lot of drawing operations. This can be alleviated by 441using hardware layers to render the view to a hardware texture. The hardware texture can 442then be used to animate the view, eliminating the need for the view to constantly redraw itself 443when it is being animated. The view is not redrawn unless you change the view's 444properties, which calls {@link android.view.View#invalidate invalidate()}, or if you call {@link 445android.view.View#invalidate invalidate()} manually. If you are running an animation in 446your application and do not obtain the smooth results you want, consider enabling hardware layers on 447your animated views.</p> 448 449 <p>When a view is backed by a hardware layer, some of its properties are handled by the way the 450 layer is composited on screen. Setting these properties will be efficient because they do not 451 require the view to be invalidated and redrawn. The following list of properties affect the way 452 the layer is composited. Calling the setter for any of these properties results in optimal 453 invalidation and no redrawing of the targeted view:</p> 454 455 <ul> 456 <li><code>alpha</code>: Changes the layer's opacity</li> 457 458 <li><code>x</code>, <code>y</code>, <code>translationX</code>, <code>translationY</code>: 459Changes the layer's position</li> 460 461 <li><code>scaleX</code>, <code>scaleY</code>: Changes the layer's size</li> 462 463 <li><code>rotation</code>, <code>rotationX</code>, <code>rotationY</code>: Changes the 464 layer's orientation in 3D space</li> 465 466 <li><code>pivotX</code>, <code>pivotY</code>: Changes the layer's transformations origin</li> 467 </ul> 468 469 <p>These properties are the names used when animating a view with an {@link 470 android.animation.ObjectAnimator}. If you want to access these properties, call the appropriate 471 setter or getter. For instance, to modify the alpha property, call {@link 472 android.view.View#setAlpha setAlpha()}. The following code snippet shows the most efficient way 473 to rotate a viewiew in 3D around the Y-axis:</p> 474 <pre> 475view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 476ObjectAnimator.ofFloat(view, "rotationY", 180).start(); 477</pre> 478 479 <p>Because hardware layers consume video memory, it is highly recommended that you enable them 480only for the duration of the animation and then disable them after the animation is done. You 481can accomplish this using animation listeners:</p> 482 <pre> 483View.setLayerType(View.LAYER_TYPE_HARDWARE, null); 484ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); 485animator.addListener(new AnimatorListenerAdapter() { 486 @Override 487 public void onAnimationEnd(Animator animation) { 488 view.setLayerType(View.LAYER_TYPE_NONE, null); 489 } 490}); 491animator.start(); 492</pre> 493 494 <p>For more information on property animation, see <a href= 495 "{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a>.</p> 496 497 <h2 id="tips">Tips and Tricks</h2> 498 499 <p>Switching to hardware accelerated 2D graphics can instantly increase performance, but you 500 should still design your application to use the GPU effectively by following these 501 recommendations:</p> 502 503 <dl> 504 <dt><strong>Reduce the number of views in your application</strong></dt> 505 506 <dd>The more views the system has to draw, the slower it will be. This applies to the software 507 rendering pipeline as well. Reducing views is one of the easiest ways to optimize your UI.</dd> 508 509 <dt><strong>Avoid overdraw</strong></dt> 510 511 <dd>Do not draw too many layers on top of each other. Remove any views that are completely 512 obscured by other opaque views on top of it. If you need to draw several layers blended on top 513 of each other, consider merging them into a single layer. A good rule of thumb with current 514 hardware is to not draw more than 2.5 times the number of pixels on screen per frame 515 (transparent pixels in a bitmap count!).</dd> 516 517 <dt><strong>Don't create render objects in draw methods</strong></dt> 518 519 <dd>A common mistake is to create a new {@link android.graphics.Paint} or a new {@link 520android.graphics.Path} every time a rendering method is invoked. This forces the garbage 521collector to run more often and also bypasses caches and optimizations in the hardware 522pipeline.</dd> 523 524 <dt><strong>Don't modify shapes too often</strong></dt> 525 526 <dd>Complex shapes, paths, and circles for instance, are rendered using texture masks. Every 527 time you create or modify a path, the hardware pipeline creates a new mask, which can be 528 expensive.</dd> 529 530 <dt><strong>Don't modify bitmaps too often</strong></dt> 531 532 <dd>Every time you change the content of a bitmap, it is uploaded again as a GPU texture the 533 next time you draw it.</dd> 534 535 <dt><strong>Use alpha with care</strong></dt> 536 537 <dd>When you make a view translucent using {@link android.view.View#setAlpha setAlpha()}, 538 {@link android.view.animation.AlphaAnimation}, or {@link android.animation.ObjectAnimator}, it 539 is rendered in an off-screen buffer which doubles the required fill-rate. When applying alpha 540 on very large views, consider setting the view's layer type to 541 <code>LAYER_TYPE_HARDWARE</code>.</dd> 542 </dl> 543