Android14 显示系统剖析5 ———— BLASTBufferQueue 初始化

6/12/2024

本文基于 aosp android-14.0.0_r15 版本讲解。

# 1. 引子

示例代码接下来就要 new 一个 BLASTBufferQueue 对象。

    mBlastBufferQueue = new BLASTBufferQueue("DemoBLASTBufferQueue", surfaceControl, 
                                             resolution.getWidth(), resolution.getHeight(),
                                             PIXEL_FORMAT_RGBA_8888);
1
2
3

在分析之前我们可以将 BLASTBufferQueue 作为一个黑盒,仅关注整体流程:

20240702161348

  1. App 调用 dequebuffer 向 BLASTBufferQueue 申请一个 buffer
  2. App 拿到 buffer 后开始渲染,所谓渲染就是把显示指令转换为内存数据写入 buffer
  3. 渲染完成后,将写入数据的 buffer 通过事务的方式提交给 SurfaceFligner,SurfaceFlinger 负责 buffer 的合成显示。

了解了整体流程,我们再看代码就能有整体上的把握了。

# 2. 构造函数实现分析

BLASTBufferQueue 是一个非常重要的类,它是帧缓存的大管家。其内部通过 BufferQueueCore BBQBufferQueueProducer BufferQueueConsumer 等类辅助管理帧缓存。

接下来,我们就一步步分析其内部实现。

看下构造函数的实现:

// /frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
                                   int width, int height, int32_t format)
      : BLASTBufferQueue(name) {
    update(surface, width, height, format);
}
1
2
3
4
5
6

BLASTBufferQueue 构造函数中会先调用另一个构造函数重载,然后调用 update 函数,我们先看构造函数的实现:

// /frameworks/native/libs/gui/include/gui/BLASTBufferQueue.h

sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
sp<BLASTBufferItemConsumer> mBufferItemConsumer;

// /frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
      : mSurfaceControl(nullptr),
        mSize(1, 1),
        mRequestedSize(mSize),
        mFormat(PIXEL_FORMAT_RGBA_8888),
        mTransactionReadyCallback(nullptr),
        mSyncTransaction(nullptr),
        mUpdateDestinationFrame(updateDestinationFrame) {
    
    // new 一个 BufferQueueCore 对象
    // 初始化 mConsumer 和 mProducer 成员
    createBufferQueue(&mProducer, &mConsumer);
    // since the adapter is in the client process, set dequeue timeout
    // explicitly so that dequeueBuffer will block
    mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());

    // safe default, most producers are expected to override this
    // 设置 buffer 数量
    mProducer->setMaxDequeuedBufferCount(2);
    // 初始化 mBufferItemConsumer 成员
    mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
                                                      GraphicBuffer::USAGE_HW_COMPOSER |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                      1, false, this);
    static std::atomic<uint32_t> nextId = 0;
    mProducerId = nextId++;
    mName = name + "#" + std::to_string(mProducerId);
    auto consumerName = mName + "(BLAST Consumer)" + std::to_string(mProducerId);
    mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(mProducerId);
    mBufferItemConsumer->setName(String8(consumerName.c_str()));
    
    // 这里注册了 listener 回调,this 就是 BLASTBufferQueue
    mBufferItemConsumer->setFrameAvailableListener(this);
    
    ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);

    // ?
    mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
    mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
    mNumAcquired = 0;
    mNumFrameAvailable = 0;

    TransactionCompletedListener::getInstance()->addQueueStallListener(
            [&](const std::string& reason) {
                std::function<void(const std::string&)> callbackCopy;
                {
                    std::unique_lock _lock{mMutex};
                    callbackCopy = mTransactionHangCallback;
                }
                if (callbackCopy) callbackCopy(reason);
            },
            this);

    BQA_LOGV("BLASTBufferQueue created");
}
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

构造函数中核心主要两点:

  • createBufferQueue 函数中,new 一个 BufferQueueCore 对象,初始化 mConsumer 和 mProducer 成员
  • 先 new 一个 BLASTBufferItemConsumer 对象,接着再调用一堆函数配置这个对象

接下来我们详细分析这两步的实现。

# 2.1 BufferQueueCore 的初始化

我们先看 createBufferQueue 函数的实现:

