关于 Android 渲染你应该了解的知识点

作者:程序员江同学

前言

谈到AndroidUI绘制,大家可能会想到onMeasureonLayoutonDraw三大流程。但我们的View到底是如何一步一步显示到屏幕上的?onDraw之后到View显示到屏幕上,具体又做了哪些工作?
带着这些问题,我们今天就深入学习一下Android渲染的流程吧,本文主包括以下内容:

  1. Android渲染的整体架构是怎样的?
  2. Android渲染的生产者包括哪些?SkiaOpenGl的区别是什么?
  3. 什么是硬件加速?硬件绘制与软件绘制的区别
  4. Android渲染缓冲区是什么?什么是黄油计划?
  5. Android渲染的消费者是什么? 什么是SurfaceFlinger?

Android渲染整体架构

我们先来看一下Android渲染的整体架构,具体可分为以下几个部分

  • image stream produceers: 渲染数据的生产者,如Appdraw方法会把绘制指令通过canvas传递给framework层的RenderThread线程。
  • native Framework: RenderThread线程通过surface.dequeue得到缓冲区graphic bufer,然后在上面通过OpenGL来完成真正的渲染命令。在把缓冲区交还给BufferQueue队列中。
  • image stream consumers: surfaceFlinger从队列中获取数据,同时和HAL完成layer的合成工作,最终交给HAL展示。
  • HAL: 硬件抽象层。把图形数据展示到设备屏幕

可以看出,这其实是个很典型的生产者消费者模式

  • 图像生产者: 也就是我们的APP,再深入点就是canvas->surface
  • 图像消费者:SurfaceFlinger
  • 图像缓冲区:BufferQueue,一般是3缓冲区

下面我们就从生产者,消费者,缓冲区三个部分来详细了解下Android渲染的过程

图像生产者

从上面的架构图可知,图像的生产者主要有MediaPlayerCameraPreviewNDK(Skia)OpenGl ES
其中MediaPlayerCamera Preview是通过直接读取图像源来生成图像数据,NDK(Skia)OpenGL ES是通过自身的绘制能力生产的图像数据

OpenGLVulkanSkia的区别

  • OpenGL: 是一种跨平台的3D图形绘制规范接口。OpenGL EL则是专门针对嵌入式设备,如手机做了优化。
  • Skiaskia是图像渲染库,2D图形绘制自己就能完成。3D效果(依赖硬件)由OpenGLVulkanMetal支持。它不仅支持2D3D,同时支持CPU软件绘制和GPU硬件加速。Androidflutter都是使用它来完成绘制。
  • Vulkan: Android引入了Vulkan支持。VulKan是用来替换OpenGL的。它不仅支持3D,也支持2D,同时更加轻量级

硬件加速

关于硬件加速,相信大家也经常听到,尤其是有些API不支持硬件加速,因此需要我们手动关闭,那么硬件加速到底是什么呢?

CPUGPU的区别

除了屏幕,UI 渲染还要依赖另外两个核心的硬件:CPUGPU

  • CPUCentral Processing Unit,中央处理器),是计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元;
  • GPUGraphics Processin Unit,图形处理器),是一种专门用于图像运算的处理器,在计算机系统中通常被称为 "显卡"的核心部件就是 GPU

UI 组件在绘制到屏幕之前,都需要经过 Rasterization(栅格化)操作,而栅格化又是一个非常耗时的操作。

Rasterization 栅格化是绘制那些 ButtonShapePathStringBitmap 等显示组件最基础的操作。栅格化将这些 UI 组件拆分到显示器的不同像素上进行显示。这是一个非常耗时的操作,GPU 的引入就是为了加快栅格化。

硬件绘制与软件绘制

  • 从图中可以看到,软件绘制使用 Skia 库,它是一款能在低端设备,如手机呈现高质量的 2D 跨平台图形框架,类似 ChromeFlutter 内部使用的都是 Skia 库。
  • 硬件绘制的思想就是通过底层软件代码,将 CPU 不擅长的图形计算转换成 GPU 专用指令,由 GPU 完成绘制任务。

所以说硬件加速的本质就是使用GPU代替CPU完成Graphic Buffer绘制工作,以实现更好的性能,Android从4.0开始默认开启了硬件加速,但还有一些API不支持硬件加速,因此需要手动关闭硬件加速。
需要注意的是,软件绘制使用的Skia库,但这不代表Skia不支持硬件加速,从Android 8开始,我们可以选择使用Skia进行硬件加速,Android 9开始就默认使用Skia来进行硬件加速。Skia的硬件加速主要是通过 copybit 模块调用OpenGL或者SKia来实现。

图像缓冲区

Android中的图像生产者OpenGLSkiaVulkan将绘制的数据存放在图像缓冲区中,Android中的图像消费SurfaceFlinger从图像缓冲区将数据取出,进行加工及合成
那么图像缓冲区我们又需要注意哪些内容呢?

黄油计划

