BufferQueue的管理
1. 对buffer的管理符合“生产者-消费者”模型,这里有以下几个相关的类:
1) BufferQueueProducer.cpp是IGraphicBufferProducer对应客户端的实现,负责缓冲区的申请
2) BufferQueueConsumer.cpp是IGraphicBufferProducer对应的服务端的实现,是buffer消费者
3) BufferQueueCore.cpp,当有可以消费的buffer时,是通过BufferQueueCore通知到BufferQueueConsumer,具体是通过ConsumerListener来实现的。
BufferQueueCore.h // mConsumerListener is used to notify the connected consumer of // asynchronous events that it may wish to react to. It is initially // set to NULL and is written by consumerConnect and consumerDisconnect. sp<IConsumerListener> mConsumerListener; // ConsumerListener is the interface through which the BufferQueue notifies the consumer of events // that the consumer may wish to react to. Because the consumer will generally have a mutex that is // locked during calls from the consumer to the BufferQueue, these calls from the BufferQueue to the // consumer *MUST* be called only when the BufferQueue mutex is NOT locked. IConsumerListener.h class ConsumerListener : public virtual RefBase { public: ConsumerListener() {} virtual ~ConsumerListener(); // onDisconnect is called when a producer disconnects from the BufferQueue. virtual void onDisconnect() {} /* Asynchronous */ // onFrameAvailable is called from queueBuffer each time an additional frame becomes available // for consumption. This means that frames that are queued while in asynchronous mode only // trigger the callback if no previous frames are pending. Frames queued while in synchronous // mode always trigger the callback. The item passed to the callback will contain all of the // information about the queued frame except for its GraphicBuffer pointer, which will always be // null (except if the consumer is SurfaceFlinger). // // This is called without any lock held and can be called concurrently by multiple threads. virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */ // onFrameReplaced is called from queueBuffer if the frame being queued is replacing an existing // slot in the queue. Any call to queueBuffer that doesn't call onFrameAvailable will call this // callback instead. The item passed to the callback will contain all of the information about // the queued frame except for its GraphicBuffer pointer, which will always be null. // // This is called without any lock held and can be called concurrently by multiple threads. virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */ // onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released // its references to one or more GraphicBuffers contained in its slots. The buffer consumer // should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers. // // This is called without any lock held and can be called concurrently by multiple threads. virtual void onBuffersReleased() = 0; /* Asynchronous */ // onSidebandStreamChanged is called to notify the buffer consumer that the BufferQueue's // sideband buffer stream has changed. This is called when a stream is first attached and when // it is either detached or replaced by a different stream. virtual void onSidebandStreamChanged() = 0; /* Asynchronous */ // Notifies the consumer of any new producer-side timestamps and returns the combined frame // history that hasn't already been retrieved. // // WARNING: This method can only be called when the BufferQueue is in the consumer's process. virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/, FrameEventHistoryDelta* /*outDelta*/) {} }; class IConsumerListener : public ConsumerListener, public IInterface { public: DECLARE_META_INTERFACE(ConsumerListener) };BufferQueueCore中有一个重要的成员数组BufferQueueDefs::SlotsType mSlots,面在说的surface中也有一个同名的成员数组BufferSlot mSlots[NUM_BUFFER_SLOTS]都是BufferSlot类型,只是定义有差别。
Surface.h struct BufferSlot { sp<GraphicBuffer> buffer; Region dirtyRegion; }; // mSlots stores the buffers that have been allocated for each buffer slot. // It is initialized to null pointers, and gets filled in with the result of // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. BufferSlot mSlots[NUM_BUFFER_SLOTS]; BufferQueueCore.h // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer // and consumer without sending a GraphicBuffer over Binder. The entire // array is initialized to NULL at construction time, and buffers are // allocated for a slot when requestBuffer is called with that slot's index. BufferQueueDefs::SlotsType mSlots; BufferQueueDefs.h namespace android { class BufferQueueCore; namespace BufferQueueDefs { typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; } // namespace BufferQueueDefs } // namespace android // BufferQueue will keep track of at most this value of buffers. // Attempts at runtime to increase the number of buffers past this // will fail. static constexpr int NUM_BUFFER_SLOTS = 64; BufferSlot.h struct BufferSlot { BufferSlot() : mGraphicBuffer(nullptr), mEglDisplay(EGL_NO_DISPLAY), mBufferState(), mRequestBufferCalled(false), mFrameNumber(0), mEglFence(EGL_NO_SYNC_KHR), mFence(Fence::NO_FENCE), mAcquireCalled(false), mNeedsReallocation(false) { } // mGraphicBuffer points to the buffer allocated for this slot or is NULL // if no buffer has been allocated. sp<GraphicBuffer> mGraphicBuffer; // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects. EGLDisplay mEglDisplay; // mBufferState is the current state of this buffer slot. BufferState mBufferState; // mRequestBufferCalled is used for validating that the producer did // call requestBuffer() when told to do so. Technically this is not // needed but useful for debugging and catching producer bugs. bool mRequestBufferCalled; // mFrameNumber is the number of the queued frame for this slot. This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). uint64_t mFrameNumber; // mEglFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a // new sync object in releaseBuffer. (This is deprecated in favor of // mFence, below.) EGLSyncKHR mEglFence; // mFence is a fence which will signal when work initiated by the // previous owner of the buffer is finished. When the buffer is FREE, // the fence indicates when the consumer has finished reading // from the buffer, or when the producer has finished writing if it // called cancelBuffer after queueing some writes. When the buffer is // QUEUED, it indicates when the producer has finished filling the // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been // passed to the consumer or producer along with ownership of the // buffer, and mFence is set to NO_FENCE. sp<Fence> mFence; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; // Indicates whether the buffer was re-allocated without notifying the // producer. If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when // dequeued to prevent the producer from using a stale cached buffer. bool mNeedsReallocation; };一个buffer可以有5种状态,如下:
1) FREE表明缓冲区当前可用,可以被生产者dequeued,这个slots的owner是BufferQueue,当dequeueBuffer后会转变为DEQUEUED。
2) DEQUEUED表明这个buffer已经被生产者dequeued,但是还没被queued或者canceled,生产者可以修改这个buffer的内容,现在buffer的owner是producer(应用程序),可以通过调用queueBuffer或attachBuffer转成QUEUED,也可以通过调用cancelBuffer或detachBuffer转成FREE。
3) QUEUED表明这个buffer已经被Producer填充了数据,可以被consumer使用,现在buffer的owner是BufferQueue,可以通过调用acquireBuffer转成ACQUIRED,
4) ACQUIRED表明这个buffer已经被consumer acquired了,现在的owner是consumer,通过releasebuffer可以转成FREE。
5) SHARED表明这个buffer被用于sharedbuffer mode。在同一时间,它可以是除FREE外的其他的状态的集合。
BufferSlot.h // BufferState tracks the states in which a buffer slot can be. struct BufferState { // All slots are initially FREE (not dequeued, queued, acquired, or shared). BufferState() : mDequeueCount(0), mQueueCount(0), mAcquireCount(0), mShared(false) { } uint32_t mDequeueCount; uint32_t mQueueCount; uint32_t mAcquireCount; bool mShared; // A buffer can be in one of five states, represented as below: // // | 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 | // // FREE indicates that the buffer is available to be dequeued by the // producer. The slot is "owned" by BufferQueue. It transitions to DEQUEUED // when dequeueBuffer is called. // // DEQUEUED indicates that the buffer has been dequeued by the producer, but // has not yet been queued or canceled. The producer may modify the // buffer's contents as soon as the associated release fence is signaled. // The slot is "owned" by the producer. It can transition to QUEUED (via // queueBuffer or attachBuffer) or back to FREE (via cancelBuffer or // detachBuffer). // // QUEUED indicates that the buffer has been filled by the producer and // queued for use by the consumer. The buffer contents may continue to be // modified for a finite time, so the contents must not be accessed until // the associated fence is signaled. The slot is "owned" by BufferQueue. It // can transition to ACQUIRED (via acquireBuffer) or to FREE (if another // buffer is queued in asynchronous mode). // // ACQUIRED indicates that the buffer has been acquired by the consumer. As // with QUEUED, the contents must not be accessed by the consumer until the // acquire fence is signaled. The slot is "owned" by the consumer. It // transitions to FREE when releaseBuffer (or detachBuffer) is called. A // detached buffer can also enter the ACQUIRED state via attachBuffer. // // SHARED indicates that this buffer is being used in shared buffer // mode. It can be in any combination of the other states at the same time, // except for FREE (since that excludes being in any other state). It can // also be dequeued, queued, or acquired multiple times. inline bool isFree() const { return !isAcquired() && !isDequeued() && !isQueued(); } inline bool isDequeued() const { return mDequeueCount > 0; } inline bool isQueued() const { return mQueueCount > 0; } inline bool isAcquired() const { return mAcquireCount > 0; } inline bool isShared() const { return mShared; } inline void reset() { *this = BufferState(); } const char* string() const; inline void dequeue() { mDequeueCount++; } inline void detachProducer() { if (mDequeueCount > 0) { mDequeueCount--; } } inline void attachProducer() { mDequeueCount++; } inline void queue() { if (mDequeueCount > 0) { mDequeueCount--; } mQueueCount++; } inline void cancel() { if (mDequeueCount > 0) { mDequeueCount--; } } inline void freeQueued() { if (mQueueCount > 0) { mQueueCount--; } } inline void acquire() { if (mQueueCount > 0) { mQueueCount--; } mAcquireCount++; } inline void acquireNotInQueue() { mAcquireCount++; } inline void release() { if (mAcquireCount > 0) { mAcquireCount--; } } inline void detachConsumer() { if (mAcquireCount > 0) { mAcquireCount--; } } inline void attachConsumer() { mAcquireCount++; } };Producer通常是指应用程序,应用程序不断刷新UI,把产生的显示数据写到buffer中,当Producer需要一块buffer时,先向BufferQueue发起dequeue申请,然后才能对指定的缓冲区进行填充操作。当填充完成后,通过调用queueBuffer把这个buffer入队到Bufferqueue中,由BufferQueueCore通知consumer有可以消费的buffer了。
2. BufferQueue缓冲区的分配
分析缓冲区的分配,就是分析BufferSlot数组中的指针mGraphicBuffer的空间分配。这个指针一开始是null,下面看什么情况下为mSlots数组中的一个slot分配实际空间。整个需求的起点是Producer对buffer的dequeueBuffer,所以从分析这个函数开始:
BufferQueueProducer.cpp status_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) { ... { // Autolock scope std::unique_lock<std::mutex> lock(mCore->mMutex); ... //step1,这个while循环,查找一个可用的slot。具体是通过 waitForFreeSlotThenRelock函数实现,也就是found的有效值。 int found = BufferItem::INVALID_BUFFER_SLOT; while (found == BufferItem::INVALID_BUFFER_SLOT) { status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found); if (status != NO_ERROR) { return status; } // This should not happen if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); // If we are not allowed to allocate new buffers, // waitForFreeSlotThenRelock must have returned a slot containing a // buffer. If this buffer would require reallocation to meet the // requested attributes, we free it and attempt to get another one. //如果不允许分配新的buffers,waitForFreeSlotThenRelock还必须返回一个包含buffer的slot;如果这个buffer需要充分配才能满足要求,就要先把它free了,然后尝试再获取一个。 if (!mCore->mAllowAllocation) { if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { if (mCore->mSharedBufferSlot == found) { BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer"); return BAD_VALUE; } mCore->mFreeSlots.insert(found); mCore->clearBufferSlotLocked(found); found = BufferItem::INVALID_BUFFER_SLOT; continue; } } } const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if (mCore->mSharedBufferSlot == found && buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { BQ_LOGE("dequeueBuffer: cannot re-allocate a shared" "buffer"); return BAD_VALUE; } if (mCore->mSharedBufferSlot != found) { mCore->mActiveBuffers.insert(found); } //step2,成功找到slot序号,接下来对这个bufferslot对象做初始化。 //还要判断要不要为这个slot重新分配空间。 *outSlot = found; ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlots[found].mNeedsReallocation; mSlots[found].mNeedsReallocation = false; mSlots[found].mBufferState.dequeue(); if ((buffer == nullptr) || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { mSlots[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; } else { // We add 1 because that will be the frame number when this buffer // is queued mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber; } ... eglDisplay = mSlots[found].mEglDisplay; eglFence = mSlots[found].mEglFence; // Don't return a fence in shared buffer mode, except for the first // frame. *outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; // If shared buffer mode has just been enabled, cache the slot of the // first buffer that is dequeued and mark it as the shared buffer. if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == BufferQueueCore::INVALID_BUFFER_SLOT) { mCore->mSharedBufferSlot = found; mSlots[found].mBufferState.mShared = true; } } // Autolock scope //step3,上一步的判断结果需要重新分配空间。 if (returnFlags & BUFFER_NEEDS_REALLOCATION) { ... sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.string(), mConsumerName.size()}); status_t error = graphicBuffer->initCheck(); { // Autolock scope std::lock_guard<std::mutex> lock(mCore->mMutex); if (error == NO_ERROR && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.notify_all(); ... VALIDATE_CONSISTENCY(); } // Autolock scope } ... return returnFlags; }对其中关键步骤做详细分析:
step1,怎么找到一个可用的slot。found指的是这个buffer slot在mSlots数组中的序号。
BufferQueueProducer.cpp status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock, int* found) const { auto callerString = (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer"; bool tryAgain = true; while (tryAgain) { ... // mActiveBuffers这个集合中包含所有非free的buffer。然后分别统计dequeued的个数,acquired的个数。 int dequeuedCount = 0; int acquiredCount = 0; for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isDequeued()) { ++dequeuedCount; } if (mSlots[s].mBufferState.isAcquired()) { ++acquiredCount; } } // Producers are not allowed to dequeue more than // mMaxDequeuedBufferCount buffers. // This check is only done if a buffer has already been queued //不允许Producersdequeue的数量的超过mMaxDequeuedBufferCount,这个判断只在buffer已经被queued的情况下。 //mMaxDequeuedBufferCount是Producer一次可以dequeue的buffers的数量,默认是1,可以通过setMaxDequeuedBufferCount来修改。 if (mCore->mBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) { // Supress error logs when timeout is non-negative. if (mDequeueTimeout < 0) { BQ_LOGE("%s: attempting to exceed the max dequeued buffer " "count (%d)", callerString, mCore->mMaxDequeuedBufferCount); } return INVALID_OPERATION; } *found = BufferQueueCore::INVALID_BUFFER_SLOT; // If we disconnect and reconnect quickly, we can be in a state where // our slots are empty but we have many buffers in the queue. This can // cause us to run out of memory if we outrun the consumer. Wait here if // it looks like we have too many buffers queued up. const int maxBufferCount = mCore->getMaxBufferCountLocked(); bool tooManyBuffers = mCore->mQueue.size() > static_cast<size_t>(maxBufferCount); if (tooManyBuffers) { BQ_LOGV("%s: queue size is %zu, waiting", callerString, mCore->mQueue.size()); } else { // If in shared buffer mode and a shared buffer exists, always // return it. //如果在shared buffer mode,并且有一个shared buffer存在,就返回这个slot。 if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = mCore->mSharedBufferSlot; } else { //slot的获取,主要来自两个集合,mFreeSlots和mFreeBuffers, //mFreeSlots包含的是所有状态是free,并且没有attached的slots, //mFreeBuffers包含所有状态是free,但是已经attached的slots。 if (caller == FreeSlotCaller::Dequeue) { // If we're calling this from dequeue, prefer free buffers //如果调用来自与dequeue,优先选择mFreeBuffers中的。 int slot = getFreeBufferLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else if (mCore->mAllowAllocation) { *found = getFreeSlotLocked(); } } else { // If we're calling this from attach, prefer free slots //如果调用来自于attache,优先选择mFreeSlots中的。 int slot = getFreeSlotLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else { *found = getFreeBufferLocked(); } } } } // If no buffer is found, or if the queue has too many buffers // outstanding, wait for a buffer to be acquired or released, or for the // max buffer count to change. //如果没有找到符合要求的buffer,或者queue的buffers还有太多没有完成,就要等待这个buffer被acquired或者released,或者修改最大的buffer数量。 //这里使用条件变量mDequeueCondition进入wait,当有buffer被释放时,这个条件就会满足,然后继续查找。 tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { // Return an error if we're in non-blocking mode (producer and // consumer are controlled by the application). // However, the consumer is allowed to briefly acquire an extra // buffer (which could cause us to have to wait here), which is // okay, since it is only used to implement an atomic acquire + // release (e.g., in GLConsumer::updateTexImage()) if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) && (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } if (mDequeueTimeout >= 0) { std::cv_status result = mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(mDequeueTimeout)); if (result == std::cv_status::timeout) { return TIMED_OUT; } } else { mCore->mDequeueCondition.wait(lock); } } } // while (tryAgain) return NO_ERROR; } int BufferQueueProducer::getFreeBufferLocked() const { if (mCore->mFreeBuffers.empty()) { return BufferQueueCore::INVALID_BUFFER_SLOT; } int slot = mCore->mFreeBuffers.front(); mCore->mFreeBuffers.pop_front(); return slot; } int BufferQueueProducer::getFreeSlotLocked() const { if (mCore->mFreeSlots.empty()) { return BufferQueueCore::INVALID_BUFFER_SLOT; } int slot = *(mCore->mFreeSlots.begin()); mCore->mFreeSlots.erase(slot); return slot; } BufferQueueCore.h // mFreeSlots contains all of the slots which are FREE and do not currently // have a buffer attached. std::set<int> mFreeSlots; // mFreeBuffers contains all of the slots which are FREE and currently have // a buffer attached. std::list<int> mFreeBuffers;step2,找到可用的slot,还要判断是否要重新分配空间,即needsReallocation。如果buffer的属性跟要求的属性不符(主要指宽,高,格式,usage),就要重新分配。最后的返回值会加上returnFlags |= BUFFER_NEEDS_REALLOCATION标记。
Step3,这里new了一个GraphicBuffer,这个GraphicBuffer会赋值给BufferQueueCore中的变量mSlots中的slot的mGraphicBuffer。
BufferQueueProducer.cpp中的dequeueBuffer的源头是在surface中调用的dequeueBuffer,所以BufferQueueProducer.cpp这边执行完会返回到Surface.cpp中
Surface.cpp int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ... status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, reqFormat, reqUsage, &mBufferAge, enableFrameTimestamps ? &frameTimestamps : nullptr); ... if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) { if (mReportRemovedBuffers && (gbuf != nullptr)) { mRemovedBuffers.push_back(gbuf); } result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); mGraphicBufferProducer->cancelBuffer(buf, fence); return result; } } ... return OK; }调用requestBuffer是获取最新的buffer地址,BufferQueueProducer中分配的buffer是在服务端进程空间的,而surface需要的buffer是要在客户端进程,也就是应用进程空间使用的,这两块buffer应该指向同一块物理内存,怎么实现让两块buffer指向同一块物理内存的,这就是requestbuffer的作用。
这个方法是BpGraphicBufferProducer中的方法:
IGraphicBufferProducer.cpp class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> { ... virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); //只传了在mSlots中的序号 bufferIdx,第二个参数* buf实际是一个出参。 data.writeInt32(bufferIdx); //开始跨进程操作。 status_t result =remote()->transact(REQUEST_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } //读取服务端返回的信息,在执行跨进程操作时,client端会被挂起,等服务端处理完成返回结果时,在唤醒client继续执行 bool nonNull = reply.readInt32(); if (nonNull) { //这里生成一个GraphicBuffer实例,实际是一个空壳,要通过服务端的返回值来填充。 *buf = new GraphicBuffer(); //使用服务端的返回的结果填充**buf ,这个**buf具体指的什么?从Surface.cpp传入的参数说起: //sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);这个gbuf 是一个指向 mSlots[buf].buffer的引用 //传入requestBuffer中的实参是&gbuf,也就是说*buf指针指向的是 gbuf 的地址,所以**buf指向的就是 gbuf代表的内容,也就是 mSlots[buf].buffer。 result = reply.read(**buf); if(result != NO_ERROR) { (*buf).clear(); return result; } } result = reply.readInt32(); return result; } }相应client请求的代码如下:
IGraphicBufferProducer.cpp status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { //匹配请求的业务码 REQUEST_BUFFER。 case REQUEST_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); //读取要处理的slot序号。 int bufferIdx = data.readInt32(); sp<GraphicBuffer> buffer; int result = requestBuffer(bufferIdx, &buffer); //写入本地端是否成功获取到了对应的GraphicBuffer,这个GraphicBuffer就是dequeuebuffer中申请的 //也即是BufferQueueCore中的mSlots[slot].mGraphicBuffer。 reply->writeInt32(buffer != nullptr); if (buffer != nullptr) { //把 mGraphicBuffer写入reply,等待客户端读取。 reply->write(*buffer); } reply->writeInt32(result); return NO_ERROR; } ... } }上面的实现中,清晰的描述了怎样跨进程传递一个对象。
在surface执行dequeuebuffer的过程中,如果需要重新分配空间,就要调用requestbuffer来更新client端mSlots中相应的缓冲区信息,这样就保证了Surface和BufferQueueCore之前数据在缓冲区上的一致。
3. 应用程序跟BufferQueue的关系
应用程序不会直接使用BufferQueue,接下来分析应用程序跟bufferQueue之间是怎么配合完成图形绘制的。
分析的起点是SurfaceComposerClient,它是应用程序与surfaceflinger之间的通信桥梁,不过SurfaceComposerClient只是一个封装,实质是通过内部的ISurfaceComposerClient来执行的,ISurfaceComposerClient对应的服务端实现是Client。
代码参见android P SurfaceFlinger---图层创建过程。
再回头看下SurfaceFlinger.cpp 方法createBufferQueueLayer()中的实现:*handle= (*outLayer)→getHandle(),其中的handle是什么类型,又起了什么作用呢?
Layer.cpp sp<IBinder> Layer::getHandle() { Mutex::Autolock _l(mLock); if (mGetHandleCalled) { ALOGE("Get handle called twice" ); return nullptr; } mGetHandleCalled = true; return new Handle(mFlinger, this); } Layer.h public: /* * The layer handle is just a BBinder object passed to the client * (remote process) -- we don't keep any reference on our side such that * the dtor is called when the remote side let go of its reference. * * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for * this layer when the handle is destroyed. */ class Handle : public BBinder, public LayerCleaner { public: Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) : LayerCleaner(flinger, layer), owner(layer) {} wp<Layer> owner; };创建了一个handle对象,并传入的surfaceflinger。这个handle只是传给client端的一个BBbinder,当客户端释放了这个引用时,会调用其析构函数,那么它的析构函数做了什么事情呢?Handle本身没写析构函数,所以要做的事情就在其父类LayerCleaner的析构函数中。LayerCleaner的析构函数,调用了surfaceflinger的onLayerDestroyed。
Layer.h /* * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer) * is called. */ class LayerCleaner { sp<SurfaceFlinger> mFlinger; sp<Layer> mLayer; protected: ~LayerCleaner() { // destroy client resources mFlinger->onHandleDestroyed(mLayer); } public: LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) : mFlinger(flinger), mLayer(layer) {} }; SurfaceFlinger.h // A set of layers that have no parent so they are not drawn on screen. // Should only be accessed by the main thread. // The Layer pointer is removed from the set when the destructor is called so there shouldn't // be any issues with a raw pointer referencing an invalid object. std::unordered_set<Layer*> mOffscreenLayers; inline void onLayerDestroyed(Layer* layer) { { Mutex::Autolock lock(mLayerCountLock); mNumLayers--; } mOffscreenLayers.erase(layer); }Layer中很多变量的实例化,都是在onFirstRef中完成的,当Layer实例第一次被引用时会执行onFirstRef函数。此处以BufferQueueLayer为例说明:
BufferQueueLayer.cpp void BufferQueueLayer::onFirstRef() { BufferLayer::onFirstRef(); // Creates a custom BufferQueue for SurfaceFlingerConsumer to use sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; //通过BufferQueue创建BufferQueueProducer,BufferQueueConsumer,这样标识了 IGraphicBufferProducer对应的服务端是BufferQueueProducer, IGraphicBufferConsumer对应的服务端是 BufferQueueConsumer BufferQueue::createBufferQueue(&producer, &consumer, true); //这里返回给client端的并不是 IGraphicBufferProducer,而是对它的封装类 MonitoredProducer //MonitoredProducer并没有增加新的功能,只是在 IGraphicBufferProducer被销毁时,通知Surfaceflinger做些操作。 mProducer = new MonitoredProducer(producer, mFlinger, this); { // Grab the SF state lock during this since it's the only safe way to access RenderEngine Mutex::Autolock lock(mFlinger->mStateLock); mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this); } mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mConsumer->setContentsChangedListener(this); mConsumer->setName(mName); // BufferQueueCore::mMaxDequeuedBufferCount is default to 1 if (!mFlinger->isLayerTripleBufferingDisabled()) { mProducer->setMaxDequeuedBufferCount(2); } if (const auto display = mFlinger->getDefaultDisplayDevice()) { updateTransformHint(display); } }我们只关注MonitoredProducer的析构函数,看在IGraphicBufferProducer被销毁时,它要做什么。
MonitoredProducer.cpp MonitoredProducer::~MonitoredProducer() { // Remove ourselves from SurfaceFlinger's list. We do this asynchronously // because we don't know where this destructor is called from. It could be // called with the mStateLock held, leading to a dead-lock (it actually // happens). sp<LambdaMessage> cleanUpListMessage = new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() { Mutex::Autolock lock(flinger->mStateLock); flinger->mGraphicBufferProducerList.erase(asBinder); }); mFlinger->postMessageAsync(cleanUpListMessage); }类GLConsumer简介
GLConsumer.h /* * GLConsumer consumes buffers of graphics data from a BufferQueue, * and makes them available to OpenGL as a texture. * * A typical usage pattern is to set up the GLConsumer with the * desired options, and call updateTexImage() when a new frame is desired. * If a new frame is available, the texture will be updated. If not, * the previous contents are retained. * * By default, the texture is attached to the GL_TEXTURE_EXTERNAL_OES * texture target, in the EGL context of the first thread that calls * updateTexImage(). * * This class was previously called SurfaceTexture. */ class GLConsumer : public ConsumerBase ConsumerBase.h // ConsumerBase is a base class for BufferQueue consumer end-points. It // handles common tasks like management of the connection to the BufferQueue // and the buffer pool. class ConsumerBase : public virtual RefBase,protected ConsumerListener IConsumerListener.h // ConsumerListener is the interface through which the BufferQueue notifies the consumer of events // that the consumer may wish to react to. Because the consumer will generally have a mutex that is // locked during calls from the consumer to the BufferQueue, these calls from the BufferQueue to the // consumer *MUST* be called only when the BufferQueue mutex is NOT locked. class ConsumerListener : public virtual RefBaseclass GLConsumer :public ConsumerBase {}
class ConsumerBase :public virtual RefBase,protected ConsumerListener {}
GLConsumer有继承自ConsumerBase,间接继承了ConsumerListener。
接下来逐层分析逐个继承关系。
GLConsumer会消费来自BufferQueue的缓冲区或者叫图形数据,并把他们转做texture为opengl使用。一个典型的使用方式是使用所需要的选项设置GLConsumer,然后当有一帧需要时,调用updateTexImage,这个函数会获取最近queued的buffer,然后绑定这个buffer到GLtexture,如果这一帧是可用的,texture会被更新,如果不可用,前一帧的内容会被保留。
ConsumerBase是BufferQueue消费者的基类,它处理一些通用任务,比如到BufferQueue的连接,buffer池的管理,其中的成员变量sp<IGraphicBufferConsumer>mConsumer;就是SurfaceFlingerConsumer传过来的,ConsumerBase是通过IGraphicBufferConsumer对象来对BufferQueue执行操作的。
简单做个总结:
1)应用程序通过BufferQueue执行绘图,surfaceflinger会把系统中所有应用程序最终的绘图结果进行混合,然后送到物理屏幕显示。应用程序跟surfaceflinger之间的通信桥梁是IsurfaceComposrClient。
这个类被封装在SurfaceComposerClient中。
2)应用程序通过SurfaceComposerClient调用CreateSurface的过程中,除了得到IGraphicBufferProducer实例外,还创建了一个layer。把控制这个layer的handle,IGraphicBufferProducer对象,连同SurfaceComposerClient自身都保存在应用端的Surfacecontrol中。
3)Surface,应用程序通过Surfacecontrol的getSurface获取,其内部持有IGraphicBufferProducer对象,即BufferQueueProducer的实现接口。如果egl想通过Surface这个本地窗口完成某个功能,Surface实际上是利用IGraphicBufferProducer取得远程端的服务,完成egl的请求。
4)应用程序跟layer应该是一对多的关系,因为createSurface是可以被调用多次的,并且,一个应用程序申请的多个layer可以通过addClientLayer添加到一个全局变量mLayers中。应用程序申请的layer,一方面要记录都各个Client的内部变量mLayers中,另一方面还要告知SurfaceFlinger,这个操作也是在addClientLayer函数中完成的,即把layer添加到全局变量mCurrentState.layerSortByZ,Surfaceflinger会对这个列表中的所有layer排序,排序的结果直接影响了屏幕显示的画面。
5)每个layer对应一个BufferQueue,所以一个应用程序可能对应多个BufferQueue。layer并没有直接持有BufferQueue对象,而是通过其内部的IGraphicBufferProducer,mSurfaceFlingerConsumer来管理。