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>&lt;application&gt;</code></a> tag to enable hardware acceleration for your entire
95  application:</p>
96
97<pre>
98&lt;application android:hardwareAccelerated="true" ...&gt;
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>&lt;activity&gt;</code></a> element. The following example enables hardware acceleration
107for the  entire application but disables it for one activity:</p>
108
109<pre>
110&lt;application android:hardwareAccelerated="true"&gt;
111    &lt;activity ... /&gt;
112    &lt;activity android:hardwareAccelerated="false" /&gt;
113&lt;/application&gt;
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    &#064;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