Android中GPU硬件加速控制及其在2D图形绘制上的局限

图形的渲染可分为两种:软件渲染和硬件渲染。软件渲染是靠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硬件加速会提升程序的绘图效率,但是也存在一定的局限性。

  1. 启用GPU硬件加速会增加内存的使用。

  2. Android中有些2D绘图API在GPU硬件加速时不能使用或者要到某个指定的版本才能使用。

    • Canvas
      以下为Canvas中在GPU硬件加速时受限制的功能:
      第一列是受限制的方法,第二列是开始支持的API Level,红叉代表到目前还不支持。
      Android中GPU硬件加速控制及其在2D图形绘制上的局限_第1张图片

    • Paint
      以下为Paint中在GPU硬件加速时受限制的功能:
      Android中GPU硬件加速控制及其在2D图形绘制上的局限_第2张图片

    • Xfermode
      以下为Xfermode在GPU硬件加速时受限制的功能:
      Android中GPU硬件加速控制及其在2D图形绘制上的局限_第3张图片

    • Shader
      以下为Shader在GPU硬件加速时受限制的功能:
      这里写图片描述

    • Canvas缩放
      Android中硬件加速的2D渲染管线最初只支持无缩放的绘图,这会导致在将缩放比例设置为很大的时候,绘图质量会明显降低。最初,GPU加速下的2D绘图操作会被渲染成一个缩放比例为1.0的纹理,然后GPU会将它缩放到指定比例尺。在API Level小于17的时候,随着缩放比例scale的变大,绘图质量就更加难以保证。下面的表格表示了从什么版本开始Android能在GPU硬件计算下正确处理2D图形的大比例缩放问题:
      Android中GPU硬件加速控制及其在2D图形绘制上的局限_第4张图片

    • 现在我们开发的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机制。

相关阅读:
我的Android博文整理汇总
Android中Canvas绘图基础详解(附源码下载)

你可能感兴趣的:(android,view,GPU,2d,硬件加速)