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 fps 显示视频时,队列的值从 0 到 1 变化,因为 ~60 fps 显示可以跟上源。 SurfaceFlinger 仅在有工作要做时才会唤醒,而不是每秒 60 次。如果没有任何内容更新屏幕,系统会尝试避免工作并禁用 VSYNC。

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

格拉洛克

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

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

例如,如果生产者的缓冲区格式指定RGBA_8888像素,并且生产者指示将从软件访问该缓冲区(意味着应用程序将接触 CPU 上的像素),则 Gralloc 会按 RGBA 顺序创建每个像素 4 字节的缓冲区。相反,如果生产者指定其缓冲区只能从硬件访问并作为 GLES 纹理,则 Gralloc 可以执行 GLES 驱动程序想要的任何操作,例如 BGRA 排序、非线性混合布局和替代颜色格式。允许硬件使用其首选格式可以提高性能。

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

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

受保护的缓冲区

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

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

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