Android Surfaceflinger服務(一) ----- BufferQueue分析

來源:互聯網
上載者:User

標籤: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):

  1. dequeueBuffer
  2. requestBuffer
  3. queueBuffer

BufferQueue消費步驟(消費者介面BufferQueueConsumer):

  1. acquireBuffer
  2. 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分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.