Home | History | Annotate | Download | only in graphics
      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 
     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 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>
     54 
     55   <p>Hardware acceleration is enabled by default if your Target API level is &gt;=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>
     63 
     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>
     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>&lt;application&gt;</code></a> tag to enable hardware acceleration for your entire
     85   application:</p>
     86 
     87 <pre>
     88 &lt;application android:hardwareAccelerated="true" ...&gt;
     89 </pre>
     90 
     91   <h4>Activity level</h4>
     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>&lt;activity&gt;</code></a> element. The following example enables hardware acceleration for
     97   the entire application but disables it for one activity:</p>
     98 
     99 <pre>
    100 &lt;application android:hardwareAccelerated="true"&gt;
    101     &lt;activity ... /&gt;
    102     &lt;activity android:hardwareAccelerated="false" /&gt;
    103 &lt;/application&gt;
    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 id="software-model">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 views 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 id="hardware-model">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 hierarchys
    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   views display list, you must call {@link android.view.View#invalidate invalidate()}. Forgetting
    220   to do so causes a view to look the same even after it has been changed.</p>
    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
    261   supported.</p>
    262 
    263   <p>The following table describes the support level of various operations across API levels:</p>
    264 
    265   <style type="text/css">
    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;}
    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">&lt; 16</td>
    284         <td class="s3">16</td>
    285         <td class="s2">17</td>
    286         <td class="s3">18</td>
    287     </tr>
    288     <tr>
    289         <td colspan="5" class="s5">Canvas</td>
    290     </tr>
    291     <tr>
    292         <td class="s10">drawBitmapMesh() (colors array)</td>
    293         <td class="g_neg">&#10007;</td>
    294         <td class="w_neg">&#10007;</td>
    295         <td class="g_neg">&#10007;</td>
    296         <td class="w_pos">&#10003;</td>
    297     </tr>
    298     <tr>
    299         <td class="s10">drawPicture()</td>
    300         <td class="g_neg">&#10007;</td>
    301         <td class="w_neg">&#10007;</td>
    302         <td class="g_neg">&#10007;</td>
    303         <td class="w_neg">&#10007;</td>
    304     </tr>
    305     <tr>
    306         <td class="s10">drawPosText()</td>
    307         <td class="g_neg">&#10007;</td>
    308         <td class="w_pos">&#10003;</td>
    309         <td class="g_pos">&#10003;</td>
    310         <td class="w_pos">&#10003;</td>
    311     </tr>
    312     <tr>
    313         <td class="s10">drawTextOnPath()</td>
    314         <td class="g_neg">&#10007;</td>
    315         <td class="w_pos">&#10003;</td>
    316         <td class="g_pos">&#10003;</td>
    317         <td class="w_pos">&#10003;</td>
    318     </tr>
    319     <tr>
    320         <td class="s10">drawVertices()</td>
    321         <td class="g_neg">&#10007;</td>
    322         <td class="w_neg">&#10007;</td>
    323         <td class="g_neg">&#10007;</td>
    324         <td class="w_neg">&#10007;</td>
    325     </tr>
    326     <tr>
    327         <td class="s10">setDrawFilter()</td>
    328         <td class="g_neg">&#10007;</td>
    329         <td class="w_pos">&#10003;</td>
    330         <td class="g_pos">&#10003;</td>
    331         <td class="w_pos">&#10003;</td>
    332     </tr>
    333     <tr>
    334         <td class="s10">clipPath()</td>
    335         <td class="g_neg">&#10007;</td>
    336         <td class="w_neg">&#10007;</td>
    337         <td class="g_neg">&#10007;</td>
    338         <td class="w_pos">&#10003;</td>
    339     </tr>
    340     <tr>
    341         <td class="s10">clipRegion()</td>
    342         <td class="g_neg">&#10007;</td>
    343         <td class="w_neg">&#10007;</td>
    344         <td class="g_neg">&#10007;</td>
    345         <td class="w_pos">&#10003;</td>
    346     </tr>
    347     <tr>
    348         <td class="s10">clipRect(Region.Op.XOR)</td>
    349         <td class="g_neg">&#10007;</td>
    350         <td class="w_neg">&#10007;</td>
    351         <td class="g_neg">&#10007;</td>
    352         <td class="w_pos">&#10003;</td>
    353     </tr>
    354     <tr>
    355         <td class="s10">clipRect(Region.Op.Difference)</td>
    356         <td class="g_neg">&#10007;</td>
    357         <td class="w_neg">&#10007;</td>
    358         <td class="g_neg">&#10007;</td>
    359         <td class="w_pos">&#10003;</td>
    360     </tr>
    361     <tr>
    362         <td class="s10">clipRect(Region.Op.ReverseDifference)</td>
    363         <td class="g_neg">&#10007;</td>
    364         <td class="w_neg">&#10007;</td>
    365         <td class="g_neg">&#10007;</td>
    366         <td class="w_pos">&#10003;</td>
    367     </tr>
    368     <tr>
    369         <td class="s10">clipRect() with rotation/perspective</td>
    370         <td class="g_neg">&#10007;</td>
    371         <td class="w_neg">&#10007;</td>
    372         <td class="g_neg">&#10007;</td>
    373         <td class="w_pos">&#10003;</td>
    374     </tr>
    375     <tr>
    376         <td colspan="5" class="s5">Paint</td>
    377     </tr>
    378     <tr>
    379         <td class="s10">setAntiAlias() (for text)</td>
    380         <td class="g_neg">&#10007;</td>
    381         <td class="w_neg">&#10007;</td>
    382         <td class="g_neg">&#10007;</td>
    383         <td class="w_pos">&#10003;</td>
    384     </tr>
    385     <tr>
    386         <td class="s10">setAntiAlias() (for lines)</td>
    387         <td class="g_neg">&#10007;</td>
    388         <td class="w_pos">&#10003;</td>
    389         <td class="g_pos">&#10003;</td>
    390         <td class="w_pos">&#10003;</td>
    391     </tr>
    392     <tr>
    393         <td class="s10">setFilterBitmap()</td>
    394         <td class="g_neg">&#10007;</td>
    395         <td class="w_neg">&#10007;</td>
    396         <td class="g_pos">&#10003;</td>
    397         <td class="w_pos">&#10003;</td>
    398     </tr>
    399     <tr>
    400         <td class="s10">setLinearText()</td>
    401         <td class="g_neg">&#10007;</td>
    402         <td class="w_neg">&#10007;</td>
    403         <td class="g_neg">&#10007;</td>
    404         <td class="w_neg">&#10007;</td>
    405     </tr>
    406     <tr>
    407         <td class="s10">setMaskFilter()</td>
    408         <td class="g_neg">&#10007;</td>
    409         <td class="w_neg">&#10007;</td>
    410         <td class="g_neg">&#10007;</td>
    411         <td class="w_neg">&#10007;</td>
    412     </tr>
    413     <tr>
    414         <td class="s10">setPathEffect() (for lines)</td>
    415         <td class="g_neg">&#10007;</td>
    416         <td class="w_neg">&#10007;</td>
    417         <td class="g_neg">&#10007;</td>
    418         <td class="w_neg">&#10007;</td>
    419     </tr>
    420     <tr>
    421         <td class="s10">setRasterizer()</td>
    422         <td class="g_neg">&#10007;</td>
    423         <td class="w_neg">&#10007;</td>
    424         <td class="g_neg">&#10007;</td>
    425         <td class="w_neg">&#10007;</td>
    426     </tr>
    427     <tr>
    428         <td class="s10">setShadowLayer() (other than text)</td>
    429         <td class="g_neg">&#10007;</td>
    430         <td class="w_neg">&#10007;</td>
    431         <td class="g_neg">&#10007;</td>
    432         <td class="w_neg">&#10007;</td>
    433     </tr>
    434     <tr>
    435         <td class="s10">setStrokeCap() (for lines)</td>
    436         <td class="g_neg">&#10007;</td>
    437         <td class="w_neg">&#10007;</td>
    438         <td class="g_neg">&#10007;</td>
    439         <td class="w_pos">&#10003;</td>
    440     </tr>
    441     <tr>
    442         <td class="s10">setStrokeCap() (for points)</td>
    443         <td class="g_neg">&#10007;</td>
    444         <td class="w_neg">&#10007;</td>
    445         <td class="g_neg">&#10007;</td>
    446         <td class="w_neg">&#10007;</td>
    447     </tr>
    448     <tr>
    449         <td class="s10">setSubpixelText()</td>
    450         <td class="g_neg">&#10007;</td>
    451         <td class="w_neg">&#10007;</td>
    452         <td class="g_neg">&#10007;</td>
    453         <td class="w_neg">&#10007;</td>
    454     </tr>
    455     <tr>
    456         <td colspan="5" class="s5">Xfermode</td>
    457     </tr>
    458     <tr>
    459         <td class="s10">AvoidXfermode</td>
    460         <td class="g_neg">&#10007;</td>
    461         <td class="w_neg">&#10007;</td>
    462         <td class="g_neg">&#10007;</td>
    463         <td class="w_neg">&#10007;</td>
    464     </tr>
    465     <tr>
    466         <td class="s10">PixelXorXfermode</td>
    467         <td class="g_neg">&#10007;</td>
    468         <td class="w_neg">&#10007;</td>
    469         <td class="g_neg">&#10007;</td>
    470         <td class="w_neg">&#10007;</td>
    471     </tr>
    472     <tr>
    473         <td class="s10">PorterDuff.Mode.DARKEN (framebuffer)</td>
    474         <td class="g_neg">&#10007;</td>
    475         <td class="w_neg">&#10007;</td>
    476         <td class="g_neg">&#10007;</td>
    477         <td class="w_neg">&#10007;</td>
    478     </tr>
    479     <tr>
    480         <td class="s10">PorterDuff.Mode.LIGHTEN (framebuffer)</td>
    481         <td class="g_neg">&#10007;</td>
    482         <td class="w_neg">&#10007;</td>
    483         <td class="g_neg">&#10007;</td>
    484         <td class="w_neg">&#10007;</td>
    485     </tr>
    486     <tr>
    487         <td class="s10">PorterDuff.Mode.OVERLAY (framebuffer)</td>
    488         <td class="g_neg">&#10007;</td>
    489         <td class="w_neg">&#10007;</td>
    490         <td class="g_neg">&#10007;</td>
    491         <td class="w_neg">&#10007;</td>
    492     </tr>
    493     <tr>
    494         <td colspan="5" class="s5">Shader</td>
    495     </tr>
    496     <tr>
    497         <td class="s10">ComposeShader inside ComposeShader</td>
    498         <td class="g_neg">&#10007;</td>
    499         <td class="w_neg">&#10007;</td>
    500         <td class="g_neg">&#10007;</td>
    501         <td class="w_neg">&#10007;</td>
    502     </tr>
    503     <tr>
    504         <td class="s10">Same type shaders inside ComposeShader</td>
    505         <td class="g_neg">&#10007;</td>
    506         <td class="w_neg">&#10007;</td>
    507         <td class="g_neg">&#10007;</td>
    508         <td class="w_neg">&#10007;</td>
    509     </tr>
    510     <tr>
    511         <td class="s10">Local matrix on ComposeShader</td>
    512         <td class="g_neg">&#10007;</td>
    513         <td class="w_neg">&#10007;</td>
    514         <td class="g_neg">&#10007;</td>
    515         <td class="w_pos">&#10003;</td>
    516     </tr>
    517     </tbody>
    518   </table>
    519 
    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   &lt;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">&lt; 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">&#10007;</td>
    553         <td class="w_neg">&#10007;</td>
    554         <td class="g_pos">&#10003;</td>
    555     </tr>
    556     <tr>
    557         <td class="s10">drawPosText()</td>
    558         <td class="g_neg">&#10007;</td>
    559         <td class="w_neg">&#10007;</td>
    560         <td class="g_neg">&#10007;</td>
    561     </tr>
    562     <tr>
    563         <td class="s10">drawTextOnPath()</td>
    564         <td class="g_neg">&#10007;</td>
    565         <td class="w_neg">&#10007;</td>
    566         <td class="g_neg">&#10007;</td>
    567     </tr>
    568     <tr>
    569         <td class="s10">Simple Shapes*</td>
    570         <td class="g_neg">&#10007;</td>
    571         <td class="w_pos">&#10003;</td>
    572         <td class="g_pos">&#10003;</td>
    573     </tr>
    574     <tr>
    575         <td class="s10">Complex Shapes*</td>
    576         <td class="g_neg">&#10007;</td>
    577         <td class="w_neg">&#10007;</td>
    578         <td class="g_neg">&#10007;</td>
    579     </tr>
    580     <tr>
    581         <td class="s10">drawPath()</td>
    582         <td class="g_neg">&#10007;</td>
    583         <td class="w_neg">&#10007;</td>
    584         <td class="g_neg">&#10007;</td>
    585     </tr>
    586     <tr>
    587         <td class="s10">Shadow layer</td>
    588         <td class="g_neg">&#10007;</td>
    589         <td class="w_neg">&#10007;</td>
    590         <td class="g_neg">&#10007;</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 
    602   <p>If your application is affected by any of these missing features or limitations, you can turn
    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.
    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     &#064;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>
    766