优化是无止境的,Google 在 2012 年的 I/O 大会上宣布了 Project Butter 黄油计划,并且在 Android 4.1 中正式开启了这个机制。

VSYNC信号

VSYNC(Vertical Synchronization)是理解 Project Butter 的核心。对于 Android 4.0CPU 可能会因为在忙其他的事情,导致没来得及处理 UI 绘制。
为了解决这个问题,系统在收到VSync信号后,将马上开始下一帧的渲染。即一旦收到VSync通知(16ms触发一次),CPUGPU 才立刻开始计算然后把数据写入buffer。如下图

CPU/GPU根据VSYNC信号同步处理数据,可以让CPU/GPU有完整的16ms时间来处理数据,减少了jank
一句话总结,VSync同步使得CPU/GPU充分利用了16.6ms时间,减少jank

三缓冲机制

Android 4.0之前,Android采用双缓冲机制,让绘制和显示器拥有各自的bufferGPU 始终将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Frame Buffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。

但是如果界面比较复杂,CPU/GPU的处理时间较长 超过了16.6ms呢,双缓冲机制会带来什么问题?如下图:

  • 在第二个时间段内,但却因 GPU 还在处理 B 帧,缓存没能交换,导致 A 帧被重复显示。
  • B完成后,又因为缺乏VSync信号,它只能等待下一个signal的来临。于是在这一过程中,有一大段时间是被浪费的。
  • 当下一个VSync出现时,CPU/GPU马上执行操作(A帧),且缓存交换,相应的显示屏对应的就是B。这时看起来就是正常的。只不过由于执行时间仍然超过16ms,导致下一次应该执行的缓冲区交换又被推迟了——如此循环反复,便出现了越来越多的“Jank”。

三缓冲就是在双缓冲机制基础上增加了一个Graphic Buffer缓冲区,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个Graphic Buffer所占用的内存。

三缓冲机制有效利用了等待vysnc的时间,可以帮助我们减少了jank

RenderThread

经过 Android 4.1Project Butter 黄油计划之后,Android 的渲染性能有了很大的改善。不过你有没有注意到这样一个问题,虽然利用了 GPU 的图形高性能运算,但是从计算 DisplayList,到通过 GPU 绘制到 Frame Buffer,整个计算和绘制都在 UI 主线程中完成。

UI 线程任务过于繁重。如果整个渲染过程比较耗时,可能造成无法响应用户的操作,进而出现卡顿的情况。GPU 对图形的绘制渲染能力更胜一筹,如果使用 GPU 并在不同线程绘制渲染图形,那么整个流程会更加顺畅。

正因如此,在 Android 5.0 引入两个比较大的改变。一个是引入了 RenderNode 的概念,它对 DisplayList 及一些 View 显示属性都做了进一步封装。另一个是引入了 RenderThread,所有的 GL 命令执行都放到这个线程上,渲染线程在 RenderNode 中存有渲染帧的所有信息,可以做一些属性动画,这样即便主线程有耗时操作的时候也可以保证动画流程。

图像消费者

SurfaceFlingerAndroid系统中最重要的一个图像消费者,Activity绘制的界面图像,都会传递到SurfaceFlinger来,SurfaceFlinger的作用主要是接收GraphicBuffer,然后交给HWComposer或者OpenGL做合成,合成完成后,SurfaceFlinger会把最终的数据提交给FrameBuffer

SurfaceFlinger是图像数据的消费者。在应用程序请求创建surface的时候,SurfaceFlinger会创建一个LayerLayerSurfaceFlinger操作合成的基本单元。所以,一个surface对应一个Layer
当应用程序把绘制好的GraphicBuffer数据放入BufferQueue后,接下来的工作就是SurfaceFlinger来完成了。

系统会有多个应用程序,一个程序有多个BufferQueue队列。SurfaceFlinger就是用来决定何时以及怎么去管理和显示这些队列的。
SurfaceFlinger请求HAL硬件层,来决定这些Buffer是硬件来合成还是自己通过OpenGL来合成。
最终把合成后的buffer数据,展示在屏幕上。

总结

总得来说,Android图像渲染机制是一个生产者消费者的模型,如下图所示:

  • onMeasureonLayout计算出view的大小和摆放的位置,这都是UI线程要做的事情,在draw方法中进行绘制,但此时是没有真正去绘制。而是把绘制的指令封装为displayList,进一步封装为RenderNode,在同步给RenderThread
  • RenderThread通过dequeue拿到graphic buffersurfaceFlinger的缓冲区),根据绘制指令直接操作OpenGL的绘制接口,最终通过GPU设备把绘制指令渲染到了离屏缓冲区graphic buffer
  • 完成渲染后,把缓冲区交还给SurfaceFlingerBufferQueueSurfaceFlinger会通过硬件设备进行layer的合成,最终展示到屏幕。

原文地址:https://blog.csdn.net/weixin_61845324

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


