本文翻译自Android官网的内容:https://source.android.com/devices/graphics
Android framework提供了多种2D和3DGraphics渲染API,这些接口API与厂商的Graphics驱动实现交互,所以有必要对这些API的工作原理和进行深入的了解。此页面介绍了Graphics HAL层,HAL层构建于这些驱动之上。
应用程序开发者可以通过两种方式将一张图片绘制到屏幕:Canvas 或 OpenGL。参考Android Graphics -2 架构概述 关于Android Graphics 组件的详细描述。
android.graphics.Canvas(画布) 是一个2D图形API,并且在开发者中非常流行。在Android中画布操作可以绘制所有的原生的和自定义的View(android.view.Views)。在Android中,硬件加速(hardware-accelerated)Canvas API是一个高端的操作,它使用一个叫做OpenGLRenderer绘制库来进行绘制,这个库可以把画布操作翻译成OpenGL操作,从而使他们可以使用GPU。
自Android 4.0开始,硬件加速Canvas就默认支持了。因此Android4.0以后的设备必须拥有一个支持OpenGL ES 2.0 的硬件GPU。参考https://developer.android.com/guide/topics/graphics/hardware-accel.html ,此链接描述了硬件加速的工作原理以及它和软件绘制的区别。
除了Canvas外,另一个主要方法是使用OpenGL ES直接把内容渲染到surface上。Android提供了android.opengl包,开发者可以用它来调用到他们的GL实现,使用SDK或者NDK提供的native API。
Android开发者可以使用“drawElements Quality Program” 来对OpenGL ES功能进行测试,简称为deqp。
无论开发者使用哪种接口,所有的内容都会被渲染到“Surface”之上。surface表示一个buffer queue的生产者端,buffer queue通常被SurfaceFlinger消费。Android平台上被创建的每一个窗口都会有一个Surface对应。所有完场渲染的可见Surface都会被SurfaceFlinger合成到display上去显示。
下图是Graphics的核心组件
图1. Surface如何渲染
关于上图的描述如下:
一个图像流生产者表示可以产生图像buffer的任何组件。例如包括Open ES,Canvas 2D 和mediaserver vide decoders。
大部分情况下,通常的图像流消费者是SurfaceFlinger,SurfaceFlinger是一个系统服务用于消费当前的可见surface并且将他们合成到display,前提是使用Window Manager提供的参数。SurfaceFlinger是唯一可以修改显示内容的服务。SurfaceFlinger使用OpenGL和硬件合成器来来合成一组surface。
其他的OpenGL ES应用也可以消耗图像流,例如Camera app消耗了camera 预览图像流。非GL应用也可以成为消费者,例如ImageReader 类。
控制窗口的Android系统服务,窗口是view的容器。一个窗口总是对应一个surface。这个服务监督窗口的生命周期,输入和焦点事件,屏幕方向,透明度,动画,位置,形变,z-order等等。窗口管理器发送所有的window元数据到SurfaceFlinger,从而SurfaceFlinger可以使用这些数据来合成surface。
显示子系统的硬件抽象。SurfaceFlinger可以授权一些特定的合成工作到硬件合成器,从而降低OpenGL和GPU的工作负担。SurfaceFlinger仅仅是另一个OpenGL ES客户端。所以例如当SurfaceFlinger积极地将一个或多个buffer合成到第三个时,它使用的是OpenGL ES。这使得在合成时比用GPU进行全部的计算功耗更低。
硬件合成器抽象层负责一半的工作并且是Android图行渲染的中心点。硬件合成器需要支持event,例如VSYNC(另一个时间是HDMI的热插拔事件支持)。
图形内存分配器,用于分配图像生产者请求的内存。详细内容,参考:https://source.android.com/devices/graphics/architecture.html#gralloc_HAL
下图表述了Android的图形管线:
图2. Android的图形数据流
图形的左侧是渲染器生产的graphics buffer,例如home界面,状态栏,system UI。SurfaceFlinger是排版者,硬件合成器是合成者。
BufferQueue在Android图形组件之间起到粘合作用。这是一对queue,用于实现从生产者到消费者的恒定循环。一旦生产者交出buffer,SurfaceFlinger就承担起将所有东西合成到display的责任。
下图是BufferQueue的通信过程
图3. BufferQueue通信过程
BufferQueue包含把图像流生产者和图像流消费者绑定到一起的逻辑。一些图像生产者的例子是camera预览,是由camera HAL或者OpenGL ES游戏产生的。一些图像消费者的例子是SurfaceFlinge或者某些显示OpenGL ES 流的app,例如camera aoo显示camera取景器(viewfinder)。
BufferQueue是一个讲buffer池(pool)和一个队列组合在一起的数据结构,并且使用Binder IPC来传递buffer。名词生产者接口,或者说你传给想要生成graphic buffer的人的内容,叫做IGraphicBufferProducer(SurfaceTexture的一部分)。BufferQueue通常用于渲染到Surface、使用GL Consumer来消耗等其他任务。BufferQueue有三种不通的操作模式:
类同步模式(Synchronous-like mode)- BufferQueue默认使用这种模式,在这种模式下,从生产者那里得到的每个buffer都会进入消耗者,不会丢弃任何buffer。如果生产者太快,生产buffer的速度快于排出的速度,那么他将被block,直到buffer空闲。
非阻塞模式(Non-blocking mode)- BufferQueue还可以在非阻塞模式下运行,在这种模式下,它宁愿发生错误也不会等待buffer。在此模式下也不会丢弃任何buffer。这对于避免程序软件中隐藏的死锁有所帮助,这些死锁往往是因为framework中复杂的依赖关系导致的。
放弃模式 (Discard mode)- 最后,BufferQueue可以配置成宁愿放弃老的buffer也不会产生错误或等待。例如,执行一次到texture view的渲染,绘制要尽可能得快,有些buffer可能被丢弃。
因为Android graphics没有明确的并行性,vendor长期以来在自己的驱动中实施隐式的同步策略。使用Android Graphics同步框架后这将不再需要。参考详细的介绍:https://source.android.com/devices/graphics/implement-vsync.html#explicit_synchronization
同步框架明确地描述了不同异步操作之间的依赖关系。此框架提供了一组简单的API,让组件在buffer被释放后发出信号。同时还允许从kernel到userspace或 userspace的进程之间传递同步原语。
举个例子,应用程序可以将需要执行的工作放在GPU中排队,然后GPU开始绘制图像。尽管图像还没有绘制到内存中,buffer的指针仍然可以与一个fence被传到窗口合成器,fence可以表示GPU什么时候完成工作。然后窗口合成器可以提前开始工作,并将工作移交给display controller。一旦GPU完成工作,display controller可以立马进行图像的显示。
同步框架还可以允许实现着在自己的硬件组件中使用同步资源。最后,此框架提供Graphics管线的可视性来帮助调试。