图形的渲染可分为两种:软件渲染和硬件渲染。软件渲染是靠CPU计算各种坐标并绘制,主要是占用内存;硬件渲染是靠GPU,主要占用显存,一般的3D图形程序(OpenGL、DirectX)都是GPU加速的。
在Android3.0之前,2D绘图API只支持软件渲染模式,从Android3.0开始,2D绘图API开始支持GPU硬件渲染,即View中的Canvas的绘图操作会使用GPU,所以从Android 3.0(API Level 11)开始,View中就多了一些和硬件相关的方法。如果App的AndroidManifest.xml文件中定义的 targetSdkVersion大于或等于14(Android 4.0),那么Android会默认为App启用GPU渲染2D图形,我们也可以自己决定是否使用GPU,见下文。如果开启了GPU硬件加速,那么Android会用OpengGL绘图中常见的Display List技术对OpenGL ES中的绘图命令进行缓存,提高绘图效率与速度。关于Android中GPU硬件加速的Display List绘图机制会在以后专门写文章进行阐述,本文不做过多介绍。
控制是否使用GPU
我们也可以显式地启用或禁用GPU渲染,并且可以从多个Application、Activity、Window、View多个级别对其进行控制。
-
Application
在AndroidMenifest.xml的中添加如下的属性即可在整个App的所有Activity的View中启用GPU硬件加速渲染2D图形:
<application android:hardwareAccelerated="true" ...>
-
Activity
你既可以在Application级别上控制GPU是否启用,也可以在Activity级别对其就进行控制。比如你的App中有多个Activity,你想让大部分Activity启用GPU硬件加速,但有一个Activity你不想启用硬件加速,你可以通过以下的配置实现:<application android:hardwareAccelerated="true">
<activity ... />
<activity android:hardwareAccelerated="false" />
</application> -
Window
如果你想要更加细粒度地对GPU的使用进行控制,你可以通过代码对指定的Window启用GPU硬件加速,如下代码所示:getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);需要注意的是在运行时不能通过代码禁用掉某个Window的硬件加速。
-
View
你也可以在运行时通过如下代码为某个指定的View禁用掉GPU硬件加速:if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
//View从API Level 11才加入setLayerType方法
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}View从API Level 11才加入setLayerType方法,所以在使用前需要判断一下当前系统运行的版本。 需要注意的是,在运行时不能通过代码为某个View启用GPU硬件加速。
判断当前是否处于硬件加速中
从Android 3.0(API Level 11)开始,View和Canvas类都加入了isHardwareAccelerated()方法,可以用于判断当前View和Canvas是否处于硬件加速中。
View.isHardwareAccelerated()
如果View的isHardwareAccelerated()方法返回true,仅仅表示该View被加入到一个处于硬件加速的Window中,其有可能仍然使用一个非硬件加速的Canvas进行实际的渲染。所以,通常来说View的isHardwareAccelerated()方法实际用处不太大。Canvas.isHardwareAccelerated()
我们在View的onDraw回调方法中可以得到Canvas对象,如果Canvas的isHardwareAccelerated()方法返回true,那么表示当前Canvas是用GPU硬件加速渲染的,如果返回false就表示是用软件渲染的。通常,判断当前Canvas是否处于GPU硬件加速中对于绘制自定义的View来说比较重要,下面会解释。
硬件加速时2D图形绘制的局限
开启GPU硬件加速会提升程序的绘图效率,但是也存在一定的局限性。
启用GPU硬件加速会增加内存的使用。
-
Android中有些2D绘图API在GPU硬件加速时不能使用或者要到某个指定的版本才能使用。
Canvas
以下为Canvas中在GPU硬件加速时受限制的功能:
第一列是受限制的方法,第二列是开始支持的API Level,红叉代表到目前还不支持。Paint
以下为Paint中在GPU硬件加速时受限制的功能:Xfermode
以下为Xfermode在GPU硬件加速时受限制的功能:Shader
以下为Shader在GPU硬件加速时受限制的功能:Canvas缩放
Android中硬件加速的2D渲染管线最初只支持无缩放的绘图,这会导致在将缩放比例设置为很大的时候,绘图质量会明显降低。最初,GPU加速下的2D绘图操作会被渲染成一个缩放比例为1.0的纹理,然后GPU会将它缩放到指定比例尺。在API Level小于17的时候,随着缩放比例scale的变大,绘图质量就更加难以保证。下面的表格表示了从什么版本开始Android能在GPU硬件计算下正确处理2D图形的大比例缩放问题:现在我们开发的App一般将targetSdkVersion写为最新版本,肯定大于API Level 14了,并且市场上的手机绝大部分都是Android 4.0以上的,所以我们现在开发的App默认情况下在绝大部分手机上基本都是默认开启了GPU硬件加速的。如果我们自己要自定义一个View,我们要重写其onDraw方法,通过调用各种绘图方法实现复杂的效果,但是如果我们调用的API在GPU硬件加速下不支持的话,就画不出我们想要的效果,举个例子,比如我们想在自定义View中绘制一个具有模糊效果的椭圆,需要调用画笔Paint的setMaskFilter()方法,但是我们通过上面的受限API列表可以发现,在GPU硬件加速下,Pait的setMaskFilter()方法不被支持,虽然调用不报错,但是不会起到任何效果。为了画出我们想要的效果,我们可以通过View的setLayerType(View.LAYER_TYPE_SOFTWARE, null)方法单独把我们的View禁用掉GPU硬件加速,这样在软件渲染模式下所有的2D绘图API都可以正常使用了。
最后有点需要说明,上述Android在GPU硬件加速下2D图形绘制API存在的局限问题是基于当前最新API Level 23的,随着以后更新Android版本的发布,可能上述受限API会逐渐在GPU下得到更好的支持。
希望本文对大家初步了解Android中GPU硬件渲染2D图形有所帮助,后面会写文章深入探讨Android在GPU硬件渲染下绘制2D图形的Display List机制。