AndroidQ 图形系统(3)dequeueBuffer函数分析

上一篇文章分析了生产者-消费者模型,构成此模型最重要的三个类就是生产者BufferQueueProducer,消费者BufferQueueConsumer,buffer队列BufferQueue,而buffer队列的核心就是BufferQueueCore。

本篇文章来分析一下dequeueBuffer这个函数,这个函数的作用是应用程序一端请求绘制图像时,向BufferQueue中申请一块可用的GraphicBuffer,有了这个buffer就可以绘制图像数据了。

在分析这个函数之前先来看看BufferQueueCore中维护的许多生产者-消费者模型需要用到的基本数据结构,首先来看看成员变量Fifo,如下所示:

typedef Vector<BufferItem> Fifo;

这是一个BufferItem的Vector,BufferItem是用来封装生产者生产的具体图形信息的,每次queueBuffer时都会创建一个,我们说的BufferQueue队列其实就是这个数据结构,使用如下成员变量mQueue来表示的

// mQueue is a FIFO of queued buffers used in synchronous mode.
    Fifo mQueue;

再来看看成员变量mSlots:

    BufferQueueDefs::SlotsType mSlots;

BufferQueueDefs::SlotsTyp定义在BufferQueueDefs.h中:

namespace BufferQueueDefs {
        typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
    }

其实mSlots就是一个BufferSlot数组,大小为NUM_BUFFER_SLOTS等于64,BufferSlot主要是用来绑定GraphicBuffer的,一个BufferSlot绑定一个GraphicBuffer,它很重要,它里面还有一个BufferState专门用来描述当前存储的这个GraphicBuffer的状态:

BufferState()
    : mDequeueCount(0),
      mQueueCount(0),
      mAcquireCount(0),
      mShared(false) {
    }
    //         | 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      |
    //

BufferState的5种状态:FREE、 DEQUEUED、 QUEUED、 ACQUIRED、 SHARED,状态由引用计数来表示的,例如mDequeueCount为1,mShared为false,mQueueCount和mAcquireCount都为0则表示状态为DEQUEUED。

再看看成员变量mFreeSlots:

// mFreeSlots contains all of the slots which are FREE and do not currently
    // have a buffer attached.
    std::set<int> mFreeSlots;

mFreeSlots代表所有没有绑定GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。

继续看成员变量mFreeBuffers:

 // mFreeBuffers contains all of the slots which are FREE and currently have
    // a buffer attached.
    std::list<int> mFreeBuffers;

mFreeBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。

继续看成员变量mActiveBuffers:

// mActiveBuffers contains all slots which have a non-FREE buffer attached.
    std::set<int> mActiveBuffers;

mActiveBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态不为FREE,可以是另外四种状态的任意一种。

继续看成员变量mUnusedSlots:

 // mUnusedSlots contains all slots that are currently unused. They should be
    // free and not have a buffer attached.
    std::list<int> mUnusedSlots;

mUnusedSlots代表当前没有使用的BufferSlot集合。
需要注意是以上的数据结构存储的都是BufferSlot的index

这几个数据结构都是为了给BufferSlot分类,以便获取GraphicBuffer时更加高效。

接着我们分析申请GraphicBuffer的函数dequeueBuffer,从Surface.cpp的dequeueBuffer为入口开始,这个函数比较多,分部分来看看

dequeueBuffer
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ATRACE_CALL();
    ALOGV("Surface::dequeueBuffer");

    uint32_t reqWidth;
    uint32_t reqHeight;
    PixelFormat reqFormat;
    uint64_t reqUsage;
    bool enableFrameTimestamps;

    {
        Mutex::Autolock lock(mMutex);
        if (mReportRemovedBuffers) {
            mRemovedBuffers.clear();
        }

        reqWidth = mReqWidth ? mReqWidth : mUserWidth;
        reqHeight = mReqHeight ? mReqHeight : mUserHeight;

        reqFormat = mReqFormat;
        reqUsage = mReqUsage;

        enableFrameTimestamps = mEnableFrameTimestamps;

        if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                BufferItem::INVALID_BUFFER_SLOT) {
            sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
            if (gbuf != nullptr) {
                *buffer = gbuf.get();
                *fenceFd = -1;
                return OK;
            }
        }
    } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer  
        ......
 }
