深入剖析android新特性 第九章 笔记
第九章 图形系统改进
早期android卡顿,jelly bean 4.0后有改进
9.1 图形系统整体架构
AP有两种绘制图形方法,
canvas:
android.graphics.Canvas是2D的图形API,Canvas API的硬件加速通过一个名为OpenGLRenderer的绘图库实现,
它将Canvas操作转换为OpenGL操作,以便可以在GPU上执行。
4.0开始,Canvas默认就会启动硬件加速,所以GPU支持OGLES 2.0是强制性的。
OpenGL:
开发人员渲染图形的另一个主要方式是用OGLES,Android在android.opengl软件包提供OpenGLES接口,开发人员可用SDK或者AndroidNDK提供原生API调用其GL实现。
9.1.1, Android图形组件
无论用什么API,最终都在Surface上渲染,
Surface描述了BufferQueue的生产者,BufferQueue的消费者通常是SurfaceFlinger
Android平台上所有窗口在创建时都伴随这surface,
所有可见的surface由surfaceflinger负责合成并最终显示到显示器上。
Android图形系统的架构与主要组件:
IMAGE STREAM PRODUCERS
Media Player Camera Preview NDK OpenGL ES
WINDOW POSITIONG NATIVE FRAMEWORK(frameworks/native/libs/gui)
WindowManager Surface.cpp
IMAGE STREAM CONSUMERS---------------> GLConsumer.cpp
OpenGLES Apps IGraphicBufferProducer
SurfaceFlinger------------|
|
HAL
Hardware Composer Gralloc
说明:
Image Stream Producers:
图形流生产者,是任何可能产生Graphics Buffer的对象,如OpenGLES,Canvas 2D,或者mediaserver视频解码器
Image Stream Consumers:
图形流消费者,最常见的消费者是SurfaceFlinger,这个系统服务根据当前可见的Surface并且根据WindowManager提供的信息,来将它们合成并且输出到显示屏上。
SurfaceFlinger是唯一可以修改显示屏内容的组件,它使用OpenGL和Hardware Composer来合成Surface。
除了SurfaceFlinger,其他消费者可能是OGLES(如相机),也可能不是OGL应用,如ImageReader。
imageReader是干嘛的?
Window Manager:
窗口管理器,系统中专门用来管理窗口的系统服务。
窗口是View的容器,每个窗口都会包含一个Surface。
WindowManager管理窗口的各方面,包括:生命周期,输入,焦点事件,屏幕旋转,切换动画,位置,转换,Z-order,等。
WindowManager会将Window的这双鞋元数据传递给SurfaceFlinger,
这样SF便知道如何将它们合成并显示出来
Hardware Composer:
硬件合成器,这是显示子系统的硬件抽象。
SF会委派一个合成的工作给Hardware Composer,来减轻OGL和GPU的负载。
这样做比单纯通过GPU去合成消耗更少的电量。
HWComposer的硬件抽象层主导了另外一半的工作,它是Android图形渲染的核心。
HWComposer必须支持事件,如VSYNC事件和hotplug(HDMI即插即用)事件。
Gralloc:
图形内存分配器,Graphics memory allocator,
用来分配图形的内存
Android图形系统的显示流程:
SurfaceFlinger HWCOMPOSER
STATUS BAR ->GPU ------->BUFFER QUEUE -------> GPU->BUFFER QUEUE -------->DISPLAY CONTROLLER
SYSTEM BAR ->GPU ------->BUFFER QUEUE ------->
BACKGROUND RENDERER->GPU ->BUFFERQUEUE
ICONS/WIDGETS REDNERER->GPU->BUFFERQUEUE
左边的对象如Home Screen,Status Bar,SystemUI,是GraphicsBuffer的生产者,
中间的SurfaceFlinger是排版者Compositor,
右边的HardwareComposer是最终的合成者Composer
9.1.2 组件
从Android图形系统的实现来看,整个系统主要包含以下组件,
底层组件:
1,BufferQueue与gralloc:
BufferQueue生成图形数据Buffer(生产者)的内容连接到接收数据进程显示或者进一步处理(消费者)的模块上。
图形数据的Buffer通过图形内存分配器Gralloc进行分配。这些分配器由厂商的HAL接口实现。
2,SF,HWComposer与虚拟显示器:
SF接收来自多个数据源的数据缓冲区,将它们合成并发送到显示器上,
HWComposer HAL(HWC)根据硬件情况决定最高效的缓冲合成方式,虚拟显示使系统内的合成输出可用,
如录制屏幕或者通过网络发送屏幕。
3,Surface,Canvas,SurfaceFlinger:
surface会产生一个被SF使用的缓冲区队列。
当渲染到Surface上时,结果将在缓冲区中被传递给消费者。
Canvas API提供了一个软件实现(具有硬件加速支持),用于直接在Surface(OpenGLES的底层代替)上绘制的方法,
任何与视图相关的内容都涉及SurfaceHolder,它提供API来获取和设置Surface的参数,如尺寸和格式。
4,EGLSurface和OpenGLES
OpenGLES定义了图形渲染API,它与EGL组合,该库通过操作系统来创建和访问窗口(若是绘制纹理多边形,则用GLES调用;若是将渲染结果显示在屏幕上,则用EGL调用)
5,Vulkan
Vulkan是一套跨平台的高性能3D图形API。像OGLES一样,Vulkan提供了在AP中创建高质量、实时图形的工具。
Vulkan优势包括降低GPU开销,支持SPIR-V二进制中间语言。
上层组件:
1,SurfaceView和GLSurfaceView
SurfaceView结合了Surface和View,
SurfaceView的View组件由SurfaceFlinger(而不是APP)合成,可以从单独的线程/进程渲染,并与AP的UI呈现隔离。
GLSurfaceView提供帮助类来管理EGL上下文,跨线程通信以及与Activity生命周期的交互(但不需要使用GLES)
2,SurfaceTexture:
SurfaceTexture结合了一个Sureface和GLES纹理来创建一个BufferQueue,APP是消费者。
当生产者将新的缓冲区排入队列时,它会通知APP,APP会依次释放先前占有的缓冲区,
从队列中获取新缓冲区并执行EGL调用,从而使GLES可将此缓冲区作为外部纹理。
Android7增加了对保护视频内容进行GPU后处理的安全纹理视频播放的支持。
3,TextureView
TextureView将View与SurfaceTexture结合在一起
TextureView包装一个SurfaceTexture,并且负责响应回调和获取新的缓冲区,
绘图时,TextureView使用最近收到的缓冲区的内容作为其数据源,根据View状态指示,
在它应该渲染的位置和以它应该渲染的方式进行渲染,View合成始终通过GLES执行,这意味着内容更新可能导致其他Vie元素重绘。
9.1.3 Android如何绘制视图
当Activity接收到焦点时,系统将会对其布局进行进行绘制,
Android框架将处理绘图过程,但是Activity必须提供其布局层次结构的根节点,
绘制从布局的根节点开始,绘制过程遍历整个ViewTree结构并渲染每一个View,
相应的,每个ViewGroup负责请求每个子项被绘制(通过draw()方法),
每个View负责绘制其本身。
因为ViewTree被顺序的遍历,这意味着父母将在他们的孩子之前(即后面)被绘制,同一个层次的View将按照他们出现在树中的顺序进程绘制。
绘制ViewTree包含两步骤:测量和布局
测量
测量由measure(int, int)实现,按照ViewTree自顶向下遍历。
在地柜期间,每个View在树上报告其自身的尺寸。
在测量结束时,每个View都存储了策略结果。
布局
布局通过layout(int, int, int)实现,也是自顶向下的。在此过程中,每个父元素通过在前一步得到的每个子元素的尺寸来布局。
开发者可以通过invalidate()对View进程强制绘制。
当View对象的measure()方法返回时,必须设置其getMeasuredWidth()和getMeasuredHeight()以及所有View子元素的值。
View对象的宽度和高度值必须遵守View对象的父元素施加的约束。
这保证了测量结束时,所欲父元素都接受所有子元素的尺寸。
父View可能会在其子元素上多次调用measure(),如,父元素可以用未指定的尺寸度量每个子元素一次,以找出他们想要多大,若所有孩子的无约束大小的总和太大或者太小,再用实际数据调用measure()(也就是说子元素不同意他们各自获得的多数空间,父元素将介入并在第二步时设定规则)
策略通过两个类表达维度:ViewGroup.LayoutParams和MeasureSpec
LayoutParams类告诉他们的父元素他们自身如何被测量和定位。三种:
一个确切数字
MATCH_PARENT,View要和其父元素一样大
WRAP_CONTENT,View想要足够大以包含其内容
MeasureEpec对象用于从父元素推送要求到子对象。三种模式:
UNSPCIFIED:用于父View确定子View的所需尺寸,
EXACTLY:父View使用这个方式对子View施加确切的大小
AT_MOST:父View对子View限制最大的大小。
9.1.4 硬件加速
Android从3.0(API level 11)开始2D图形渲染支持硬件加速,
从4.0(API Level>14)开始则默认打开
不使用硬件加速的情况下,所有渲染工作通过软件实现,最终由CPU完成。
而在使用硬件加速的情况下,通过OpenGLREdnerer由GPU进行渲染。
软件渲染,与 使用硬件加速渲染的流程:
SoftWare rendering:
View.onDraw() -> Canvas.draw() -> Rasterizer -> Display
HardwareRendering:
View.onDraw() -> Canvas.draw() -> OpenGLRenderer -> GPU -> Display
对开发者来说,硬件加速可以下四个层次进行控制:
App,Activity,Window,View
App与Acitivty的硬件加速控制直接在AndroidManifest.xml设置:
<application android:hardwareAccelerated="ture">
<acitivyt .../>
<activity android:hardwareAccelerated="false" />
</application>
Window的硬件加速开关通过代码设置:
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWER_ACCELERATED,
WindowManager.LayoutPraams.FLAG_HARDWER_ACCELERATED
);
View的硬件加速开关也是通过代码:
view.setLayerTYpe(View.LAYER_TYPE_SOFTWAER, null);
另外,框架还提供了接口来查询是否启用了硬件加速
View.siHardwareAccelerated();
Canvas.isHardwareAccelerated();
推荐资料:
https://source.android.com/devices/graphics/
https://developer.android.coim/guide/topics/ui/how-android-draws.html
https://developer.android.com/guide/topics/graphics/2d-graphics.html
https://developer.android.com/guide/topics/graphics/hardware-accel.html