当前位置: 首页 > news >正文

SurfaceFlinger BufferQueue(三) DequeueBuffer

上一篇介绍了BufferQueue初始化相关的内容,本篇开始了解DequeueBuffer流程。

1. Surface dequeueBuffer

在SurfaceFlinger BufferQueue(一) App绘制
这一篇中了解到App draw流程中,会走到frameworks/native/libs/gui/Surface.cpp的dequeueBuffer函数中。

// frameworks/native/libs/gui/Surface.cpp
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,dqInput.height, dqInput.format,dqInput.usage, &mBufferAge,dqInput.getTimestamps ?&frameTimestamps : nullptr);...sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);...result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);...*buffer = gbuf.get();
}

mGraphicBufferProducer是BlastBufferQueue.createSurface();时,把自己的mProducer传递给Surface的。因此我们来看下BufferQueueProducer.cpp的dequeueBuffer处理。

2. dequeueBuffer

dequeueBuffer函数非常长,所以我打算一部分一部分贴出来分析。

2.1 waitForFreeSlotThenRelock

// frameworks/native/libs/gui/BufferQueueProducer.cppstatus_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;while (found == BufferItem::INVALID_BUFFER_SLOT) {status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);

found初始值被赋值为INVALID_BUFFER_SLOT = -1;然后进入waitForFreeSlotThenRelock函数,第一个参数是Dequeue.

frameworks/native/libs/gui/BufferQueueProducer.cppstatus_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,std::unique_lock<std::mutex>& lock, int* found) const {...int dequeuedCount = 0;int acquiredCount = 0;// mark 1for (int s : mCore->mActiveBuffers) {if (mSlots[s].mBufferState.isDequeued()) {++dequeuedCount;}if (mSlots[s].mBufferState.isAcquired()) {++acquiredCount;}}...// mark 2if (caller == FreeSlotCaller::Dequeue) {// If we're calling this from dequeue, prefer free buffers// mark 3int slot = getFreeBufferLocked();if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {*found = slot;} else if (mCore->mAllowAllocation) {// mark 4*found = getFreeSlotLocked();}} else {// If we're calling this from attach, prefer free slotsint slot = getFreeSlotLocked();if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {*found = slot;} else {*found = getFreeBufferLocked();}}}}...return NO_ERROR;}
  • 在上一篇讲BufferQueueCore初始化的时候,我们聊到了各个内部成员的初始值。mActiveBuffers是一个int 类型的 set集合,在BufferQueueCore初始化时,并没有给它赋值,所以它是空的,上面的mark 1不会走。
  • dequeueBuffer在调用waitForFreeSlotThenRelock的时候,第一个参数是Dequeue,所以mark 2会走进来。
  • 进入mark 3 getFreeBufferLocked会从mFreeBuffers里取找,但在BufferQueueCore初始化时,并没有给它赋值,所以它也是空的。
    返回invalid。于是走进mark 4
// frameworks/native/libs/gui/BufferQueueProducer.cppint BufferQueueProducer::getFreeSlotLocked() const {if (mCore->mFreeSlots.empty()) {return BufferQueueCore::INVALID_BUFFER_SLOT;}int slot = *(mCore->mFreeSlots.begin());mCore->mFreeSlots.erase(slot);return slot;}

BufferQueueCore初始化时, mFreeSlots里有3个成员,分别对应BufferQueueCore.mSlots[0] ~ BufferQueueCore.mSlots[2]
这里取mFreeSlots集合的首元素赋值给slot并返回。并且删除mFreeSlots首元素。
getFreeSlotLocked返回值又赋值给了dequeueBuffer传入进来的found, 此时found != -1 了.
图1

2.2 mSlots update

回到BufferQueueProducer::dequeueBuffer 继续看下一段代码。

			// mark 1const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);...// mark 2if (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}*outSlot = found;ATRACE_BUFFER_INDEX(found);...// mark 3mSlots[found].mBufferState.dequeue();if ((buffer == nullptr) ||buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)){// mark 4mSlots[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;} 
  • ** mark 1**处found是上一小节找到的mSlots下角标0,mSlots[0]里面存的是BufferSlot对象,BufferSlot是一个结构体,内部成员mGraphicBuffer初始值等于null,所以sp指针buffer此时指向null. 另外将outSlot指向buffer, *outSlot也就等于1.
  • mSharedBufferSlot在share mode下才会被赋值,后面遇到再说,mSharedBufferSlot也是在BufferQueueCore是被初始化为-1,所以mark 2会走进来,mActiveBuffers集合插入元素found(0).
  • ** mark 3** 目的是为了更新BufferSlot状态,BufferState的dequeue函数会调用mDequeueCount++; 根据BufferSlot.h的注释,可以知道此时mSlots[0]中BufferSlot的状态是DEQUEUED
//         | 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      |

那么此时我们再更新一下我们的图,就会是:
图2

  • buffer为空,所以* mark 4**走进来,更新mSlots各个变量。值得关注的是给returnFlags |= BUFFER_NEEDS_REALLOCATION, 这个后面会用到。

2.3 new GraphicBuffer

继续分析BufferQueueProducer::dequeueBuffer

	// mark 1if (returnFlags & BUFFER_NEEDS_REALLOCATION) {BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage,{mConsumerName.string(), mConsumerName.size()});status_t error = graphicBuffer->initCheck();

在2.2的最后介绍到returnFlags |= BUFFER_NEEDS_REALLOCATION,所以mark 1的if条件可以走进来,在其中new了GraphicBuffer。
在2.2小节mark 1处,outSlot被指向found,所以此处代码就是mSlots[0].mGraphicBuffer = graphicBuffer mSlots的第一个元素BufferSlot的mGraphicBuffer也终于不为null了,而是指向刚申请的GraphicBuffer。 在 GraphicBuffer 的构造函数中会通过 Binder IPC 通知 HAL 调用 Gralloc 来真正分配实际物理内存,并这块内存的"句柄"给 GraphicBuffer。

2.4 onFrameDequeued

        { // Autolock scopestd::lock_guard<std::mutex> lock(mCore->mMutex);if (error == NO_ERROR && !mCore->mIsAbandoned) {graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);// mark 2mSlots[*outSlot].mGraphicBuffer = graphicBuffer;if (mCore->mConsumerListener != nullptr) {mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId());}}

我们分析的BufferQueueProducer::dequeueBuffer 的最后一段代码。
在上一篇文章介绍过,在BLASTBufferQueue构造函数中,会创建BLASTBufferItemConsumer对象,它的父类的父类ConsumerBase在构造函数中会调用mConsumer->consumerConnect(proxy, controlledByApp);将自己注册给BufferQueueCore的mConsumerListener。
那么上面这段代码其实就会走到ConsumerBase的onFrameDequeued函数。

// frameworks/native/libs/gui/ConsumerBase.cppvoid ConsumerBase::onFrameDequeued(const uint64_t bufferId) {CB_LOGV("onFrameDequeued");sp<FrameAvailableListener> listener;{Mutex::Autolock lock(mFrameAvailableMutex);listener = mFrameAvailableListener.promote();}if (listener != nullptr) {listener->onFrameDequeued(bufferId);}
}

ConsumerBase::onFrameDequeued又调用了mFrameAvailableListener的onFrameDequeued,mFrameAvailableListener是BLASTBufferQueue在构造函数中,注册进来的:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name): mSurfaceControl(nullptr),mSize(1, 1),mRequestedSize(mSize),mFormat(PIXEL_FORMAT_RGBA_8888),mNextTransaction(nullptr) {createBufferQueue(&mProducer, &mConsumer);mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,GraphicBuffer::USAGE_HW_COMPOSER |GraphicBuffer::USAGE_HW_TEXTURE,1, false, this);// 在这里将BLASTBufferQueue自己注册给ConsumerBase的mFrameAvailableListenermBufferItemConsumer->setFrameAvailableListener(this);}

