解读BufferQueue
# Android禅修之路
前语
在之前的文章中, 咱们介绍了组成的进程中, 用到的出产者和顾客的规划形式, 而且还提到了一个缓冲区, 这篇文章, 就来详细阐明一下这个缓冲区, 究竟是一个什么东西。
首要,咱们先看官方供给的阐明图。
众所周知, SurfaceFlinger 运用了出产者和顾客模型, 那么这个出产者和顾客之间的数据是怎么封装和传递的呢? 答案便是 BufferQueue , 接下来咱们就来聊聊什么是 BufferQueue 和它究竟有什么效果,最终再研究一下这个出产者和顾客模型是怎么运作的。
首要咱们看出产者的缓冲区是怎么供给出来的, 之前在SurfaceFlinger 组成中的作业咱们看到了获取缓冲区的逻辑, 是调用 Surface.cpp 中的GraphicBufferProducer 的 dequeueBuffer, 而这儿的 GraphicBufferProducer 其实是一个 BpGraphicBufferProducer, 它用到了 Binder 进行进程通信, 今天咱们就来看看它的详细完结
一 BufferQueue是什么
首要,咱们看看这个 BufferQueue 是什么。当然,要看它是什么,最先看的当然是看这个类的界说和官方供给的注释。
class BufferQueue {
public:
// Buffer 的最大绑定数
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
// 当 Slot 没有和绑守时的枚举值
enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT };
// IGraphicBufferConsumer.h 头文件中的别号
enum {
NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
PRESENT_LATER = IGraphicBufferConsumer::PRESENT_LATER,
};
// 在异步形式下,保留两个 Slot 以保证出产者和顾客能够异步运转。
enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
typedef ::android::ConsumerListener ConsumerListener;
// 一个 ConsumerListener 的完结, 它保持了一个 ConsumerListener 的弱引证
// 它可用将调用转发到顾客目标
// 运用它可用避免 BufferQueue 和出产者 Consumer 的循环引证
class ProxyConsumerListener : public BnConsumerListener {
public:
explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
~ProxyConsumerListener() override;
void onDisconnect() override;
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
void onBuffersReleased() override;
void onSidebandStreamChanged() override;
void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
private:
// IConsumerListener 的弱引证
wp<ConsumerListener> mConsumerListener;
};
// 出产者和顾客运用的 Slot 是由 BufferQueue 进行办理的, 而缓冲区的分配则是由 allocator 进行的
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger = false);
};
BufferQueue 这个类比较简略,不过仍是先介绍一下这儿及今后呈现的一些名词或许概念。
- NUM_BUFFER_SLOTS:BufferSlot 数组的最大长度,数量是32。(BufferSlot 对应的翻译统一为缓冲槽)
- INVALID_BUFFER_SLOT:BufferSlot 绑定状况的枚举值,默许是 INVALID_BUFFER_SLOT,也便是没有对应的缓冲槽。
- ConsumerListener:顾客的监听器,它用于将调用转发给顾客。
由于 BufferQueue 中只要一个 createBufferQueue 函数,所以接下来咱们就来看一下 createBufferQueue 函数的完结。
1.1 createBufferQueue
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;
}
这个函数也是非常的简略, 它就创立了三个目标
- BufferQueueCore: 这个便是 BufferQueue 中真实作业的目标
- BufferQueueProducer: 出产者目标
- BufferQueueConsumer: 顾客目标
1.2 BufferQueueCore
假如咱们看过出产者 BufferQueueProducer::dequeueBuffer 中的代码, 咱们就会见到 mCore 这个目标, 它便是 BufferQueueCore
关于 BufferQueueCore 的界说,这儿就不放代码了,不过 BufferQueueCore 中比较重要的一处便是它里边保护了4个数组,现在咱们就来看一下 BufferQueueCore 中保存的这些 buffer 数组目标, 还有它们的效果
1.3 BufferQueueCore 保护的数组
BufferQueueCore中保护了4个数组, 这些数组保存的目标是 BufferSlot, 它们别离如下
// mFreeSlots 包括一切 Free 状况的且当时没有绑定 buffer 的 slots
std::set<int> mFreeSlots;
// mFreeBuffers 包括一切 Free 状况的且当时绑定了 buffer 的 slots
std::list<int> mFreeBuffers;
// mUnusedSlots 包括一切 Free 状况且没有绑定 buffer 且未运用的 slots.
std::list<int> mUnusedSlots;
// mActiveBuffers 包括了当时一切绑定了非 Free 状况 buffer 的 slots
std::set<int> mActiveBuffers;
这儿咱们只是简略列举出这4个数组,后续用到它们的时分,咱们在进一步阐明。接下来咱们来看看和这些数组对应的缓冲槽 BufferSlot 目标。
二 BufferSlot
BufferSlot 这个目标的结构体比较短, 这儿就悉数列举出来了
struct BufferSlot {
BufferSlot()
: mGraphicBuffer(nullptr), // 一个缓冲槽对应一个图形缓冲区 GraphicBuffer
mEglDisplay(EGL_NO_DISPLAY),
mBufferState(),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
mFence(Fence::NO_FENCE),
mAcquireCalled(false),
mNeedsReallocation(false) {
}
// mGraphicBuffer 指向为此 Slot 分配的 GraphicBuffer, 假如没有分配则为 NULL
sp<GraphicBuffer> mGraphicBuffer;
// EGLDisplay , 用于创立 EGLSyncKHR
EGLDisplay mEglDisplay;
// 当时 buffer slot 的状况
BufferState mBufferState;
// 奉告 procducer 是否被调用 requestBuffer
// 用于 debug 和查找bug
bool mRequestBufferCalled;
// mFrameNumber 是此 slot 的 Frame 行列编号, 这是用于 buffer 行列的 LRU排序
// 由于 buffer 或许这宣布 release fence 信号之前 release
uint64_t mFrameNumber;
// mEglFence是EGL sync目标,它关联的 slot 有必要在 dequeue 之前宣布信号
// 在创立 buffer 的时分它会被初始化为 EGL_NO_SYNC_KHR , 而且它能够设置为 releaseBuffer 中的新同步目标
EGLSyncKHR mEglFence;
// mFence 说一个围栏, 当之前的 buffer 的一切者完结启动作业时, 它就会宣布信号
// 当这个 buffer 是 Free 状况时, 这个围栏会指示顾客何时完结 buffer 的读取作业
// 或许指示当出产者何时现已完结写入, 假如它在写入数据数据后调用了 cancelBuffer
// 当这个 buffer 是 QUEUED 状况时, 它指示出产者何时完结 buffer 的填充
// 当这个 buffer 是 DEQUEUED/ACQUIRED 时, 这个围栏会和 buffer 一起传递给出产者或许顾客,而且设置为 NO_FENCE
sp<Fence> mFence;
// 指示顾客是否看到了此缓冲区
bool mAcquireCalled;
// Indicates whether the buffer was re-allocated without notifying the producer.
If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued to prevent the producer from using a stale cached buffer.
假如是这样,它需求在退出行列时设置缓冲区需求从头分配标志,以防止出产者运用过期的缓存缓冲区。
// 指示是否在没有告诉出产者的状况下从头分配了 buffer
// 假如是的, 那么当这个 buffer 出队时它需求设置为 BUFFER_NEEDS_REALLOCATION , 以防止出产者运用了一个过期的 buffer
bool mNeedsReallocation;
};
BufferSlot 这个类里边界说的东西尽管比较多,可是都很简单了解,这儿也不需求悉数记住,假如后续遇到,再回过头从头查看即可。唯独有一个需求阐明的是这儿面和 Fence 相关目标,
Fence 是 Android 的图形体系中,用于处理缓冲区同步用的,之前现已说过了,Android 的图形体系中,用到了出产者和顾客模型,所以必定涉及到出产者和顾客之前的同步,而且由于这儿的出产者和顾客形式不在同一个进程,乃至涉及到 CPU 和 GPU 的同步,所以弄了一套 Fence 机制,关于 Fence 机制,这儿就不多介绍了,详细的能够看 [解读Fence]-(未完结) 。这儿咱们假定现已了解了 Fence 机制,当然不了解也没有关系,看完本篇文章之后,再去了解 Fence 机制,然后再回来验证一遍,会更加了解 BufferQueue 的作业原理。
这儿咱们先只重视里边的 BufferState 这个目标。
2.1 BufferState
首要, 咱们先看 BufferState 的结构体界说, 里边的方法比较简略, 首要便是界说了5个状况值。
// BufferState 是盯梢缓冲区 slot 运转的状况。
struct BufferState {
// 一切的 slot 最初都是 Free 状况
BufferState()
: mDequeueCount(0),
mQueueCount(0),
mAcquireCount(0),
mShared(false) {
}
uint32_t mDequeueCount;
uint32_t mQueueCount;
uint32_t mAcquireCount;
bool mShared;
// 一个缓冲区可用处于5种状况, 它们别离是
//
// | 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 |
// FREE : 标识这个缓冲区是能够出队给出产者运用, 此缓冲区对应的 slot 归于 BufferQueue ,
// 当它被调用 dequeueBuffer 时, 状况会转变为 DEQUEUED
// DEQUEUED : 表明此缓冲区现现已过出产者出队, 可是还没有入队或许取消, 一旦宣布相关开释围栏的信号,出产者就能够修正缓冲区的内容。
// 此缓冲区对应的 slot 一切者是出产者, 当调用 queueBuffer/attachBuffer 时状况就会变成 QUEUED ,
// 当调用 cancelBuffer/detachBuffer 时,状况就会变成 FREE
// QUEUED : 表明缓冲区现已被出产者填充, 能够入队供给给顾客运用
// 缓冲区的内容或许会持续改动, 所以这相关的 fence 信号宣布前,此缓冲区对应 slot 的具有者是 BufferQueue
// 当调用 acquireBuffer 时状况会转变为 ACQUIRED ,
// 或许在异步形式下另一个 buffer 入队时, 此 buffer 的状况会转变为 FREE
// ACQUIRED : 表明这个 buffer 现已被顾客获得, 可是和 QUEUED 状况一样,在获取 fence 信号之前,顾客不得拜访内容。
// 这个缓冲区对应的 slot 的一切者是顾客, 在调用 releaseBuffer/detachBuffer 时会转变为 FREE
// 一个独立的缓冲区也能够经过调用 attachBuffer 进入 ACQUIRED 状况
// SHARED : 表明此缓冲区处于同享形式中, 它能够和其他的几种状况组合(可是不能和FREE状况组合),
// 它也能够多次的入队/出队/获取
inline bool isFree() const {
return !isAcquired() && !isDequeued() && !isQueued();
}
inline bool isDequeued() const {
return mDequeueCount > 0;
}
inline bool isQueued() const {
return mQueueCount > 0;
}
inline bool isAcquired() const {
return mAcquireCount > 0;
}
inline bool isShared() const {
return mShared;
}
inline void reset() {
*this = BufferState();
}
const char* string() const;
inline void dequeue() {
mDequeueCount++;
}
inline void detachProducer() {
if (mDequeueCount > 0) {
mDequeueCount--;
}
}
inline void attachProducer() {
mDequeueCount++;
}
inline void queue() {
if (mDequeueCount > 0) {
mDequeueCount--;
}
mQueueCount++;
}
inline void cancel() {
if (mDequeueCount > 0) {
mDequeueCount--;
}
}
inline void freeQueued() {
if (mQueueCount > 0) {
mQueueCount--;
}
}
inline void acquire() {
if (mQueueCount > 0) {
mQueueCount--;
}
mAcquireCount++;
}
inline void acquireNotInQueue() {
mAcquireCount++;
}
inline void release() {
if (mAcquireCount > 0) {
mAcquireCount--;
}
}
inline void detachConsumer() {
if (mAcquireCount > 0) {
mAcquireCount--;
}
}
inline void attachConsumer() {
mAcquireCount++;
}
};
对照着Google官方供给的 BufferQueue 缓冲区的流通图,接下来简略阐明一下一个 BufferSlot 的一生
- BufferSlot 的出世, 每个 BufferSlot 出世时都是 FREE 状况, 它的一切者是 BufferQueue
- 出产者调用 dequeue , BufferSlot 出队, 此刻 BufferSlot 的状况转变为 DEQUEUED , 它的一切者是出产者
- DEQUEUED 状况下, 出产者会将内容填充到 BufferSlot 对应的缓冲区中
- 出产者也能够调用 cancelBuffer/detachBuffer , 之后缓冲区的状况就会转变为 FREE
- 出产者填充完数据后,调用 queue 将 BufferSlot 入队, 此刻 BufferSlot 的状况转变为 QUEUED , BufferSlot 的一切者为 BufferQueue
- 顾客调用 acquire 获取 BufferQueue 中的 BufferSlot, 此刻 BufferSlot 的状况转变为 ACQUIRED , BufferSlot 的一切者为顾客
- 顾客读取完数据后,调用 release 开释 BufferSlot, 之后 BufferSlot 的状况又会从头变成 FREE , BufferSlot 的一切者为 BufferQueue
留意:这儿一切的缓冲区流通,咱们只说了一切权,在图形体系中,缓冲区除了一切权,还有一个运用权。咱们能够把他了解为一个图书馆,不同的人来借书,借书的人有运用权,可是没有书的一切权。
在了解了这些概念之后,咱们顺着出产者和顾客模型的次序,看一遍 BufferQueue 的作业流程
三 dequeueBuffer
首要从出产者向 BufferQueue 请求 BufferSlot 开始,这个函数是 BufferQueueProducer::dequeueBuffer。由于这个函数较长,所以咱们将它拆成几个部分看。
3.1 dequeueBuffer 的榜首部分
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) {
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
// 首要判别缓冲区的状况是否弃用,mIsAbandoned 初始化的值为 false
// 在 consumerDisconnect 中它会被修正为 true
if (mCore->mIsAbandoned) {
return NO_INIT;
}
// 接着判别缓冲区是否和 Surface 建立了连接, 假如没有也直接回来
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
return NO_INIT;
}
}
// 判别出产者需求的宽高是否合法,要么全为0,要么全不为0
if ((width && !height) || (!width && height)) {
return BAD_VALUE;
}
// 设置参数的默许值
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{
std::unique_lock<std::mutex> lock(mCore->mMutex);
// 假如当时没有闲暇的 Buffer , 可是当时正在分配, 则等候分配完结, 而不去重复分配
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock);
mDequeueWaitingForAllocation = false;
mDequeueWaitingForAllocationCondition.notify_all();
}
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// 敞开顾客请求的标志
usage |= mCore->mConsumerUsageBits;
//假如宽和高都是0, 则运用默许的宽高
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
int found = BufferItem::INVALID_BUFFER_SLOT;
....
}
留意,这儿体系只是判别了 mFreeBuffer 数组,假如 mFreeBuffer 数组为空,而且 mIsAllocating 为 true,就会调用 waitWhileAllocatingLocked 堕入等候。
SurfaceFlinger 中运用的缓冲区是有数量约束的,假如当时处于正在分配缓冲区的状况,就会导致堵塞。而 mIsAllocating 表明是否正在分配,假如是正在分配,则不会重复进行分配,而是进入堵塞。
接下来咱们看第二部分的代码。
3.2 dequeueBuffer 的第二部分
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) {
...
// 先初始化 found 的值为无效的缓冲槽
int found = BufferItem::INVALID_BUFFER_SLOT;
//留意, 这儿有一个循环,也便是说假如没有找到缓冲槽,就会一直循环
while (found == BufferItem::INVALID_BUFFER_SLOT) {
// 调用 waitForFreeSlotThenRelock 开始查找可用的缓冲槽
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
// 正常状况是不能履行到此处的代码
return -EBUSY;
}
// 留意,将找到的 BufferSlot 对应的图形缓冲区赋值给了 buffer
// 咱们之前在介绍 BufferSlot 时说过,一个 BufferSlot 对应一个图形缓冲区(GraphicBuffer)
// 可是并没有说这个缓冲区现在现已分配好了,也便是说这个缓冲区还或许并没有真实分配
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// 假如咱们现在不答应分配新的缓冲区
if (!mCore->mAllowAllocation) {
// buffer 又需求一个缓冲区
if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
// 假如是同享缓冲区形式就直接回来了,一般不是此形式
if (mCore->mSharedBufferSlot == found) {
return BAD_VALUE;
}
// 找到的 found 没有缓冲区,可是现在又要缓冲区,那咋办嘛,从头找呗
// 只好把 found 放回去,再从头找吧。留意,这儿放进的是 mFreeSlots 数组
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
// 履行完 while 循环,那么 found 要么现已有了缓冲区,要么是能够分配缓冲区
// 仍是老样子,不管有没有,先放进去
// 把 while 中找到的 mGraphicBuffer 的地址赋值给 buffer
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
// 仍是先判别同享缓冲区形式
return BAD_VALUE;
}
// 现在找到的这个 found 肯定是咱们要用的了,先放到 mActiveBuffers 数组
// [1.3]中介绍了4个数组别离寄存什么类型的 BufferSlot
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found);
}
// 将找到的成果保存
*outSlot = found;
}
第二部分首要便是 mSlots 的查找进程,这部分代码现已加了详细的注释。查找进程便是经过调用 waitForFreeSlotThenRelock 完结的,这个查找的详细进程咱们后边再看。先看 dequeueBuffer 的第三部分的代码
3.3 dequeueBuffer 的第三部分
...
*outSlot = found;
attachedByConsumer = mSlots[found].mNeedsReallocation;
mSlots[found].mNeedsReallocation = false;
// 修正找到 Buffer 的状况,还记得 Google 的官方图吗
mSlots[found].mBufferState.dequeue();
// 现在看这个 buffer 是现已有了,仍是没有需求从头分配
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
// 假如是没有,需求从头分配
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
// returnFlags 标志翻开需求从头分配的开关
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// 设置 mBufferAge,这将是该缓冲区排队时的帧编号
mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
// 不要在同享缓冲区形式下回来 Fence,榜首帧除外
// 在查找 BufferSlot 的时分,还会经过回来参数拿到一个 Fence,
// 这个 Fence 决定了这个 BufferSlot 的上一任主人有没有处理完作业,也便是说当时的主人有没有运用权
*outFence = (mCore->mSharedBufferMode &&
mCore->mSharedBufferSlot == found) ?
Fence::NO_FENCE : mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
// 假如启用了同享缓冲区形式,缓存的榜首个出队的slot,标记为同享缓冲区
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = found;
mSlots[found].mBufferState.mShared = true;
}
} // Autolock scope
第三部分是查找到了 mSlots 之后,对 mSlots 状况的更新。假如查找到的 BufferSlot 需求从头分配缓冲区,那么就会初始化 BufferSlot 的成员变量
3.4 dequeueBuffer 的第四部分
// 假如 BUFFER_NEEDS_REALLOCATION 的标志敞开,就创立一个新的 GraphicBuffer 目标
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
status_t error = graphicBuffer->initCheck();
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
if (error == NO_ERROR && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
// 将创立的缓冲区放进 BufferSlot
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
}
mCore->mIsAllocating = false;
// 还记得榜首部分的堵塞吗,假如正在分配,就堵塞,这儿进行唤醒操作
mCore->mIsAllocatingCondition.notify_all();
if (error != NO_ERROR) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
return error;
}
if (mCore->mIsAbandoned) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
return NO_INIT;
}
}
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// 假如呈现问题,记载过错,但回来缓冲区而不同步拜访它。 此刻间断出队操作为时已晚。
eglDestroySyncKHR(eglDisplay, eglFence);
}
if (outBufferAge) {
// 回来帧编号
*outBufferAge = mCore->mBufferAge;
}
//
addAndGetFrameTimestamps(nullptr, outTimestamps);
return returnFlags;
第四部分的代码也比较简略,仅有需求留意的便是 GraphicBuffer 的创立和内存分配。不过 GraphicBuffer 的内存分配其实是一个非常复杂的进程,这儿就不深入了,详细的能够看[解读GraphicBuffer] todo
接下来,就来看看 BufferSlot 的查找进程 waitForFreeSlotThenRelock
四 BufferSlot 的查找
4.1 waitForFreeSlotThenRelock
waitForFreeSlotThenRelock 这个函数比较简略, 它首要经过两个函数来获取缓冲区
- getFreeBufferLocked: 它是从 FreeBuffer 数组中获取缓冲区
- getFreeSlotLocked: 它是从 FreeSlot 数组中获取缓冲区
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 (mCore->mIsAbandoned) {
// BufferQueue 的状况不对
return NO_INIT;
}
int dequeuedCount = 0;
int acquiredCount = 0;
// 计算 ActiveBuffers 中 DEQUEUED 和 ACQUIRED 的 BufferSlot 的数量
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount;
}
if (mSlots[s].mBufferState.isAcquired()) {
++acquiredCount;
}
}
// 当缓冲区入队时,查看出产者的 Dequeue 的 BufferSlot 数量是否超越了 mMaxDequeuedBufferCount
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
return INVALID_OPERATION;
}
// 上面都是计算和一些参数判别,现在才真实开始查找
// 仍是老样子,初始化一个值
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
// 假如咱们快速断开和从头连接,咱们或许会处于一种状况,即slot是空的,
// 但行列中有许多缓冲区。这或许导致咱们在超越运用者时耗尽内存。假如看起来有太多缓冲区在排队,则等候
// 先拿到最大的 Buffer 数量,一般是双缓冲的2,或许三缓冲的3
const int maxBufferCount = mCore->getMaxBufferCountLocked();
// 假如入队的 BufferSlot 太多,就会 tooManyBuffers
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
} else {
// 假如是同享缓冲区形式而且存在同享缓冲区,则运用同享缓冲区
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = mCore->mSharedBufferSlot;
} else {
if (caller == FreeSlotCaller::Dequeue) {
// 假如调用的是出队 Dequeue , 则优先运用 FreeBuffer
// 由于 FreeBuffer 中的 Slot 现已和 buffer 进行过绑定
// 这样就不需求从头分配 buffer
int slot = getFreeBufferLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else if (mCore->mAllowAllocation) {
*found = getFreeSlotLocked();
}
} else {
// 假如调用的是 attach , 则优先运用 FreeSlot
int slot = getFreeSlotLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else {
*found = getFreeBufferLocked();
}
}
}
}
// 假如没有找到缓冲区, 或许是 tooManyBuffers, 就再试一次
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
tooManyBuffers;
if (tryAgain) {
if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
// 假如是非堵塞形式则直接回来过错(出产者和顾客由应用程序控制)
return WOULD_BLOCK;
}
// 等候锁, 假如超时就回来, 假如没有超时, 就重试
if (mDequeueTimeout >= 0) {
std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
std::chrono::nanoseconds(mDequeueTimeout));
if (result == std::cv_status::timeout) {
return TIMED_OUT;
}
} else {
// 堕入等候,等候唤醒
mCore->mDequeueCondition.wait(lock);
}
}
} // while (tryAgain)
return NO_ERROR;
}
尽管 waitForFreeSlotThenRelock 调用的是 BufferQueueProducer , 可是真实的完结是 BufferQueueCore。详细的查找进程能够分为以下几步
- dequeueBuffer() 优先从 mFreeBuffers 中获取一个 BufferSlot。
- 假如 mFreeBuffers 为空,则从 mFreeSlots 中获取 BufferSlot,并为它分配一块指定大小的 buffer。
- 将其对应的 BufferSlot 状况从 FREE 修正为 DEQUEUED,然后将该 slot 从 mFreeSlots 迁移到 mActiveBuffers 中。
- 将获取到的 slot 作为出参回来给调用者。假如该 BufferSlot 绑定的 GraphicBuffer 是从头分配的,则回来值为 BUFFER_NEEDS_REALLOCATION,否则为 NO_ERROR
当咱们运用 dequeueBuffer 获取 BufferSlot 的时分,会优先从 FreeBuffer 数组中获取缓冲区,由于它里边是 Slot 现已和 buffer 进行了绑定,这样咱们就能够省去 buffer 的请求和绑定的进程,当然,假如 FreeBuffer 数组为空,或许没有可用的 buffer,那么就会从 FreeSlot 数组中请求,这种状况下,还会进行一个 GraphicBuffer 的请求和绑定的进程,这些逻辑在 dequeueBuffer 现已看到了。
别的,在 waitForFreeSlotThenRelock 中,咱们还看到一种状况,便是 tooManyBuffers,那么什么状况下回呈现 tooManyBuffers 呢?就拿比较常用的三缓冲来说吧,一个缓冲区用来给出产者写,一个缓冲区用来给顾客显现,还有一个缓冲区用来给 SurfaceFlinger 组成。那么假如这时分出产者用力的请求缓冲区写内容,而且将写好的 GraphicBuffer 放进 BufferQueue,而顾客底子来不及消费,就会导致 tooManyBuffers 呈现了。
当然,正常状况一般是出产者生成内容不及时,绘制时刻过长,导致 GraphicBuffer 没有及时传递给 BufferQueue,导致显现丢帧,可是看体系源码咱们发现,出产者生成过慢不行,生成过快相同也是不行的。
4.2 getFreeBufferLocked和getFreeSlotLocked
在 waitForFreeSlotThenRelock 中,咱们还看到了 getFreeBufferLocked 和 getFreeSlotLocked 这两个函数。不过它们都比较简略, 这儿就不过多介绍了
int BufferQueueProducer::getFreeBufferLocked() const {
if (mCore->mFreeBuffers.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = mCore->mFreeBuffers.front();
mCore->mFreeBuffers.pop_front();
return slot;
}
int BufferQueueProducer::getFreeSlotLocked() const {
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = *(mCore->mFreeSlots.begin());
mCore->mFreeSlots.erase(slot);
return slot;
}
到这儿,dequeueBuffer 的根本流程就现已介绍完了,至于出产者拿到了 BufferSlot 做了哪些,并不是本文的重点,接下来咱们再看看当出产者完结出产之后,BufferSlot 的入队操作。
五 queueBuffer
queueBuffer 是出产者完结了出产之后,将 BufferSlot 转交给 BufferQueue 的进程。这个函数咱们也它拆成几个部分看。
5.1 queueBuffer 的榜首部分
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
int64_t requestedPresentTimestamp;
bool isAutoTimestamp;
android_dataspace dataSpace;
Rect crop(Rect::EMPTY_RECT);
int scalingMode;
uint32_t transform;
uint32_t stickyTransform;
sp<Fence> acquireFence;
bool getFrameTimestamps = false;
// input 是输入参数,这儿将 input 中的变量取出,保存到 requestedPresentTimestamp 等等的传入参数中
input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
const Region& surfaceDamage = input.getSurfaceDamage();
const HdrMetadata& hdrMetadata = input.getHdrMetadata();
if (acquireFence == nullptr) {
return BAD_VALUE;
}
auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);
// 缩放形式,便是当 Buffer 内容的大小和屏幕的代销不符的时分,怎么处理,假如没有设置则直接回来
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
break;
default:
return BAD_VALUE;
}
// 界说了一些变量
sp<IConsumerListener> frameAvailableListener;
sp<IConsumerListener> frameReplacedListener;
int callbackTicket = 0;
uint64_t currentFrameNumber = 0;
// 界说一个 BufferItem
BufferItem item;
}
榜首部分的代码也比较简略
- 界说一系列变量准备给后边用
- input 是一个 QueueBufferInput 结构体,里边封装了 BufferSlot 相关的一系列变量,这儿将 input 中的变量取出来
- scalingMode 是 BufferSlot 的缩放形式,便是当 Buffer 内容的大小和屏幕的代销不符的时分,怎么处理,这个需求设置,假如没有设置会直接回来 BAD_VALUE
- 界说了一个 BufferItem 目标
5.2 queueBuffer 的第二部分
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
BufferItem item;
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 惯例的状况判别
if (mCore->mIsAbandoned) {
return NO_INIT;
}
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
return NO_INIT;
}
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
return BAD_VALUE;
} else if (!mSlots[slot].mBufferState.isDequeued()) {
return BAD_VALUE;
} else if (!mSlots[slot].mRequestBufferCalled) {
return BAD_VALUE;
}
// 假如刚刚启用了同享缓冲区形式,缓冲区的榜首个缓冲槽已入队,就将其标记为同享缓冲区
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = slot;
mSlots[slot].mBufferState.mShared = true;
}
// 将 BufferSlot 的 GraphicBuffer 保存到 graphicBuffer
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
// 拿到 GraphicBuffer 的宽高
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
// 界说裁剪区域
Rect croppedRect(Rect::EMPTY_RECT);
// 裁剪 bufferRect 中处于裁剪区域的内容
crop.intersect(bufferRect, &croppedRect);
// 裁剪之后 croppedRect 便是 crop
if (croppedRect != crop) {
return BAD_VALUE;
}
// 假如 dataSpace 为 Unknown 则设置为默许值
if (dataSpace == HAL_DATASPACE_UNKNOWN) {
dataSpace = mCore->mDefaultBufferDataSpace;
}
// 传递 Fence,后续顾客根据这个来判别是否有运用权
mSlots[slot].mFence = acquireFence;
// 修正 BufferSlot 的状况为 QUEUE
mSlots[slot].mBufferState.queue();
// 增加帧计数器并将其本地版本存储在 mCore->mMutex 上的锁外部运用
++mCore->mFrameCounter;
currentFrameNumber = mCore->mFrameCounter;
mSlots[slot].mFrameNumber = currentFrameNumber;
// 将参数封装进 BufferItem
item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mCrop = crop;
item.mTransform = transform &
~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
item.mTransformToDisplayInverse =
(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
item.mScalingMode = static_cast<uint32_t>(scalingMode);
item.mTimestamp = requestedPresentTimestamp;
item.mIsAutoTimestamp = isAutoTimestamp;
item.mDataSpace = dataSpace;
item.mHdrMetadata = hdrMetadata;
item.mFrameNumber = currentFrameNumber;
item.mSlot = slot;
item.mFence = acquireFence;
item.mFenceTime = acquireFenceTime;
item.mIsDroppable = mCore->mAsyncMode ||
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
item.mSurfaceDamage = surfaceDamage;
item.mQueuedBuffer = true;
item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
item.mApi = mCore->mConnectedApi;
mStickyTransform = stickyTransform;
...
第二部分代码也比较简略,便是结构了一个 BufferItem,将传递进来的 input 里的值设置到 BufferItem 中。这儿仅有需求留意的是对 GraphicBuffer 内容进行的裁剪,由于 GraphicBuffer 有或许超出要显现的区域,所以需求裁剪出满意条件的内容。
bool Rect::intersect(const Rect& with, Rect* result) const {
result->left = max(left, with.left);
result->top = max(top, with.top);
result->right = min(right, with.right);
result->bottom = min(bottom, with.bottom);
return !(result->isEmpty());
}
5.3 queueBuffer 的第三部分
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
...
mStickyTransform = stickyTransform;
// 缓存同享缓冲区数据,以便能够从头创立 BufferItem
if (mCore->mSharedBufferMode) {
mCore->mSharedBufferCache.crop = crop;
mCore->mSharedBufferCache.transform = transform;
mCore->mSharedBufferCache.scalingMode = static_cast<uint32_t>(
scalingMode);
mCore->mSharedBufferCache.dataspace = dataSpace;
}
output->bufferReplaced = false;
// 将 BufferItem 入队,这儿分为几种状况
if (mCore->mQueue.empty()) {
// 当 BufferQueue 行列为空,咱们能够疏忽 MDEQUEUEBUFERCANNOTBLOCK,将此缓冲区入队
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
} else {
// 当行列不为空时,咱们需求查看行列中的最终一个缓冲区,看看是否需求替换它
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
if (!last.mIsStale) {
mSlots[last.mSlot].mBufferState.freeQueued();
// After leaving shared buffer mode, the shared buffer will still be around. Mark it as no longer shared if this operation causes it to be free.
// 脱离同享缓冲区形式后,同享缓冲区依然存在。假如此操作导致其闲暇,则将其标记为不再同享
if (!mCore->mSharedBufferMode &&
mSlots[last.mSlot].mBufferState.isFree()) {
mSlots[last.mSlot].mBufferState.mShared = false;
}
// 不要将同享缓冲区放在闲暇列表上
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;
}
}
// 修正 BufferQueue 的变量,发送告诉
mCore->mBufferHasBeenQueued = true; // BufferQueue 是否现已有 Buffer 入队
mCore->mDequeueCondition.notify_all(); // 告诉 mDequeueCondition 锁相关的线程
mCore->mLastQueuedSlot = slot; // 保存 slot 到 mLastQueuedSlot
// 即将回来的参数保存到 output
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
output->transformHint = mCore->mTransformHint;
// 现在待消费的 Buffer
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
// 下一帧的编号
output->nextFrameNumber = mCore->mFrameCounter + 1;
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
// 获取回调函数的票证
callbackTicket = mNextCallbackTicket++;
}
第三部分则是将创立的 BufferItem 入队。这儿入队会分为几种状况别离处理
- BufferQueue 为空,则直接入队
- BufferQueue 不为空
- 最终一帧的内容是否可掩盖,假如是可掩盖的,就丢掉最终一帧的内容,将新的 BufferItem 入队
- 假如最终一帧的内容不行掩盖,则将新 BufferItem 入队
然后修正 BufferQueue 的变量,并宣布告诉。还记得在 dequeueBuffer 中堕入等候的几种状况吗[见3.3],假如找不到 BufferSlot 或许呈现 tooManyBuffer 的状况就会让线程堕入等候。说到底便是出产者请求 Buffer 太快了。
5.4 queueBuffer 的第四部分
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
...
// 当运用者是 SurfaceFinger 时,能够不铲除 GraphicBuffer,
// 由于能够保证 BufferQueue 在 SurfaceFinger 的进程内,而且不会有绑定器调用
if (!mConsumerIsSurfaceFlinger) {
item.mGraphicBuffer.clear();
}
// 回调尽管没有持有没有主缓冲行列锁,可是持有对应的回调锁,所以也能够保证回调是有序的
int connectedApi;
sp<Fence> lastQueuedFence;
{
std::unique_lock<std::mutex> lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(lock);
}
// 告诉监听器有 BufferSlot 能够进行消费了
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
connectedApi = mCore->mConnectedApi;
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
mLastQueuedCrop = item.mCrop;
mLastQueuedTransform = item.mTransform;
++mCurrentCallbackTicket;
mCallbackCondition.notify_all();
}
// 更新并获取FrameEventHistory
nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
NewFrameEventsEntry newFrameEventsEntry = {
currentFrameNumber,
postedTime,
requestedPresentTimestamp,
std::move(acquireFenceTime)
};
// 做一个记载
addAndGetFrameTimestamps(&newFrameEventsEntry,
getFrameTimestamps ? &output->frameTimestamps : nullptr);
// 无锁等候
if (connectedApi == NATIVE_WINDOW_API_EGL) {
// 在此处等候答应两个已满的缓冲区入队,但不答应第三个缓冲区入队。
lastQueuedFence->waitForever("Throttling EGL Production");
}
return NO_ERROR;
}
第四部分首要便是进行一些回谐和告诉了,而且定了了一些 mLast 相关的变量。
5.5 queueBuffer 总结
比较于 dequeueBuffer,queueBuffer 的逻辑简略太多了,便是将出产者传入的一些参数解析后,创立一个对应的 BufferItem 入队到 BufferQueue 中,然后根据最终一帧是否可掩盖别离处理,然后修正一些状况。最终回调告诉。
六 acquireBuffer
看完出产者 BufferQueueProducer 的两个函数,接下来咱们再看看顾客 BufferQueueConsumer 的两个函数,首要是 acquireBuffer。
6.1 acquireBuffer 的榜首部分
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
std::unique_lock<std::mutex> lock(mCore->mMutex);
// 先计算现已 Acquired 的 Buffer
int numAcquiredBuffers = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
// 假如现已 Acquired 的 Buffer 超出最大数 mMaxAcquiredBufferCount 的约束就回来
// 这儿的最大数答应超出1个,是为了顾客能够运用新的 Buffer 替换旧的 Buffer
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
return INVALID_OPERATION;
}
bool sharedBufferAvailable = mCore->mSharedBufferMode &&
mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// 在异步形式下,列表保证是一个缓冲区深,而在同步形式下,咱们运用最旧的缓冲区。
if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
// 获取 BufferQueue 行列的迭代器
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
}
榜首部分的逻辑比较简略
- 首要判别当时 acquire 的缓冲区是否现已超越了能够 acquire 的最大缓冲区数量,一般状况下这个数量是1,不过这儿会在这个数量的基础上再加1,由于为了让顾客能够用新的缓冲区替换旧的缓冲区
- 非同享形式,假如缓冲区行列是空,就回来没有可用缓冲区
6.2 acquireBuffer 的第二部分
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
...
// 假如指定了 expectedPresent,咱们或许还不想回来缓冲区。
// 假如它被指定而且有多个缓冲区排队,咱们或许想要删去一个缓冲区。
// 假如咱们处于同享缓冲区形式而且行列为空,则跳过此进程,由于在这种状况下咱们将只回来同享缓冲区。
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
// expectedPresent 参数表明这个 buffer 是期望被什么时分显现到屏幕上
// 假如 buffer 的 desiredPresent 时刻早于 expectedPresent 时刻,那么这个 buffer 就会准时显现或许赶快显现
// 假如想显现它,就 acquire 而且回来它,假如在 expectedPresent 时刻之前都不想显现它,就回来 PRESENT_LATER
// 留意:代码假定来自体系时钟的单调时刻值为正。
// 首要查看咱们是否能够丢帧。 假如时刻戳是由 Surface 主动生成的,咱们将跳过此查看。
// 假如应用程序没有明确生成时刻戳,则它或许不希望根据它们的时刻戳丢掉帧。
// mIsAutoTimestamp 代表这个缓冲区是否有主动生成的时刻戳
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
const BufferItem& bufferItem(mCore->mQueue[1]);
// 假如删去 entry[0] 会给咱们留下一个顾客没有准备好的缓冲区,请不要删去它。
if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
break;
}
// 假如 entry[1] 是及时的,则删去 entry[0](并重复)。 咱们在这儿应用了一个额外的规范:假如咱们的 desiredPresent 在 expectedPresent 的 +/- 1 秒内,咱们只删去较早的缓冲区。
// 否则,虚假的 desiredPresent 时刻(例如,0 或较小的相对时刻戳),通常意味着“疏忽时刻戳并立即获取”,将导致咱们丢帧。
// 假如 entry[1] 的栅门没有宣布信号,则不要删去较早的缓冲区。
if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresent) {
// 这个缓冲区设置为在不久的将来显现,或许 desiredPresent 是垃圾。 无论哪种方式,咱们都不想为了更快地将其显现在屏幕上而丢掉前一个缓冲区。
break;
}
if (!front->mIsStale) {
// 队首的缓冲区仍在 mSlots 中,因此将插槽标记为闲暇
mSlots[front->mSlot].mBufferState.freeQueued();
// 脱离同享缓冲区形式后,同享缓冲区依然存在。 假如此操作导致其免费,则将其标记为不再同享。
if (!mCore->mSharedBufferMode &&
mSlots[front->mSlot].mBufferState.isFree()) {
mSlots[front->mSlot].mBufferState.mShared = false;
}
// 不要将同享缓冲区放在闲暇列表中
if (!mSlots[front->mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(front->mSlot);
mCore->mFreeBuffers.push_back(front->mSlot);
}
listener = mCore->mConnectedProducerListener;
++numDroppedBuffers;
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// 查看是否准备好获取前端缓冲区
nsecs_t desiredPresent = front->mTimestamp;
bool bufferIsDue = desiredPresent <= expectedPresent ||
desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
bool consumerIsReady = maxFrameNumber > 0 ?
front->mFrameNumber <= maxFrameNumber : true;
if (!bufferIsDue || !consumerIsReady) {
return PRESENT_LATER;
}
}
第二部分首要是判别旧的缓冲区是否能够被新缓冲区代替。假如旧的缓冲区有主动生成的时刻戳,而且新缓冲区也马上就要显现了,那么这种状况下,会直接运用新的缓冲区,假如新的缓冲区还要很久才会被用到,那么就运用旧的缓冲区。
6.3 acquireBuffer 的第三部分
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
if (sharedBufferAvailable && mCore->mQueue.empty()) {
// 在获取缓冲区之前保证缓冲区已完结分配
mCore->waitWhileAllocatingLocked(lock);
slot = mCore->mSharedBufferSlot;
// 从前次排队时缓存的数据为同享缓冲区从头创立 BufferItem。
outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
outBuffer->mFence = Fence::NO_FENCE;
outBuffer->mFenceTime = FenceTime::NO_FENCE;
outBuffer->mCrop = mCore->mSharedBufferCache.crop;
outBuffer->mTransform = mCore->mSharedBufferCache.transform &
~static_cast<uint32_t>(
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode;
outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace;
outBuffer->mFrameNumber = mCore->mFrameCounter;
outBuffer->mSlot = slot;
outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
outBuffer->mTransformToDisplayInverse =
(mCore->mSharedBufferCache.transform &
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
outBuffer->mQueuedBuffer = false;
outBuffer->mIsStale = false;
outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
mCore->mAutoRefresh;
} else {
slot = front->mSlot;
*outBuffer = *front;
}
if (!outBuffer->mIsStale) {
mSlots[slot].mAcquireCalled = true;
// 假如 BufferItem 之前不在行列中,则不要减少行列计数。 当行列为空而且上面创立了 BufferItem 时,会在同享缓冲区形式下发生这种状况。
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
mSlots[slot].mBufferState.acquire();
}
mSlots[slot].mFence = Fence::NO_FENCE;
}
// 假如缓冲区先前已被顾客获取,则将 mGraphicBuffer 设置为 NULL 以避免在顾客端不用要地从头映射此缓冲区
if (outBuffer->mAcquireCalled) {
outBuffer->mGraphicBuffer = nullptr;
}
mCore->mQueue.erase(front);
// 咱们或许在丢掉旧缓冲区时开释了一个 Slot,或许出产者或许被堵塞
mCore->mDequeueCondition.notify_all();
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
}
// 回调
if (listener != nullptr) {
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
}
return NO_ERROR;
}
6.4 acquireBuffer 总结
和出产者想必,顾客的逻辑要简略许多,acquireBuffer 的首要作业如下
- 首要判别现已处于 ACQUIRED 状况缓冲区的数量,假如数量超出了约束,就不会回来新的缓冲区。不过这儿会在最大数量的基础上加1,为了做新旧缓冲区的替换
- 判别缓冲区是否有主动生成的时刻戳,这个时刻戳用于丢掉旧的缓冲区。然后根据这个时刻戳再判别旧缓冲区是否能够直接运用新缓冲区代替
- 将确定好的缓冲区回来出去,而且改变 Slot 的状况为 ACQUIRED,告诉其他堵塞的线程,然后调用回调函数。
七 releaseBuffer
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
releaseFence == nullptr) {
// slot 不合法或许 releaseFence 为空
return BAD_VALUE;
}
sp<IProducerListener> listener;
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 假如帧的序号由于缓冲区从头分配而改动,咱们能够疏忽旧缓冲区 releaseBuffer。
// 关于同享缓冲区,请疏忽这一点,其中由于缓冲区正在排队并同时获取,帧号很简单不同步。
if (frameNumber != mSlots[slot].mFrameNumber &&
!mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
// 判别 Slot 的状况,Slot 的状况有必要是 ACQUIRED
if (!mSlots[slot].mBufferState.isAcquired()) {
return BAD_VALUE;
}
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
mSlots[slot].mBufferState.release();
// 脱离同享缓冲区形式后,同享缓冲区依然存在。 假如此操作导致其 FREE,则将其标记为不再同享。
if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
mSlots[slot].mBufferState.mShared = false;
}
// 不要将同享缓冲区放在 FREE 列表中
if (!mSlots[slot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(slot);
mCore->mFreeBuffers.push_back(slot);
}
listener = mCore->mConnectedProducerListener;
mCore->mDequeueCondition.notify_all();
}
// 无锁回调
if (listener != nullptr) {
listener->onBufferReleased();
}
return NO_ERROR;
}
releaseBuffer 便是顾客运用完缓冲区后,开释缓冲区的进程。在调用 releaseBuffer 函数之后,mSlot 的状况就会变成 FREE 状况。
八 总结
SurfaceFlinger 中 BufferQueue 的作业流程和原理到此就根本理清了,联系之前的 SurfaceFlinger 组成的作业流程,SurfaceFlinger 组成作业中,最关键的流程现已根本学习完毕了。当然,关于 SurfaceFlinger 作业来说,这连冰山一角都算不上,前路漫漫。