// /frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                         sp<IGraphicBufferConsumer>* outConsumer) {

    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");

    // 创建 BufferQueue 核心类,主要负责缓冲区的调度工作
    sp<BufferQueueCore> core(new BufferQueueCore());
    LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");

    // 创建生产者,用于串联图形生产者流程
    sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
    LOG_ALWAYS_FATAL_IF(producer == nullptr,
                        "BLASTBufferQueue: failed to create BBQBufferQueueProducer");

    // 创建消费者,用于串联图形消费者流程
    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
    consumer->setAllowExtraAcquire(true);
    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
                        "BLASTBufferQueue: failed to create BufferQueueConsumer");

    *outProducer = producer;
    *outConsumer = consumer;
}
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

核心的主要三点:

  • new 一个 BufferQueueCore 对象
  • new 一个 BBQBufferQueueProducer 对象赋值给 producer
  • new BufferQueueConsumer 对象赋值给 consumer

一个个看:

BufferQueueCore 的构造函数如下:

BufferQueueCore::BufferQueueCore()
      : mMutex(),
        mIsAbandoned(false),
        mConsumerControlledByApp(false),
        mConsumerName(getUniqueName()),
        mConsumerListener(),
        mConsumerUsageBits(0),
        mConsumerIsProtected(false),
        mConnectedApi(NO_CONNECTED_API),
        mLinkedToDeath(),
        mConnectedProducerListener(),
        mBufferReleasedCbEnabled(false),
        mSlots(),
        mQueue(),
        mFreeSlots(),
        mFreeBuffers(),
        mUnusedSlots(),
        mActiveBuffers(),
        mDequeueCondition(),
        mDequeueBufferCannotBlock(false),
        mQueueBufferCanDrop(false),
        mLegacyBufferDrop(true),
        mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
        mDefaultWidth(1),
        mDefaultHeight(1),
        mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
        mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
        mMaxAcquiredBufferCount(1),
        mMaxDequeuedBufferCount(1),
        mBufferHasBeenQueued(false),
        mFrameCounter(0),
        mTransformHint(0),
        mIsAllocating(false),
        mIsAllocatingCondition(),
        mAllowAllocation(true),
        mBufferAge(0),
        mGenerationNumber(0),
        mAsyncMode(false),
        mSharedBufferMode(false),
        mAutoRefresh(false),
        mSharedBufferSlot(INVALID_BUFFER_SLOT),
        mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
                           HAL_DATASPACE_UNKNOWN),
        mLastQueuedSlot(INVALID_BUFFER_SLOT),
        mUniqueId(getUniqueId()),
        mAutoPrerotation(false),
        mTransformHintInUse(0) {
    int numStartingBuffers = getMaxBufferCountLocked();
    for (int s = 0; s < numStartingBuffers; s++) {
        mFreeSlots.insert(s);
    }
    for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
            s++) {
        mUnusedSlots.push_front(s);
    }
}
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

BufferQueueCore 的构造函数就是给一堆成员变量做初始化,其中比较重要的成员有:

BufferQueueDefs::SlotsType mSlots;
Fifo mQueue;
std::set<int> mFreeSlots;
std::list<int> mFreeBuffers;
std::list<int> mUnusedSlots;
std::set<int> mActiveBuffers;
1
2
3
4
5
6

接下来一个个看:

mSlots 是一个 BufferSlot 数组,默认大小是 64

// typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
// static constexpr int NUM_BUFFER_SLOTS = 64;
BufferQueueDefs::SlotsType mSlots;
1
2
3

问题来了,BufferSLot 是什么?

BufferSLot 的定义如下:

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;

    // 用于表示 GPU 是否已经完成了与图形缓冲区相关的渲染操作
    // 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;

    // 用于 SurfaceFlinger 内部的图形合成和显示操作
    // 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;
};
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

BufferSlot 可以认为是一个存放帧缓存及其相关信息的地方。

我们主要关注 BufferSlot 的几个重要成员:

  • sp<GraphicBuffer> mGraphicBuffer:指向当前 BufferSlot 相关联的 buffer,如果没有 buffer,就是 null
  • BufferState mBufferState:当前 Slot 的状态
  • bool mNeedsReallocation;:是否需要重新分配这个buffer;
  • sp<Fence> mFence,用于 SurfaceFlinger 内部的图形合成和显示操作
  • EGLSyncKHR mEglFence,用于表示 GPU 是否已经完成了与图形缓冲区相关的渲染操作

其中 GraphicBuffer 代表一块显示内存,其定义如下:

// /frameworks/native/libs/ui/include/ui/GraphicBuffer.h

class GraphicBuffer
    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
      public Flattenable<GraphicBuffer>
{
    // ......
}
1
2
3
4
5
6
7
8