第一部分主要是给一些buffer的参数设置,这些值由外部应用程序设置,如buffer宽高,格式等,接着如果满足mSharedBufferMode等一些条件则通过index为mSharedBufferSlot直接从mSlots中获取buffer,不太清楚mSharedBufferMode这是一种什么模式,默认值为false,想必是外部应用程序请求的,暂时不管了

接着看第二部分,我们重点需要分析的dequeueBuffer函数调用:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ......
    int buf = -1;
    sp<Fence> fence;
    nsecs_t startTime = systemTime();

    FrameEventHistoryDelta frameTimestamps;
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
    ......

Fence和资源同步相关,其实可以看到dequeueBuffer的很多参数都是生产者这边传递过去对buffer的一些设置,重要的是buf这个参数,它是个int类型,代表dequeueBuffer获取到的BufferSlot的下标,前面我们分析过,BufferQueueCore中有几个用来管理BufferSlot的数据结构mFreeSlots,mFreeBuffers等保存的都是下标,这里将buf传递过去,最终获取到可用BufferSlot的下标,再根据下标从mSlots中获取BufferSlot,这点等下再说,先看看dequeueBuffer获取BufferSlot的具体规则是什么?
调用的是生产者BufferQueueProducer的dequeueBuffer函数:

BufferQueueProducer::dequeueBuffer
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) {
    ATRACE_CALL();
    { // Autolock scope
        std::lock_guard<std::mutex> lock(mCore->mMutex);
        mConsumerName = mCore->mConsumerName;

        if (mCore->mIsAbandoned) {
            BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
            return NO_INIT;
        }

        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
            BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");
            return NO_INIT;
        }
    } // Autolock scope

    BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64, width, height, format, usage);

    if ((width && !height) || (!width && height)) {
        BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
        return BAD_VALUE;
    }

    status_t returnFlags = NO_ERROR;
    EGLDisplay eglDisplay = EGL_NO_DISPLAY;
    EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
    bool attachedByConsumer = false;

    { // Autolock scope
        std::unique_lock<std::mutex> lock(mCore->mMutex);

        // If we don't have a free buffer, but we are currently allocating, we wait until allocation
        // is finished such that we don't allocate in parallel.
        if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
            mDequeueWaitingForAllocation = true;
            mCore->waitWhileAllocatingLocked(lock);
            mDequeueWaitingForAllocation = false;
            mDequeueWaitingForAllocationCondition.notify_all();
        }

        if (format == 0) {
            format = mCore->mDefaultBufferFormat;
        }

        // Enable the usage bits the consumer requested
        usage |= mCore->mConsumerUsageBits;

        const bool useDefaultSize = !width && !height;
        if (useDefaultSize) {
            width = mCore->mDefaultWidth;
            height = mCore->mDefaultHeight;
        }
        ......
这个函数代码也非常多,我们分部分来看,mCore->mIsAbandoned代表当前BufferQueue的状态,如果不可用直接return,mCore->mConnectedApi这个是从Surface那边传递获取的,是否与BufferQueue建立连接,通常是调用native_window_api_connect这个API实现的,如果没有建立连接也直接return,接着就是检查宽高的合法性,定义好最终的返回值returnFlags,EGLDisplay,EGLSyncKHR暂时不清楚用来干嘛的,接着来到如下段代码:

if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
            mDequeueWaitingForAllocation = true;
            mCore->waitWhileAllocatingLocked(lock);
            mDequeueWaitingForAllocation = false;
            mDequeueWaitingForAllocationCondition.notify_all();
        }

