Android6.0 显示系统(三) 管理图像缓冲区

来源:互联网 发布:数据监控是什么工作 编辑:程序博客网 时间:2024/06/14 08:07

篇博客最后分析到MonitoredProducer对象,这个对象只是一个代理,真正实是BufferQueueProducer类,这个对象和BufferQueueCore有关联,可以管理最多达64块的缓冲区。Surface可以理解为一张画布,那么Surface为何要和一个缓冲区队列相关呢?在播放动画时,美妙至少要播放24帧画面才能形成比较真实的动画效果。而这些数据是通过cpu解码得到的,准备他们需要时间。对于图像显示设备而言,刷新周期是固定的,我们必须要在它需要数据的时候把数据准备好。视频播放的每一帧也需要在指定的时间播放,因此解码器会提前准备好一批数据,这些数据保存在解码器内存的缓冲区中,当时间到达是,解码器会把内部缓冲区的图像复制到Surface中,但是显示设备并不是立刻就把数据取走的,因此Surface也需要缓冲区来临时保存数据。


一、BufferQueueCore BufferQueueProducer BufferQueueConsumer

上篇博客在Layer的onFirstRef函数中,调用了下面函数,创建了3个对象BufferQueueCore BufferQueueProducer BufferQueueConsumer。其中BufferCore是核心,把BufferQueueProducer和BufferQueueConsumer对象连接在一起。

[cpp] view plain copy
  1. void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,  
  2.         sp<IGraphicBufferConsumer>* outConsumer,  
  3.         const sp<IGraphicBufferAlloc>& allocator) {  
  4.   
  5.     sp<BufferQueueCore> core(new BufferQueueCore(allocator));  
  6.     sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));  
  7.     sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));  
  8.   
  9.     *outProducer = producer;  
  10.     *outConsumer = consumer;  
  11. }  


1.1 生产者和core的联系

IGraphicBufferProducer 的大致接口如下,BufferQueueProducer类是接口IGraphicBufferProducer 的实现,使用BufferQueueProducer之前先要调用connect函数,使用结束后调用disconnect断开连接。

[cpp] view plain copy
  1. class IGraphicBufferProducer : public IInterface  
  2. {  
  3. public:  
  4.     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;  
  5.   
  6.     virtual status_t setBufferCount(int bufferCount) = 0;  
  7.   
  8.     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,  
  9.             uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0;  
  10.   
  11.     virtual status_t detachBuffer(int slot) = 0;  
  12.   
  13.     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,  
  14.             sp<Fence>* outFence) = 0;  
  15.   
  16.     virtual status_t attachBuffer(int* outSlot,  
  17.             const sp<GraphicBuffer>& buffer) = 0;  
  18.   
  19.     virtual status_t queueBuffer(int slot,  
  20.             const QueueBufferInput& input, QueueBufferOutput* output) = 0;  
  21.     virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0;  
  22.     virtual int query(int what, int* value) = 0;  
  23.     virtual status_t connect(const sp<IProducerListener>& listener,  
  24.             int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;  
  25.   
  26.     virtual status_t disconnect(int api) = 0;  
  27.     virtual status_t setSidebandStream(const sp<NativeHandle>& stream) = 0;  
  28.     virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,  
  29.             PixelFormat format, uint32_t usage) = 0;  
  30.     virtual status_t allowAllocation(bool allow) = 0;  
  31.   
  32.     virtual status_t setGenerationNumber(uint32_t generationNumber) = 0;  
  33.   
  34.     virtual String8 getConsumerName() const = 0;  
  35. };  

在BufferQueueCore类中定义了一个64项的数据mSlots。

[cpp] view plain copy
  1. BufferQueueDefs::SlotsType mSlots;  


[cpp] view plain copy
  1. typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];  

每个缓冲区的类型是BufferSlot类型。它有两个重要的成员变量,mGraphicBuffer是指向图像缓冲区GraphicBuffer的指针,mBufferState表示图像缓冲区的状态。

