Surface 和 SurfaceHolder

Surface 对象支持应用渲染要在屏幕上呈现的图像。SurfaceHolder 接口支持应用编辑和控制 Surface。

Surface

Surface 是一种供生产者与消费者交换缓冲区的接口。

显示 Surface 的 BufferQueue 通常配置为三倍缓冲。缓冲区按需分配,因此,如果生产者生成缓冲区的速度足够慢(例如在 60 fps 显示屏上以 30 fps 的速度生成缓冲区),则队列中可能只有两个已分配的缓冲区。按需分配缓冲区有助于最大限度地减少内存消耗。您可以在 dumpsys SurfaceFlinger 输出中查看与每个图层关联的缓冲区的摘要。

大多数客户端都使用 OpenGL ESVulkan 渲染到 Surface 上。但是,有些客户端使用画布渲染到 Surface 上。

画布渲染

画布实现由 Skia Graphics Library 提供。如果您要绘制矩形,可以调用 Canvas API,它会在缓冲区中适当地设置字节。为了确保缓冲区不会被两个客户端同时更新,或者在显示时被写入,请锁定缓冲区以访问它。使用以下命令来处理画布锁定

  • lockCanvas() 锁定缓冲区以在 CPU 上进行渲染,并返回要用于绘制的画布。
  • unlockCanvasAndPost() 解锁缓冲区并将其发送到合成器。
  • lockHardwareCanvas() 锁定缓冲区以在 GPU 上进行渲染,并返回要用于绘制的画布。

生产者首次从 BufferQueue 请求缓冲区时,系统会分配缓冲区并将其初始化为零。初始化对于避免在进程之间无意中共享数据是必要的。但是,如果您重复使用缓冲区,则以前的内容仍然存在。如果您重复调用 lockCanvas()unlockCanvasAndPost() 而不绘制任何内容,则生产者会在先前渲染的帧之间循环。

Surface 锁定/解锁代码会保留对先前渲染的缓冲区的引用。如果您在锁定 Surface 时指定了脏区域,它会从上一个缓冲区复制非脏像素。SurfaceFlinger 或 HWC 通常会处理缓冲区;但由于我们只需要从缓冲区读取,因此无需等待独占访问。

SurfaceHolder

SurfaceHolder 是系统用来与应用共享 Surface 所有权的接口。一些使用 Surface 的客户端想要 SurfaceHolder,因为用于获取和设置 Surface 参数的 API 是通过 SurfaceHolder 实现的。SurfaceView 包含 SurfaceHolder。

大多数与视图交互的组件都涉及 SurfaceHolder。其他一些 API(如 MediaCodec)则在 Surface 本身之上运行。