上一篇说完App申请完vsync后要进行绘制,本来要说一下绘制的过程,但是感觉进度有点慢,主要研究sf,所以转换下学习思路。
一、BufferQueue基本概念:
BufferQueue的核心逻辑是生产者消费者逻辑又是GraphicBuffer管理者,在BufferQueue这个生产者消费者框架中, BufferQueuecore可以理解为数据缓冲区的管理者,代码逻辑在BufferQueue.cpp和BufferQueuecore.cpp中。它的消费者是BufferQueueConsumer,生产者是BufferQueueProducer。
先看一张比较权威的BufferQueue相关基本操作流程,
首先初始状态下,所有可用BufferSlot全是FREE状态,在mFreeSlots中管理。
- Producer 从 BufferQueue中dequeue一个FREE BufferSlot, Dequeue成功后,BufferSlot状态从FREE变为DEQUEUED;
- Producer端填充好BufferSlot数据后,queue到BufferQueue中,BufferSlot状态从DEQUEUED变为QUEUED,且调用消费者onFrameAvailable通知它有可消费的BufferSlot;
- Consumer从BufferQueue中acquire一个有数据的BufferSlot,BufferSlot状态从QUEUED变为ACQUIRED;
- Consumer 使用完BufferSlot后,BufferSlot状态从ACQUIRED变为FREE
总结一下BufferSlot的5种状态:FREE、DEQUEUED、QUEUED、ACQUIRED、SHARED。
从源码中看下buffer状态改变原理
/frameworks/native/include/gui/BufferSlot.h
A buffer can be in one of five states, represented as below:
| 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 |
举例一个mQueueCount变化
inline bool isQueued const {
return mQueueCount> 0;
}
inline void queue() {
if (mDequeueCount > 0) {
mDequeueCount--;
}
mQueueCount++;
}
queue()方法调用后,mQueueCount++,isQueued() 方法返回值当然就为true;
可以明显的看到 buffer的状态由引用计数来表示。
二、BufferQueue内部结构
/frameworks/native/libs/gui/BufferQueue.cpp
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) {
sp<BufferQueueCore> core(new BufferQueueCore());
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
*outProducer = producer;
*outConsumer = consumer;
}
通过其createBufferQueue方法可以看到会创建
BufferQueueCore、BufferQueueProducer、BufferQueueConsumer。
BufferQueueCore 负责维护 BufferQueue 的基本数据结构,而 BufferQueueProducer 和 BufferQueueConsumer 则负责提供操作 BufferQueue 的基本接口。
三、BufferSlot和BufferItem详解
1、BufferSlot和GraphicBuffer关联
BufferQueueCore中管理着数据缓冲区,而数据的核心GraphicBuffer关联在BufferSlot中。
/frameworks/native/include/gui/BufferQueueCore.h
class BufferQueueCore : public virtual RefBase {
......
BufferQueueDefs::SlotsType mSlots;
} @1
/frameworks/native/libs/gui/include/gui/BufferQueueDefs.h
namespace BufferQueueDefs {
Typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} @2
/frameworks/native/libs/gui/include/gui/BufferSlot.h
struct BufferSlot {
sp<GraphicBuffer> mGraphicBuffer;
} @3
由@1知BufferQueueCore定义了BufferQueueDefs::SlotsType mSlots,
由@2知mSlots实际上是一个BufferSolt的数组。
由@3知 BufferSolt中定义了一个GraphicBuffer的強指针用于关联mGraphicBuffer。
这样BufferSlot 和 GraphicBuffer 就关联上了。
2、BuffetItem关联BufferSlot
BufferQueue框架中,消费者和生产者对缓冲区数据操作的单元核心就是一个BufferSlot,也就是取GraphicBuffer,放GraphicBuffer的操作其实是针对BufferSlot来完成的。
/frameworks/native/libs/gui/include/gui/BufferQueueCore.h
class BufferQueueCore : public virtual RefBase {
......
typedef Vector<BufferItem> Fifo;
......
Fifo mQueue;
}
/frameworks/native/libs/gui/include/gui/BufferItem.h
class BufferItem:public Flattenable<BufferItem>{
//mSlot is the slot idex of this buffer(default INVALID_BUFFER_SLOT)
Int mSlot;
}
- BufferSlot 的存和取是在BufferQueueCore中定义了Fifo mQueue,Fifo是向量集,里面存的是BufferItem,而 BufferItem中又定义了mSlot的索引值。这样就可以和BufferSlot关联上了,可以在dequeue,queue,acquire方法中看出其关系。
- 生产者从mQueue上获取BufferItem从而找到了对应的BufferSlot,并对它完成一系列的操作之后,放回到mQueue中供消费者使用,消费者也是从mQueue上获取BufferItem从而找到对应的BufferSlot来消费,消费完成之后放回mQueue。不过需要注意实际上不是真正的把BufferSlot取出放回mQueue,而是mSlots索引值的传递过程。
3、BufferSlot状态说明
image.png说明:
mSlots BufferSlot结构体数组,数组长度为64
- mFreeSlots BufferSlot状态为FREE,且没有GraphicBuffer与之相绑定的slot集合
- mFreeBuffers BufferSlot状态为FREE,且有GraphicBuffer与之相绑定的slot集合
- mActiveBuffers BufferSlot状态不为FREE(即DEQUEUED、QUEUED、ACQUIRED、SHARED)的slot集合。既然状态不是FREE,那么该BufferSlot必然有一个GraphicBuffer与之相绑定
- mUnusedSlots 未参与使用的slot集合,由 mMaxBufferCount 决定
- mSlots = mFreeSlots + mFreeBuffers + mActiveBuffers + mUnusedSlots
四、BufferQueue生产者和消费者详解
我们知道 一个widow对应一个layer,一个layer对应一个生产者消费者模型。
BufferQueueConsumer 和 BufferQueueProducer 分别对应文件BufferQueueConsumer.cpp 和 BufferQueueProducer.cpp 和 BufferQueueCore.cpp 在同级目录都在/frameworks/native/libs/gui目录下。
1、两个类的继承关系和重要函数:
BuffeQueueProducer继承关系:
(BufferQueueProducer.h) BufferQueueProducer : public BnGraphicBufferProducer,private IBinder::DeathRecipient
(IGraphicBufferProducer.h)BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
(IInterface.h)class BnInterface : public INTERFACE, public BBinder
可以看到BufferQueueProducer继承了BnGraphicBufferProducer而BnGraphicBufferProducer又继承了IGraphicBufferProducer和BnInterface ,来完成主要的BufferSlot的流转操作,也提供了远程代理接口,实现跨进程binder调用。
同时BufferQueueProducer还继承了DeathRecipient 用来处理Binder死亡通知。
BuffeQueueProducer关键方法:
- requestBuffer 获取对应BufferSlot的GraphicBuffer地址。
- setMaxDequeuedBufferCount 设置最大同时可以dequeue出来的的BufferSlot数量。
- dequeueBuffer 从FREE状态下的BufferSlots中队列中获取空闲的BufferSlot做生产使用,优先从mFreeBuffers中获取,如果没有则从mFreeSlots中获取。
- attachBuffer 绑定已经分配好的GraphicBuffer到FREE状态下的BufferSlot中,优先从- mFreeSlots中查找BufferSlot,如果没有则从mFreeBuffers中查找并绑定。
- queueBuffer 生产者把生产好的BufferSlot放到队列中供消费者使用。
- detachBuffer 把attachBuffer了GraphicBuffer的 Active状态下的BufferSlot的放到mFreeBuffers之后直接取消GraphicBuffer的绑定。
- detachNextBuffer 把需要释放的BufferSlot中的GraphicBuffer指针赋值到outBuffer输出之后,把BufferSlot的放到mFreeBuffers并解绑定GraphicBuffer。
- cancelBuffer 把BufferSlot放回到mfreeBuffers中,不会释放graphicbuffer。
- connect 生产者通过该接口把IProducerListener注册到BufferQueueCore中供消费者回调,同时建立了Binder死亡通知通路。
- disconnect断开BufferQueueProducer和BufferQueueCore之间建立的链接关系。
BufferQueueConsumer继承关系:
(BufferQueueConsumer.h) BufferQueueConsumer : public BnGraphicBufferConsumer
(IGraphicBufferConsumer.h)BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer>
(SafeInterface.h)SafeBnInterface:public BnInterface<Interface>
可以看到BufferQueueConsumer的实现结构和BufferQueueProducer很相似继承了BnGraphicBufferConsumer 而BnGraphicBufferConsumer又最终继承了IGraphicBufferConsumer和SafeBnInterface,来完成主要的BufferSlot的流转操作,也提供了远程代理接口,实现跨进程binder调用。
BufferQueueConsumer关键方法:
- acquireBuffer 获取QUEUE状态下的BufferSlot进行消费。
- releaseBuffer消费完成之后把BufferSlot放回mFreeBuffers队列中。
- attachBuffer 把消费者的GraphicBuffer绑定到BufferSlot上使用。
- detachBuffer把消费者的GraphicBuffer从BufferSlot上解绑。
- setMaxBufferCount 设置最大可用BufferSlot数量。
- setMaxAcquiredBufferCount 设置最大同时可以acquire的BufferSlot数量。
- connect 建立消费者和BufferQueueCore之间的链接,注册IConsumerListener回调。
- disconnect 销毁消费者和BufferQueue之间的链接。
2、BufferQueueConsumer关键流程分析
(1). acquirebuffer的流程
主要流程是首先判断acquireBuffers是否已经超过最大一次能够Acquire的数量,mQueue是否为空,然后从mQueue中获取迭代器的第一个元素赋值给outBuffer输出,同时把mBufferState状态改为Acquired 并从mQueue中移除
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
...
{
//判断AcquireBuffers是否已经超过最大一次能够Acquire的数量。
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
return INVALID_OPERATION;
}
//判断mQueue队列是否为空
if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
//mCore->mQueue.begin()返回iterator,指向第一个元素赋值给front
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
if (sharedBufferAvailable && mCore->mQueue.empty()) {//共享buffer的处理逻辑
...
} else {//正常非共享模式下的逻辑
slot = front->mSlot; //从front获取对应的slot,front是一个BufferItem指针
*outBuffer = *front; //把front指向的BufferItem赋值给outBuffer,outBuffer就是要的buffer
}
if (!outBuffer->mIsStale) {
mSlots[slot].mAcquireCalled = true;
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
mSlots[slot].mBufferState.acquire(); //把BufferState修改成acquired状态
}
}
mCore->mQueue.erase(front); //把acquired slot 对应的BufferItem从mQueue中移除。
mCore->mDequeueCondition.notify_all();
}
return NO_ERROR;
}
(2). releasebuffer的流程
releasebuffer主要流程是先做slot frameNumber 以及 BufferState有效性检查,修改mBufferState状态成FREE状态。然后把对应的slot从mActiveBuffers中移除并放回mFreeBuffers的过程。
这个过程中不做GraphicBuffer和BufferSlot的解绑定操作,也就是说GraphicBuffer不会被释放。
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
//slot的合法性判断。
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
releaseFence == nullptr) {
BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
releaseFence.get());
return BAD_VALUE;
}
sp<IProducerListener> listener;
{
//判断frameNumber是否有效,如果做过reallocated frameNumber将会改变。
//这个frameNumber是什么?
if (frameNumber != mSlots[slot].mFrameNumber &&
!mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
//判断BufferState是否是acquired状态
if (!mSlots[slot].mBufferState.isAcquired()) {
return BAD_VALUE;
}
mSlots[slot].mBufferState.release(); //调用mBufferState.release()将acqiure状态释放。
if (!mSlots[slot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(slot); //将slot从mActiveBuffers中移除
mCore->mFreeBuffers.push_back(slot); //将slot放入到mFreeBuffers队列中
}
listener = mCore->mConnectedProducerListener; //获取ProducerListener
mCore->mDequeueCondition.notify_all();
}
if (listener != nullptr) {
listener->onBufferReleased(); //调用Producer的onBufferReleased回调通知Producer完成释放。
}
return NO_ERROR;
}
3、BufferQueueProducer关键流程分析
(1). dequeuebuffer的流程
dequeuebuffer是生产者端从BufferQueueCore上获取一个GraphicBuffer进行生产的过程,生产者BufferQueueProducer 会在去获取一个FREE状态的的BufferSlot。
同时把mBufferState状态修改成Dequeue状态,把BufferSlot放到mActiveBuffers中管理。也由此可见GraphicBuffer是在这里实际创建的。
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
int found = BufferItem::INVALID_BUFFER_SLOT;
//调用waitForFreeSlotThenRelock 找到可以dequeue的 FREE状态下的BufferSlot
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); //把获取到的mGraphicBuffer地址赋值给buffer。
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found); //把找到的slot放到mActiveBuffers中管理
}
*outSlot = found; //赋值给outSlot输出
mSlots[found].mBufferState.dequeue(); //修改BufferState 状态成dequeue状态。
}
return returnFlags;
}
FREE状态的BufferSlot又包含了mFreeSlots和mFreebuffers两组slots,dequeue的时候会先从mFreebuffers查找如果有可用的就使用,如果没有就从mFreeSlots获取BufferSlot并分配GraphicBuffer。
这个过程在waitForFreeSlotThenRelock中实现
下面是waitForFreeSlotThenRelock的流程:
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
auto callerString = (caller == FreeSlotCaller::Dequeue) ?
"dequeueBuffer" : "attachBuffer";
bool tryAgain = true;
while (tryAgain) {
if (){
} else {
if (caller == FreeSlotCaller::Dequeue) { //Dequeuebuffer调用这段代码,先调用getFreeBufferLocked从mFreeBuffers中获取,如果找到了就返回。
// If we're calling this from dequeue, prefer free buffers
int slot = getFreeBufferLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else if (mCore->mAllowAllocation) { // 如果没找到,在调用getFreeSlotLocked从mFreeSlots中获取。
*found = getFreeSlotLocked();
}
} else {
// If we're calling this from attach, prefer free slots
int slot = getFreeSlotLocked(); //attachbuffer调用这段代码,优先先调用getFreeSlotLocked从mFreeSlots中获取,如果找到了就返回。
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else {
*found = getFreeBufferLocked(); 如果没找到,在调用getFreeBufferLocked从mFreeBuffers中获取。
}
}
}
}
}
return NO_ERROR;
}
int BufferQueueProducer::getFreeSlotLocked() const {
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = *(mCore->mFreeSlots.begin());
mCore->mFreeSlots.erase(slot);
return slot;
}
(2). attachbuffer的流程
如上面的waitForFreeSlotThenRelock流程,attachBuffer也是从FREE状态的slots上获取BufferSlot,但是和dequeueBuffer不同attachBuffer是优先从mfreeslots上获取,如果mfreeslots没有,再从mfreebuffers上获取。
waitForFreeSlotThenRelock获取到BufferSlot之后,再把已有的申请好的GraphicBuffer绑定到这个BufferSlot上。同时把mBufferState状态修改成Dequeued状态。把BufferSlot放到mActiveBuffers中管理。
status_t BufferQueueProducer::attachBuffer(int* outSlot,
const sp<android::GraphicBuffer>& buffer) {
//调用waitForFreeSlotThenRelock 找到可以FREE状态下的BufferSlot
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, lock, &found);
*outSlot = found; //把找到的slot赋值给outSlot
mSlots[*outSlot].mGraphicBuffer = buffer; //把准备好的buffer关联到slot的mGraphicBuffer上
mSlots[*outSlot].mBufferState.attachProducer(); // 修改BufferState成Dequued状态
mCore->mActiveBuffers.insert(found); // 把slot放到mActiveBuffers中管理。
return returnFlags;
}
(3). queuebuffer的流程
queuebuffer是生产者完成对GraphicBuffer的处理之后调用queuebuffer把GraphicBuffer放回mQueue的操作,同时把mBufferState修改成QUEUE状态。
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
sp<IConsumerListener> frameAvailableListener;
sp<IConsumerListener> frameReplacedListener;
BufferItem item;
{ // Autolock scope
mSlots[slot].mBufferState.queue(); //修改mBufferState状态为QUEUE状态。
//增加mFrameCounter
++mCore->mFrameCounter;
currentFrameNumber = mCore->mFrameCounter;
mSlots[slot].mFrameNumber = currentFrameNumber;
//给BufferItem赋值
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mSlot = slot;
output->bufferReplaced = false;
if (mCore->mQueue.empty()) { //如果mQueue为空,就直接把BufferItem push到mQueue尾部。
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
} else { //如mQueue不为空,需要判断一下last BufferItem是否被替换,如果可以替换就替换,如果不可以替换就直接把BufferItem放到mQueue尾部。
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
if (!last.mIsStale) {
mSlots[last.mSlot].mBufferState.freeQueued();
// Don't put the shared buffer on the free list.
if (!mSlots[last.mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(last.mSlot);
mCore->mFreeBuffers.push_back(last.mSlot);
output->bufferReplaced = true;
}
}
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener;
} else {
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
}
}
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item); //调用消费者的onFrameAvailable通知消费者,有queue状态的BufferSlot可以使用。
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item); //调用消费者的onFrameReplaced通知消费者,有queue状态的BufferSlot可以被替换。
}
} // Autolock scope
return NO_ERROR;
}
(4). detachBuffer的流程
detachBuffer主要是对应生产者端的attachbuffer操作,将attachbuffer之后的BufferSlot,放回到mFreeSlots中,并解除对GraphicBuffer的绑定,并通知消费者Buffer释放。
status_t BufferQueueProducer::detachBuffer(int slot) {
sp<IConsumerListener> listener;
mSlots[slot].mBufferState.detachProducer(); //修改BufferState的Dequeued状态成FREE状态
mCore->mActiveBuffers.erase(slot); //把slot从mActiveBuffers中移除
mCore->mFreeSlots.insert(slot); //把slot加到mFreeSlots中。
mCore->clearBufferSlotLocked(slot); //清除slot和Graphicbuffer的绑定关系。
mCore->mDequeueCondition.notify_all();
listener = mCore->mConsumerListener; //把消费者回调的listener赋值给listener
}
if (listener != nullptr) {
listener->onBuffersReleased();//调用消费者的listener接口通知消费者Buffer释放
}
return NO_ERROR;
}
五、总结
BufferQueue的生产消费和BufferSlot状态关系用一张图总结下:
image.png
网友评论