[cpp] view plain copy
  1. sp<GraphicBuffer> mGraphicBuffer;  
  2. ......  
  3. BufferState mBufferState;  

BufferState的状态有下面几个

[cpp] view plain copy
  1. enum BufferState {  
  2.     FREE = 0,//空闲  
  3.     DEQUEUED = 1,//生产状态,被生产者拥有  
  4.     QUEUED = 2,//保存数据状态,被BufferQueue拥有  
  5.     ACQUIRED = 3//消费状态,被消费者拥有  
  6. };  


BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取得一块缓冲区。得到缓冲区,如果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态


1.2 消费者和core的联系

下面是IGraphicBufferComsumer接口的几个主要函数:

[cpp] view plain copy
  1. virtual status_t acquireBuffer(BufferItem* outBuffer,  
  2.         nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;  
  3. ......  
  4.   
  5. virtual status_t releaseBuffer(int slot, uint64_t frameNumber,  
  6.         const sp<Fence>& releaseFence, EGLDisplay display,  
  7.         EGLSyncKHR fence);  
  8.   
  9.   
  10. virtual status_t connect(const sp<IConsumerListener>& consumerListener,  
  11.         bool controlledByApp);  
  12. 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
  1.     ......  
  2.     *outSlot = found;//found复制到outslot  
  3.     ATRACE_BUFFER_INDEX(found);  
  4.   
  5.     attachedByConsumer = mSlots[found].mAttachedByConsumer;  
  6.   
  7.     mSlots[found].mBufferState = BufferSlot::DEQUEUED;//slot的状态修改变成生产状态  
  8.   
  9.     const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);  
  10.     if ((buffer == NULL) ||//为空,或者需要重新分配  
  11.             buffer->needsReallocation(width, height, format, usage))  
  12.     {  
  13.         mSlots[found].mAcquireCalled = false;  
  14.         mSlots[found].mGraphicBuffer = NULL;  
  15.         mSlots[found].mRequestBufferCalled = false;  
  16.         mSlots[found].mEglDisplay = EGL_NO_DISPLAY;  
  17.         mSlots[found].mEglFence = EGL_NO_SYNC_KHR;  
  18.         mSlots[found].mFence = Fence::NO_FENCE;  
  19.         mCore->mBufferAge = 0;  
  20.   
  21.         returnFlags |= BUFFER_NEEDS_REALLOCATION;//需要重启分配缓冲区  
  22.     } else {  
  23.         // We add 1 because that will be the frame number when this buffer  
  24.         // is queued  
  25.         mCore->mBufferAge =  
  26.                 mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;  
  27.     }  
  28.   
  29.     BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,  
  30.             mCore->mBufferAge);  
  31.   
  32.     if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {  
  33.         BQ_LOGE("dequeueBuffer: about to return a NULL fence - "  
  34.                 "slot=%d w=%d h=%d format=%u",  
  35.                 found, buffer->width, buffer->height, buffer->format);  
  36.     }  
  37.   
  38.     eglDisplay = mSlots[found].mEglDisplay;  
  39.     eglFence = mSlots[found].mEglFence;  
  40.     *outFence = mSlots[found].mFence;  
  41.     mSlots[found].mEglFence = EGL_NO_SYNC_KHR;  
  42.     mSlots[found].mFence = Fence::NO_FENCE;  
  43.   
  44.     mCore->validateConsistencyLocked();  
  45. // Autolock scope  
  46.   
  47. if (returnFlags & BUFFER_NEEDS_REALLOCATION) {//如果需要重启分配图像缓冲区  
  48.     status_t error;  
  49.     BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);  
  50.     sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(//创建图像缓冲区  
  51.             width, height, format, usage, &error));  
  52.     if (graphicBuffer == NULL) {  
  53.         BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");  
  54.         return error;  
  55.     }  
  56.   
  57.     { // Autolock scope  
  58.         Mutex::Autolock lock(mCore->mMutex);  
  59.   
  60.         if (mCore->mIsAbandoned) {  
  61.             BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");  
  62.             return NO_INIT;  
  63.         }  
  64.   
  65.         graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);  
  66.         mSlots[*outSlot].mGraphicBuffer = graphicBuffer;  
  67.     } // Autolock scope  
  68. }  
  69. ......  

