Android 框架提供了各种用于 2D 和 3D 图形渲染的 API,可与制造商的图形驱动程序实现代码交互,因此务必更好地了解这些 API 的工作原理。这类驱动程序的构建基于图形硬件抽象层 (HAL),本页介绍了相关图形 HAL。在继续学习本部分之前,请先熟悉以下术语:
Canvas
(API 元素)Surface
对象来处理实际位合成。Canvas
包含关于位图、线条、圆形、矩形、文字等的标准计算机绘制方法,并与位图或 Surface 相关联。画布是在屏幕上绘制 2D 对象的最简便方法。基类为 Canvas
。
android.graphics.drawable
的子类。如需详细了解可绘制对象和其他资源,请参阅资源。
android.opengl
和 javax.microedition.khronos.opengles
软件包提供 OpenGL ES 功能。Surface
(API 元素)Surface
对象,并提供各种辅助方法来绘制图层和调整界面大小。请使用 SurfaceView
类,而不是直接使用 Surface
类。
SurfaceView
(API 元素)View
对象,它封装用于绘制的 Surface
对象,并提供相应的方法来动态指定其大小和格式。Surface 视图针对资源密集型操作(例如游戏或相机预览)提供了一种独立于界面线程进行绘制的方式,但也会因此占用额外的内存。Surface 视图同时支持画布和 OpenGL ES 图形。SurfaceView
对象的基类是 SurfaceView
。
R.style
中,并以 Theme_
开头。View
(API 元素)View
类是 activity 或对话框界面的大多数布局组件(如文本框和窗口)的基类。View
对象接收来自其父对象(请参阅 ViewGroup
)的调用,以绘制自身,并告知父对象其首选大小和位置,但父对象不一定会遵循。如需了解详情,请参阅 View
。
ViewGroup
(API 元素)widget
软件包中,但会扩展 ViewGroup
类。
android.widget
软件包中。Window
(API 元素)Window
抽象类的对象,可指定常规窗口的元素,例如外观和风格、标题栏文字、菜单的位置和内容。对话框和 activity 使用 Window
类的实现来渲染 Window
对象。您无需在应用中实现 Window
类或使用窗口。应用开发者可通过三种方式将图像绘制到屏幕上:使用画布、OpenGL ES 或 Vulkan。
Android 图形组件
无论开发者使用什么渲染 API,一切内容都会渲染到 surface 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。
下图显示了关键组件如何协同工作:
主要组件如下所述:
图像流生产方
图像流生产方可以是生成图形缓冲区以供消耗的任何内容。例如 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。
图像流消耗方
图像流的最常见消耗方是 SurfaceFlinger,该系统服务会消耗当前可见的 Surface,并使用窗口管理器中提供的信息将它们合成到屏幕。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。
其他 OpenGL ES 应用也可以消耗图像流,例如相机应用会消耗相机预览图像流。非 GL 应用也可以是使用方,例如 ImageReader 类。
硬件混合渲染器
显示子系统的硬件抽象实现。SurfaceFlinger 可以将某些合成工作委托给硬件混合渲染器,以分担 OpenGL 和 GPU 上的工作量。SurfaceFlinger 只是充当另一个 OpenGL ES 客户端。因此,在 SurfaceFlinger 将一个或两个缓冲区合成到第三个缓冲区中的过程中,它会使用 OpenGL ES。这会让合成的功耗比通过 GPU 执行所有计算时更低。
硬件混合渲染器 HAL 则进行另一半的工作,是所有 Android 图形渲染的中心点。Hardware Composer 必须支持事件,其中之一是 VSYNC(另一个是支持即插即用 HDMI 的热插拔)。
Gralloc
需要使用显存分配器 (Gralloc) 来分配图像生产方请求的内存。有关详情,请参阅 Gralloc HAL。
数据流
有关 Android 图形管道的描述,请参见下图:
左侧的对象是生成图形缓冲区的渲染器,如主屏幕、状态栏和系统界面。SurfaceFlinger 是合成器,而硬件混合渲染器是混合渲染器。
BufferQueue
BufferQueues 是 Android 图形组件之间的粘合剂。它们是一对队列,可以调解缓冲区从生产方到消耗方的固定周期。一旦生产方移交其缓冲区,SurfaceFlinger 便会负责将所有内容合成到显示部分。
有关 BufferQueue 通信过程,请参见下图。
BufferQueue 包含将图像流生产方与图像流消耗方结合在一起的逻辑。图像生产方的一些示例包括由相机 HAL 或 OpenGL ES 游戏生成的相机预览。图像消耗方的一些示例包括 SurfaceFlinger 或显示 OpenGL ES 流的另一个应用,如显示相机取景器的相机应用。
BufferQueue 是将缓冲区池与队列相结合的数据结构,它使用 Binder IPC 在进程之间传递缓冲区。生产方接口,或者您传递给想要生成图形缓冲区的某个人的内容,即是 IGraphicBufferProducer(SurfaceTexture 的一部分)。BufferQueue 通常用于渲染到 Surface,并且与 GL 消耗方及其他任务一起消耗内容。
BufferQueue 可以在三种不同的模式下运行:
类同步模式 - 默认情况下,BufferQueue 在类同步模式下运行,在该模式下,从生产方进入的每个缓冲区都在消耗方那退出。在此模式下不会舍弃任何缓冲区。如果生产方速度太快,创建缓冲区的速度比消耗缓冲区的速度更快,它将阻塞并等待可用的缓冲区。
非阻塞模式 - BufferQueue 还可以在非阻塞模式下运行,在此类情况下,它会生成错误,而不是等待缓冲区。在此模式下也不会舍弃缓冲区。这有助于避免可能不了解图形框架的复杂依赖项的应用软件出现潜在死锁现象。
舍弃模式 - 最后,BufferQueue 可以配置为丢弃旧缓冲区,而不是生成错误或进行等待。例如,如果对纹理视图执行 GL 渲染并尽快绘制,则必须丢弃缓冲区。
为了执行这项工作的大部分环节,SurfaceFlinger 就像另一个 OpenGL ES 客户端一样工作。例如,当 SurfaceFlinger 正在积极地将一个缓冲区或两个缓冲区合成到第三个缓冲区中时,它使用的是 OpenGL ES。
Hardware Composer HAL 执行另一半工作。该 HAL 充当所有 Android 图形渲染的中心点。