BufferQueue 和 Gralloc

BufferQueue 类将图形数据缓冲区(生产者)的生成组件连接到接受数据以进行显示或进一步处理(消费者)的组件。几乎所有在系统中移动图形数据缓冲区的操作都依赖于 BufferQueue。

Gralloc 内存分配器执行缓冲区分配,并通过两个供应商特定的 HIDL 接口(请参阅 hardware/interfaces/graphics/allocator/hardware/interfaces/graphics/mapper/)来实现。allocate() 函数接受预期的参数(宽度、高度、像素格式)以及一组用法标志。

BufferQueue 生产者和消费者

消费者创建并拥有 BufferQueue 数据结构,并且可以与生产者位于不同的进程中。当生产者需要缓冲区时,它通过调用 dequeueBuffer() 从 BufferQueue 请求空闲缓冲区,并指定缓冲区的宽度、高度、像素格式和用法标志。然后,生产者填充缓冲区并通过调用 queueBuffer() 将缓冲区返回到队列。接下来,消费者使用 acquireBuffer() 获取缓冲区并使用缓冲区内容。当消费者完成操作后,它通过调用 releaseBuffer() 将缓冲区返回到队列。同步框架控制缓冲区在 Android 图形管道中的移动方式。

BufferQueue 的某些特性(例如它可以容纳的最大缓冲区数)由生产者和消费者共同决定。但是,BufferQueue 会在需要时分配缓冲区。除非特性发生变化,否则会保留缓冲区;例如,如果生产者请求具有不同大小的缓冲区,则会释放旧缓冲区,并根据需要分配新缓冲区。

BufferQueue 永远不会复制缓冲区内容,因为移动如此多的数据效率低下。相反,缓冲区始终通过句柄传递。

使用 Systrace 跟踪 BufferQueue

要了解图形缓冲区是如何移动的,请使用 Systrace,这是一款可在短时间内记录设备活动的工具。系统级图形代码以及许多相关的应用框架代码都经过了良好的检测。

要使用 Systrace,请启用 gfxviewsched 标记。BufferQueue 对象会显示在跟踪记录中。例如,如果您在 Grafika 的播放视频 (SurfaceView) 运行时进行跟踪,则标记为 SurfaceView 的行会告诉您在任何给定时间有多少缓冲区排队。

当应用处于活动状态时,该值会递增,这会触发 MediaCodec 解码器渲染帧。当 SurfaceFlinger 工作并使用缓冲区时,该值会递减。当以 30 帧/秒的速度显示视频时,队列的值在 0 到 1 之间变化,因为约 60 帧/秒的显示屏可以跟上源。SurfaceFlinger 仅在有工作要做时才会唤醒,而不是每秒唤醒 60 次。系统会尝试避免工作,并且在没有任何内容更新屏幕时停用 VSYNC。

如果您切换到 Grafika 的播放视频 (TextureView) 并获取新的跟踪记录,您会看到标记为 com.android.grafika / com.android.grafika.PlayMovieActivity 的行。这是主 UI 图层,它是另一个 BufferQueue。由于 TextureView 渲染到 UI 图层而不是单独的图层,因此所有视频驱动的更新都会在此处显示。

Gralloc

Gralloc 分配器 HAL hardware/libhardware/include/hardware/gralloc.h 通过用法标志执行缓冲区分配。用法标志包括以下属性:

  • 从软件 (CPU) 访问内存的频率
  • 从硬件 (GPU) 访问内存的频率
  • 内存是否将用作 OpenGL ES (GLES) 纹理
  • 内存是否将由视频编码器使用

例如,如果生产者缓冲区格式指定 RGBA_8888 像素,并且生产者表明将从软件访问缓冲区(意味着应用将接触 CPU 上的像素),则 Gralloc 会创建一个缓冲区,其中每个像素有 4 个字节,顺序为 R-G-B-A。相反,如果生产者指定其缓冲区仅从硬件访问并作为 GLES 纹理,则 Gralloc 可以执行 GLES 驱动程序所需的任何操作,例如 BGRA 排序、非线性交错布局和备用颜色格式。允许硬件使用其首选格式可以提高性能。

某些值无法在某些平台上组合。例如,视频编码器标志可能需要 YUV 像素,因此添加软件访问并指定 RGBA_8888 会失败。

Gralloc 返回的句柄可以通过 Binder 在进程之间传递。

受保护的缓冲区

Gralloc 用法标志 GRALLOC_USAGE_PROTECTED 允许图形缓冲区仅通过硬件保护路径显示。这些叠加层是显示 DRM 内容的唯一方法(SurfaceFlinger 或 OpenGL ES 驱动程序无法访问受 DRM 保护的缓冲区)。

受 DRM 保护的视频只能在叠加层上呈现。支持受保护内容的视频播放器必须使用 SurfaceView 实现。在不受保护的硬件上运行的软件无法读取或写入缓冲区;硬件保护路径必须出现在硬件合成器叠加层上(也就是说,如果硬件合成器切换到 OpenGL ES 合成,受保护的视频将从显示屏上消失)。

有关受保护内容的详细信息,请参阅 DRM