




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android6.0 显示系统(三) 管理图像缓冲区一、BufferQueueCore BufferQueueProducer BufferQueueConsumer上篇博客在Layer的onFirstRef函数中,调用了下面函数,创建了3个对象BufferQueueCore BufferQueueProducer BufferQueueConsumer。其中BufferCore是核心,把BufferQueueProducer和BufferQueueConsumer对象连接在一起。cpp view plain copy 在CODE上查看代码片派生到我的代码片void BufferQueue:createBufferQueue(sp* outProducer, sp* outConsumer, const sp& allocator) sp core(new BufferQueueCore(allocator); sp producer(new BufferQueueProducer(core); sp consumer(new BufferQueueConsumer(core); *outProducer = producer; *outConsumer = consumer; 1.1 生产者和core的联系IGraphicBufferProducer 的大致接口如下,BufferQueueProducer类是接口IGraphicBufferProducer 的实现,使用BufferQueueProducer之前先要调用connect函数,使用结束后调用disconnect断开连接。cpp view plain copy 在CODE上查看代码片派生到我的代码片class IGraphicBufferProducer : public IInterface public: virtual status_t requestBuffer(int slot, sp* buf) = 0; virtual status_t setBufferCount(int bufferCount) = 0; virtual status_t dequeueBuffer(int* slot, sp* fence, bool async, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0; virtual status_t detachBuffer(int slot) = 0; virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence) = 0; virtual status_t attachBuffer(int* outSlot, const sp& buffer) = 0; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; virtual void cancelBuffer(int slot, const sp& fence) = 0; virtual int query(int what, int* value) = 0; virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; virtual status_t disconnect(int api) = 0; virtual status_t setSidebandStream(const sp& stream) = 0; virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) = 0; virtual 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上查看代码片派生到我的代码片typedef BufferSlot SlotsTypeNUM_BUFFER_SLOTS; 每个缓冲区的类型是BufferSlot类型。它有两个重要的成员变量,mGraphicBuffer是指向图像缓冲区GraphicBuffer的指针,mBufferState表示图像缓冲区的状态。cpp view plain copy 在CODE上查看代码片派生到我的代码片sp mGraphicBuffer; . BufferState mBufferState; BufferState的状态有下面几个cpp view plain copy 在CODE上查看代码片派生到我的代码片enum BufferState FREE = 0,/空闲 DEQUEUED = 1,/生产状态,被生产者拥有 QUEUED = 2,/保存数据状态,被BufferQueue拥有 ACQUIRED = 3/消费状态,被消费者拥有 ; BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取得一块缓冲区。得到缓冲区,如果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态。1.2 消费者和core的联系下面是IGraphicBufferComsumer接口的几个主要函数:cpp view plain copy 在CODE上查看代码片派生到我的代码片virtual status_t acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override; . virtual status_t releaseBuffer(int slot, uint64_t frameNumber, const sp& releaseFence, EGLDisplay display, EGLSyncKHR fence); virtual status_t connect(const sp& consumerListener, bool controlledByApp); virtual status_t disconnect(); BufferQueueConsumer类是接口IGraphicBufferComsumer的实现,在使用它之前,先要调用connect函数建立联系,这里传递的参数是IConsumerListener对象,是一个回调接口,如果BufferQueue中有数据准备好了就会调用它的onFrameAvailable函数来通知消费者取走数据。取走数据的时候,需要调用acquireBuffer函数,将缓冲区状态变成ACQUIRED,使用完之后调用releaseBuffer函数可以吧缓冲区数据归还给BufferQueueCore,这样缓冲区就变成FREE。1.3 三者联系对象BufferQueueProducer和BufferQueueConsumer好像没有直接联系,其实都是通过共同的BufferQueueCore对象连接在一起的,很多操作时直接使用BufferQueueCore对象的成员变量而不是函数来完成的。二、GraphicBuffer对象的创建对Surface而言,图像缓冲区是一个重要的数据结构,它是用户进程和图像显示器之间的纽带,下面我们来看看Surface的图像缓冲区是如何创建的。2.1 内存缓冲区的创建前面介绍了过dequeueBuffer函数,图像缓冲区GraphicBuffer就是在这个函数中创建的,当从BufferQueueCore中获取到空间的slot时,如果这个slot没有缓冲区就要新建一个。下面是dequeueBuffer函数的部分代码,在从BufferQueueCore中获取到slot的时候,如果需要重新分配图像缓冲区就会调用mCore-mAllocator-createGraphicBuffer函数来重新创建一个图像缓冲区。cpp view plain copy 在CODE上查看代码片派生到我的代码片 . *outSlot = found;/found复制到outslot ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlotsfound.mAttachedByConsumer; mSlotsfound.mBufferState = BufferSlot:DEQUEUED;/slot的状态修改变成生产状态 const sp& buffer(mSlotsfound.mGraphicBuffer); if (buffer = NULL) |/为空,或者需要重新分配 buffer-needsReallocation(width, height, format, usage) mSlotsfound.mAcquireCalled = false; 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 because 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: 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; mSlotsfound.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(mCore-mAllocator-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: BufferQueue has been abandoned); return NO_INIT; graphicBuffer-setGenerationNumber(mCore-mGenerationNumber); mSlots*outSlot.mGraphicBuffer = graphicBuffer; / Autolock scope . mAllocator的类型是IGraphicBufferAlloc,也是一个Binder对象,它是在BufferQueueCore的构造函数中得到的,这个时候allocator为空的,具体要从Layer的构造函数中调用BufferQueue:createBufferQueue函数是,那个时候allocator参数就为空。然后通过getComposerService来调用createGraphicBufferAlloc函数来创建这个mAllocator对象。之前的博客分析过getComposerService返回的是和SurfaceFlinger进程的Binder对象,因此最后是到SurfaceFlinger的createGraphicBufferAlloc函数中去了(但是这里有点搞不明白明明是在一个进程中为什么要用Binder呢?)。cpp view plain copy 在CODE上查看代码片派生到我的代码片. if (allocator = NULL) sp composer(ComposerService:getComposerService(); mAllocator = mposer-createGraphicBufferAlloc(); if (mAllocator = NULL) BQ_LOGE(createGraphicBufferAlloc failed); . 下面我们来看SurfaceFlinger的createGraphicBufferAlloc函数。cpp view plain copy 在CODE上查看代码片派生到我的代码片sp SurfaceFlinger:createGraphicBufferAlloc() sp gba(new GraphicBufferAlloc(); return gba; 因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore-mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。cpp view plain copy 在CODE上查看代码片派生到我的代码片sp GraphicBufferAlloc:createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, status_t* error) sp graphicBuffer( new GraphicBuffer(width, height, format, usage); status_t err = graphicBuffer-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(GraphicBufferMapper: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, int32_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(inWidth); height = static_cast(inHeight); format = inFormat; usage = static_cast(inUsage); stride = static_cast(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, buffer_handle_t* handle, uint32_t* stride) . err = mAllocDev-alloc(mAllocDev, static_cast(width), static_cast(height), format, static_cast(usage), handle, &outStride); 在GraphicBufferAllocator的构造函数中装载了Gralloc模块,因此mAllocDev指向了Gralloc模块。这个会在后面的博客中分析cpp view plain 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: cant find the %s module, GRALLOC_HARDWARE_MODULE_ID); if (err = 0) gralloc_open(module, &mAllocDev); 这里调用alloc分配了一块共享的内存缓冲区,alloc函数将返回共享区的fd和缓冲区的指针。既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的。2.2 内存缓冲区的fd传递到客户进程GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。cpp view plain copy 在CODE上查看代码片派生到我的代码片class GraphicBuffer : public ANativeObjectBase, public Flattenable 我们先来看下flatten函数,fds参数用来传递文件句柄,函数把handle中的句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t GraphicBuffer:flatten(void*& buffer, size_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(buffer); buf0 = GBFR; buf1 = width; buf2 = height; buf3 = stride; buf4 = format; buf5 = usage; buf6 = static_cast(mId 32); buf7 = static_cast(mId & 0xFFFFFFFFull); buf8 = static_cast(mGenerationNumber); buf9 = 0; buf10 = 0; if (handle) buf9 = handle-numFds; buf10 = handle-numInts; memcpy(fds, handle-data,/把handle中的中复制到fds中 static_cast(handle-numFds) * sizeof(int); memcpy(&buf11, handle-data + handle-numFds, static_cast(handle-numInts) * sizeof(int); buffer = static_cast(static_cast(buffer) + sizeNeeded); size -= sizeNeeded; if (hanc
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年学历类自考康复护理学-资产评估参考题库含答案解析(5套试卷)
- 2025年学历类自考幼儿园组织与管理-成本会计参考题库含答案解析(5套试卷)
- 2025年学历类自考幼儿园教育基础-企业管理概论参考题库含答案解析(5套试卷)
- 2025年学历类自考小学数学教学论-学前教育史参考题库含答案解析(5套试卷)
- 2025年学历类自考小学教育科学研究-会计制度设计参考题库含答案解析(5套试卷)
- 2025年学历类自考小学教育心理学-古代汉语参考题库含答案解析(5套试卷)
- 2025年学历类自考学前教育史-马克思主义基本原理参考题库含答案解析(5套试卷)
- 2025年学历类自考学前卫生学-学前教育科学研究参考题库含答案解析(5套试卷)
- 2025年学历类自考国际金融-经济法概论参考题库含答案解析(5套试卷)
- 2025年监控摄像头项目规划申请报告
- 2025年智能家居产业互联互通标准与产业发展现状及问题研究报告
- 感染性心内膜炎术后护理查房
- 2025年领导干部政治理论知识必考题库及答案
- 2025年提取公积金租房合同范本
- 推理能力题目及答案
- 2025年湖南省社区工作者招聘考试(公共基础知识和写作)历年参考题库含答案详解(5套)
- 2025年部编版新教材语文七年级上册教学计划(含进度表)
- 湖北省武汉市武昌区重点名校2026届中考语文全真模拟试题含解析
- 2.4抽象函数的周期性与对称性-讲义(原卷版)
- 喷粉挂钩管理办法
- 2025手机维修服务合同范本
评论
0/150
提交评论