Android 硬件加速总结

2014-08-07 党洁 更多博文 » 博客 » GitHub »

原文链接 https://jiedang.github.io/2014/08/07/%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F%E7%9B%B8%E5%85%B3.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


不支持硬件加速的记录

不被硬件加速所支持的绘图操作

在硬件加速的时候,2D渲染管道支持大多数的通常用于Canvas的绘图操作,以及一些很少使用的操作。被用于渲染应用程序的所有的绘图操作都有发送给

Android系统,默认的Widget和布局,以及一些常用的可视效果,如反射和瓷砖的纹理效果都是被支持的。以下列出了已知的不支持硬件加速的操作:

1.

Canvas

chipPath()

chipRegion()

drawPicture()

drawPosText()

drawTextOnPath()

drawVertives()

2.

Paint

setLinearText()

setMaskFilter()

setRasterizer()

另外,还有一些操作行为会因启用了硬件加速而不同:

  1. Canvas clipRect():

硬件加速会忽略XOR、Difference和ReverseDifference三种剪辑模式,3D变换不适用于剪辑矩形。 drawBitmapMesh():硬件加速会忽略颜色数组。 drawLines():硬件加速不支持抗锯齿处理。 setDrawFilter():硬件加速能够被设置,但是会被忽略。

  1. Paint setDither(): 硬件加速会忽略其设置。 setFilterBitmap():位图过滤是始终打开的。

setShadowLayer():该项设置只对文本有效。

  1. ComposeShader
    ComposeShader对象只能包含不同类型的着色器(例如,BitmapShader和LinearGradient,但是不能够包含两个BitmapShader对象的实例)。
    ComposeShader对象不能够包含一个ComposeShader对象。 如果应用程序受到这些错误的功能或限制的影响,那么能够通过调用setLayerType(View.LAYER_TYPE_SOFTWARE, null)方法针对应用程序受到影响的部分来关闭硬件加速。这种方法,依然还能够在其他的地方利用硬件加速。

View层

在Android的所有版本中,通过使用View对象的绘图缓冲,或使用Canvas.saveLayer()方法,View对象都具有在屏幕外缓冲区呈现的能力。屏幕外缓冲区或层由多种用途。在呈现复杂的动画或使用组合效果时,它们能够获得更好的性能。例如,使用Canvas.saveLayer()方法暂时把一个View对象呈现在一个层中,然后使用不透明因子把该View对象合成到屏幕上,从而实现淡入淡出的效果。 从Android3.0(API Level 11)开始,用View.setLayerType()方法使用层的方式和时机会更多的控制。这个API需要两个参数:一个是层的类型,另一个是可选的,用于描述层应该如何被合成的Paint对象。能够使用这个Paint对象来进行颜色过滤、特殊的混合模式、或者层的透明度。View对象能够使用以下三种层类型: LAYER_TYPE_NONE:View对象用普通的方式来呈现,并且不是由屏幕外缓存来返回的。这种类型是默认的行为; LAYER_TYPE_HARDWARE:如果应用程序是硬件加速的,那么该View对象被呈现在硬件的一个硬件纹理中。如果没有被硬件加速,那么这种层类型的行为与LAYER_TYPE_SOFTWARE相同。 LAYER_TYPE_SOFTWARE:View对象会被呈现在软件的一个位图中。

使用哪种层的类型,依赖以下目标:

  1. 性能: 使用硬件层类型,把View呈现到一个硬件纹理中。一旦该View对象被呈现到一 个层中,那么它的绘图代码直到调用该View对象的invalidate()方法时才会被执行。对于某些动画,如alpha动画,就能够直接使用该层,这么做对于GPU来说是非常高效的。

  2. 视觉效果:使用硬件或软件层类型和一个Paint对象,能够把一些特殊的视觉处理应用 给一个View对象。例如,使用ColorMatrixColorFilter对象绘制一个黑白相间的View对象。

  3. 兼容性:使用软件层类型会强制把一个View对象呈现在软件中。如果View对象被硬件 加速(例如,如果整个应用程序都被硬件加速)发生呈现问题,那么使用软件层类型来解决硬件呈现管道的限制是一个容易的方法。 View层和动画 当应用程序被硬件加速的时候,硬件层能够传递更快、更平滑的动画。当播放具有复杂的绘图操作的动画时,以每秒60帧的速度播放不总是可能。这样能够通过使用硬件层把View对象呈现在硬件纹理中,可以缓解这种情况。硬件纹理能够被用于动画视图,这样在该View对象呈现动画时,就可以消除View对象所需要的重绘操作。直到View对象的属性发生变化时(invalidate()方法被调用),该View对象才会被重绘。如果在应用程序运行一个动画,并且没有获得想要的平滑结果,就要考虑在动画View上启用硬件层。

当一个View被硬件层返回时,通过层方法处理的某些属性会被合成到屏幕上。因为它们不 需要让View对象失效和重绘,所以设置这些属性是非常高效的。下面列出了影响层被合成的方式。调用这些属性设置器,会导致失效处理的优化,并且不会对目标View对象进行重绘:

  1. alpha:改变层的透明度;

  2. x,y,translation,translation:改变层的位置;

  3. scaleX,scaleY:改变成的尺寸;

  4. rotation,rotation,rotationY:改变3D空间中层的方向;

  5. pivotX,pivotY:改变层的变换起源。

这些属性是在用ObjectAnimator对象给View对象设置动画时所使用的名称。如果想要访问这些属性,就要调用相应的set或get方法。 例如,要修改alpha属性,就要调用setAlpha()方法。下面的代码展示了在3D空间中围绕Y轴旋转View对象的最有效的方法:

        view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 
        ObjectAnimator.ofFloat(view, "rotationY", 180).start();

因为硬件层会消耗显示内存,因此强烈推荐只在动画播放期间启用硬件层,并且在动画播放结束后就禁用该硬件层。能够使用动画监听器来完成这种操作:

        View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
        animator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                view.setLayerType(View.LAYER_TYPE_NONE, null);
            }
        });
        animator.start();

提示和技巧 切换到硬件加速的2D图形能够有效改善性能,但是依然要通过以下推荐的方式来设计应用程序,以便有效的使用GPU:

  1. 减少应用程序中View对象的数量 系统绘制越多的View对象,就会越慢。这种情况也适用于软件呈现管道。减少View对象的有效方法之一就是优化UI。

  2. 避免过度绘图 在彼此的顶部不要绘制太多的层。因为删除View时要同时删除遮盖在该View对象之上所有其他的不透明的View对象。如果需要绘制几个图层,要尽量在上面采用合成模式,考虑把它们合并成一个层。一个好的规则是:每帧的像素数不要大于屏幕上像素数的2.5倍(以位图的透明点阵数来计算)。

  3. 不要在绘图方法中创建呈现对象 一个常见的错误时每次调用呈现方法时创建一个新的Paint对象或Path对象。这样就会强制频繁的运行垃圾回收,并且会绕过硬件管道中的缓存和优化。

  4. 不要经常的编辑形状 对于复杂的形状,如路径和圆,是使用纹理掩码来呈现的。每次创建或修改路径,硬件通道都要创建一个新的掩码,这样会消耗大量的资源。

    1. 不要经常的编辑位图 每次改变位图内容,都会在下次绘图时再次更新GPU的纹理。
    2. 要小心的使用alpha相关的方法 当使用setAlpha()、AlphaAnimation或ObjectAnimator,让一个View对象半透明时,会需要双倍填充率的屏幕外缓存。当在一个大的View对象上应用透明效果时,要考虑把View对象的层类型设置为LAYER_TYPE_HARDWARE。