mAllocator的类型是IGraphicBufferAlloc,也是一个Binder对象,它是在BufferQueueCore的构造函数中得到的,这个时候allocator为空的,具体要从Layer的构造函数中调用BufferQueue::createBufferQueue函数是,那个时候allocator参数就为空。然后通过getComposerService来调用createGraphicBufferAlloc函数来创建这个mAllocator对象。

之前的博客分析过getComposerService返回的是和SurfaceFlinger进程的Binder对象,因此最后是到SurfaceFlinger的createGraphicBufferAlloc函数中去了(但是这里有点搞不明白明明是在一个进程中为什么要用Binder呢?)。

[cpp] view plain copy
  1. ......  
  2. if (allocator == NULL) {  
  3.     sp<ISurfaceComposer> composer(ComposerService::getComposerService());  
  4.     mAllocator = composer->createGraphicBufferAlloc();  
  5.     if (mAllocator == NULL) {  
  6.         BQ_LOGE("createGraphicBufferAlloc failed");  
  7.     }  
  8. }  
  9. ......  

下面我们来看SurfaceFlinger的createGraphicBufferAlloc函数。

[cpp] view plain copy
  1. sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()  
  2. {  
  3.     sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());  
  4.     return gba;  
  5. }  

因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore->mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。

[cpp] view plain copy
  1. sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,  
  2.         uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {  
  3.     sp<GraphicBuffer> graphicBuffer(  
  4.             new GraphicBuffer(width, height, format, usage));  
  5.     status_t err = graphicBuffer->initCheck();  
  6.     *error = err;  
  7.     ......//错误处理  
  8.     return graphicBuffer;  
  9. }  

我们来看下GraphicBuffer对象的构造函数中调用了initSize函数。

[cpp] view plain copy
  1. GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,  
  2.         PixelFormat inFormat, uint32_t inUsage)  
  3.     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),  
  4.       mInitCheck(NO_ERROR), mId(getUniqueId())  
  5. {  
  6.     ......  
  7.     mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);  
  8. }  

在initSize函数中调用GraphicBufferAllocator的alloc来分配内存。

[cpp] view plain copy
  1. status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,  
  2.         PixelFormat inFormat, uint32_t inUsage)  
  3. {  
  4.     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();  
  5.     uint32_t outStride = 0;  
  6.     status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,  
  7.             &handle, &outStride);  
  8.     if (err == NO_ERROR) {  
  9.         width = static_cast<int>(inWidth);  
  10.         height = static_cast<int>(inHeight);  
  11.         format = inFormat;  
  12.         usage = static_cast<int>(inUsage);  
  13.         stride = static_cast<int>(outStride);  
  14.     }  
  15.     return err;  
  16. }  
alloc又调用了成员变量mAllocDev的alloc函数。

[cpp] view plain copy
  1. status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,  
  2.         PixelFormat format, uint32_t usage, buffer_handle_t* handle,  
  3.         uint32_t* stride)  
  4. {  
  5.     ......  
  6.     err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),  
  7.             static_cast<int>(height), format, static_cast<int>(usage), handle,  
  8.             &outStride);  

在GraphicBufferAllocator的构造函数中装载了Gralloc模块,因此mAllocDev指向了Gralloc模块。这个会在后面的博客中分析

[cpp] view plain copy
  1. GraphicBufferAllocator::GraphicBufferAllocator()  
  2.     : mAllocDev(0)  
  3. {  
  4.     hw_module_t const* module;  
  5.     int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);  
  6.     ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);  
  7.     if (err == 0) {  
  8.         gralloc_open(module, &mAllocDev);  
  9.     }  
  10. }  

