標籤:lists ica info async update 成員函數 available mos locking
生產者和消費者模型是編程中運用比較廣泛的模型。在SurfaceFlinger映像繪製、合成、顯示也用到了該模型。利用該模型合理的管理映像緩衝區buffer。讓整個android系統從繪製到顯示的過程有條不紊的進行。
BufferQueue映像緩衝管理者。其成員函數createBufferQueue建立一個緩衝區隊列。
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, const sp<IGraphicBufferAlloc>& allocator) { LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); sp<BufferQueueCore> core(new BufferQueueCore(allocator)); LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core)); LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer;}
- outProducer outConsumer為輸出參數,輸出對應的生產者介面,和消費者介面
- allocator為輸入參數,輸入一個映像緩衝區記憶體配置介面,用於記憶體的申請
- 首先通用allocator構造一個BufferQueueCore對象,然後在用該物件建構生產者對象(BufferQueueProducer)和消費者對象(BufferQueueConsumer)
class BufferQueueCore : public virtual RefBase { friend class BufferQueueProducer; friend class BufferQueueConsumer;public: // Used as a placeholder slot number when the value isn‘t pointing to an // existing buffer. enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // We reserve two slots in order to guarantee that the producer and // consumer can run asynchronously. enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; // The default API number used to indicate that no producer is connected enum { NO_CONNECTED_API = 0 }; typedef Vector<BufferItem> Fifo; // BufferQueueCore manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the needed // gralloc buffers. BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL); virtual ~BufferQueueCore();private: // Dump our state in a string void dump(String8& result, const char* prefix) const; // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we‘re in asynchronous mode. int getMinUndequeuedBufferCountLocked(bool async) const; // getMinMaxBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. The async parameter tells whether // we‘re in asynchonous mode. int getMinMaxBufferCountLocked(bool async) const; // getMaxBufferCountLocked returns the maximum number of buffers that can be // allocated at once. This value depends on the following member variables: // // mDequeueBufferCannotBlock // mMaxAcquiredBufferCount // mDefaultMaxBufferCount // mOverrideMaxBufferCount // async parameter // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. int getMaxBufferCountLocked(bool async) const; // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots // that will be used if the producer does not override the buffer slot // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The // initial default is 2. status_t setDefaultMaxBufferCountLocked(int count); // freeBufferLocked frees the GraphicBuffer and sync resources for the // given slot. void freeBufferLocked(int slot); // freeAllBuffersLocked frees the GraphicBuffer and sync resources for // all slots. void freeAllBuffersLocked(); // stillTracking returns true iff the buffer item is still being tracked // in one of the slots. bool stillTracking(const BufferItem* item) const; // waitWhileAllocatingLocked blocks until mIsAllocating is false. void waitWhileAllocatingLocked() const; // validateConsistencyLocked ensures that the free lists are in sync with // the information stored in mSlots void validateConsistencyLocked() const; // mAllocator is the connection to SurfaceFlinger that is used to allocate // new GraphicBuffer objects. sp<IGraphicBufferAlloc> mAllocator; // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueueCore objects. It must be locked whenever any // member variable is accessed. mutable Mutex mMutex; // mIsAbandoned indicates that the BufferQueue will no longer be used to // consume image buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the // consumerDisconnect method. A BufferQueue that is abandoned will return // the NO_INIT error from all IGraphicBufferProducer methods capable of // returning an error. bool mIsAbandoned; // mConsumerControlledByApp indicates whether the connected consumer is // controlled by the application. bool mConsumerControlledByApp; // mConsumerName is a string used to identify the BufferQueue in log // messages. It is set by the IGraphicBufferConsumer::setConsumerName // method. String8 mConsumerName; // 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; // mConsumerUsageBits contains flags that the consumer wants for // GraphicBuffers. uint32_t mConsumerUsageBits; // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated // by the connect and disconnect methods. int mConnectedApi; // mConnectedProducerToken is used to set a binder death notification on // the producer. sp<IProducerListener> mConnectedProducerListener; // 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; // mQueue is a FIFO of queued buffers used in synchronous mode. Fifo mQueue; // 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; // mOverrideMaxBufferCount is the limit on the number of buffers that will // be allocated at one time. This value is set by the producer by calling // setBufferCount. The default is 0, which means that the producer doesn‘t // care about the number of buffers in the pool. In that case, // mDefaultMaxBufferCount is used as the limit. int mOverrideMaxBufferCount; // mDequeueCondition is a condition variable used for dequeueBuffer in // synchronous mode. mutable Condition mDequeueCondition; // mUseAsyncBuffer indicates whether an extra buffer is used in async mode // to prevent dequeueBuffer from blocking. bool mUseAsyncBuffer; // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and // consumer are controlled by the application. bool mDequeueBufferCannotBlock; // mDefaultBufferFormat can be set so it will override the buffer format // when it isn‘t specified in dequeueBuffer. PixelFormat mDefaultBufferFormat; // mDefaultWidth holds the default width of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultWidth; // mDefaultHeight holds the default height of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultHeight; // mDefaultBufferDataSpace holds the default dataSpace of queued buffers. // It is used in queueBuffer if a dataspace of 0 (HAL_DATASPACE_UNKNOWN) // is specified. android_dataspace mDefaultBufferDataSpace; // mDefaultMaxBufferCount is the default limit on the number of buffers that // will be allocated at one time. This default limit is set by the consumer. // The limit (as opposed to the default limit) may be overriden by the // producer. int mDefaultMaxBufferCount; // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer // via setMaxAcquiredBufferCount, but this may only be done while no // producer is connected to the BufferQueue. This value is used to derive // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. int mMaxAcquiredBufferCount; // mBufferHasBeenQueued is true once a buffer has been queued. It is reset // when something causes all buffers to be freed (e.g., changing the buffer // count). bool mBufferHasBeenQueued; // mFrameCounter is the free running counter, incremented on every // successful queueBuffer call and buffer allocation. uint64_t mFrameCounter; // mTransformHint is used to optimize for screen rotations. uint32_t mTransformHint; // mSidebandStream is a handle to the sideband buffer stream, if any sp<NativeHandle> mSidebandStream; // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which // releases mMutex while doing the allocation proper). Producers should not modify any of the // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to // false. bool mIsAllocating; // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. mutable Condition mIsAllocatingCondition; // mAllowAllocation determines whether dequeueBuffer is allowed to allocate // new buffers bool mAllowAllocation; // mBufferAge tracks the age of the contents of the most recently dequeued // buffer as the number of frames that have elapsed since it was last queued uint64_t mBufferAge; // mGenerationNumber stores the current generation number of the attached // producer. Any attempt to attach a buffer with a different generation // number will fail. uint32_t mGenerationNumber;}; // class BufferQueueCore
- 這個類是一個比較關鍵的類
- 成員變數mSlots管理著隊列中各個緩衝區的狀態
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) { } // 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; // BufferState represents the different states in which a buffer slot // can be. All slots are initially FREE. enum BufferState { FREE = 0, DEQUEUED = 1, QUEUED = 2, ACQUIRED = 3 }; static const char* bufferStateName(BufferState state); // 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 this buffer needs to be cleaned up by the // consumer. This is set when a buffer in ACQUIRED state is freed. // It causes releaseBuffer to return STALE_BUFFER_SLOT. bool mNeedsCleanupOnRelease; // Indicates whether the buffer was attached on the consumer side. // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued // to prevent the producer from using a stale cached buffer. bool mAttachedByConsumer;};
- BufferState定義了緩衝區的五種狀態
- 該結構體描述了每個緩衝區的狀態與屬性
BufferQueue的生產步驟(生產者介面BufferQueueProducer):
- dequeueBuffer
- requestBuffer
- queueBuffer
BufferQueue消費步驟(消費者介面BufferQueueConsumer):
- acquireBuffer
- releaseBuffer
生產者在緩衝區填充完成後,調用queueBuffer方法將緩衝區排入佇列,並且通知消費者。
status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { ....... frameAvailableListener = mCore->mConsumerListener; ...... frameAvailableListener->onFrameAvailable(item); ...... }
- 擷取BufferQueueCore內的成員變數mConsumerListener(消費者監聽介面)
- 回調介面方法onFrameAvailable
那麼問題又來了,mConsumerListener又是在哪裡給設定的呢?
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;}
- BufferQueueConsumer::connect函數中會傳入consumerListener介面指標,並設定給mCore->mConsumerListener
- 最終決定在哪消費就那BufferQueueConsumer介面調用connect函數時傳入的介面物件類型
Android Surfaceflinger服務(一) ----- BufferQueue分析