图形

Android Graphics HAL icon

Android 框架为 2D 和 3D 图形提供了各种渲染 API,这些 API 与制造商对图形驱动程序的实现进行交互,因此务必充分了解这些 API 在较高层级上的工作原理。本页介绍了构建这些驱动程序所依据的图形硬件抽象层 (HAL)。在继续阅读本部分之前,请先熟悉以下术语

canvas(通用术语), Canvas(API 元素)
canvas 是一个绘图表面,可处理位图或 Surface 对象实际位的合成。Canvas 具有用于位图、线条、圆形、矩形、文本等标准计算机绘图的方法,并且绑定到位图或 surface。canvas 是在屏幕上绘制 2D 对象的最简单、最便捷的方式。基类是 Canvas
可绘制对象
drawable 是一个编译后的视觉资源,可用作屏幕的背景、标题或其他部分。drawable 通常会加载到另一个 UI 元素中,例如作为背景图片。drawable 无法接收事件,但会分配各种其他属性(例如状态和调度),以启用子类(例如动画对象或图片库)。许多 drawable 对象从 drawable 资源文件(描述图片的 XML 或位图文件)加载。Drawable 资源会编译到 android.graphics.drawable 的子类中。如需详细了解 drawable 和其他资源,请参阅资源
布局资源
布局资源是一个 XML 文件,用于描述 Activity 屏幕的布局。如需了解详情,请参阅布局资源
nine-patch(9-patch、NinePatch)
nine-patch 是一种可调整大小的位图资源,可用作设备上的背景或其他图片。如需了解详情,请参阅 Nine-patch
OpenGL ES
OpenGL ES 是一个用于渲染 2D 和 3D 图形的跨平台 API。Android 提供了 OpenGL ES 库,用于硬件加速 3D 渲染。对于 2D 渲染,canvas 是更简单的选择。OpenGL ES 在 Android Native Development Kit (NDK) 中提供。android.opengljavax.microedition.khronos.opengles 软件包公开了 OpenGL ES 功能。
surface(通用术语), Surface(API 元素)
surface 表示一块内存,它会被合成为屏幕。surface 包含一个用于绘图的 canvas,并提供各种辅助方法来绘制图层和调整 Surface 对象的大小。请使用 SurfaceView 类,而不是直接使用 Surface 类。
surface view(通用术语), SurfaceView(API 元素)
surface view 是一个 View 对象,它封装了用于绘图的 Surface 对象,并公开了动态指定其大小和格式的方法。surface view 提供了一种独立于 UI 线程进行绘制的方式,适用于资源密集型操作(例如游戏或相机预览),但会导致占用更多内存。surface view 同时支持 canvas 和 OpenGL ES 图形。SurfaceView 对象的基础类是 SurfaceView
主题
主题是一组属性(例如文本大小和背景颜色),捆绑在一起以定义各种默认显示设置。Android 提供了一些标准主题,这些主题在 R.style 中列出,并以 Theme_ 作为前缀。
view(通用术语), View(API 元素)
view 在屏幕上绘制一个矩形区域,并处理点击、击键和其他互动事件。View 类是 Activity 或对话框屏幕的大多数布局组件(例如文本框和窗口)的基类。View 对象接收来自其父对象(请参阅 ViewGroup)的调用以绘制自身,并将其首选大小和位置告知其父对象,父对象可能不会遵循此大小和位置。如需了解详情,请参阅 View
view group(通用术语), ViewGroup(API 元素)
view group 对一组子视图进行分组。view group 负责决定子视图的定位位置和大小,以及在适当时调用每个子视图来绘制自身。有些 view group 是不可见的,仅用于布局,而另一些则具有固有的 UI,例如滚动列表框。View group 位于 widget 软件包中,但扩展了 ViewGroup 类。
视图层级结构
视图层级结构是 view 和 view group 对象的排列,用于定义应用的每个组件的用户界面。层级结构由包含一个或多个子视图或 view group 的 view group 组成。您可以使用 Android SDK 随附的 Hierarchy Viewer 获取视图层级结构的可视化表示,以便进行调试和优化。
Vulkan
Vulkan 是一个低开销的跨平台 API,适用于高性能 3D 图形。
小部件
widget 是一组完全实现的 view 子类之一,用于渲染表单元素和其他 UI 组件,例如文本框或弹出式菜单。由于 widget 是完全实现的,因此它可以处理测量、绘制自身以及响应屏幕事件。widget 位于 android.widget 软件包中。
window(通用术语), Window(API 元素)
在 Android 应用中,window 是一个从 Window 抽象类派生的对象,用于指定通用窗口的元素,例如外观、标题栏文本以及菜单的位置和内容。对话框和 Activity 使用 Window 类的实现来渲染 Window 对象。您无需在应用中实现 Window 类或使用窗口。