mFreeBuffers前面已经分析过,代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE,如果mFreeBuffers为空(代表当前没有绑定了GraphicBuffer的BufferSlot)并且当前正在为GraphicBuffer分配内存空间,则调用waitWhileAllocatingLocked等待空间分配,等待\唤醒机制利用的是C++的条件变量,接着如果format == 0则使用mDefaultBufferFormat,接着如果宽高为0则使用BufferQueueCore的默认宽高。

第一部分已经分析完了,接着看第二部分:

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) {
    ......
        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.
            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;
                }
            }
        }
    ......
}


这第二部分就是寻找可用BufferSlot的核心代码了,通过一个while循环不断的查找,直到found != BufferItem::INVALID_BUFFER_SLOT,首先found初始化状态为BufferItem::INVALID_BUFFER_SLOT,进入While循环,调用核心函数waitForFreeSlotThenRelock,这个函数代码也挺多的,把这个函数分三部分来分析,首先看第一部分。

waitForFreeSlotThenRelock
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) {
        if (mCore->mIsAbandoned) {
            BQ_LOGE("%s: BufferQueue has been abandoned", callerString);
            return NO_INIT;
        }

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


这整个函数就是一个while循环,直到找到可用BufferSlot或者发生错误,首先获取当前调用此函数的是dequeueBuffer还是attachBuffer,定义while的开关tryAgain默认为true,会一直尝试获取,进入while循环,如果当前BufferQueue已经被弃用则直接return,
接着看看如下小段代码:

        int dequeuedCount = 0;
        int acquiredCount = 0;
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isDequeued()) {
                ++dequeuedCount;
            }
            if (mSlots[s].mBufferState.isAcquired()) {
                ++acquiredCount;
            }
        }

定义了两个值dequeuedCount和acquiredCount分别用来统计mActiveBuffers(所有绑定了GraphicBuffer的BufferSlot集合,并且状态不为FREE的BufferSlot)中,状态为DEQUEUED和状态为ACQUIRED的BufferSlot的数量。
接着继续看一小段代码:

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

这段代码主要是检查生产者不允许申请超过mMaxDequeuedBufferCount数量的BufferSlot

接着看第二部分代码:

status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
        std::unique_lock<std::mutex>& lock, int* found) const {

        ......
        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.
            if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
                    BufferQueueCore::INVALID_BUFFER_SLOT) {
                *found = mCore->mSharedBufferSlot;
            } else {
                if (caller == FreeSlotCaller::Dequeue) {
                    // If we're calling this from dequeue, prefer free buffers
                    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
                    int slot = getFreeSlotLocked();
                    if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
                        *found = slot;
                    } else {
                        *found = getFreeBufferLocked();
                    }
                }
            }
        }

       ......

    return NO_ERROR;
}


首先获取BufferQueue最大buffer数量,一般为2或者3,如果当前mQueue的大小已经大于最大buffer数量则应该等待buffer的消费,mQueue的大小会在queueBuffer时增加,queueBuffer这个函数在下一篇文章分析,接着看else分支:
首先如果当前使用的是共享buffer模式,并且mSharedBufferSlot是有效的,则直接返回mCore->mSharedBufferSlot,关于共享buffer模式不太了解,接着如果不是共享buffer模式:调用者是dequeueBuffer函数则首先调用getFreeBufferLocked从mFreeBuffers头部获取BufferSlot,这段代码也比较简单:

int BufferQueueProducer::getFreeBufferLocked() const {
    if (mCore->mFreeBuffers.empty()) {
        return BufferQueueCore::INVALID_BUFFER_SLOT;
    }
    int slot = mCore->mFreeBuffers.front();
    mCore->mFreeBuffers.pop_front();
    return slot;
}

mFreeBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。如果从mFreeBuffers能找到可用BufferSlot并且是有效的则说明已经找到了,就给found赋值,接着如果没有找到则进入else if分支,代表当前没有绑定了GraphicBuffer的BufferSlot,需要重新给GraphicBuffer分配内存空间,所以else if的条件是当前是否允许分配空间,接着看getFreeSlotLocked函数:

int BufferQueueProducer::getFreeSlotLocked() const {
    if (mCore->mFreeSlots.empty()) {
        return BufferQueueCore::INVALID_BUFFER_SLOT;
    }
    int slot = *(mCore->mFreeSlots.begin());
    mCore->mFreeSlots.erase(slot);
    return slot;
}

这个函数也比较简单,如果mFreeSlots不为空就获取mFreeSlots第一个元素,获取之后从mFreeSlots删除,mFreeSlots代表所有没有绑定GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。

好了else分支分析完了,我们可以知道获取BufferSlot的规律了,会优先从mFreeBuffers中寻找,找不到再从mFreeSlots寻找。

接着来看waitForFreeSlotThenRelock最后一部分代码:

status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
        std::unique_lock<std::mutex>& lock, int* found) const {
          ......
               // 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.
        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)
          ......  
      }


注意这三部分都是在while循环中进行的,第二部分我们已经找到了BufferSlot,此时的BufferSlot有两种情况(不考虑共享buffer模式),一种是从mFreeBuffers中获取的已经绑定了GraphicBuffer,另一种是从mFreeSlots中获取的还没有绑定GraphicBuffer,首先来看tryAgain的赋值,如果前面没有获取到有效BufferSlot或者tooManyBuffers为true则需要tryAgain继续尝试获取,其实最后如果真的需要tryAgain更多是当前queue的buffer已经太多了,需要等待消费者acquire(非同步模式的情况,即mAsyncMode为false),到这里waitForFreeSlotThenRelock函数已经分析完了,这个函数代码多其实逻辑很简单,就是一个获取BufferSlot的规则,先从mFreeBuffers中获取,再从mFreeSlots中获取。

接着我们再回到dequeueBuffer函数的第二部分:

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) {
    ......
        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.
            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;
                }
            }
        }
    ......
}


waitForFreeSlotThenRelock函数之后已经获取到了可用的BufferSlot(再强调一遍,获取的BufferSlot都是下标index),接着根据获取到的BufferSlot下标从mSlots中拿到BufferSlot,并通过BufferSlot绑定的GraphicBuffer创建一个
GraphicBuffer,注意此时BufferSlot绑定的GraphicBuffer有可能为空的,接着判断当前BufferQueue是否允许分配空间,如果不允许,并且当前GraphicBuffer需要分配空间(即waitForFreeSlotThenRelock函数是从mFreeSlots中获取到的BufferSlot),共享buffer模式不管,那么就重新将当前这个BufferSlot再插入mFreeSlots中,并且清空当前这个BufferSlot的各种状态,然后将found再置为BufferItem::INVALID_BUFFER_SLOT,并再进入下次循环,好了dequeueBuffer第二部分已经分析完了,总结:这部分其实就是在while循环中不断的获取BufferSlot,直到
found != BufferItem::INVALID_BUFFER_SLOT为止,

接着看dequeueBuffer函数的第三部分:

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) {
        ......
        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);
        }
        *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;
        }

        BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
                mCore->mBufferAge);

        if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
            BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
                    "slot=%d w=%d h=%d format=%u",
                    found, buffer->width, buffer->height, buffer->format);
        }

        eglDisplay = mSlots[found].mEglDisplay;
        eglFence = mSlots[found].mEglFence;
        // 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
        ......
    
}


首先根据found获取到BufferSlot,根据BufferSlot的GraphicBuffer创建GraphicBuffer,BufferSlot的GraphicBuffer有可能为空,共享buffer模式跳过,如果found不是mSharedBufferSlot,则将found插入mActiveBuffers,mActiveBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态不为FREE,可以是另外四种状态的任意一种。虽说mActiveBuffers中的BufferSlot一定绑定了GraphicBuffer,但此时此刻,BufferSlot的GraphicBuffer任然可能是空的,继续看代码,这个outSlot是最终返回给Surface那一端的,接着获取当前found的BufferSlot的mNeedsReallocation,是否需要重新分配空间,然后再修改为false,接着修改当前found的BufferSlot的状态为DEQUEUED,然后我们再看接下来一小段代码:

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