这里调用alloc分配了一块共享的内存缓冲区,alloc函数将返回共享区的fd和缓冲区的指针。既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的。



2.2 内存缓冲区的fd传递到客户进程

GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。

[cpp] view plain copy
  1. class GraphicBuffer  
  2.     : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,  
  3.       public Flattenable<GraphicBuffer>  

我们先来看下flatten函数,fds参数用来传递文件句柄,函数把handle中的句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。

[cpp] view plain copy
  1. status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {  
  2.     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();  
  3.     if (size < sizeNeeded) return NO_MEMORY;  
  4.   
  5.     size_t fdCountNeeded = GraphicBuffer::getFdCount();  
  6.     if (count < fdCountNeeded) return NO_MEMORY;  
  7.   
  8.     int32_t* buf = static_cast<int32_t*>(buffer);  
  9.     buf[0] = 'GBFR';  
  10.     buf[1] = width;  
  11.     buf[2] = height;  
  12.     buf[3] = stride;  
  13.     buf[4] = format;  
  14.     buf[5] = usage;  
  15.     buf[6] = static_cast<int32_t>(mId >> 32);  
  16.     buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);  
  17.     buf[8] = static_cast<int32_t>(mGenerationNumber);  
  18.     buf[9] = 0;  
  19.     buf[10] = 0;  
  20.   
  21.     if (handle) {  
  22.         buf[9] = handle->numFds;  
  23.         buf[10] = handle->numInts;  
  24.         memcpy(fds, handle->data,//把handle中的中复制到fds中  
  25.                 static_cast<size_t>(handle->numFds) * sizeof(int));  
  26.         memcpy(&buf[11], handle->data + handle->numFds,  
  27.                 static_cast<size_t>(handle->numInts) * sizeof(int));  
  28.     }  
  29.   
  30.     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);  
  31.     size -= sizeNeeded;  
  32.     if (handle) {  
  33.         fds += handle->numFds;  
  34.         count -= static_cast<size_t>(handle->numFds);  
  35.     }  
  36.   
  37.     return NO_ERROR;  
  38. }  
再来看unflatten函数,调用这个函数时,共享区的文件句柄已经准备好了,但是内存还没有进行映射,调用了mBufferMapper.registerBuffer函数来进行内存映射。
[cpp] view plain copy
  1. status_t GraphicBuffer::unflatten(  
  2.         void const*& buffer, size_t& size, int const*& fds, size_t& count) {  
  3.     ......  
  4.     if (handle != 0) {  
  5.         status_t err = mBufferMapper.registerBuffer(handle);  
  6.         ......  
  7.     }  
  8.   
  9.     buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);  
  10.     size -= sizeNeeded;  
  11.     fds += numFds;  
  12.     count -= numFds;  
  13.   
  14.     return NO_ERROR;  
  15. }  
我们看下GraphicBufferMapper::registerBuffer函数,调用了mAllocMod的registerBuffer函数,mAllocMod同样是指向了Gralloc模块的指针,在GraphicBufferMapper的构造函数中创建,因此实际是调用了Gralloc模块的gralloc_register_buffer函数。这个函数就是调用了mmap来进行共享内存的映射。在后续的博客我们再详细分析。
[cpp] view plain copy
  1. status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)  
  2. {  
  3.     ATRACE_CALL();  
  4.     status_t err;  
  5.   
  6.     err = mAllocMod->registerBuffer(mAllocMod, handle);  
  7.   
  8.     ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",  
  9.             handle, err, strerror(-err));  
  10.     return err;  
  11. }  

在硬件设备支持Framebuffer缓冲区的情况下,Surface中绘制图形的缓冲区就是Framebuffer的缓冲区,绘制完成后,如果不需要进行图像合成,只需要flip操作就能完成图像的输出,中间完全不用复制的过程,很高效。

原创粉丝点击