原文链接: https://source.android.com/devices/graphics/arch-bq-gralloc

BufferQueue and gralloc

摘要:BufferQueue生产者和消费者,gralloc HAL使用flags,使用systrace跟踪BufferQueue

让我们从BufferQueue和gralloc HAL的幕后开始来理解Android 图形系统

BufferQueue类是Android图形系统的核心。它的扮演的角色很简单:把生成图形数据的组件(生产者)和接收数据并用来显示或进一步处理的组件(消费者)联系在一起。几乎所有需要在系统种传输图形数据的组件都依赖BufferQueue。

gralloc内存分配器可以执行buffer分配并且通过特定厂商的HAL接口来实现(参考:hardware/libhardware/include/hardware/gralloc.h).alloc() 函数需要除了需要参数(width,height,pixel format)外还需要一组使用标志(细节如下)。

BufferQueue生产者和消费者(BufferQueue producers and consumers)

基础的使用方法是显而易见的:生产者请求一个空闲的buffer(dequeueBuffer()),指定一组包括width,height,pixel format 和使用标志的参数。生产者填充buffer然后将它返回到队列中。稍后,消费者请求buffer(acquireBufferQueue())并且使用这个buffer。当消费者完成任务后,将buffer返回给队列(releaseBuffer())。

近期的Android设备支持同步框架,这使System能够在与能够异步操作图形数据的硬件组件结合时做出漂亮事情。举例来说,一个生产者可以在提交一系列OpenGL ES绘制命令之后,然后在渲染完成前将输出buffer排队。因为和buffer在一起的有一个叫做fence的东西,fence可以在渲染完成时发出信号。第二种伴随buffer的fence是在它返回到空闲列表时,所以消费者可以在内容仍在使用时释放buffer。这种设计改善了buffer在系统种传输时的延迟和吞吐量的问题。

队列的一些特征,例如最大可持有的buffer数由生产者和消费者共同决定。但是BufferQueue负责根据需求分配buffer。除非特征发生变化,否则Buffer将会保留。例如,如果生产者请求不同大小的buffer,老的buffer会被释放,新的buffer将会被分配。

生产者和消费者可以存在于不同的进城。目前,消费者总是创建并拥有数据结构。在老版本的Android平台上,只有生产者端是被绑定的(例如 生产者可以作为一个远程的线程,但是消费者必须存在于queue所在的线程中)。Android 4.4以后,此处的实现朝着更加通用性的方向发展。

BufferQueue绝不会copybuffer的内容(移动如此多的数据会变的效率底下),而是buffer总是通过句柄(handle)传递。

gralloc HAL 使用标志 (gralloc HAL usage flags)

gralloc分配器不仅仅是另外一种在本地堆内存种申请的方法。在某些情况下,分配的内存可能不是缓存一致性的或者完全不能在用户空间访问。分配的性质由使用标志决定,其中包括以下属性:

  • How often the memory will be accessed from software (CPU) CPU访问内存的频率
  • How often the memory will be accessed from hardware (GPU)GPU访问内存的频率
  • Whether the memory will be used as an OpenGL ES (GLES) texture 内存是否被OpenGL ES texture访问
  • Whether the memory will be used by a video encoder 内存是否被Video编解码器使用

举个例子,如果你指定RGBA 8888 像素格式,这意味着你想要一个可以从软件访问的buffer(也就是说你的app会直接访问到每一个像素),那么分配器就必须创建一个按照RGBA排序的4字节每像素的内存。如果你不这样做,而是说想要一个仅从硬件访问并且作为一个GLES texture的时候,分配器可以做任何GLES dirver想要的事情---可能是BGRA排序,非线性旋转布局(non-linear swizzled layouts),可选的颜色格式(alternative color formats)等等。让硬件使用它想要的格式可以提高性能。

某些值不能在特定的平台上组合。例如,视频编解码器请求YUV像素,所以添加软件访问和指定RGBA 8888将会发生错误。

从gralloc分配器返回的buffer句柄可以通过Binder传输。

使用systrace跟踪BufferQueue (Tracking BufferQueue with systrace)

想要了解graphics buffer如何被移动的,使用systrace。systrace可以很好的检测系统级的Graphics代码和很多相关app的framework代码。去完成的描述如何有效的使用systrace将会占用大量的篇幅。从打开gfx,view,sched 标志开始。你也可以在trace里看到BufferQueue。如果你之前使用过systrace,你可能会看到他们,或许你不知道他们是什么。举个例子,如果你在Grafika的“Play video(SurfaceView)”正在运行时抓了一个trace,一列被标示的SurfaceView会告诉你在给定的时间内有多少buffer被排队了。

这个值在app活跃时增加(例如MediaCodec decoder触发帧的渲染),在SurfaceFlinger开始工作消耗buffer时,这个值会降低。当播放30fps的视频时,队列的的值可能变化很小(0~1),因为60fps的显示器可以轻松保持30fps的帧率。(另外请注意,SurfaceFlinger会在有工作的时候唤醒,而不是60次每秒。系统会尽量避免工作并且在屏幕不用刷新时关闭VSYNC)。

如果你切换到Grafika's "Play video(TextureView)"并且抓了一个trace时,你会看到一组符号:com.android.grafika/com.android.grafika.PlayMovieActivity. 这是主UI布局,是另外一个BufferQueue。因为TextureVIew是渲染到UI布局(而不是独立的layer),你会在这看到所有视频驱动的更新。

关于systrace工具,参考:Systrace documentation.

 

 

更多相关文章

  1. android中和c++中生产者和消费者模式
  2. C++解决方法:多线程同步经典案例之生产者消费者问题
  3. 简述分配器的作用是什么?
  4. Spring Cloud第二篇:服务消费者RestTemplate+Ribbon
  5. Spring Cloud第三篇:服务消费者Feign
  6. 阻塞队列实现生产者消费者模式
  7. 【荐读】基于文本数据的消费者洞察
  8. python-多线程3-生产者消费者
  9. 生产者-消费者问题

随机推荐

  1. cocos2d for android
  2. android手机获取手机唯一识别号
  3. 在android中嵌入脚本语言综述
  4. Android平台Firefox――Fennec编译手记
  5. Android平台通用安全问题分析及策略
  6. [分享]android 人机界面指南(androdi设计
  7. Windows+eclipse与Android studio添加手
  8. 研究开源OpenWnn Android输入法源代码
  9. 4种Android屏幕自适应解决方案
  10. ReactNative Android 实现加载本地图片