如果found的BufferSlot并没有绑定GraphicBuffer或者GraphicBuffer需要分配空间则将found的BufferSlot的状态全部clear,置为初始状态值,否则将BufferQueueCore的mBufferAge +1,mFrameCounter和mFrameNumber一般是相等的,代表当前queue的buffer数量,eglDisplay,eglFence不太清楚具体用处,暂时跳过,这部分最后也是和共享buffer模式有关,跳过。

接着我们来看dequeue最后一部分代码:

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) {
        ......
        if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
        BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
        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();

            if (error != NO_ERROR) {
                mCore->mFreeSlots.insert(*outSlot);
                mCore->clearBufferSlotLocked(*outSlot);
                BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
                return error;
            }

            if (mCore->mIsAbandoned) {
                mCore->mFreeSlots.insert(*outSlot);
                mCore->clearBufferSlotLocked(*outSlot);
                BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
                return NO_INIT;
            }

            VALIDATE_CONSISTENCY();
        } // Autolock scope
    }

    if (attachedByConsumer) {
        returnFlags |= BUFFER_NEEDS_REALLOCATION;
    }

    if (eglFence != EGL_NO_SYNC_KHR) {
        EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
                1000000000);
        // If something goes wrong, log the error, but return the buffer without
        // synchronizing access to it. It's too late at this point to abort the
        // dequeue operation.
        if (result == EGL_FALSE) {
            BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
                    eglGetError());
        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
            BQ_LOGE("dequeueBuffer: timeout waiting for fence");
        }
        eglDestroySyncKHR(eglDisplay, eglFence);
    }

    BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
            *outSlot,
            mSlots[*outSlot].mFrameNumber,
            mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);

    if (outBufferAge) {
        *outBufferAge = mCore->mBufferAge;
    }
    addAndGetFrameTimestamps(nullptr, outTimestamps);

    return returnFlags;
}


首先判断如果GraphicBuffer需要分配空间,则new一个GraphicBuffer,关于GraphicBuffer分配空间的内容比较复杂(需要使用Gralloc HAL进行内存分配),本篇文章就不看了,new了之后会通过mIsAllocatingCondition.notify_all唤醒如果有因为mIsAllocating陷入等待的线程,还会将分配好的graphicBuffer和BufferSlot进行绑定,如果分配空间失败便会将BufferSlot插入mFreeSlots中,并通过clearBufferSlotLocked函数情况BufferSlot状态,如果BufferQueue当前已经被弃用则同样将BufferSlot插入mFreeSlots中并清空状态,接着如果attachedByConsumer为true,则添加上BUFFER_NEEDS_REALLOCATION的flag,eglDisplay, eglFence不清楚,暂时跳过,剩下的代码就不看了。

到此dequeueBuffer函数已经分析完毕,虽然代码很多,也分析了很多,但这个函数的核心就是申请BufferSlot,先从mFreeBuffers取,没取到再从mFreeSlots取,然后再看取到的BufferSlot是否绑定了GraphicBuffer,如果没有则还需要为GraphicBuffer分配内存空间,其实有很多的代码都是对异常情况的处理。

dequeueBuffer函数执行完毕之后,Surface一端就拿到了可用的BufferSlot的下标。

我们再接着看Surface的dequeueBuffer函数的剩下部分:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ......
    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
    ...
    
    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;
        }
    }
    *buffer = gbuf.get();
    return OK;
}


最后部分就选了上面的代码来看,首先Surface这一端创建GraphicBuffer指向BufferQueueProducer获取到的BufferSlot绑定的GraphicBuffer,接着如果刚刚dequeueBuffer函数返回的result为BUFFER_NEEDS_REALLOCATION,或者gbuf为空,则调用requestBuffer函数到BufferQueueProducer一端重新给BufferSlot绑定GraphicBuffer,代码就不看了,很简单,最后将gbuf给到*buffer返回给最终的应用层,拿到GraphicBuffer之后就可以进行各种绘制操作了。
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值