忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
-- 服装学院的IT男
Surface系统-1-应用与SurfaceFlinger建立链接
Surface系统-2-SurfaceControl的创建(java层)
Surface系统-3-SurfaceControl的创建(native层)
Surface系统-4-BLASTBufferQueue和Surface的创建
Surface系统-5-BLASTBufferQueue工作流程概览
本篇同时已收录于Activity短暂的一生系列
正文
Surface 系统工作模式就是个生产消费者模型,其中涉及到的几个类之前也大概介绍过。
本来对4个关键方法介绍一下,对整个模型有个概念
下面的代码以软绘的流程来分析
1 软绘流程简述
#ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
//持有的画布
final Canvas canvas;
...
try {
...
//1. 申请画布对象,该画布初始大小为dirty的尺寸
canvas = mSurface.lockCanvas(dirty);
//设置密度
canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
...
} catch (IllegalArgumentException e) {
...
return false;
} finally {
...
}
try {
......
// 2. DecorView draw()方法
mView.draw(canvas);
......
} finally {
try {
// 3. 提交绘制的内容到Surface
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
...
}
}
return true;
}
软绘分3步: 1. canvas = mSurface.lockCanvas(dirty); 申请画布,获取canvas对象 2. mView.draw(canvas); View 树绘制 3. surface.unlockCanvasAndPost(canvas); 绘制完提交
其中第一步对应 BufferQueueProducer::dequeueBuffer 流程,等应用绘制完之后需要显示了,第三步对应 BufferQueueProducer::queueBuffer 将 buff 放回集合,等待消费者拿去给 SurfaceFlinger 合成。
2. dequeueBuffer 获取 buff
2.1 Surface::lockCanvas 获取一个 canvas
这一步从 Surface::lockCanvas 开始分析
# Surface
// 内部的 canvas
private final Canvas mCanvas = new CompatibleCanvas();
// native层的句柄
long mNativeObject; // package scope only for SurfaceControl access
public Canvas lockCanvas(Rect inOutDirty)
throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
......
// 打印
Log.d(TAG, "lockCanvas");
......
// 进入native层
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}
这里就直接进入native方法了,注意下参数。
# android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
// 拿到 native 层 Surface
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
......
// 定义一个buff,这个很重要,因为View绘制的内容都保存在这个buff上
ANativeWindow_Buffer buffer;
// 1. 获取surface的缓冲区
status_t err = surface->lock(&buffer, dirtyRectPtr);
......// 如果获取失败则抛出异常
// 2. 创建一个Graphics Canvas对象, 参数为对应的java层canvas
graphics::Canvas canvas(env, canvasObj);
// 3. 将 buffer设置到canvas中
canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
......
// 4. 创建一个名为 lockedSurface 的智能指针对象,并将其指向 surface
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
// 返回一个对Surface对象的引用
return (jlong) lockedSurface.get();
}
-
- 通过 Surface::lock 获取一块存放绘制数据段buff
-
- 创建一个canvas,这个canvas对应着参数传进来的java层的canvas (这里的canvas实际是SkiaCanvas)
-
- 将 buff 设置给 canvas
-
- 返canva给 java 层进行绘制,后续的绘制内容都将保存在 canvas 下的 buff 中
这么一来,java 层的 Canvas 就有一个从 Surface 中获取的 buff ,这个 buff 可以存放绘制数据。后续 View::Draw 流程会用这个 Canvas 进行绘制,绘制的数据都将保存到这块 buff 中。
这里的 buff 是 ANativeWindow_Buffer 类型,上篇看到的是GraphicBuffer。它们之间有什么关系,也是后面需要关注的一个点。
当前顺着主线继续看 Surface::lock 的实现。
# Surface.h
// must be used from the lock/unlock thread
// 重点* 1. 当前正在使用的buff
sp<GraphicBuffer> mLockedBuffer;
//上一次提交的buff
sp<GraphicBuffer> mPostedBuffer;
# Surface.cpp
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
/ 重点* 2. 如果当前有已经在使用的buff
if (mLockedBuffer != nullptr) {
ALOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
......
// 定义一个buff
ANativeWindowBuffer* out;
int fenceFd = -1;
// 重点* 3. 取出一个buff
status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
// 转换成当前要处理的GraphicBuffer
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
......// 重点* 4. 省略从判断是否能从上一帧buff copy 数据逻辑
// 重点* 5. 锁定buff
void* vaddr;
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
......
if (res != 0) {
err = INVALID_OPERATION;
} else {
// 将获取的buff设置给mLockedBuffer
mLockedBuffer = backBuffer;
// 重点* 6. 将获取的buff的属性设置给出参
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
// vaddr赋值给bits
outBuffer->bits = vaddr;
}
}
return err;
}
-
- Surface下定义了一个 GraphicBuffer 变量:mLockedBuffer,表示当前真正锁定(使用)的是哪个 buff ,这个值在 unlockCanvasAndPost 会置为 null
-
- 在 Surface::lock 方法首先会判断当前 mLockedBuffer 是否有值,有的话就不需要执行后续逻辑了
-
- 通过 Surface::dequeueBuffer 取出一块 buff ,内部还是 GBP 来实现
-
- 不是每次刷新都会全部重绘整个区域,所以中间省略的代码是判断是否可以从上一帧 copy 一些可以复用的数据。这部分代码不是这次重点,所以省略
-
- GraphicBuffer 一般简称为 buff ,首先他本来只是一个数据结构,但是他为什么这么重要,能作为图像数据的载体,本质原因还是因为其内部的bits变量代表着一块内存区域。这也是为什么被简称为 buff 的原因,android 是基于 linux 的,在 linux 中 buff 代表一块和内存缓存相关的内容。这一步是锁定一块内存区域,在下一步会设置给 GraphicBuffer
-
- 将 backBuffer 的数据设置给出参,也就是最终被设置给 canvas 的那个 buff ,这里要着重注意 bit s的赋值 至于GraphicBuffer的这块区域是怎么设置给canvas的,是**通过 SkBitmap::setPixels 方法将这块内存地址设置给 canvas 下的 bitmap **
其中 GraphicBuffer::lockAsync 就是锁定一块内存区域的方法没什么好看的,主要还是看 Surface::dequeueBuffer 是如何获取一块 buff 的。
2.2 dequeueBuffer
# Surface.cpp
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
// 代表的是mSlots的角标
int buf = -1;
......
// 获取buff
// Surface 下的 mGraphicBufferProducer 变量在构造的时候就赋值了,这个代码之前看过了。
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
dqInput.height, dqInput.format,
dqInput.usage, &mBufferAge,
dqInput.getTimestamps ?
&frameTimestamps : nullptr);
// 获取对应位置的GraphicBuffer
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
......
// 申请空间,映射内存区(可能也不是)
ALOGE("Surface::requestBuffer"); // 自己加的日志
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
......
// 出参赋值
*buffer = gbuf.get();
......
}
知道这个方法的目标就是给参数 buffer 赋值,将定义在 BLASTBufferCore 下的 mSlots 数组下某一块 GraphicBuffer 赋值给它。
-
- 定义一个 int 值,代表后续返回的 buff 所在集合的位置
-
- 通过 GraphicBufferProducer::dequeueBuffer 获取一个可用的 buff
-
- 定义变量 gbuf,其值为 GraphicBufferProducer::dequeueBuffe 方法执行后 mSlots 对应位置的 GraphicBuffer
-
- IGraphicBufferProducer::requestBuffer 这个方法目前没太看明白,后面单独讲
-
- 将 buff 设置给出参参数,也是这个方法最终的目的:获取一个可用的 buff
那么这个方法关注的重点就是 BufferQueueProducer::dequeueBuffer 方法是怎么获取一个 buff 的。
2.3 BufferQueueProducer::dequeueBuffer (重点)
这个方法也是最终的重点,是要分析的4个方法之一。
# BufferQueueProducer.cpp
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) {
......
// 定义局部变量,表示mSlots的哪个位置下的buff可以使用
int found = BufferItem::INVALID_BUFFER_SLOT;
// 找到空闲的Slot并锁定
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
......
}
......
// 设置给出参
*outSlot = found;
......
// 设置这个位置的buff状态为DEQUEUE
mSlots[found].mBufferState.dequeue();
......
// 判断是否需要分配 需要则分配
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
// 打印log
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
// 新建一个GraphicBuffer
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
......
// 放入对应的BufferSLot中
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
......
}
......
}
BufferQueueProducer::dequeueBuffer 方法主要是给参数 outSlot 赋值,确认可以使用 mSlots 下的哪个 GraphicBuffer 。
-
- 定义局部变量 found,然后开始执行 waitForFreeSlotThenRelock 方法来查找哪个卡槽的可以使用,如果找到了就将位置设置给 found
-
- 将 found 设置给出参
-
- 设置这个位置的 buff 状态为 DEQUEUE
-
- 如果需要重新分配则新建一个 GraphicBuffer 放到 mSlots 对应的位置下
总之这个方法执行完后,可以知道 mSlots 下哪个位置 的GraphicBuffer 是可用的。
2.4 小结
BufferQueueProducer::dequeueBuffer 逻辑是生成消费者模型的第一步,对应 APP 开发来说就是一个 View 树绘制前,获取 canvas 的步骤。
这里有以下几个注意点:
-
- 方法主要功能就是获取一个可以用的 buff 给生产者绘制 UI
-
- 获取的来源是通过 GraphicBufferProducer::dequeueBuffer,从 mSlots 中获取
-
- 将 mSlots 对应位置的 buff 状态设置为 DEQUEUE
-
- mSlots 之前分析过,实际上定义在 BLASTBufferCore下的, 因为GraphicBufferProducer是其友元类,并且构造的时候也有将GraphicBufferProducer传递进去,所以能直接访问
-
- GraphicBufferProducer 作为 buff 的生产者,面向的是上层应用端,另外他操作的对象本质上是 BLASTBufferCore 下的 mSlots
这部分的调用栈如下:
ViewRootImpl::drawSoftware
Surface::lockCanvas
android_view_Surface::nativeLockCanvas -- JNI
Surface::lock -- 获取一个有buff的canvas
Surface::dequeueBuffer
BufferQueueProducer::dequeueBuffer -- dequeueBuffer
BufferState::dequeue -- 设置状态 DEQUEUE
其中还有很多细节没分析,比如是怎么从 BLASTBufferCore 获取 buff 的,这个也是一个核心逻辑。
3. queueBuffer
上传通过 BufferQueueProducer::dequeueBuffer 获取到 buff 后会进行绘制,绘制完需要提交到屏幕上,所以绘制完就需要执行 BufferQueueProducer::queueBuffer 来通知整个生成消费模式有个 buff 已经绘制好了。
还是和之前一样已软绘为例,这一步的触发逻辑是 Surface::unlockCanvasAndPost
# Surface
public void unlockCanvasAndPost(Canvas canvas) {
synchronized (mLock) {
checkNotReleasedLocked();
if (mHwuiContext != null) {
mHwuiContext.unlockAndPost(canvas);
} else {
// 软绘正常走这
unlockSwCanvasAndPost(canvas);
}
}
}
private void unlockSwCanvasAndPost(Canvas canvas) {
......
try {
// 执行native方法
nativeUnlockCanvasAndPost(mLockedObject, canvas);
} finally {
nativeRelease(mLockedObject);
mLockedObject = 0;
}
}
JNI 的实现在 android_view_Surface.cpp
# android_view_Surface.cpp
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj) {
// 拿到 native 层 Surface
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
return;
}
// detach the canvas from the surface
graphics::Canvas canvas(env, canvasObj);
// 将 canvas 下的 buff 置空 (将Canvas与Surface分离)
canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
// unlock surface
// 重点* 解锁 Surface 并将绘图缓冲区提交到 Surface
status_t err = surface->unlockAndPost();
if (err < 0) {
jniThrowException(env, IllegalArgumentException, NULL);
}
}
重点看 Surface::unlockAndPost 方法,
# Surface.cpp
status_t Surface::unlockAndPost()
{
// mLockedBuffer不能为null
if (mLockedBuffer == nullptr) {
ALOGE("Surface::unlockAndPost failed, no locked buffer");
return INVALID_OPERATION;
}
int fd = -1;
// 解锁内存
status_t err = mLockedBuffer->unlockAsync(&fd);
ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
// 重点 * 入队
err = queueBuffer(mLockedBuffer.get(), fd);
ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
// 赋值
mPostedBuffer = mLockedBuffer;
// 置空
mLockedBuffer = nullptr;
return err;
}
可以看得出来这里的操作和 Surface::lock 的对应的。 重点方法 BufferQueueProducer::queueBuffer 来了。
# BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
......
// 重点* 1. 局部变量
BufferItem item;
......
// 拿到buff (根据下标)
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
......
// 重点* 2. 设置状态为QUEUE
mSlots[slot].mBufferState.queue();
......
// 将buff设置到临时变量item中
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
......// 其他属性的处理
// 重点* 3. 入队处理
if (mCore->mQueue.empty()) {
// When the queue is empty, we can ignore mDequeueBufferCannotBlock
// and simply queue this buffer
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
} else {
// When the queue is not empty, we need to look at the last buffer
// in the queue to see if we need to replace it
// 翻译:当队列不为空时,我们需要查看最后一个缓冲区,在队列中查看是否需要更换
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
......
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener;
} else {
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
}
}
......
if (frameAvailableListener != nullptr) {
// 重点* 4. 触发回调,告知Consumer
frameAvailableListener->onFrameAvailable(item);
} .......
......
}
-
- 定义BufferItem类型的局部变量item, 这个对象后面会被添加到BLASTBufferCore下的mQueue中。 (mQueue这个队列的元素是BufferItem,定义在BufferQueueCore.h下)
-
- 将 mSlots 对应位置的buff状态设置为QUEUE
-
- BufferItem的入队处理,这里分为3种情况。但是目的都是一样
- 3.1 BufferItem放入mQueue
- 3.2 frameAvailableListener赋值,用于后续通知Consumer
-
- 通知 Consumer(消费者) buff已经准备好了可以拿去给 SurfaceFlinger 进行合成了
经过应用绘制后的数据,会单独构造出一个 BufferItem 放在 mQueue 下,这个 BufferItem 内部也保存了 buff 信息。
3.1 小结
BufferQueueProducer::queueBuffer 和 BufferQueueProducer::dequeueBuffer 的操作是对立的,也比较好理解。 最后是执行了 “frameAvailableListener->onFrameAvailable(item);” ,当一块 buff 绘制好后,生产者的工作就完成了,后面就要交给消费者来处理,最终的目的就把这个 buff 拿给 SurfaceFlinger 最终交给屏幕显示。
而最终执行这个回调的方法是 BLASTBufferQueue::onFrameAvailable ,这个在 BLASTBufferQueue 构造方法里设置的监听,之前分析过。
这部分的调用栈如下:
ViewRootImpl::drawSoftware
Surface::lockCanvas
View::draw
Surface::unlockCanvasAndPost
Surface::unlockSwCanvasAndPost
Surface::nativeUnlockCanvasAndPost -- 开始进入native层
android_view_Surface::nativeUnlockCanvasAndPost
Surface::unlockAndPost
Surface::queueBuffer
BufferQueueProducer::queueBuffer
BufferState::queue -- 设置状态 QUEUE
BLASTBufferQueue::onFrameAvailable -- 通知消费者
结合前面获取 buff 的堆栈,完整调用链如下:
ViewRootImpl::drawSoftware
Surface::lockCanvas
android_view_Surface::nativeLockCanvas -- JNI
Surface::lock -- 获取一个有buff的canvas
Surface::dequeueBuffer
BufferQueueProducer::dequeueBuffer -- dequeueBuffer
BufferState::dequeue -- 设置状态 DEQUEUE
BufferQueueProducer::requestBuffer
GraphicBuffer::lockAsync -- 锁定一块内存给GraphicBuffer
View::draw
Surface::unlockCanvasAndPost
Surface::unlockSwCanvasAndPost
Surface::nativeUnlockCanvasAndPost -- 开始进入native层
android_view_Surface::nativeUnlockCanvasAndPost
Surface::unlockAndPost
Surface::queueBuffer
BufferQueueProducer::queueBuffer
BufferState::queue -- 设置状态 QUEUE
BLASTBufferQueue::onFrameAvailable -- 通知消费者
4. acquireBuffer
BufferQueueProducer::queueBuffer 将有数据的 buff 包装成一个 BufferItem 放在 mQueue 后会触发 BLASTBufferItemConsumer::onFrameAvailable 回调来告知监听者有数据的 buff 已经拿到了,各位该干活了。
这个 BLASTBufferItemConsumer 是在 BLASTBufferQueue 创建的时候构建的,BufferQueueProducer::queueBuffer 中通过"mCore->mConsumerListener"来获取的监听者其实就是BLASTBufferItemConsumer,构建的时候调用了 BLASTBufferItemConsumer::setFrameAvailableListener 传递了“this”,也就是设置监听者为 BLASTBufferQueue。 也就是说 BufferQueueProducer::queueBuffer 中触发的 onFrameAvailable 回调执行是在 BLASTBufferQueue::onFrameAvailable 中。
# BLASTBufferQueue.cpp
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
......
// 最终会提交给 SurfaceFlinger 合成
acquireNextBufferLocked(std::nullopt);
......
}
忽略其他只看当前分析的主线
# BLASTBufferQueue.cpp
status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
......
// 准备事务对象 Transaction
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
if (transaction) {
t = *transaction;
applyTransaction = false;
}
......
// 1. 调用 acquireBuffer 函数 从队列中获取到一个 BufferItem 对象
BufferItem bufferItem;
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
......
// 拿到buff
auto buffer = bufferItem.mGraphicBuffer;
// t 是准备提交给 SurfaceFlinger 的事务对象
// 根据 bufferItem 来配置
......
// 2. SurfaceFliger 完成消费后回调,释放这个buff
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
......
// 3. 注意这里传入了回调对象和buff
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
......// 忽略一大堆 事务的配置
mergePendingTransactions(t, bufferItem.mFrameNumber);
if (applyTransaction) { // 进入分支
// All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
// 4. 提交事务 apply
t->setApplyToken(mApplyToken).apply(false, true);
mAppliedLastTransaction = true;
mLastAppliedFrameNumber = bufferItem.mFrameNumber;
} else {
......
}
......
return OK;
}
这个方法很长,目前简单整理出3步:
-
- 通过 GraphicBufferConsumer::acquireBuffer 获取到buff 这个也是本次分析的重点
-
- 构建了 releaseBuffer 回调
-
- 构建一个事务,并且将 buff 和回调设置了进去
-
- 执行事务,后面逻辑会触发 SurfaceFlinger 相关方法最终申请 Vsync 完成上帧
目前只看 BufferItemConsumer::acquireBuffer 方法,看看是怎么给参数 bufferItem 赋值的
# BufferItemConsumer.cpp
status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
nsecs_t presentWhen, bool waitForFence) {
......
// 这个方法定义在父类中
err = acquireBufferLocked(item, presentWhen);
......
// 拿到对应的 buff 赋值给参数
item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer;
return OK;
}
# ConsumerBase.cpp
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
......
// 这个 mConsumer 是 BufferQueueConsumer
status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
......
}
这里经过 ConsumerBase::acquireBufferLocked 处理后 “item->mSlot” 已经有值了,再将对应下标的 mGraphicBuffer 赋值给参数流程就结束了。
4.1 BufferQueueConsumer::acquireBuffer
经过上面的调用终于来到了 BufferQueueConsumer::acquireBuffer 方法。
# BufferQueueConsumer.cpp
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
......
// 获取mQueue队列的迭代器
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
......
// 迭代mQueue元素
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
.......
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// 初始化一个无效的缓冲区插槽变量
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
// 一些检查
if (sharedBufferAvailable && mCore->mQueue.empty()) {
......
} else if {
......
} else {
// 获取当前缓冲区的插槽,并将当前缓冲区的属性复制到输出缓冲区中
slot = front->mSlot;
*outBuffer = *front;
}
......
// 2个方法都是将状态改为 ACQUIRED
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
mSlots[slot].mBufferState.acquire();
}
......
if (outBuffer->mAcquireCalled) {
// 对应BufferItem下的buff置空
outBuffer->mGraphicBuffer = nullptr;
}
// 将 Buffer 从 mQueue 中移除
mCore->mQueue.erase(front);
......
return NO_ERROR;
}
-
- 将 mSlots 对应位置的 BufferState 改为 ACQUIRED 状态
-
- 将该 Buffer 从 mQueue 中移除
4.2 小结
这部分是应用完成会之后,由消费者拿着 buff 去使用的逻辑,目前只简单看了一下 BufferQueueConsumer::acquireBuffer 逻辑,完整的逻辑后面还应该有 SurfaceFlinger 的流程已经 HWC 合成。
这部分调用栈如下:
BufferQueueProducer::queueBuffer -- 生产者绘制完成
BLASTBufferQueue::onFrameAvailable
BLASTBufferQueue::acquireNextBufferLocked
BufferItemConsumer::acquireBuffer
ConsumerBase::acquireBufferLocked
BufferQueueConsumer::acquireBuffer
BufferState::acquire -- 状态改为 ACQUIRED
BLASTBufferQueue::onBufferReleased -- 最终会通知到SurfaceFlinger
SurfaceComposerClient::Transaction::init -- 构建提交给 SF 的事务
SurfaceComposerClient::Transaction::apply -- 提交
5. releaseBuffer
# BLASTBufferQueue.cpp
static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
sp<BLASTBufferQueue> blastBufferQueue = context.promote();
if (blastBufferQueue) {
// 走这
blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
} else {
ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
}
}
void BLASTBufferQueue::releaseBufferCallback(
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
std::lock_guard _lock{mMutex};
BBQ_TRACE();
releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount,
false /* fakeRelease */);
}
void BLASTBufferQueue::releaseBufferCallbackLocked(
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount, bool fakeRelease) {
......
// 主线
releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
......
}
void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId,
const sp<Fence>& releaseFence) {
......
ALOGE("biubiubiu C++ BLASTBufferQueue::releaseBuffer");
mNumAcquired--;
BBQ_TRACE("frame=%" PRIu64, callbackId.framenumber);
BQA_LOGV("released %s", callbackId.to_string().c_str());
// 调用到 BufferQueueConsumer
mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
mSubmitted.erase(it);
// Remove the frame number from mSyncedFrameNumbers since we can get a release callback
// without getting a transaction committed if the buffer was dropped.
mSyncedFrameNumbers.erase(callbackId.framenumber);
}
5.1 BufferQueueConsumer::releaseBuffer
SurfaceFlinger 使用完buff后,需要将buff 进行释放,这一步由 BufferQueueConsumer::releaseBuffer 完成
# BufferQueueConsumer.cpp
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
......
sp<IProducerListener> listener;
......
// 释放,FREE 状态
mSlots[slot].mBufferState.release();
if (!mSlots[slot].mBufferState.isShared()) {
// 从mActiveBuffers中移除
mCore->mActiveBuffers.erase(slot);
// 加入到mFreeBuffers中
mCore->mFreeBuffers.push_back(slot);
}
......
if (listener != nullptr) {
// 回调
listener->onBufferReleased();
}
return NO_ERROR;
}
-
- 将 BufferState 改为 FREE 状态,
-
- 将 BufferlSlot 放在 mFreeBuffers 集合
这部分调用链如下:
BLASTBufferQueue::releaseBufferCallbackThunk
BLASTBufferQueue::releaseBufferCallback
BLASTBufferQueue::releaseBufferCallbackLocked
BLASTBufferQueue::releaseBuffer
BufferQueueConsumer::releaseBuffer