一.入口
生产者入口
本篇详细介绍下生产者--图形缓冲区--消费者这个模型的具体工作流程,我们还是从应用层调用流程着手。
在demo示例中,我们获取buffer-->填充数据-->送出显示的代码(简略版伪代码,重点分析BufferQueue流程的)如下:
// 9. 从生产者(Surface)出队一个缓冲区,用于后续绘制操作
// 出队操作会从BufferQueue中取出一个空闲缓冲区,返回缓冲区的ANativeWindowBuffer指针
// 同时返回一个释放栅栏(releaseFenceFd),用于等待前一个使用者完成对该缓冲区的操作
ANativeWindowBuffer *nativeBuffer = nullptr;
int releaseFenceFd = -1;
err = nativeWindow->dequeueBuffer(nativeWindow, &nativeBuffer, &releaseFenceFd);
if (err != NO_ERROR) {
ALOGE("error: dequeueBuffer failed: %s (%d)",
strerror(-err), -err);
break;
}
// 10. 通过释放栅栏确保当前代码真正控制了这个出队的缓冲区
// 释放栅栏表示GPU或之前的消费者对该缓冲区的使用已经完成
// 等待这个栅栏确保我们可以安全地写入缓冲区,避免数据竞争
sp<Fence> releaseFence(new Fence(releaseFenceFd));
int waitResult = releaseFence->waitForever("dequeueBuffer_EmptyNative");
if (waitResult != OK) {
ALOGE("dequeueBuffer_EmptyNative: Fence::wait returned an error: %d", waitResult);
break;
}
// 将ANativeWindowBuffer转换为GraphicBuffer对象以便后续操作
sp<GraphicBuffer> buf(GraphicBuffer::from(nativeBuffer));
// 11. 调用lock函数获取缓冲区的虚拟内存地址
// GRALLOC_USAGE_SW_WRITE_OFTEN标志表示我们将频繁地通过CPU写入此缓冲区
// lock成功后,img指针指向缓冲区在内存中的起始位置,我们可以直接向其中写入数据
uint8_t* img = nullptr;
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
if (err != NO_ERROR) {
ALOGE("error: lock failed: %s (%d)", strerror(-err), -err);
break;
}
// 12. 使用RGB数据填充缓冲区
// countFrame是一个帧计数器,用于在三帧之间循环,每帧显示一种颜色(红、绿、蓝)
// fillRGBA8Buffer函数将缓冲区填充为指定的颜色,这里依次为红、绿、蓝
countFrame = (countFrame+1)%3;
fillRGBA8Buffer(img, nativeSurface->width(), nativeSurface->height(), buf->getStride(),
countFrame == 0 ? 255 : 0, // 红色分量
countFrame == 1 ? 255 : 0, // 绿色分量
countFrame == 2 ? 255 : 0); // 蓝色分量
// 解锁缓冲区,表示我们已经完成对缓冲区的CPU写入操作
err = buf->unlock();
if (err != NO_ERROR) {
ALOGE("error: unlock failed: %s (%d)", strerror(-err), -err);
break;
}
// 13. 将处理完成的缓冲区重新入队,准备显示
// queueBuffer会将缓冲区标记为已完成,可以提交给消费者(如SurfaceFlinger)进行合成显示
// 同时返回一个获取栅栏(acquireFenceFd),消费者需要使用此栅栏等待GPU渲染完成
int acquireFenceFd = -1;
err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), acquireFenceFd);
if (err != NO_ERROR) {
ALOGE("error: queueBuffer failed: %s (%d)", strerror(-err), -err);
break;
}
如下是对上述流程的总结:
| 步骤 | 函数 | 作用 | 对应 BufferQueue 状态变化 |
|---|---|---|---|
| 9 | dequeueBuffer |
从 BufferQueue 获取一个空闲缓冲区,用于写入新内容 | 缓冲区状态:FREE → DEQUEUED |
| 10 | Fence::waitForever |
等待 GPU/前一个使用者完成对该缓冲区的操作,确保可以安全写入 | 同步操作,不改变状态 |
| 11 | GraphicBuffer::lock |
锁定缓冲区,获取 CPU 可访问的内存地址,准备写入数据 | 缓冲区锁定,CPU 可访问 |
| 12 | fillRGBA8Buffer |
向缓冲区写入实际的图像/像素数据(这里用纯色填充) | 数据填充阶段 |
| 12 | buf->unlock() |
解锁缓冲区,表示CPU写入完成 | 缓冲区解锁 |
| 13 | queueBuffer |
将处理完成的缓冲区提交回 BufferQueue,准备显示 | 缓冲区状态:DEQUEUED → QUEUED |
然后我们把重点聚焦到图形缓冲区的使用上
获取图形缓冲区调用流程:
ANativeWindow::dequeueBuffer ==> Surface::hook_dequeueBuffer ==> Surface::dequeueBuffer ==> BufferQueueProducer::dequeueBuffer
将处理完成的缓冲区返还的流程:
ANativeWindow::queueBuffer ==> Surface::hook_queueBuffer ==> Surface::queueBuffer ==> BufferQueueProducer::queueBuffer
前面的文章提到在BLASTBufferQueue中创建Surface对象时,初始化其成员变量mGraphicBufferProducer,这个就是指向了一个GraphicBufferProducer对象。
当然,上述是应用层调用,只能看出生产者工作流程,消费者如何工作的呢?
生产者与消费者流程概括
先用一张图概括一下:

上述基本展示了BufferQueue的工作逻辑以及buffer的流转过程以及状态变化
流程详细说明
1. 生产者请求空闲缓冲区
-
操作 :
dequeueBuffer() -
状态变化: FREE → DEQUEUED
-
说明: 生产者从缓冲队列请求一个空闲缓冲区,缓冲队列将缓冲区状态标记为"已出队",表示该缓冲区已被生产者占用
2. 生产者填充缓冲区
-
操作: FILL BUFFER
-
状态: DEQUEUED
-
说明: 生产者获得缓冲区后,向其填充数据(如渲染图形、解码视频帧等)
3. 生产者归还已填充缓冲区
-
操作 :
queueBuffer() -
状态变化: DEQUEUED → QUEUED
-
说明: 生产者完成数据填充后,将缓冲区归还给缓冲队列,并标记为"已入队",表示缓冲区已准备好供消费者使用
4. 消费者请求已填充缓冲区
-
操作 :
acquireBuffer() -
状态变化: QUEUED → ACQUIRED
-
说明: 消费者从缓冲队列请求一个已填充数据的缓冲区,缓冲队列将缓冲区状态标记为"已获取",表示该缓冲区已被消费者占用
5. 消费者使用缓冲区
-
操作: USE BUFFER
-
状态: ACQUIRED
-
说明: 消费者使用缓冲区中的数据(如显示到屏幕、进行图像处理等)
6. 消费者释放缓冲区
-
操作 :
releaseBuffer() -
状态变化: ACQUIRED → FREE
-
说明: 消费者使用完缓冲区后,将其释放回缓冲队列,状态重新变为"空闲",等待下一次生产请求
缓冲区状态机
FREE → DEQUEUED → QUEUED → ACQUIRED → FREE
二.生产者相关逻辑
源码位置:framework/native/libs/gui/BufferQueueProducer.cpp
1.申请图形缓冲区
dequeueBuffer:申请图形缓冲区,是从队列中取出一个可用的graphic buffer,它的作用是在应用程序一端准备绘制图像时,向BufferQueue申请一块可用的GraphicBuffer,有了这个buffer就可以把图像数据写入送去做处理和显示。
如下是dequeueBuffer函数加中文注释的代码:
status_t BufferQueueProducer::dequeueBuffer(
int* outSlot, // 输出参数,返回获取到的缓冲区槽位索引
sp<android::Fence>* outFence, // 输出参数,返回同步栅栏对象(用于GPU/CPU同步)
uint32_t width, uint32_t height, // 请求的缓冲区宽高
PixelFormat format, // 请求的缓冲区像素格式
uint64_t usage, // 请求的缓冲区使用标志(如GPU读写、CPU读写等)
uint64_t* outBufferAge, // 输出参数,返回缓冲区的"年龄"(被重用的时间间隔)
FrameEventHistoryDelta* outTimestamps) // 输出参数,返回帧事件时间戳信息
{
ATRACE_CALL(); // 开始性能跟踪标记
// 第一段加锁范围:检查BufferQueue基本状态
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
// 检查BufferQueue是否已被弃用(如Consumer端已断开连接)
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT; // 返回错误码:初始化失败
}
// 检查Producer是否已正确连接到BufferQueue
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");
return NO_INIT;
}
}
BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64,
width, height, format, usage);
// 检查请求的宽高参数是否有效(宽高需同时为0或同时非0)
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
return BAD_VALUE; // 返回错误码:参数错误
}
// 初始化返回标志和EGL同步相关变量
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
// 用于回调的监听器及相关标志
sp<IConsumerListener> listener;
bool callOnFrameDequeued = false;
uint64_t bufferId = 0;
// 第二段加锁范围:核心处理逻辑
{
std::unique_lock<std::mutex> lock(mCore->mMutex);
// 等待分配完成:如果没有空闲缓冲区且当前正在分配中,则等待分配完成
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock); // 等待条件变量
mDequeueWaitingForAllocation = false;
mDequeueWaitingForAllocationCondition.notify_all();
}
// 如果未指定格式,使用默认格式
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// 合并Consumer端请求的usage标志位
usage |= mCore->mConsumerUsageBits;
// 处理默认尺寸:如果宽高均为0,使用默认宽高
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
// 自动旋转处理:如果需要自动旋转90度,交换宽高
if (mCore->mAutoPrerotation &&
(mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
std::swap(width, height);
}
}
// 核心步骤1:查找可用的缓冲区槽位
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
// 等待并获取一个空闲的缓冲区槽位[1,2](@ref)
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
// 不应发生的情况:未找到可用槽位
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY; // 返回系统繁忙错误
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// 如果不允许分配新缓冲区,但当前缓冲区需要重新分配,则释放它并重新查找
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
// 将槽位放回空闲集合,清除槽位状态,重新查找[5](@ref)
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue; // 继续while循环
}
}
}
// 获取找到的槽位对应的缓冲区
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// 检查缓冲区是否需要重新分配(缓冲区为空或参数不匹配)
bool needsReallocation = buffer == nullptr ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);
// 共享缓冲区特殊处理:不能重新分配共享缓冲区
if (mCore->mSharedBufferSlot == found && needsReallocation) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared buffer");
return BAD_VALUE;
}
// 如果不是共享缓冲区模式,将找到的槽位加入活跃缓冲区集合
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found); // 添加到活跃集合[1,5](@ref)
}
*outSlot = found; // 设置输出槽位
ATRACE_BUFFER_INDEX(found); // 跟踪缓冲区索引
// 记录是否需要重新分配(由Consumer触发)
attachedByConsumer = mSlots[found].mNeedsReallocation;
mSlots[found].mNeedsReallocation = false;
// 改变缓冲区状态:从FREE变为DEQUEUED[2,5](@ref)
mSlots[found].mBufferState.dequeue();
// 核心步骤2:处理缓冲区分配需求
if (needsReallocation) {
// 详细的重分配日志记录
if (CC_UNLIKELY(ATRACE_ENABLED())) {
// 跟踪信息,记录重分配详情
}
// 重置槽位状态,准备重新分配缓冲区
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 |= BUFFER_NEEDS_REALLOCATION; // 设置重分配标志
} else {
// 计算缓冲区年龄:当前帧号与缓冲区最后使用帧号的差值
mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge);
// 检查fence是否异常
if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence");
}
// 设置输出fence(共享缓冲区模式有特殊处理)
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ?
Fence::NO_FENCE : mSlots[found].mFence; // 共享模式可能不需要fence
mSlots[found].mEglFence = EGL_NO_SYNC_KHR; // 重置EGL fence
mSlots[found].mFence = Fence::NO_FENCE; // 重置fence
// 共享缓冲区模式初始化:首次dequeue时设置共享槽位
if (mCore->mSharedBufferMode &&
mCore->mSharedBufferSlot == BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = found;
mSlots[found].mBufferState.mShared = true; // 标记为共享状态
}
// 设置回调标志(如果不是重新分配的情况)
if (!(returnFlags & BUFFER_NEEDS_REALLOCATION)) {
callOnFrameDequeued = true;
bufferId = mSlots[*outSlot].mGraphicBuffer->getId();
}
listener = mCore->mConsumerListener; // 获取Consumer监听器
}
// 核心步骤3:如果需要重新分配,创建新的GraphicBuffer
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
// 创建新的GraphicBuffer对象[2,4](@ref)
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
// 扩展分配路径(支持额外选项)
std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;
// ... 准备分配选项
const GraphicBufferAllocator::AllocationRequest allocRequest = {
.importBuffer = true,
.width = width,
.height = height,
.format = format,
.layerCount = BQ_LAYER_COUNT,
.usage = usage,
.requestorName = {mConsumerName.c_str(), mConsumerName.size()},
.extras = std::move(tempOptions),
};
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
#else
// 标准分配路径
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.c_str(), mConsumerName.size()});
#endif
status_t error = graphicBuffer->initCheck(); // 检查分配是否成功
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
if (error == NO_ERROR && !mCore->mIsAbandoned) {
// 设置缓冲区世代号并保存到对应槽位
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer; // 关联缓冲区到槽位
callOnFrameDequeued = true;
bufferId = mSlots[*outSlot].mGraphicBuffer->getId();
}
// 清除分配中标志并通知等待线程
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
// 错误处理:分配失败时清理状态
if (error != NO_ERROR) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
// 检查是否在分配过程中被弃用
if (mCore->mIsAbandoned) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
VALIDATE_CONSISTENCY(); // 验证内部一致性(调试用)
}
}
// 核心步骤4:回调通知
if (listener != nullptr && callOnFrameDequeued) {
listener->onFrameDequeued(bufferId); // 通知Consumer帧已出队[2](@ref)
}
// 处理Consumer触发的重分配标志
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
// 核心步骤5:EGL fence同步等待
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0, 1000000000);
// 处理等待结果(错误或超时)
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence", eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence); // 销毁EGL同步对象
}
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
*outSlot, mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer != nullptr ?
mSlots[*outSlot].mGraphicBuffer->handle : nullptr, returnFlags);
// 设置输出参数
if (outBufferAge) {
*outBufferAge = mCore->mBufferAge;
}
addAndGetFrameTimestamps(nullptr, outTimestamps); // 填充时间戳信息
return returnFlags; // 返回最终状态(可能包含BUFFER_NEEDS_REALLOCATION标志)
}
BufferQueueProducer::dequeueBuffer是 Android 图形系统中 生产者-消费者模型 的关键接口,主要作用是为生产者(如 App)获取一个可用的图形缓冲区(GraphicBuffer)用于内容绘制。
核心功能流程
-
状态验证:检查 BufferQueue 是否有效且已连接。
-
参数处理:处理宽高、格式等参数,使用默认值(若需要)并与 Consumer 的 usage 标志合并。
-
查找空闲槽位 :通过
waitForFreeSlotThenRelock在 BufferQueueCore 的缓冲区槽位数组mSlots中寻找可用槽位。优先从mFreeBuffers(有绑定 GraphicBuffer 且状态为 FREE 的槽位集合)中获取,其次从mFreeSlots(无绑定 GraphicBuffer 且状态为 FREE 的槽位集合)中获取。 -
状态转换 :将获取到的槽位状态从 FREE 转换为 DEQUEUED ,并将其加入
mActiveBuffers集合。 -
缓冲区分配/验证 :检查现有 GraphicBuffer 是否满足要求(尺寸、格式等)。如不满足,设置
BUFFER_NEEDS_REALLOCATION标志,并在后续创建新的 GraphicBuffer。 -
同步处理 :返回与缓冲区关联的
Fence对象,用于生产者(如 GPU)与后续消费者(如 SurfaceFlinger)之间的同步。 -
回调通知 :通过
onFrameDequeued回调通知 Consumer 缓冲区已被取出。
关键数据结构与状态管理
-
BufferQueueCore :核心数据管理器,维护了
mSlots(缓冲区槽位数组)、mFreeBuffers、mFreeSlots、mActiveBuffers等关键集合。 -
BufferState :通过
mDequeueCount、mQueueCount、mAcquireCount和mShared标志来精确追踪每个缓冲区的状态(FREE, DEQUEUED, QUEUED, ACQUIRED, SHARED)。 -
GraphicBuffer:存储图像数据的实际载体,其生命周期由 BufferQueue 管理。
查找空闲槽位
上面的代码中有关键的一步,查找空闲槽位,waitForFreeSlotThenRelock函数,它的作用是在mSlot数组中查找FREE状态的slot,如果找到了就返回这个slot中的index
// 等待空闲缓冲区槽位并重新加锁的函数
// 这是BufferQueueProducer中获取可用缓冲区槽位的核心函数
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) {
// 1. 检查BufferQueue是否已被废弃
if (mCore->mIsAbandoned) {
BQ_LOGE("%s: BufferQueue has been abandoned", callerString);
return NO_INIT; // 返回初始化失败错误
}
// 2. 统计当前已出队和已获取的缓冲区数量
int dequeuedCount = 0; // 被生产者出队但尚未入队的缓冲区数量
int acquiredCount = 0; // 被消费者获取但尚未释放的缓冲区数量
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount; // 统计DEQUEUED状态的缓冲区
}
if (mSlots[s].mBufferState.isAcquired()) {
++acquiredCount; // 统计ACQUIRED状态的缓冲区
}
}
// 3. 检查是否超过最大可出队缓冲区数量限制
// 此检查仅在已有缓冲区入队后执行,防止生产者出队过多缓冲区
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
// 当超时时间为负数时,才输出错误日志(通常表示没有超时限制)
if (mDequeueTimeout < 0) {
BQ_LOGE("%s: attempting to exceed the max dequeued buffer "
"count (%d)", callerString,
mCore->mMaxDequeuedBufferCount);
}
return INVALID_OPERATION; // 返回无效操作错误
}
// 4. 初始化为无效槽位
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
// 5. 检查是否有过多缓冲区在队列中等待处理
// 在快速断开和重新连接的情况下,可能出现槽位为空但队列中有很多缓冲区的情况
const int maxBufferCount = mCore->getMaxBufferCountLocked(); // 获取最大缓冲区数量
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
BQ_LOGV("%s: queue size is %zu, waiting", callerString,
mCore->mQueue.size()); // 记录等待原因
} else {
// 6. 查找空闲槽位或缓冲区的逻辑
// 如果是共享缓冲区模式且存在共享缓冲区槽位,则总是返回共享槽位
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = mCore->mSharedBufferSlot; // 使用共享缓冲区槽位
} else {
// 根据调用者类型使用不同的查找策略
if (caller == FreeSlotCaller::Dequeue) {
// 从dequeue调用:优先查找已有缓冲区的空闲槽位
int slot = getFreeBufferLocked(); // 查找有缓冲区的空闲槽位
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot; // 使用找到的已有缓冲区的槽位
} else if (mCore->mAllowAllocation) {
// 如果允许分配新缓冲区,则查找完全空闲的槽位
*found = getFreeSlotLocked(); // 查找空闲槽位
}
} else {
// 从attach调用:优先查找完全空闲的槽位
int slot = getFreeSlotLocked(); // 查找空闲槽位
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot; // 使用找到的空闲槽位
} else {
// 如果没有空闲槽位,则查找已有缓冲区的空闲槽位
*found = getFreeBufferLocked();
}
}
}
}
// 7. 判断是否需要重新尝试(未找到槽位或缓冲区过多)
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
tooManyBuffers;
if (tryAgain) {
// 8. 非阻塞模式处理
// 如果处于非阻塞模式(由应用程序控制生产者和消费者)且已获取缓冲区数量未超过限制
if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK; // 返回阻塞错误
}
// 9. 等待条件满足
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; // 成功找到可用槽位
}
1. 函数作用
waitForFreeSlotThenRelock函数是 BufferQueueProducer 中获取可用缓冲区槽位的核心函数,负责在缓冲区槽位紧张时协调生产者和消费者,避免缓冲区过度分配和内存耗尽。
2. 缓冲区状态管理
函数内部维护了重要的缓冲区状态跟踪:
// 缓冲区状态转换图
FREE → DEQUEUED → QUEUED → ACQUIRED → FREE
-
dequeuedCount: 被生产者取出但尚未提交的缓冲区数量
-
acquiredCount: 被消费者获取但尚未释放的缓冲区数量
3. 主要逻辑流程
步骤1-2: 状态检查和统计
-
检查 BufferQueue 是否有效
-
统计当前处于不同状态的缓冲区数量
步骤3: 出队数量限制检查
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
return INVALID_OPERATION;
}
防止生产者一次出队过多缓冲区,可能导致:
-
内存浪费
-
消费者处理不及时
-
系统性能下降
步骤4-5: 缓冲区数量控制
bool tooManyBuffers = mCore->mQueue.size() > maxBufferCount;
控制队列中的缓冲区数量,防止生产者生产速度过快超过消费者处理能力。
步骤6: 槽位查找策略
根据调用者和模式使用不同查找策略:
| 调用者 | 优先级 | 策略说明 |
|---|---|---|
| dequeue | 1. getFreeBufferLocked 2. getFreeSlotLocked | 优先重用已有缓冲区的槽位,减少分配开销 |
| attach | 1. getFreeSlotLocked 2. getFreeBufferLocked | 优先使用完全空闲的槽位 |
步骤7-9: 等待机制
当没有可用槽位或缓冲区过多时:
-
非阻塞模式 : 立即返回
WOULD_BLOCK -
超时模式 : 等待指定时间后返回
TIMED_OUT -
阻塞模式: 无限等待直到条件满足
2.填充数据后返还给图形缓冲区
客户端/应用通过调用dequeueBuffer获取到一个可用的buffer后,就可以往这个buffer中填充数据了,在我们的demo中这一过程是在fillRGBA8Buffer函数内完成的,具体可见代码。 填充好数据后,就要把这个buffer再返还给BufferQueue,调用的方法是queueBuffer。
// 生产者将已填充数据的缓冲区入队的核心函数
// 这是BufferQueueProducer中处理生产者提交已完成渲染的缓冲区的关键函数
status_t BufferQueueProducer::queueBuffer(int slot, // 缓冲区槽位索引
const QueueBufferInput &input, // 入队输入参数(包含时间戳、裁剪、变换等信息)
QueueBufferOutput *output) { // 入队输出参数(包含帧号、尺寸等信息)
ATRACE_CALL(); // 开始性能追踪
ATRACE_BUFFER_INDEX(slot); // 追踪特定缓冲区的操作
// 1. 从输入参数中解析各种信息
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.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
// 获取表面损坏区域和HDR元数据
const Region& surfaceDamage = input.getSurfaceDamage();
const HdrMetadata& hdrMetadata = input.getHdrMetadata();
// 2. 验证acquireFence是否有效(生产者必须提供有效的栅栏)
if (acquireFence == nullptr) {
BQ_LOGE("queueBuffer: fence is NULL");
return BAD_VALUE; // 返回参数错误
}
// 3. 创建FenceTime对象用于追踪栅栏时间
auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);
// 4. 验证缩放模式是否有效
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:
BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
return BAD_VALUE; // 无效的缩放模式
}
// 5. 各种监听器和状态变量的声明
sp<IConsumerListener> frameAvailableListener; // 帧可用监听器
sp<IConsumerListener> frameReplacedListener; // 帧替换监听器
int callbackTicket = 0; // 回调票号(用于保证回调顺序)
uint64_t currentFrameNumber = 0; // 当前帧号
BufferItem item; // 缓冲区项(将添加到队列)
int connectedApi; // 连接的API类型
sp<Fence> lastQueuedFence; // 上一次入队的栅栏
// 6. 核心加锁范围(保护BufferQueue核心状态)
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 6.1 检查BufferQueue是否被废弃
if (mCore->mIsAbandoned) {
BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
// 6.2 检查生产者是否已连接
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("queueBuffer: BufferQueue has no connected producer");
return NO_INIT;
}
// 6.3 验证槽位索引有效性
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
}
// 6.4 验证缓冲区状态必须是DEQUEUED(否则生产者无权入队)
else if (!mSlots[slot].mBufferState.isDequeued()) {
BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
"(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
// 6.5 验证缓冲区是否已通过requestBuffer分配
else if (!mSlots[slot].mRequestBufferCalled) {
BQ_LOGE("queueBuffer: slot %d was queued without requesting "
"a buffer", slot);
return BAD_VALUE;
}
// 6.6 共享缓冲区模式特殊处理
// 如果刚启用共享缓冲区模式,标记第一个入队的缓冲区为共享缓冲区
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = slot;
mSlots[slot].mBufferState.mShared = true;
}
// 6.7 记录详细的入队日志
BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
" validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
transform,
BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
// 6.8 获取图形缓冲区并验证裁剪区域
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
Rect croppedRect(Rect::EMPTY_RECT);
crop.intersect(bufferRect, &croppedRect);
if (croppedRect != crop) {
BQ_LOGE("queueBuffer: crop rect is not contained within the "
"buffer in slot %d", slot);
return BAD_VALUE;
}
// 6.9 如果数据空间为未知,使用消费者默认值
if (dataSpace == HAL_DATASPACE_UNKNOWN) {
dataSpace = mCore->mDefaultBufferDataSpace;
}
// 6.10 更新缓冲区状态:保存栅栏,改变状态为QUEUED
mSlots[slot].mFence = acquireFence;
mSlots[slot].mBufferState.queue(); // 状态:DEQUEUED → QUEUED
// 6.11 递增帧计数器并保存当前帧号
++mCore->mFrameCounter;
currentFrameNumber = mCore->mFrameCounter;
mSlots[slot].mFrameNumber = currentFrameNumber;
// 6.12 准备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;
// 6.13 判断缓冲区是否可丢弃(多种条件)
item.mIsDroppable = mCore->mAsyncMode || // 异步模式
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) || // SurfaceFlinger消费者且允许丢弃
(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;
// 6.14 保存粘性变换
mStickyTransform = stickyTransform;
// 6.15 如果是共享缓冲区模式,缓存共享缓冲区数据以便重建BufferItem
if (mCore->mSharedBufferMode) {
mCore->mSharedBufferCache.crop = crop;
mCore->mSharedBufferCache.transform = transform;
mCore->mSharedBufferCache.scalingMode = static_cast<uint32_t>(scalingMode);
mCore->mSharedBufferCache.dataspace = dataSpace;
}
// 6.16 初始化输出参数
output->bufferReplaced = false;
// 6.17 队列处理逻辑
if (mCore->mQueue.empty()) {
// 队列为空:直接添加缓冲区项
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();
// 共享缓冲区模式特殊处理
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; // 标记缓冲区被替换
}
}
// 合并损坏区域(将被丢弃帧的损坏区域合并到新帧)
if (last.mSurfaceDamage.bounds() == Rect::INVALID_RECT ||
item.mSurfaceDamage.bounds() == Rect::INVALID_RECT) {
item.mSurfaceDamage = Region::INVALID_REGION;
} else {
item.mSurfaceDamage |= last.mSurfaceDamage;
}
// 覆盖可丢弃的缓冲区
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener; // 通知消费者帧被替换
} else {
// 最后一帧不可丢弃:添加到队列末尾
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener; // 通知消费者有新帧可用
}
}
// 6.18 更新BufferQueue状态
mCore->mBufferHasBeenQueued = true; // 标记已有缓冲区入队
mCore->mDequeueCondition.notify_all(); // 唤醒等待出队的生产者
mCore->mLastQueuedSlot = slot; // 记录最后入队的槽位
// 6.19 设置输出参数
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
// 6.20 性能追踪和占用率追踪
ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
// 6.21 获取回调票号(保证回调顺序)
callbackTicket = mNextCallbackTicket++;
VALIDATE_CONSISTENCY(); // 验证内部一致性
// 6.22 保存局部状态供锁外使用
connectedApi = mCore->mConnectedApi;
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
mLastQueuedCrop = item.mCrop;
mLastQueuedTransform = item.mTransform;
} // 自动锁作用域结束(释放核心锁)
// 7. 如果不是SurfaceFlinger消费者,清除GraphicBuffer引用
// SurfaceFlinger在同一进程,不需要通过Binder传递,可以保留引用
if (!mConsumerIsSurfaceFlinger) {
item.mGraphicBuffer.clear();
}
// 8. 更新帧事件历史
nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
NewFrameEventsEntry newFrameEventsEntry = {
currentFrameNumber,
postedTime,
requestedPresentTimestamp,
std::move(acquireFenceTime)
};
addAndGetFrameTimestamps(&newFrameEventsEntry,
getFrameTimestamps ? &output->frameTimestamps : nullptr);
// 9. 回调通知(持有回调锁但不持有核心锁)
{
std::unique_lock<std::mutex> lock(mCallbackMutex);
// 9.1 等待轮到自己进行回调(确保回调顺序)
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(lock);
}
// 9.2 执行回调
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item); // 通知新帧可用
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item); // 通知帧被替换
}
// 9.3 递增当前回调票号,唤醒等待的线程
++mCurrentCallbackTicket;
mCallbackCondition.notify_all();
}
// 10. EGL API的特殊处理:等待上一个入队的栅栏
if (connectedApi == NATIVE_WINDOW_API_EGL) {
// 这里等待允许排队两个完整的缓冲区,但不允许第三个
// 在帧时间变化的情况下,这种设计在延迟和吞吐量之间做了一个小的权衡,偏向于延迟
lastQueuedFence->waitForever("Throttling EGL Production");
}
return NO_ERROR; // 成功返回
}
1. 函数作用
BufferQueueProducer::queueBuffer是生产者-消费者模型中生产者提交已完成渲染的缓冲区的关键函数。它将一个已填充数据的缓冲区提交给 BufferQueue,供消费者(如 SurfaceFlinger)使用。
2. 在生产者-消费者流程中的位置
根据用户提供的图片,这个函数对应流程中的 queueBuffer操作:
Producer → BufferQueue → Consumer
↓
queueBuffer
↓
QUEUED BUFFER
3. 核心流程
步骤1-4: 参数解析与验证
-
从
QueueBufferInput解析各种渲染参数 -
验证
acquireFence必须有效(生产者必须提供同步栅栏) -
验证缩放模式等参数的有效性
步骤5-6: 核心加锁处理
这是函数最复杂的部分,包含:
-
状态验证:检查 BufferQueue 状态、生产者连接、槽位有效性
-
共享缓冲区处理:如果是第一个入队的共享缓冲区,标记它
-
参数验证:验证裁剪区域在缓冲区内
-
状态更新:缓冲区状态从 DEQUEUED 变为 QUEUED
-
BufferItem创建:创建队列项,包含所有渲染参数
-
队列管理:处理可丢弃缓冲区的替换逻辑
步骤7-10: 锁外处理
-
资源清理:如果不是 SurfaceFlinger,清理缓冲区引用
-
时间戳更新:记录帧事件时间戳
-
回调通知:通知消费者有新帧可用或帧被替换
-
EGL同步:如果是 EGL API,进行特殊同步处理
到此queueBuffer 就分析完了。其中会调用了mCore->mConsumerListener; 的回调接口,来通知consumer消费数据,那么这个回调接口是在何时被传入的,接口的是什么? 这个疑问留到下一篇单独讲解。
三.总结
本文主要聚焦生产者一端的处理逻辑,分析了如何获取buffer以及填充数据后返还buffer的流程。下一篇来介绍消费者一端的处理逻辑