GraphicBuffer 继承自 Flattenable<GraphicBuffer>,说明 GraphicBuffer 对象可以通过 Binder 跨进程传输。

GraphicBuffer 继承自 ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,它是一个模板类,其定义如下:

template <typename NATIVE_TYPE, typename TYPE, typename REF,
        typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{
    // ......
}
1
2
3
4
5
6

带入泛型后,ANativeObjectBase 继承 ANativeWindowBuffer 和 RefBase

RefBase 可以让 GraphicBuffer 支持引用计数。

ANativeWindowBuffer 的定义如下:

// /frameworks/native/libs/nativebase/include/nativebase/nativebase.h
typedef struct ANativeWindowBuffer
{
#ifdef __cplusplus
    ANativeWindowBuffer() {
        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
        common.version = sizeof(ANativeWindowBuffer);
        memset(common.reserved, 0, sizeof(common.reserved));
    }

    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
    // can be used to automatically refcount ANativeWindowBuffer's.
    void incStrong(const void* /*id*/) const {
        common.incRef(const_cast<android_native_base_t*>(&common));
    }
    void decStrong(const void* /*id*/) const {
        common.decRef(const_cast<android_native_base_t*>(&common));
    }
#endif

    struct android_native_base_t common;

    int width;
    int height;
    int stride;
    int format;
    int usage_deprecated;
    uintptr_t layerCount;

    void* reserved[1];

    const native_handle_t* handle;
    uint64_t usage;

    // we needed extra space for storing the 64-bits usage flags
    // the number of slots to use from reserved_proc depends on the
    // architecture.
    void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
} ANativeWindowBuffer_t;
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

ANativeWindowBuffer 用于描述一块 Native Buffer,核心成员是 native_handle_t,其定义如下:

typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    int numFds;         /* number of file-descriptors at &data[0] */
    int numInts;        /* number of ints at &data[numFds] */
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
#endif
    int data[0];        /* numFds + numInts ints */
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} native_handle_t;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

最后一个指针 data 中指向的就是 fd,这些 fd 就是 buffer 的句柄或者说索引。

可以看出实际在进程间传递的是内存的 fd,而不是 buffer 本身,这个和前文的解析也是一致的。

BufferState 用于描述一个 BufferSlot 的状态,其定义如下:

// /frameworks/native/libs/gui/include/gui/BufferSlot.h

struct BufferState {

    BufferState()
    : mDequeueCount(0),
      mQueueCount(0),
      mAcquireCount(0),
      mShared(false) {
    }

    uint32_t mDequeueCount;
    uint32_t mQueueCount;
    uint32_t mAcquireCount;
    bool mShared;


    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++;
    }
};
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

通过四个变量来描述 Slot 的状态,一共有 5 种情况:

    //         | 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      |
1
2
3
4
5
6
7

也就是说一个 BufferSlot 可以有 5 种状态:

  • FREE
  • DEQUEUED
  • QUEUED
  • ACQUIRED
  • SHARED

这几种状态的转换逻辑如下:

  • 一个 BufferSlot 对象一开始是 FREE 状态,
  • 生产者调用 dequeueBuffer 获取 slot 后就进入 DEQUEUED 状态
  • 生产者使用完 buffer 调用 queueBuffer 后把 buffer 放到列表里就进入了 QUEUED 状态
  • 消费者使用 acquireBuffer 获取 Buffer 后,就进入ACQUIRED状态
  • 消费者使用 releaseBuffer 把 Buffer 释放后,就进入FREE状态

SHARED 状态比较特殊,这里有一个共享 Buffer 模式,看代码实现逻辑就是一直共享复用一个 buffer,这种情况这个 buffer 就是 SHARED 状态,默认情况是不使用这种模式的,一般不用关注。

这些类的关系如下图所示:

20240701224513

接着看 BufferQueueCore 的另一个成员 Fifo mQueue.

// typedef Vector<BufferItem> Fifo;
Fifo mQueue
1
2

mQueue 是 BufferItem 类型的 Vector,从名字 Fifo 可以看出,它应该是一个队列,即内部元素先进先出。

BufferItem 的定义如下:

// /frameworks/native/libs/gui/include/gui/BufferItem.h