所以最后会回调到BLASTBufferQueue的onFrameDequeued

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) {std::unique_lock _lock{mTimestampMutex};mDequeueTimestamps[bufferId] = systemTime();
};

这里就是记录一下被dequeuq buffer的时间戳。

3 requestBuffer

回到第一章节中,在Surface.cpp的dequeueBuffer中,最后调用了BufferQueueProducer的requestBuffer

// frameworks/native/libs/gui/BufferQueueProducer.cppstatus_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {...mSlots[slot].mRequestBufferCalled = true;*buf = mSlots[slot].mGraphicBuffer;return NO_ERROR;
}

这个就比较简单了,第一个参数就是上面第二章节中找到的found,把它传入进来,然后将mSlots[slot].mGraphicBuffer
赋值给第二个参数buf,这样Surface就拿到了申请到的GraphicBuffer。

http://www.dtcms.com/a/428342.html

相关文章:

  • AI智能体(Agent)大模型入门【4】--下载训练好的大模型部署到本地上
  • 网站tkd怎么做学做烘培的网站
  • 肇庆网站制作费用wordpress 开源主题
  • 【开题答辩全过程】以 NBA球星管理系统为例,包含答辩的问题和答案
  • asp.net中文官方网站江门市网站建设公司
  • 网站开发费用报价单硬件开发学什么专业
  • 网站外链怎么购买建设网站基本步骤
  • 临沧网站建设公司佛山网站建设公司价格
  • 惠海 48V 60V 80V 降 3.3V 5V 9V 12V电动车/摩托车整车芯片解决方案(下)
  • 做网站用小动画网络公司 建站 官方网站
  • 储卡器底部塑料壳外部细节建模实战分享|附完整视频教程
  • android源码下载网站宁波seo关键词费用
  • 福州做网站哪家最好不利于优化网站的因素
  • 矩阵运算:深度学习的数学基石与手工实现解析
  • 自己做的网站网站搜索潍坊程序设计网站建设公司
  • 修改网站照片需要怎么做电子商务网站前台业务系统主要是
  • 河南洛阳网站建设做个网站上百度怎么做
  • 公司品牌营销策划龙岗网站优化培训
  • 成都做营销型网站wordpress s3插件
  • html5网站正在建设中模板下载建设企业网站个人网银
  • 提高wordpress网站母婴的网站建设
  • 网站搜索引擎优化诊断公司网站开发费用济南兴田德润o评价
  • 网站上传页面ps怎样做网站大图
  • 网站建设专业可行性分析wordpress 删除版权信息
  • 深圳宝安专业做网站公司北京正邦设计
  • linux can子系统学习
  • 门户网站开发投标文件.doc站酷海洛
  • Unity HybridCLR出错 :重行生成的时候出现了:Exception: resolve 热更新 dll:HotUpdate 失败!
  • web表单提交和表单序列化的多种方式总结
  • 一路商机网化妆品网站优化