书接上文:
Android显示系统是 Canvas OpenGL ES MediaPlayer等生产者生成图像数据放入到BufferQueue中
SurfaceFling ImageReader等消费者从BufferQueue中获取数据,再进行合成并送给屏幕显示出来(送显)。
这期来讲讲 BufferQueue 以及其中的数据
首先我们回顾下这张 生产/消费者 模型图:
简单解释下生产者/消费者模型(更详细的可以看文章理解):
生产者:只关心数据产生,一旦生成新的数据,它就塞到阻塞队列中
消费者:只关心数据获取,每次都从阻塞队列中获取
如何保证生产和消费的同步呢? 如果生产的很快,不消费,队列是不是就满了
如果生产的慢,消费的快,队列就空了。
这就是阻塞队列的特性,他在塞入数据时,如果队列满了,它就会block住,这样生产者生产的快的情况下,就会暂停下来。
消费者获取数据时,如果队列为空时,就会block住,等生产者塞入数据后才能拿到数据返回,通过这样的机制同步速度。
问题二:图中的BufferQueue是什么?
(这里我们尽量不讲太多代码细节,先理解其中的概念,代码细节分另一个章节展示)
顾名思义:缓存队列 BufferQueue是封装了GraphicBuffer数据的队列。简单理解的话可以类比
ArrayBlockingQueue<GraphicBuffer>
关于BufferQueue的原理这个图更好理解一些:
BufferQueue为队列中数据GraphicBuffer对象包装了如下状态:
FREE:闲置状态,任何进程都可以获取该buffer进行操作,通常表示为APP进程可以申请使用的内存
DEQUEUED:出列状态,通常是APP进程在绘图,使用者是GPU
QUEUED:入列状态,表示APP绘图已经完成,等待从队列取出执行下一步合成,没有使用者
ACQUIRED:锁定状态,通常表示sf进程从队列取出,正在做合成工作,此时使用者可能是hwc也有可能是GPU
SHARED:共享状态,7.0版本加入的新状态,没找到相关介绍资料,合成工作完成以后共享给录屏软件?
流程梳理:
- Producer(比如Surface) 通过dequeueBuffer拿到一个FREE状态下的GraphicBuffer对象 (buffer状态从变化:FREE ---> DEQUEUED)
- 一通数据写入后Producer通过queueBuffer将Dequeued状态下的Buffer塞入BufferQueue中(buffer状态变化:DEQUEUE ---> QUEUED
- Consumer(比如SurfaceFling) 通过acquireBuffer从队列中拿到一个QUEUED状态的Buffer准备送去合成送显(buffer状态变化:QUEUED ---> ACQUIRED
- 这个数据显示完成后,Consumer通过releaseBuffer将GraphicBuffer还给BufferQueue便于重新使用(buffer状态变化:ACQUIRED ---> FREE )
- 这样周而复始,完成屏幕内容的展示 (具体的代码分析下回讲解,本期关注流程的理解)
下图为不同状态的字段值(来源BufferSlot.h):
| mShared | mDequeueCount | mQueueCount | mAcquireCount | |
|---|---|---|---|---|
| FREE | false | 0 | 0 | 0 |
| DEQUEUED | false | 1 | 0 | 0 |
| QUEUED | false | 0 | 1 | 0 |
| ACQUIRED | false | 0 | 0 | 1 |
| SHARED | true | any | any | any |
总结状态变化图:
关于 BufferQueue源码解析,GraphicBuffer具体是什么? 我们下回分解