class BufferItem : public Flattenable<BufferItem> {
    friend class Flattenable<BufferItem>;
    size_t getPodSize() const;
    size_t getFlattenedSize() const;
    size_t getFdCount() const;
    status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
    status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);

    public:
    // The default value of mBuf, used to indicate this doesn't correspond to a slot.
    enum { INVALID_BUFFER_SLOT = -1 };
    BufferItem();
    ~BufferItem();
    BufferItem(const BufferItem&) = default;
    BufferItem& operator=(const BufferItem&) = default;

    static const char* scalingModeName(uint32_t scalingMode);

    // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
    // if the buffer in this slot has been acquired in the past (see
    // BufferSlot.mAcquireCalled).
    sp<GraphicBuffer> mGraphicBuffer;

    // mFence is a fence that will signal when the buffer is idle.
    sp<Fence> mFence;

    // The std::shared_ptr<FenceTime> wrapper around mFence.
    std::shared_ptr<FenceTime> mFenceTime{FenceTime::NO_FENCE};

    // mCrop is the current crop rectangle for this buffer slot.
    Rect mCrop;

    // mTransform is the current transform flags for this buffer slot.
    // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
    uint32_t mTransform;

    // mScalingMode is the current scaling mode for this buffer slot.
    // refer to NATIVE_WINDOW_SCALING_* in <window.h>
    uint32_t mScalingMode;

    // mTimestamp is the current timestamp for this buffer slot. This gets
    // to set by queueBuffer each time this slot is queued. This value
    // is guaranteed to be monotonically increasing for each newly
    // acquired buffer.
    int64_t mTimestamp;

    // mIsAutoTimestamp indicates whether mTimestamp was generated
    // automatically when the buffer was queued.
    bool mIsAutoTimestamp;

    // mDataSpace is the current dataSpace value for this buffer slot. This gets
    // set by queueBuffer each time this slot is queued. The meaning of the
    // dataSpace is format-dependent.
    android_dataspace mDataSpace;

    // mHdrMetadata is the HDR metadata associated with this buffer slot.
    HdrMetadata mHdrMetadata;

    // mFrameNumber is the number of the queued frame for this slot.
    uint64_t mFrameNumber;

    // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
    int mSlot;

    // mIsDroppable whether this buffer was queued with the
    // property that it can be replaced by a new buffer for the purpose of
    // making sure dequeueBuffer() won't block.
    // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
    // was queued.
    bool mIsDroppable;

    // Indicates whether this buffer has been seen by a consumer yet
    bool mAcquireCalled;

    // Indicates this buffer must be transformed by the inverse transform of the screen
    // it is displayed onto. This is applied after mTransform.
    bool mTransformToDisplayInverse;

    // Describes the portion of the surface that has been modified since the
    // previous frame
    Region mSurfaceDamage;

    // Indicates that the consumer should acquire the next frame as soon as it
    // can and not wait for a frame to become available. This is only relevant
    // in shared buffer mode.
    bool mAutoRefresh;

    // Indicates that this buffer was queued by the producer. When in shared
    // buffer mode acquire() can return a BufferItem that wasn't in the queue.
    bool mQueuedBuffer;

    // Indicates that this BufferItem contains a stale buffer which has already
    // been released by the BufferQueue.
    bool mIsStale;

    // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
    int mApi;
};
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

BufferItem 和 BufferSlot 比较类似,也是帧缓存及其相关信息的集合,它的作用是什么呢?

当 App 想要显示一个图像时,就会从 mSlots 中取出一个 BufferSlot,然后把需要显示的内容写入到 BufferSlot 中的 GraphicBuffer 成员中,接着再把 BufferSlot 转换成 BufferItem 插入 Fifo mQueue 队列中。接着再从队列中取出 BufferItem,转换为 BufferSlot,获取到 Buffer,然后把这个 Buffer 提交给 sf 显示。可以看出 BufferItem 就是一个中间状态的角色,这就它的作用。

我们接着看 BufferQueueCore 的另外一个成员 mFreeSlots:

std::set<int> mFreeSlots;
1

mFreeSlots 是一个 int 类型的 set,这里的 int 值实际是 mSlots 数组中的索引,代表了一个 BufferSlot 对象。

mFreeSlots 中保存的是没有绑定 GraphicBuffer 且状态为 FREE 的 BufferSlot 集合;

接着看 BufferQueueCore 的另外一个成员 mFreeBuffers:

std::list<int> mFreeBuffers;
1

mFreeBuffers 是一个 int 类型的 set,这里的 int 值实际是 mSlots 数组中的索引,代表了一个 BufferSlot 对象。 mFreeSlots 中保存的是绑定了 GraphicBuffer 且状态为 FREE 的 BufferSlot 集合;

  std::list<int> mUnusedSlots;
