http://windrunnerlihuan.com/2017/06/22/Android-SurfaceFlinger-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF-%E4%B8%83-%E5%88%9B%E5%BB%BA%E5%9B%BE%E5%BD%A2%E7%BC%93%E5%86%B2%E5%8C%BAGraphicBuffer/
在上一篇SurfaceFlinger创建Surface流程中,我们会关联到BufferQueue对GraphicBuffer的管理机制,我们这次就来分析一下它的原理。
角色扮演
Android应用的UI显示到Display的过程中,SurfaceFlinger扮演的角色只是“Flinger”,就是定于检查Layer更新,然后计算DirtyRegion,然后将结果推送给底层显示驱动进行显示。但是在App端,Surface的内容绘制却由应用层来承担。应用层绘制UI内容都需要一个GraphicBuffer,那么Surface对GraphicBuffer的申请、绘制完毕交给SurfaceFlinger去合成然后显示,这个工作也需要一套机制去管理。所以对于GraphicBuffer的管理,Android也设计了一套机制:BufferQueue,作为SurfaceFlinger管理和消费surface的中介。
生产-消费 模型
回顾Android SurfaceFlinger 学习之路(二)—-SurfaceFlinger概述,我们可以用这副简图表示App、BufferQueue和SurfaceFlinger的关系。
虽说是三者的关系,但是他们所属的层却只有两个,app属于Java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。
生产者模型
这里IGraphicBufferProducer就是app和BufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。
根据上一篇Surface的创建流程,我们从Surface类图分析了GraphicBufferProducer在Surface中的位置,下图也可以表示:
BpGraphicBufferProducer是GraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbp(IGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SF,SF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式。
消费者模型
BufferQueue和SurfaceFlinger之间的通信模式如下:
也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。
模型实现
上一篇创建Surface流程中,当创建Layer时候,在onFirstRef里面创建了一个生产者和消费者,并对两者进行了包装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
void Layer::onFirstRef() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); mProducer = new MonitoredProducer(producer, mFlinger); mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mSurfaceFlingerConsumer->setContentsChangedListener(this); mSurfaceFlingerConsumer->setName(mName);
...... }
|
MonitoredProducer对象,这个对象只是一个代理,真正实是BufferQueueProducer类,这个对象和BufferQueueCore有关联,可以管理最多达64块的缓冲区。
SurfaceFlingerConsumer构造函数将BufferQueueConsumer传入,并设置相关回调,以便生产者填充完GraphicBuffer然后通知Consumer消费。
Core
所以创建生产者和消费者就是由BufferQueue来创建,我们可以看看BufferQueue的createBufferQueue函数,位于frameworks/native/libs/gui/BufferQueue.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, const sp<IGraphicBufferAlloc>& allocator) { ...... sp<BufferQueueCore> core(new BufferQueueCore(allocator)); ...... sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core)); ...... sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); ...... *outProducer = producer; *outConsumer = consumer; }
|
所以核心都是这个BufferQueueCore,他是管理图形缓冲区的中枢。这里举一个SurfaceTexture的例子,来看看他们之间的关系:
可以认为BufferQueueCore是一个服务中心,生产者、消费者都要通过它来管理buffer。
- 里面有一个重要的成员数组:BufferQueueDefs::SlotsType mSlots;
- 这个BufferSlot中有一个成员变量:sp< GraphicBuffer >mGraphicBuffer;记录这个slot所涉及的缓冲区;
- 另一个变量BufferState mBufferState;用于跟踪这个缓冲区的状态。
1)在BufferQueueCore类中定义了一个64项的数据mSlots,framework/native/libs/gui/BufferQueueCore.h:
1 2 3 4 5 6
|
BufferQueueDefs::SlotsType mSlots;
|
我们看看这个mSlot定义所在的位置,位于frameworks/native/include/gui/BufferQueueDefs.h中:
1 2 3 4 5 6 7 8
|
namespace BufferQueueDefs { enum { NUM_BUFFER_SLOTS = 64 };
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; }
|
我们可以看到这是一个容量大小为64的数组,因此BufferQueueCore可以管理最多64块的GraphicBuffer。
我们可以帖一幅图表示Slot的角色:
2)BufferSlot的定义位于frameworks/native/include/gui/BufferSlot.h中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
struct BufferSlot {
BufferSlot() : mEglDisplay(EGL_NO_DISPLAY), mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), mFrameNumber(0), mEglFence(EGL_NO_SYNC_KHR), mAcquireCalled(false), mNeedsCleanupOnRelease(false), mAttachedByConsumer(false) { } sp<GraphicBuffer> mGraphicBuffer; enum BufferState { FREE = 0,
DEQUEUED = 1,
QUEUED = 2,
ACQUIRED = 3 };
BufferState mBufferState; }
|
mGraphicBuffer代表一块图形缓冲区GraphicBuffer,用于应用绘制UI。
mBufferState类型为BufferState ,BufferState 的定义也位于其中,代表图形缓冲区的几种状态:
- FREE:buffer当前可用,可以被生产者dequeued,此时owner是BufferQueueCore,当dequeuebuffer调用时,状态可以转为dequeued。
- DEQUEUED:buffer已经被dequeued,还没被queue或canceld,此时owner是producer。
- QUEUED:buffer已经被生产者填充,并被queued,此时的owner是bufferQueueCore。
- ACQUIRED:buffer已经被消费者获得,此时的owner是consumer。
一般的buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个流程,我们下面会讲到它。
3)在BufferQueueCore创建时候,还会创建一个GraphicBufferAlloc,并将它赋值给BufferQueueCore的mAllocator成员变量。我们可以看看BufferQueueCore的构造函数,位于framework/native/libs/gui/BufferQueueCore.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mAllocator(allocator), mMutex(), mIsAbandoned(false), mConsumerControlledByApp(false), mConsumerName(getUniqueName()), mConsumerListener(), mConsumerUsageBits(0), mConnectedApi(NO_CONNECTED_API), mConnectedProducerListener(), mSlots(), mQueue(), mOverrideMaxBufferCount(0), mDequeueCondition(), mUseAsyncBuffer(true), mDequeueBufferCannotBlock(false), mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), mDefaultMaxBufferCount(2), mMaxAcquiredBufferCount(1), mBufferHasBeenQueued(false), mFrameCounter(0), mTransformHint(0), mIsAllocating(false), mIsAllocatingCondition() { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mAllocator = composer->createGraphicBufferAlloc(); if (mAllocator == NULL) { BQ_LOGE("createGraphicBufferAlloc failed"); } } }
|
然后回去请求SurfaceFlinger创建一个GraphicBufferAlloc,位于frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp中:
1 2 3 4 5 6
|
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() { sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); return gba; }
|
因为BufferQueueCore的mAllocator 类型为IGraphicBufferAlloc,继承于IInterface,所以又是跨进程调用创建。我们下面会分析到它的。
Producer
BufferQueueProducer是生产者的实现,需要实现IGraphicBufferProducer接口,相关方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
* This class defines the Binder IPC interface for the producer side of * a queue of graphics buffers. It's used to send graphics data from one * component to another. For example, a class that decodes video for * playback might use this to provide frames. This is typically done * indirectly, through Surface. * * The underlying mechanism is a BufferQueue, which implements * BnGraphicBufferProducer. In normal operation, the producer calls * dequeueBuffer() to get an empty buffer, fills it with data, then * calls queueBuffer() to make it available to the consumer. * * This class was previously called ISurfaceTexture. */ class IGraphicBufferProducer : public IInterface { public: ...... virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0; virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0; ...... }
|
这几个函数的注释写的很清楚,但是限于篇幅,没有贴出来。
BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取出一块缓冲区,也是从BufferQueueCore中的mSlots数组根据index获取这个位置的slot。得到缓冲区,如果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态。这些函数的使用之处我们下面会讲到。
BufferQueueProducer类图结构如下:
Consumer
同样,BufferQueueConsumer是消费者的实现,需要实现IGraphicBufferConsumer接口,相关方法如下:
1 2 3 4 5 6 7 8 9
|
class IGraphicBufferConsumer : public IInterface { public: ...... virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0; virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0; ...... }
|
注释写的很清晰,但是限于篇幅。。。
BufferQueueConsumer类是接口IGraphicBufferComsumer的实现,是一个回调接口,如果BufferQueue中有数据准备好了通知消费者取走数据。取走数据的时候,需要调用acquireBuffer函数,将缓冲区状态变成ACQUIRED,使用完之后调用releaseBuffer函数可以吧缓冲区数据归还给BufferQueueCore,这样缓冲区就变成FREE。
当一块buffer就绪后,消费者就开始工作了,consumer对buffer的处理是被动的,它必须要等到一块buffer填充好才能工作,那consumer怎么知道一块buffer已经填充好了
?
所以我们顺着Layer的onFirstRef函数,里面还有一个对于消费者的封装:SurfaceFlingerConsumer。为了方便,我再贴一遍Layer的onFirstRef函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
void Layer::onFirstRef() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); mProducer = new MonitoredProducer(producer, mFlinger); mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mSurfaceFlingerConsumer->setContentsChangedListener(this); mSurfaceFlingerConsumer->setName(mName);
}
|
为了方便起见,我们将BufferQueueConsumer和SurfaceFlingerConsumer的类图都贴出来:
为了通知消费消费GraphicBuffer,这里提供了另外一个类ConsumerListener,位于frameworks/native/include/gui/IConsumerListener.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
ConsumerListener() { } virtual ~ConsumerListener() { }
virtual void onFrameAvailable() = 0;
virtual void onBuffersReleased() = 0;
virtual void onSidebandStreamChanged() = 0; };
|
两个纯虚函数,当一块buffer可以被消费时,onFrameAvailable会被调用;当BufferQueue通知consumer它已经释放其mSlot中的一个或多个GraphicBuffer的引用时,会调用onBuffersReleased。
那么什么时候注册的这个监听呢?我们需要跟随一下SurfaceFlingerConsumer 的构造函数,位于frameworks/native/services/surfaceflinger/SurfaceFlingerConsumer.h中:
1 2 3 4 5 6
|
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t tex) : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), mTransformToDisplayInverse(false) {}
|
我们需要继续查看GLConsumer的构造函数,位于frameworks/native/libs/gui/GLConsumer.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), mCurrentFrameNumber(0), mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), mTexName(tex), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { ST_LOGV("GLConsumer");
memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); }
|
又调用了ConsumerBase的构造函数,猫腻应该在这里,我们继续查看ConsumerBase的构造函数,位于frameworks/native/libs/gui/ConsumerBase.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) : mAbandoned(false), mConsumer(bufferQueue) { mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); status_t err = mConsumer->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); } else { mConsumer->setConsumerName(mName); } }
|
上面代码主要工作有:
1)创建监听者对象;
2)包装成一个代理;
3)mConsumer调用consumerConnect函数,通过mConsumer,把consumerListener注册到服务者类bufferQueuecore中。
那么注册操作就在于第三部。这里BufferQueueConsumer调用consumerConnect函数,位于frameworks/native/libs/gui/BufferQueueConsumer.h中:
1 2 3 4
|
virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { return connect(consumer, controlledByApp); }
|
在头文件里定义了consumerConnect函数,调用connect函数,位于frameworks/native/libs/gui/BufferQueueConsumer.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
status_t BufferQueueConsumer::connect( const sp<IConsumerListener>& consumerListener, bool controlledByApp) { ATRACE_CALL();
if (consumerListener == NULL) { BQ_LOGE("connect(C): consumerListener may not be NULL"); return BAD_VALUE; }
BQ_LOGV("connect(C): controlledByApp=%s", controlledByApp ? "true" : "false");
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) { BQ_LOGE("connect(C): BufferQueue has been abandoned"); return NO_INIT; } mCore->mConsumerListener = consumerListener; mCore->mConsumerControlledByApp = controlledByApp;
return NO_ERROR; }
|
connect连接,经过层层调用,把listener监听注册到bufferQueuecore中,
这样bufferQueuecore就可以利用这个监听通知到具体的消费者。
接着就是设置监听者:mSurfaceFlingerConsumer->setContentsChangedListener(this);我们可以看看他的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
void SurfaceFlingerConsumer::setContentsChangedListener( const wp<ContentsChangedListener>& listener) { setFrameAvailableListener(listener); Mutex::Autolock lock(mMutex); mContentsChangedListener = listener; }
void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); mFrameAvailableListener = listener; }
|
这样就构成了完整的监听者模式了,有Observer,也有Observable。
这样就清楚了buffer的生产者,消费者,管理者之间的关系。
所以稍微总结一下BufferQueue机制,借助Chris Simmonds
老爷子的话,就是如下内容:
- Mechanism for passing GraphicBuffers to SurfaceFlinger
- Contains an array of between 2 and 64 GraphicBuffers
- Uses interface IGraphicBufferAlloc to allocate buffers (see later)
- Provides two Binder interfaces:
- IGraphicBufferProducer for the client (Activity)
- IGraphicBufferConsumer for the consumer (SurfaceFlinger)
- Buffers cycle between producer and consumer
分配图形缓冲区
首先buffer是共享缓冲区,故肯定会涉及到互斥锁,所以buffer的状态也有很多种,一般buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个过程。如果所示:
或者这样表示这个过程:
申请图形缓冲区
前面看到,bufferqueuecore中mSlots数组管理缓冲区,最大容量是64,这个mSlots一开始静态分配了64个bufferslot大小的空间,但是其中的数据缓冲区不是一次性分配的,不然就太浪费空间了,所以缓冲区的空间分配是动态的,具体就是producer在dequeuebuffer时,如果没有获取到可用的缓冲区,那就要重新分配空间了。
分配图形缓冲区,即GraphicBuffer,我们需要查看BufferQueueProducer的dequeuebuffer函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<android::Fence> *outFence, bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { ATRACE_CALL(); { Mutex::Autolock lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; }
BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", async ? "true" : "false", width, height, format, usage); if ((width && !height) || (!width && height)) { BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); return BAD_VALUE; } status_t returnFlags = NO_ERROR; EGLDisplay eglDisplay = EGL_NO_DISPLAY; EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; bool attachedByConsumer = false;
{ Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (format == 0) { format = mCore->mDefaultBufferFormat; }
usage |= mCore->mConsumerUsageBits;
int found; status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, &found, &returnFlags); if (status != NO_ERROR) { return status; }
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } *outSlot = found; ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
const bool useDefaultSize = !width && !height; if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; } mSlots[found].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if ((buffer == NULL) || (static_cast<uint32_t>(buffer->width) != width) || (static_cast<uint32_t>(buffer->height) != height) || (static_cast<uint32_t>(buffer->format) != format) || ((static_cast<uint32_t>(buffer->usage) & usage) != usage)) { mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; returnFlags |= BUFFER_NEEDS_REALLOCATION; }
if (CC_UNLIKELY(mSlots[found].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 = mSlots[found].mEglDisplay; eglFence = mSlots[found].mEglFence; *outFence = mSlots[found].mFence; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; } if (returnFlags & BUFFER_NEEDS_REALLOCATION) { status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( width, height, format, usage, &error)); if (graphicBuffer == NULL) { BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; }
{ Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) { BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); return NO_INIT; } mSlots[*outSlot].mFrameNumber = UINT32_MAX; mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } }
if (attachedByConsumer) { returnFlags |= BUFFER_NEEDS_REALLOCATION; } if (eglFence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0, 1000000000); if (result == EGL_FALSE) { BQ_LOGE("dequeueBuffer: error %#x waiting for fence", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { BQ_LOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(eglDisplay, eglFence); }
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", *outSlot, mSlots[*outSlot].mFrameNumber, mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
return returnFlags; }
|
代码虽然多,但是逻辑不复杂,我们分步查看:
1)先在mSlot数组中查找FREE状态的slot,如果找到了就返回这个slot中的index。这个操作是调用了waitForFreeSlotThenRelock函数,我们看看这个函数的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, bool async, int* found, status_t* returnFlags) const { bool tryAgain = true; while (tryAgain) { if (mCore->mIsAbandoned) { BQ_LOGE("%s: BufferQueue has been abandoned", caller); return NO_INIT; } const int maxBufferCount = mCore->getMaxBufferCountLocked(async); if (async && mCore->mOverrideMaxBufferCount) { if (mCore->mOverrideMaxBufferCount < maxBufferCount) { BQ_LOGE("%s: async mode is invalid with buffer count override", caller); return BAD_VALUE; } } for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { assert(mSlots[s].mBufferState == BufferSlot::FREE); if (mSlots[s].mGraphicBuffer != NULL) { mCore->freeBufferLocked(s); *returnFlags |= RELEASE_ALL_BUFFERS; } }
*found = BufferQueueCore::INVALID_BUFFER_SLOT; int dequeuedCount = 0; int acquiredCount = 0; for (int s = 0; s < maxBufferCount; ++s) { switch (mSlots[s].mBufferState) { case BufferSlot::DEQUEUED: ++dequeuedCount; break; case BufferSlot::ACQUIRED: ++acquiredCount; break; case BufferSlot::FREE: if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { *found = s; } break; default: break; } }
if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { BQ_LOGE("%s: can't dequeue multiple buffers without setting the " "buffer count", caller); return INVALID_OPERATION; }
if (mCore->mBufferHasBeenQueued) { const int newUndequeuedCount = maxBufferCount - (dequeuedCount + 1); const int minUndequeuedCount = mCore->getMinUndequeuedBufferCountLocked(async); if (newUndequeuedCount < minUndequeuedCount) { BQ_LOGE("%s: min undequeued buffer count (%d) exceeded " "(dequeued=%d undequeued=%d)", caller, minUndequeuedCount, dequeuedCount, newUndequeuedCount); return INVALID_OPERATION; } }
bool tooManyBuffers = mCore->mQueue.size() > static_cast<size_t>(maxBufferCount); if (tooManyBuffers) { BQ_LOGV("%s: queue size is %zu, waiting", caller, mCore->mQueue.size()); }
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { if (mCore->mDequeueBufferCannotBlock && (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } mCore->mDequeueCondition.wait(mCore->mMutex); } }
return NO_ERROR; }
|
代码虽然多,但是大多数都是处理特殊情况的。核心就是从现存maxBufferCount找出FREE状态的slot,然后根据LRU匹配,取出最老的slot,然后返回index给found指针内容。
这样取出来FREE的slot(如果能找到)。
如果所有的buffer都不是free的,则等待。
2)将找到的buf所对应的状态修改为DEQUEUED;
3)然后将上面查询mSlot中返回index的slot的Graphicbuffer赋给buffer变量;
4)判断这个GraphicBuffer是否需要重新分配空间,判断条件就是buffer为空,因为它初始值是null,第一次使用它需要分配空间;如果不为null,但是buffer的width、height、format、usage属性跟要求的不一致,也要重新分配,并打上BUFFER_NEEDS_REALLOCATION标志位。
5)如果上面的buffer为null,则需要重新分配GraphicBuffer,调用BufferQueueCore中的GraphicBufferAlloc中函数createGraphicBuffer,生成一个new GraphicBuffer。
6)等待eglFence状态就绪。Fence机制我们以后会讲到。
创建图形缓冲区
GraphicBuffer创建
所以上述流程的核心是GraphicBuffer的分配,我们需要沿着上面继续分析。因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore->mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。mAllocator的类型为sp< IGraphicBufferAlloc >,要跨进程调用SurfaceFlinger的createGraphicBufferAlloc函数,上面讲过了。
上面刚刚说mAllocator的类型为sp< IGraphicBufferAlloc >,所以创建GraphicBuffer的函数createGraphicBuffer也需要Bp/Bn 的IPC跨进程调用过程。GraphicBuffer通过Binder传递对象是Parcel类型可序列化的,所以他要从模板类Flattenable派生。因为这个牵扯到内存缓冲区的fd传递到客户进程,所以我们放到后面讲。
所以我们先忽略IPC过程,直接查看生成结果,位于frameworks/native/libs/gui/GraphicBufferAlloc.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, status_t* error) { sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) { if (err == NO_MEMORY) { GraphicBuffer::dumpAllocationsToSystemLog(); } ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", w, h, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer; }
|
上面创建一个GraphicBuffer对象,我们看看GraphicBuffer的构造函数,位于frameworks/native/libs/ui/GraphicBuffer.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, PixelFormat reqFormat, uint32_t reqUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { width = height = stride = format = usage = 0; handle = NULL; mInitCheck = initSize(w, h, reqFormat, reqUsage); }
|
构造函数给一些变量赋了初值,并调用了initSize函数,我们看看这个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format, uint32_t reqUsage) { GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride); if (err == NO_ERROR) { this->width = w; this->height = h; this->format = format; this->usage = reqUsage; } return err; }
|
先创建一个GraphicBufferAllocator的单例对象,我们先看看它的构造函数,位于frameworks/native/libs/ui/GraphicBufferAllocator.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
alloc_device_t *mAllocDev;
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(module, &mAllocDev); } }
|
GraphicBufferAllocator构造函数里主要是加载了gralloc设备,然后打开它,因此mAllocDev指向了Gralloc模块。这一部分可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现,Gralloc模块的加载过程、Gralloc设备的打开过程。
加载完Gralloc模块,并打开之后,接着就是分配图形缓冲区了。我们可以继续往下看看是不是,查看GraphicBufferAllocator的alloc函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, buffer_handle_t* handle, int32_t* stride) { ATRACE_CALL(); if (!w || !h) w = h = 1;
status_t err; err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", w, h, format, usage, err, strerror(-err)); if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); int bpp = bytesPerPixel(format); if (bpp < 0) { bpp = 0; } alloc_rec_t rec; rec.w = w; rec.h = h; rec.s = *stride; rec.format = format; rec.usage = usage; rec.size = h * stride[0] * bpp; list.add(*handle, rec); }
return err; }
|
这里调用alloc分配了一块共享的内存缓冲区,就是我们的图形缓冲区。内部是调用Gralloc模块中的函数gralloc_alloc,可以产查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现,分配图形缓冲区。
这样我们GraphicBuffer的创建工作就完成了。
既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的,填掉我们上面的坑。
内存缓冲区映射到应用进程
GraphicBuffer类是从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。
为了方便分析,我们可以看看GraphicBuffer的类图:
上面说到mAllocator的类型为sp< IGraphicBufferAlloc >,它的创建GraphicBuffer的函数createGraphicBuffer也需要Bp/Bn 的IPC跨进程调用过程,序列化传递和反序列话取出这里用于IPC传递数据,我们可以在这里看看客户端和服务端的工作流程。
我们先看看客户端Bp端,位于frameworks/native/libs/gui/IGraphicBufferAlloc.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc> { public: BpGraphicBufferAlloc(const sp<IBinder>& impl) : BpInterface<IGraphicBufferAlloc>(impl) { } virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); data.writeInt32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp<GraphicBuffer> graphicBuffer; status_t result = reply.readInt32(); if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); result = reply.read(*graphicBuffer); } *error = result; return graphicBuffer; } };
|
客户端这里主要通过binder驱动,取出从服务端返回的序列化后的对象replay,然后自己造一个空壳子,然后读取replay信息,反序列化出GraphicBuffer。
那么服务端(SurfaceFlinger)创建GraphicBuffer并反序列化就在Bn端,我们看看Bn端实现,同样位于位于frameworks/native/libs/gui/IGraphicBufferAlloc.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
status_t BnGraphicBufferAlloc::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
* GraphicBuffer until it is destroyed (that is, until * no local or remote process have a reference to it). */ class BufferReference : public BBinder { sp<GraphicBuffer> buffer; public: BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { } };
switch(code) { case CREATE_GRAPHIC_BUFFER: { CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t usage = data.readInt32(); status_t error; sp<GraphicBuffer> result = createGraphicBuffer(w, h, format, usage, &error); reply->writeInt32(error); if (result != 0) { reply->write(*result); reply->writeStrongBinder( new BufferReference(result) ); } return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } }
|
GraphicBufferAlloc的createGraphicBuffer函数我们上面分析过了。这样就将创建的GraphicBuffer实例序列化后,在通过binder驱动传给client。
我们知道,一个对象要在进程间传输必须继承于Flattenable类,并且实现flatten和unflatten方法,flatten方法用于序列化该对象,unflatten方法用于反序列化对象。
上面说到GraphicBuffer中的缓冲区是共享内存,使用共享内存需要传递共享内存的句柄fd,那么这个fd的传递就应该在GraphicBuffer的序列化/反序列化中,我们就来看看这个过程。
这里我先回顾一下Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现的内容:
图形缓冲区可以从系统帧缓冲区分配也可以从内存中分配,分配一个图形缓冲区后还需要将该图形缓冲区映射到分配该buffer的进程地址空间来,在Android系统中,图形缓冲区的管理由SurfaceFlinger服务来负责。在系统帧缓冲区中分配的图形缓冲区是在SurfaceFlinger服务中使用,而在内存中分配的图形缓冲区既可以在SurfaceFlinger服务中使用,也可以在其它的应用程序中使用。当其它的应用程序需要使用图形缓冲区的时候,它们就会请求SurfaceFlinger服务为它们分配并将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。在从内存中分配buffer时,已经将分配的buffer映射到了SurfaceFlinger服务进程地址空间,如果该buffer是应用程序请求SurfaceFlinger服务为它们分配的,那么还需要将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。
GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。
1)将一个对象写入到Parcel中,需要使用flatten函数序列化该对象,我们先来看下flatten函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
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<int32_t*>(buffer); buf[0] = 'GBFR'; buf[1] = width; buf[2] = height; buf[3] = stride; buf[4] = format; buf[5] = usage; buf[6] = static_cast<int32_t>(mId >> 32); buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull); buf[8] = 0; buf[9] = 0;
if (handle) { buf[8] = handle->numFds; buf[9] = handle->numInts; native_handle_t const* const h = handle; //把handle中的data复制到fds中 memcpy(fds, h->data, h->numFds*sizeof(int)); memcpy(&buf[10], h->data + h->numFds, h->numInts*sizeof(int)); }
buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { fds += handle->numFds; count -= handle->numFds; }
return NO_ERROR; }
|
这个handle类型为native_handle_t ,且typedef成了buffer_handle_t,如果忘记了这一部分,可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现。我们贴一下它的定义:
1 2 3 4 5 6 7
|
typedef struct native_handle { int version; int numFds; int numInts; int data[0]; } native_handle_t;
|
所以我们回到flatten函数中,fds参数用来传递文件句柄,函数把handle中的表示指向图形缓冲区文件描述符句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。
2)在应用程序读取来自服务进程的GraphicBuffer对象时,也就是result = reply.read(*p),会调用GraphicBuffer类的unflatten函数进行反序列化过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
status_t GraphicBuffer::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (size < 8*sizeof(int)) return NO_MEMORY;
int const* buf = static_cast<int const*>(buffer); if (buf[0] != 'GBFR') return BAD_TYPE;
const size_t numFds = buf[8]; const size_t numInts = buf[9];
const size_t sizeNeeded = (10 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = 0; if (count < fdCountNeeded) return NO_MEMORY;
if (handle) { // free previous handle if any free_handle(); }
if (numFds || numInts) { width = buf[1]; height = buf[2]; stride = buf[3]; format = buf[4]; usage = buf[5]; //创建一个native_handle对象 native_handle* h = native_handle_create(numFds, numInts); //将fds复制到native_handle对象的data中,和flatten操作相反 memcpy(h->data, fds, numFds*sizeof(int)); memcpy(h->data + numFds, &buf[10], numInts*sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; handle = NULL; }
mId = static_cast<uint64_t>(buf[6]) << 32; mId |= static_cast<uint32_t>(buf[7]);
mOwner = ownHandle;
if (handle != 0) { //使用GraphicBufferMapper将服务端创建的图形缓冲区映射到当前进程地址空间 status_t err = mBufferMapper.registerBuffer(handle); if (err != NO_ERROR) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err); return err; } }
buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; count -= numFds;
return NO_ERROR; }
|
调用unflatten函数时,共享区的文件句柄已经准备好了,但是内存还没有进行映射,调用了mBufferMapper.registerBuffer函数来进行内存映射。
GraphicBufferMapper是单例的模板类派生的,mBufferMapper对象在GraphicBuffer的构造函数中初始化赋值了,上面我们列出过了。我们看看GraphicBufferMapper的构造函数,位于frameworks/native/libs/ui/GraphicBufferMapper.cpp:
1 2 3 4 5 6 7 8 9 10 11 12
|
GraphicBufferMapper::GraphicBufferMapper() : mAllocMod(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) { mAllocMod = (gralloc_module_t const *)module; } }
|
这里根据模块ID加载Gralloc模块,并得到Gralloc模块的HMI符号首地址,并强制转换为gralloc_module_t类型指针。
我们接着看下GraphicBufferMapper::registerBuffer函数:
1 2 3 4 5 6 7 8 9 10 11
|
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocMod->registerBuffer(mAllocMod, handle);
ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)", handle, err, strerror(-err)); return err; }
|
调用了mAllocMod的registerBuffer函数,mAllocMod同样是指向了Gralloc模块的指针,因此实际是调用了Gralloc模块的gralloc_register_buffer函数。这个函数就是调用了mmap来进行共享内存的映射。
这一部分仍然可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现。我们仍然回顾一下以前的内容:
registerBuffer和unregisterBuffer分别用来注册和注销一个指定的图形缓冲区,所谓注册图形缓冲区,实际上就是将一块图形缓冲区映射到一个进程的地址空间去,而注销图形缓冲区就是执行相反的操作。lock和unlock分别用来锁定和解锁一个指定的图形缓冲区,在访问一块图形缓冲区的时候,例如,向一块图形缓冲写入内容的时候,需要将该图形缓冲区锁定,用来避免访问冲突。在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小,这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置,而参数w和h指定的是要访问的图形缓冲区的宽度和长度。锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中。另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定。
这就是内存缓冲区映射到应用进程的过程。因为需要映射共享内存,所以必须要序列化和反序列Pracel对象。如下图:
这里我们创建GraphicBuffer流程就分析完了。
小结
本节主要分析GraphicBuffer的创建过程,下一节我们分析对它的管理流程。