更新Android SDK到3.0版本时,遇到Failed to rename directory E:\android\tools to E:\android\temp\ToolPackage.old01问题,导致无法更新,出现该问题的原因是由于3.0版本与较早的sdk版本之间文件结构有冲突,解决
Android 如何解决dialog弹出时无法捕捉Activity的back事件 在一些情况下,我们需要捕捉back键事件,然后在捕捉到的事件里写入我们需要进行的处理,通常可以采用下面三种办法捕捉到back事件: 1)重写onKeyDown或者onKeyUp方法 2)重写onBackPressed方
Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法。一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小。在Button的属性中有一个是drawable
Android中的"Unable to start activity ComponentInfo"的错误 最近在做一款音乐播放器的时候,然后在调试的过程中发现一直报这个错误"Unable to start activity ComponentInfo",从字面
Android 关于长按back键退出应用程序的实现最近在做一个Android上的应用,碰到一个问题就是如何实现长按back键退出应用程序。在网上查找了很多资料,发现几乎没有这样的实现,大部分在处理时是双击back键来退出应用程序。参考了一下双击back键退出应用程序的代码,网上主流的一种方法是下面
android自带的时间选择器只能精确到分,但是对于某些应用要求选择的时间精确到秒级,此时只有自定义去实现这样的时间选择器了。下面介绍一个可以精确到秒级的时间选择器。 先上效果图: 下面是工程目录: 这个控件我也是用的别人的,好像是一个老外写的,com.wheel中的WheelView是滑动控件的主
Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing
Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的item默认的外观,下面讲解以下在使用listview时最常见的几个问题。1.如何改变item的背景色和按
如何向Android模拟器中导入含有中文名称的文件在进行Android开发的时候,如果需要向Android模拟器中导入文件进行测试,通过DDMS下手动导入或者在命令行下通过adb push命令是无法导入含有中文文件名的文件的。后来发现借用其他工具可以向模拟器中导入中文名称的文件,这个工具就是Ultr
Windows 下搭建Android开发环境一.下载并安装JDK版本要求JDK1.6+,下载JDK成功后进行安装,安装好后进行环境变量的配置【我的电脑】-——>【属性】——>【高级】 ——>【环境变量】——>【系统变量】中点击【新建】:变量名:CLASSPATH变量值:……
如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹出菜单,此时可以考虑用PopupWindow来实现。下面就来介绍一下如何使用PopupWindow实现一个弹出窗。 主Activity代码:public void onCreat
解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候,突然出现这个错误,折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案,下面给出这两种方法的链接博客:ht
AdvserView.java package com.earen.viewflipper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory;
ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY。 |值|说明| |:--:|:--| |center|保持原图的大小,显示在ImageVie
文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win10/Android studio 3.21.环境配置 在SDK Tools里选择 CMAKE/LLDB/NDK点击OK 安装这些插件. 2.创建CMakeLists.txt文件 在Project 目录下,右键app,点击新建File文件,命名为CMakeLists.txt点击OK,创建完毕! 3.配置文件 在CMa..._link c++ project with gradle
文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由mainActivity界面跳转到otherActivity界面1.写好两个layout文件,activity_main.xml和otherxml.xmlactivity_main.xml<?xml version="1.0" encoding="utf-8"?><RelativeLayout ="http://schemas..._android studio 界面跳转
文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件来用,然后发现了这两款神作,都是外国的软件,而且都是开源的软件,因此把源码下载了下来,给有需要研究代理这方面的童鞋看看。不得不说,国外的开源精神十分浓,大家相互使用当前基础的开源软件,然后组合成一个更大更强的大开源软件。好吧,废话不多说,下面简单介绍一下这两款开源项目。一、ProxyDroid:ProxyDroid功能比较强大,用到的技术也比较多,源码也_proxydroid
文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项目时Gradle Build 窗口却显示错误:程序包R不存在通常情况下是不会出现这个错误的。我是怎么遇到这个错误的呢?第一次创建项目,company Domain我使用的是:aven.com,但是创建过程在卡在了Building 'Calculator' Gradle Project info这个过程中,于是我选择了“Cancel”第二次创建项目,我还是使用相同的项目名称和项目路_r不存在
文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上使用系统自带的代理,限制灰常大,仅支持系统自带的浏览器。这样像QQ、飞信、微博等这些单独的App都不能使用系统的代理。如何让所有软件都能正常代理呢?ProxyDroid这个软件能帮你解决!使用方法及步骤如下:一、推荐从Google Play下载ProxyDroid,目前最新版本是v2.6.6。二、对ProxyDroid进行配置(基本配置:) (1) Auto S_proxydroid使用教程
文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供了一个很实用的工具Android设备监视器(Android device monitor),该监视器中最常用的一个工具就是DDMS(Dalvik Debug Monitor Service),是 Android 开发环境中的Dalvik虚拟机调试监控服务。可以进行的操作有:为测试设备截屏,查看特定进程中正在运行的线程以及堆栈信息、Logcat、广播状态信息、模拟电话_安卓摄像头调试工具