版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android6.0 显示系统(三) 管理图像缓冲区一、BufferQueueCore BufferQueueProducer BufferQueueConsumer上篇博客在Layer的onFirstRef函数中,调用了下面函数,创建了3个对象BufferQueueCore BufferQueueProducer BufferQueueConsumer。其中BufferCore是核心,把BufferQueueProducer和BufferQueueConsumer对象连接在一起。cpp view plain copy 在CODE上查看代码片派生到我的代码片void BufferQueue:c
2、reateBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, const sp<IGraphicBufferAlloc>& allocator) sp<BufferQueueCore> core(new BufferQueueCore(allocator); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core); s
3、p<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core); *outProducer = producer; *outConsumer = consumer; 1.1 生产者和core的联系IGraphicBufferProducer 的大致接口如下,BufferQueueProducer类是接口IGraphicBufferProducer 的实现,使用BufferQueueProducer之前先要调用connect函数,使用结束后调用disconnect断开连接。cpp view plain copy 在CO
4、DE上查看代码片派生到我的代码片class IGraphicBufferProducer : public IInterface public: virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0; virtual status_t setBufferCount(int bufferCount) = 0; virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, uint32_t w, uint32_
5、t h, PixelFormat format, uint32_t usage) = 0; virtual status_t detachBuffer(int slot) = 0; virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) = 0; virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0; virtual status_
6、t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0; virtual int query(int what, int* value) = 0; virtual status_t connect(const sp<IProducerListener>& listener, int api, bool p
7、roducerControlledByApp, QueueBufferOutput* output) = 0; virtual status_t disconnect(int api) = 0; virtual status_t setSidebandStream(const sp<NativeHandle>& stream) = 0; virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) = 0; virtu
8、al status_t allowAllocation(bool allow) = 0; virtual status_t setGenerationNumber(uint32_t generationNumber) = 0; virtual String8 getConsumerName() const = 0; ; 在BufferQueueCore类中定义了一个64项的数据mSlots。cpp view plain copy 在CODE上查看代码片派生到我的代码片BufferQueueDefs:SlotsType mSlots; cpp view plain copy 在CODE上查看代码
9、片派生到我的代码片typedef BufferSlot SlotsTypeNUM_BUFFER_SLOTS; 每个缓冲区的类型是BufferSlot类型。它有两个重要的成员变量,mGraphicBuffer是指向图像缓冲区GraphicBuffer的指针,mBufferState表示图像缓冲区的状态。cpp view plain copy 在CODE上查看代码片派生到我的代码片sp<GraphicBuffer> mGraphicBuffer; . BufferState mBufferState; BufferState的状态有下面几个cpp view plain copy 在CO
10、DE上查看代码片派生到我的代码片enum BufferState FREE = 0,/空闲 DEQUEUED = 1,/生产状态,被生产者拥有 QUEUED = 2,/保存数据状态,被BufferQueue拥有 ACQUIRED = 3/消费状态,被消费者拥有 ; BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取得一块缓冲区。得到缓冲区,如
11、果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态。1.2 消费者和core的联系下面是IGraphicBufferComsumer接口的几个主要函数:cpp view plain copy 在CODE上查看代码片派生到我的代码片virtual status_t acquireBuffer(BufferItem* outBuffer, nse
12、cs_t expectedPresent, uint64_t maxFrameNumber = 0) override; . virtual status_t releaseBuffer(int slot, uint64_t frameNumber, const sp<Fence>& releaseFence, EGLDisplay display, EGLSyncKHR fence); virtual status_t connect(const sp<IConsumerListener>& consumerListener, bool control
13、ledByApp); virtual status_t disconnect(); BufferQueueConsumer类是接口IGraphicBufferComsumer的实现,在使用它之前,先要调用connect函数建立联系,这里传递的参数是IConsumerListener对象,是一个回调接口,如果BufferQueue中有数据准备好了就会调用它的onFrameAvailable函数来通知消费者取走数据。取走数据的时候,需要调用acquireBuffer函数,将缓冲区状态变成ACQUIRED,使用完之后调用releaseBuffer函数可以吧缓冲区数据归还给BufferQueueCor
14、e,这样缓冲区就变成FREE。1.3 三者联系对象BufferQueueProducer和BufferQueueConsumer好像没有直接联系,其实都是通过共同的BufferQueueCore对象连接在一起的,很多操作时直接使用BufferQueueCore对象的成员变量而不是函数来完成的。二、GraphicBuffer对象的创建对Surface而言,图像缓冲区是一个重要的数据结构,它是用户进程和图像显示器之间的纽带,下面我们来看看Surface的图像缓冲区是如何创建的。2.1 内存缓冲区的创建前面介绍了过dequeueBuffer函数,图像缓冲区GraphicBuffer就是在这个函数中创
15、建的,当从BufferQueueCore中获取到空间的slot时,如果这个slot没有缓冲区就要新建一个。下面是dequeueBuffer函数的部分代码,在从BufferQueueCore中获取到slot的时候,如果需要重新分配图像缓冲区就会调用mCore->mAllocator->createGraphicBuffer函数来重新创建一个图像缓冲区。cpp view plain copy 在CODE上查看代码片派生到我的代码片 . *outSlot = found;/found复制到outslot ATRACE_BUFFER_INDEX(found); attachedByCons
16、umer = mSlotsfound.mAttachedByConsumer; mSlotsfound.mBufferState = BufferSlot:DEQUEUED;/slot的状态修改变成生产状态 const sp<GraphicBuffer>& buffer(mSlotsfound.mGraphicBuffer); if (buffer = NULL) |/为空,或者需要重新分配 buffer->needsReallocation(width, height, format, usage) mSlotsfound.mAcquireCalled = fals
17、e; mSlotsfound.mGraphicBuffer = NULL; mSlotsfound.mRequestBufferCalled = false; mSlotsfound.mEglDisplay = EGL_NO_DISPLAY; mSlotsfound.mEglFence = EGL_NO_SYNC_KHR; mSlotsfound.mFence = Fence:NO_FENCE; mCore->mBufferAge = 0; returnFlags |= BUFFER_NEEDS_REALLOCATION;/需要重启分配缓冲区 else / We add 1 becaus
18、e that will be the frame number when this buffer / is queued mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlotsfound.mFrameNumber; BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge); if (CC_UNLIKELY(mSlotsfound.mFence = NULL) BQ_LOGE("dequeueBuffer
19、: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); eglDisplay = mSlotsfound.mEglDisplay; eglFence = mSlotsfound.mEglFence; *outFence = mSlotsfound.mFence; mSlotsfound.mEglFence = EGL_NO_SYNC_KHR; mSlotsfoun
20、d.mFence = Fence:NO_FENCE; mCore->validateConsistencyLocked(); / Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) /如果需要重启分配图像缓冲区 status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp<GraphicBuffer> graphicBuffer(mCore->mAlloc
21、ator->createGraphicBuffer(/创建图像缓冲区 width, height, format, usage, &error); if (graphicBuffer = NULL) BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; / Autolock scope Mutex:Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) BQ_LOGE("dequeueBuffer: Bu
22、fferQueue has been abandoned"); return NO_INIT; graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots*outSlot.mGraphicBuffer = graphicBuffer; / Autolock scope . mAllocator的类型是IGraphicBufferAlloc,也是一个Binder对象,它是在BufferQueueCore的构造函数中得到的,这个时候allocator为空的,具体要从Layer的构造函数中调用Buff
23、erQueue:createBufferQueue函数是,那个时候allocator参数就为空。然后通过getComposerService来调用createGraphicBufferAlloc函数来创建这个mAllocator对象。之前的博客分析过getComposerService返回的是和SurfaceFlinger进程的Binder对象,因此最后是到SurfaceFlinger的createGraphicBufferAlloc函数中去了(但是这里有点搞不明白明明是在一个进程中为什么要用Binder呢?)。cpp view plain copy 在CODE上查看代码片派生到我的代码片.
24、if (allocator = NULL) sp<ISurfaceComposer> composer(ComposerService:getComposerService(); mAllocator = composer->createGraphicBufferAlloc(); if (mAllocator = NULL) BQ_LOGE("createGraphicBufferAlloc failed"); . 下面我们来看SurfaceFlinger的createGraphicBufferAlloc函数。cpp view plain copy 在CO
25、DE上查看代码片派生到我的代码片sp<IGraphicBufferAlloc> SurfaceFlinger:createGraphicBufferAlloc() sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc(); return gba; 因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore->mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。cpp v
26、iew plain copy 在CODE上查看代码片派生到我的代码片sp<GraphicBuffer> GraphicBufferAlloc:createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, status_t* error) sp<GraphicBuffer> graphicBuffer( new GraphicBuffer(width, height, format, usage); status_t err = graphicBuffer-
27、>initCheck(); *error = err; ./错误处理 return graphicBuffer; 我们来看下GraphicBuffer对象的构造函数中调用了initSize函数。cpp view plain copy 在CODE上查看代码片派生到我的代码片GraphicBuffer:GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMa
28、pper:get(), mInitCheck(NO_ERROR), mId(getUniqueId() . mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage); 在initSize函数中调用GraphicBufferAllocator的alloc来分配内存。cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t GraphicBuffer:initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_
29、t inUsage) GraphicBufferAllocator& allocator = GraphicBufferAllocator:get(); uint32_t outStride = 0; status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage, &handle, &outStride); if (err = NO_ERROR) width = static_cast<int>(inWidth); height = static_cast<int>(inH
30、eight); format = inFormat; usage = static_cast<int>(inUsage); stride = static_cast<int>(outStride); return err; alloc又调用了成员变量mAllocDev的alloc函数。cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t GraphicBufferAllocator:alloc(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage,
31、 buffer_handle_t* handle, uint32_t* stride) . err = mAllocDev->alloc(mAllocDev, static_cast<int>(width), static_cast<int>(height), format, static_cast<int>(usage), handle, &outStride); 在GraphicBufferAllocator的构造函数中装载了Gralloc模块,因此mAllocDev指向了Gralloc模块。这个会在后面的博客中分析cpp view pla
32、in copy 在CODE上查看代码片派生到我的代码片GraphicBufferAllocator:GraphicBufferAllocator() : mAllocDev(0) hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err = 0) gralloc_open
33、(module, &mAllocDev); 这里调用alloc分配了一块共享的内存缓冲区,alloc函数将返回共享区的fd和缓冲区的指针。既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的。2.2 内存缓冲区的fd传递到客户进程GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。cpp view plain copy 在CODE上查看代码片派生到我的代码片class Gra
34、phicBuffer : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, public Flattenable<GraphicBuffer> 我们先来看下flatten函数,fds参数用来传递文件句柄,函数把handle中的句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t GraphicBuffer:flatten(void*& buffer, si
35、ze_t& size, int*& fds, size_t& count) const size_t sizeNeeded = GraphicBuffer:getFlattenedSize(); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = GraphicBuffer:getFdCount(); if (count < fdCountNeeded) return NO_MEMORY; int32_t* buf = static_cast<int32_t*>(buff
36、er); buf0 = 'GBFR' buf1 = width; buf2 = height; buf3 = stride; buf4 = format; buf5 = usage; buf6 = static_cast<int32_t>(mId >> 32); buf7 = static_cast<int32_t>(mId & 0xFFFFFFFFull); buf8 = static_cast<int32_t>(mGenerationNumber); buf9 = 0; buf10 = 0; if (handle) b
37、uf9 = handle->numFds; buf10 = handle->numInts; memcpy(fds, handle->data,/把handle中的中复制到fds中 static_cast<size_t>(handle->numFds) * sizeof(int); memcpy(&buf11, handle->data + handle->numFds, static_cast<size_t>(handle->numInts) * sizeof(int); buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded); size
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030绿色建材认证体系与地产商采购偏好分析
- 2025-2030绿色低碳科技园建设路径与政策支持分析报告
- 2025-2030线上儿童教育平台用户增长与盈利模式探索报告
- 2025-2030纳米药物载体靶向治疗突破与临床试验进展报告
- 2025-2030纳米材料应用场景分析及市场增长潜力预测报告
- 检验员安全生产培训试题及答案解析
- 2025-2030纳米光刻设备行业安全生产管理与企业社会责任报告
- 2025-2030红外热成像光学系统小型化趋势与民用安防市场渠道变革分析
- 2025-2030精酿啤酒比赛评分体系优化与行业标准制定影响力分析
- 2025-2030精酿啤酒小型发酵罐家庭化应用与DIY市场培育报告
- 2025年辽宁沈阳地铁集团有限公司所属分公司招聘笔试参考题库附带答案详解
- 正弦电气EM303B变频器使用手册
- 核心素养视域下的大单元教学设计思路-以初中生物教学为例
- 物业环境主管年终总结
- 2025年春季学期 形势与政策讲稿第五讲-从教育大国迈向教育强国
- 39.猜心-小游戏课件
- 国际公法学考试题及参考答案
- 《以学生为中心》课件
- “双减”背景下的初中化学作业分层设计
- 我的家乡安顺
- 【MOOC】创新思维与创业实验-东南大学 中国大学慕课MOOC答案
评论
0/150
提交评论