应用开发者通过三种方式在屏幕上绘制图片:使用 CanvasOpenGL ESVulkan

Android 图形组件

无论开发者使用什么渲染 API,所有内容都会渲染到 surface 上。surface 表示缓冲区队列的生产者端,缓冲区队列通常由 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 surface 提供支持。所有渲染的可见 surface 都由 SurfaceFlinger 合成到显示屏上。

下图展示了关键组件如何协同工作

image rendering components

图 1. surface 的渲染方式。

主要组件描述如下

图像流生产者

图像流生产者可以是任何生成图形缓冲区以供使用的对象。示例包括 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。

图像流消费者

图像流最常见的消费者是 SurfaceFlinger,这是一种系统服务,用于消耗当前可见的 surface,并使用窗口管理器提供的信息将其合成到显示屏上。SurfaceFlinger 是唯一可以修改显示屏内容的服务。SurfaceFlinger 使用 OpenGL 和硬件合成器来合成一组 surface。

其他 OpenGL ES 应用也可以消耗图像流,例如相机应用消耗相机预览图像流。非 GL 应用也可以是消费者,例如 ImageReader 类。

硬件合成器

显示子系统的硬件抽象层。SurfaceFlinger 可以将某些合成工作委托给硬件合成器,以从 OpenGL 和 GPU 卸载工作。SurfaceFlinger 充当另一个 OpenGL ES 客户端。因此,当 SurfaceFlinger 主动将一个或两个缓冲区合成为第三个缓冲区时,例如,它会使用 OpenGL ES。这使得合成比让 GPU 执行所有计算的功耗更低。

硬件合成器 HAL 执行另一半工作,并且是所有 Android 图形渲染的中心点。硬件合成器必须支持事件,其中一个事件是 VSYNC(另一个事件是用于即插即用 HDMI 支持的热插拔)。

Gralloc

图形内存分配器 (Gralloc) 是分配图像生产者请求的内存所必需的。如需了解详情,请参阅Gralloc HAL

数据流

下图展示了 Android 图形管道的数据流

graphics data flow

图 2. 通过 Android 的图形数据流

左侧的对象是渲染器,用于生成图形缓冲区,例如主屏幕、状态栏和系统 UI。SurfaceFlinger 是合成器,硬件合成器是合成器。

BufferQueue

BufferQueue 在 Android 图形组件之间提供粘合。这些是一对队列,用于协调从生产者到消费者的缓冲区恒定循环。生产者交出缓冲区后,SurfaceFlinger 负责将所有内容合成到显示屏上。

下图展示了 BufferQueue 通信过程。

BufferQueue communication process

图 3. BufferQueue 通信过程

BufferQueue 包含将图像流生产者和图像流消费者联系在一起的逻辑。图像生产者的一些示例包括相机 HAL 或 OpenGL ES 游戏生成的相机预览。图像消费者的一些示例包括 SurfaceFlinger 或另一个显示 OpenGL ES 流的应用,例如显示相机取景器的相机应用。

BufferQueue 是一种数据结构,它将缓冲区池与队列相结合,并使用 Binder IPC 在进程之间传递缓冲区。生产者接口,或者您传递给想要生成图形缓冲区的人员的接口,是 IGraphicBufferProducer(SurfaceTexture 的一部分)。BufferQueue 通常用于渲染到 Surface 并通过 GL Consumer 使用,以及执行其他任务。

BufferQueue 可以在三种不同的模式下运行

类同步模式 - BufferQueue 默认以类同步模式运行,在这种模式下,来自生产者的每个缓冲区都会在消费者端输出。在这种模式下,永远不会丢弃任何缓冲区。如果生产者速度过快,并且创建缓冲区的速度快于缓冲区被消耗的速度,则它将阻止并等待空闲缓冲区。

非阻塞模式 - BufferQueue 也可以在非阻塞模式下运行,在这种模式下,它会生成错误,而不是在这些情况下等待缓冲区。在这种模式下,也永远不会丢弃任何缓冲区。这对于避免应用程序软件中可能不了解图形框架复杂依赖关系的潜在死锁非常有用。

丢弃模式 - 最后,BufferQueue 可以配置为丢弃旧缓冲区,而不是生成错误或等待。例如,如果对纹理视图执行 GL 渲染并尽可能快地绘制,则必须丢弃缓冲区。

为了执行大部分工作,SurfaceFlinger 充当另一个 OpenGL ES 客户端。因此,当 SurfaceFlinger 主动将一个或两个缓冲区合成为第三个缓冲区时,例如,它会使用 OpenGL ES。

硬件合成器 HAL 执行另一半工作。此 HAL 充当所有 Android 图形渲染的中心点。