1

mUnusedSlots 表示未参与使用的 slot 集合,由 mMaxBufferCount 决定

  std::set<int> mActiveBuffers;
1

mActiveBuffers 表示绑定了 GraphicBuffer 且状态为非 FREE 的 BufferSlot 集合

另外再强调一下:

mFreeSlots/mFreeBuffers/mUnusedSlots/mActiveBuffers 存储的都是 int 类型的 index,根据这个 index 去 mSlots 中获取对应的 BufferSlot 及 GraphicBuffer。 之所以划分出这么多不同的数组,都是为了给 BufferSlot 分类,以便获取 GraphicBuffer 时更加高效。

这些成员的组成如下图所示:

20240612115333

图片来自:https://blog.csdn.net/hexiaolong2009/article/details/99225637

# 2.2 BBQBufferQueueProducer 与 BufferQueueConsumer 的初始化

完成了 BufferQueueCore 的初始化,接着就是 new BBQBufferQueueProducer。

BBQBufferQueueProducer 的构造函数如下:

class BBQBufferQueueProducer : public BufferQueueProducer {
public:
    BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq)
          : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/),
            mBLASTBufferQueue(std::move(bbq)) {}

    // ......

private:
    const wp<BLASTBufferQueue> mBLASTBufferQueue;
};
1
2
3
4
5
6
7
8
9
10
11

调用父类的构造函数,将参数中传入的 bbq 保存到成员变量 mBLASTBufferQueue 中。

父类 BufferQueueProducer 构造函数如下:

BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
        bool consumerIsSurfaceFlinger) :
    mCore(core),
    mSlots(core->mSlots),
    mConsumerName(),
    mStickyTransform(0),
    mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
    mLastQueueBufferFence(Fence::NO_FENCE),
    mLastQueuedTransform(0),
    mCallbackMutex(),
    mNextCallbackTicket(0),
    mCurrentCallbackTicket(0),
    mCallbackCondition(),
    mDequeueTimeout(-1),
    mDequeueWaitingForAllocation(false) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

主要就是内部成员的初始化。

BufferQueueConsumer 的构造函数实现如下:

// /frameworks/native/libs/gui/include/gui/BufferQueueConsumer.h
class BufferQueueConsumer : public BnGraphicBufferConsumer {
    //......
  private:
    sp<BufferQueueCore> mCore;

    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
    BufferQueueDefs::SlotsType& mSlots;

    // This is a cached copy of the name stored in the BufferQueueCore.
    // It's updated during setConsumerName.
    String8 mConsumerName;
}

// /frameworks/native/libs/gui/BufferQueueConsumer.cpp
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
    mCore(core),
    mSlots(core->mSlots),
    mConsumerName() {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

就是在构造函数中使用传入的参数初始化了 mCore mSlots 成员。

# 2.3 BLASTBufferItemConsumer 的初始化与配置

接着看 new BLASTBufferItemConsumer 的过程。

// 参数 mConsumer 类型是 BufferQueueConsumer
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
                                                      GraphicBuffer::USAGE_HW_COMPOSER |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                      1, false, this);
1
2
3
4
5

BLASTBufferItemConsumer 的构造函数实现如下:

class BLASTBufferItemConsumer : public BufferItemConsumer {
public:
    BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
                            int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
          : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
            mBLASTBufferQueue(std::move(bbq)),
            mCurrentlyConnected(false),
            mPreviouslyConnected(false) {}

   // ......
};
1
2
3
4
5
6
7
8
9
10
11

这里会调用到父类 BufferItemConsumer 的构造函数:

