Android图形---硬件加速(Hardware Acceleration)(二)

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

在硬件加速的时候,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():硬件加速能够被设置,但是会被忽略。

2. Paint

setDither():硬件加速会忽略其设置。

setFilterBitmap():位图过滤是始终打开的。

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

3. 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(newAnimatorListenerAdapter(){
    
@Override
    
publicvoid onAnimationEnd(Animator animation){
        view
.setLayerType(View.LAYER_TYPE_NONE,null);
    
}
});
animator
.start();

更多的属性动画的信息,请看Property Animation(http://developer.android.com/guide/topics/graphics/prop-animation.html

提示和技巧

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

1.  减少应用程序中View对象的数量

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

2.  避免过度绘图

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

3.  不要在绘图方法中创建呈现对象

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

4.  不要经常的编辑形状

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

5.  不要经常的编辑位图

每次改变位图内容,都会在下次绘图时再次更新GPU的纹理。

6.  要小心的使用alpha相关的方法

当使用setAlpha()、AlphaAnimation或ObjectAnimator,让一个View对象半透明时,会需要双倍填充率的屏幕外缓存。当在一个大的View对象上应用透明效果时,要考虑把View对象的层类型设置为LAYER_TYPE_HARDWARE。


展开阅读全文

没有更多推荐了,返回首页