BufferItemConsumer::BufferItemConsumer(
        const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
        int bufferCount, bool controlledByApp) :
    ConsumerBase(consumer, controlledByApp)
{
    status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
    LOG_ALWAYS_FATAL_IF(err != OK,
            "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
    if (bufferCount != DEFAULT_MAX_BUFFERS) {
        err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
        LOG_ALWAYS_FATAL_IF(err != OK,
                "Failed to set max acquired buffer count to %d", bufferCount);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

接着调用父类 ConsumerBase 的构造函数

// bufferQueue 的类型是 BufferQueueConsumer
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
        mAbandoned(false),
        mConsumer(bufferQueue),
        mPrevFinalReleaseFence(Fence::NO_FENCE) {
    // Choose a name using the PID and a process-unique ID.
    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());

    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
    // reference once the ctor ends, as that would cause the refcount of 'this'
    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
    // that's what we create.
    // listener 就是 BLASTBufferItemConsumer 自己
    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
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

这里会把 BLASTBufferItemConsumer 对象转换为一个 IConsumerListener 指针,接着传递给 consumerConnect 函数,consumerConnect 函数的实现如下:

    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
            bool controlledByApp) {
        return connect(consumer, controlledByApp);
    }
1
2
3
4

接着调用 connect 函数:

status_t BufferQueueConsumer::connect(
        const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
    ATRACE_CALL();

    if (consumerListener == nullptr) {
        BQ_LOGE("connect: consumerListener may not be NULL");
        return BAD_VALUE;
    }

    BQ_LOGV("connect: controlledByApp=%s",
            controlledByApp ? "true" : "false");

    std::lock_guard<std::mutex> lock(mCore->mMutex);

    if (mCore->mIsAbandoned) {
        BQ_LOGE("connect: BufferQueue has been abandoned");
        return NO_INIT;
    }
    
    // 这里的 mConsumerListener 实际就是 BLASTBufferItemConsumer 的包装
    mCore->mConsumerListener = consumerListener;
    mCore->mConsumerControlledByApp = controlledByApp;

    return NO_ERROR;
}
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

mCore->mConsumerListener 的值其实就是之前 new 的 BLASTBufferItemConsumer 对象的包装。这点很重要,后续的代码会调用到这个回调。

小结一下:

new BLASTBufferQueue
    createBufferQueue
        new BufferQueueCore
        new BBQBufferQueueProducer
        new BufferQueueConsumer
    new BLASTBufferItemConsumer
        mCore->mConsumerListener = consumerListener;
1
2
3
4
5
6
7
  • new 了一个 BLASTBufferQueue 对象
  • new 了一个 BufferQueueCore 对象
  • new 了一个 BBQBufferQueueProducer 对象
  • new 了一个 BufferQueueConsumer 对象
  • new 了一个 BLASTBufferItemConsumer 对,将 BufferQueueCore 的 mConsumerListener 成员赋值为自己。

这些类的相互关系如下图所示:

到目前为止了,就是把这一堆对象给准备好了,等着后面来操作。

# 2.4 update 函数实现

BLASTBufferQueue 构造函数中接着再调用 update 函数:

void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
                              int32_t format) {
    LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL");

    std::lock_guard _lock{mMutex};
    if (mFormat != format) {
        mFormat = format;
        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
    }

    const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
    if (surfaceControlChanged && mSurfaceControl != nullptr) {
        BQA_LOGD("Updating SurfaceControl without recreating BBQ");
    }
    bool applyTransaction = false;

    // Always update the native object even though they might have the same layer handle, so we can
    // get the updated transform hint from WM.
    mSurfaceControl = surface;
    SurfaceComposerClient::Transaction t;
    if (surfaceControlChanged) {
        t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
                   layer_state_t::eEnableBackpressure);
        applyTransaction = true;
    }
    mTransformHint = mSurfaceControl->getTransformHint();
    mBufferItemConsumer->setTransformHint(mTransformHint);
    BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
             mTransformHint);

    ui::Size newSize(width, height);
    if (mRequestedSize != newSize) {
        mRequestedSize.set(newSize);
        mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
        if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
            // If the buffer supports scaling, update the frame immediately since the client may
            // want to scale the existing buffer to the new size.
            mSize = mRequestedSize;
            if (mUpdateDestinationFrame) {
                t.setDestinationFrame(mSurfaceControl, Rect(newSize));
                applyTransaction = true;
            }
        }
    }
    if (applyTransaction) {
        // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
        t.setApplyToken(mApplyToken).apply(false, true);
    }
}
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

update 主要是给 BLASTBufferQueue 的成员变量赋值。比较重要的是:

  • mSurfaceControl 赋值为传入的 surface 参数
  • 配置 mBufferItemConsumer

# 3. 总结

在 BLASTBufferQueue 初始化过程中,主要完成了以下工作:

  • new 了一个 BufferQueueCore 对象,该对象内部有好几数据结构,用于管理帧缓存
  • new 了一个 BBQBufferQueueProducer 对象,该对象用于从 BufferQueueCore 中取出一个 buffer,接着 app 就可以向 buffer 填充要显示的内容
  • new 了 BufferQueueConsumer 对象,该对象用于从 BufferQueueCore 中取出一个 buffer,然后提交给 sf 显示

# 参考资料