Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e614a49 authored by Jim Shargo's avatar Jim Shargo
Browse files

libgui: Add support for unlimited slot BufferQueues

BufferQueues can now be of unlimited size, according to the wishes of
the producer.

We add four new methods:

- IGBC::allowUnlimitedSlots, which permits the IGBP to call
  extendSlotCount
- IGBP::extendSlotCount, which increases the total available slot count
  to a fixed number and notifies the consumer via
  ICL::onSlotCountChanged
- ICL::onSlotCountChanged, which notifies the consumer to resize its
  personal slot vector
- IGBC::getReleasedBuffersExtented, which is like getReleasedBuffers but
  with an arbitrary sized bitvector instead of a fixed 64 bit vector

The internal representation of the slots in BufferQueueCore is now a
vector instead of an array, and can grow (but not shrink). The only
consumers of these new APIs are intented to be Surface and ConsumerBase.
Everything else is being migrated away from IGBP/IGBC anyway.

This is part of go/warren-buffers.

Bug: 341359814
Flag: com.android.graphics.libgui.flags.wb_unlimited_slots
Test: new tests, old tests

Change-Id: I0df872b9d6f9273854cc07a88d29b65451e1832a
parent 8c6afcf1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -108,6 +108,15 @@ void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t
}
#endif

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
void BufferQueue::ProxyConsumerListener::onSlotCountChanged(int slotCount) {
    sp<ConsumerListener> listener(mConsumerListener.promote());
    if (listener != nullptr) {
        listener->onSlotCountChanged(slotCount);
    }
}
#endif

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        bool consumerIsSurfaceFlinger) {
+90 −14
Original line number Diff line number Diff line
@@ -341,9 +341,9 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
            return BAD_VALUE;
        }

        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
        const int totalSlotCount = mCore->getTotalSlotCountLocked();
        if (slot < 0 || slot >= totalSlotCount) {
            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount);
            return BAD_VALUE;
        } else if (!mSlots[slot].mBufferState.isAcquired()) {
            BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
@@ -483,10 +483,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);

    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
            releaseFence == nullptr) {
        BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                releaseFence.get());
    const int totalSlotCount = mCore->getTotalSlotCountLocked();
    if (slot < 0 || slot >= totalSlotCount) {
        BQ_LOGE("releaseBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount);
        return BAD_VALUE;
    }
    if (releaseFence == nullptr) {
        BQ_LOGE("releaseBuffer: slot %d fence %p NULL", slot, releaseFence.get());
        return BAD_VALUE;
    }

@@ -515,6 +518,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
    { // Autolock scope
        std::lock_guard<std::mutex> lock(mCore->mMutex);

        const int totalSlotCount = mCore->getTotalSlotCountLocked();
        if (slot < 0 || slot >= totalSlotCount || releaseFence == nullptr) {
            BQ_LOGE("releaseBuffer: slot %d out of range [0, %d) or fence %p NULL", slot,
                    totalSlotCount, releaseFence.get());
            return BAD_VALUE;
        }

        // If the frame number has changed because the buffer has been reallocated,
        // we can ignore this releaseBuffer for the old buffer.
        // Ignore this for the shared buffer where the frame number can easily
@@ -661,6 +671,43 @@ status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
    return NO_ERROR;
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
status_t BufferQueueConsumer::getReleasedBuffersExtended(std::vector<bool>* outSlotMask) {
    ATRACE_CALL();

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

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

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

    const int totalSlotCount = mCore->getTotalSlotCountLocked();
    outSlotMask->resize(totalSlotCount);
    for (int s = 0; s < totalSlotCount; ++s) {
        (*outSlotMask)[s] = !mSlots[s].mAcquireCalled;
    }

    // Remove from the mask queued buffers for which acquire has been called,
    // since the consumer will not receive their buffer addresses and so must
    // retain their cached information
    BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
    while (current != mCore->mQueue.end()) {
        if (current->mAcquireCalled) {
            (*outSlotMask)[current->mSlot] = false;
        }
        ++current;
    }

    return NO_ERROR;
}
#endif

status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width,
        uint32_t height) {
    ATRACE_CALL();
@@ -679,6 +726,28 @@ status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width,
    return NO_ERROR;
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
status_t BufferQueueConsumer::allowUnlimitedSlots(bool allowUnlimitedSlots) {
    ATRACE_CALL();
    BQ_LOGV("allowUnlimitedSlots: %d", allowUnlimitedSlots);
    std::lock_guard<std::mutex> lock(mCore->mMutex);

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

    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
        BQ_LOGE("allowUnlimitedSlots: BufferQueue already connected");
        return INVALID_OPERATION;
    }

    mCore->mAllowExtendedSlotCount = allowUnlimitedSlots;

    return OK;
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)

status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) {
    ATRACE_CALL();

@@ -718,16 +787,23 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
        int maxAcquiredBuffers) {
    ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers);

    if (maxAcquiredBuffers < 1 ||
            maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
        BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d",
                maxAcquiredBuffers);
        return BAD_VALUE;
    }

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

        // We reserve two slots in order to guarantee that the producer and
        // consumer can run asynchronously.
        int maxMaxAcquiredBuffers =
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
                mCore->getTotalSlotCountLocked() - 2;
#else
                BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS;
#endif
        if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > maxMaxAcquiredBuffers) {
            BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", maxAcquiredBuffers);
            return BAD_VALUE;
        }

        mCore->waitWhileAllocatingLocked(lock);

        if (mCore->mIsAbandoned) {
+38 −1
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@

#include <system/window.h>

#include <ui/BufferQueueDefs.h>

namespace android {

// Macros for include BufferQueueCore information in log messages
@@ -97,7 +99,11 @@ BufferQueueCore::BufferQueueCore()
        mConnectedProducerListener(),
        mBufferReleasedCbEnabled(false),
        mBufferAttachedCbEnabled(false),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#else
        mSlots(),
#endif
        mQueue(),
        mFreeSlots(),
        mFreeBuffers(),
@@ -111,6 +117,9 @@ BufferQueueCore::BufferQueueCore()
        mDefaultWidth(1),
        mDefaultHeight(1),
        mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mAllowExtendedSlotCount(false),
#endif
        mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
        mMaxAcquiredBufferCount(1),
        mMaxDequeuedBufferCount(1),
@@ -221,6 +230,14 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
    }
}

int BufferQueueCore::getTotalSlotCountLocked() const {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    return mAllowExtendedSlotCount ? mMaxBufferCount : BufferQueueDefs::NUM_BUFFER_SLOTS;
#else
    return BufferQueueDefs::NUM_BUFFER_SLOTS;
#endif
}

int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
    // If dequeueBuffer is allowed to error out, we don't have to add an
    // extra buffer.
@@ -253,6 +270,26 @@ int BufferQueueCore::getMaxBufferCountLocked() const {
    return maxBufferCount;
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
status_t BufferQueueCore::extendSlotCountLocked(int size) {
    int previousSize = (int)mSlots.size();
    if (previousSize > size) {
        return BAD_VALUE;
    }
    if (previousSize == size) {
        return NO_ERROR;
    }

    mSlots.resize(size);
    for (int i = previousSize; i < size; i++) {
        mUnusedSlots.push_back(i);
    }

    mMaxBufferCount = size;
    return NO_ERROR;
}
#endif

void BufferQueueCore::clearBufferSlotLocked(int slot) {
    BQ_LOGV("clearBufferSlotLocked: slot %d", slot);

@@ -383,7 +420,7 @@ void BufferQueueCore::notifyBufferReleased() const {
void BufferQueueCore::validateConsistencyLocked() const {
    static const useconds_t PAUSE_TIME = 0;
    int allocatedSlots = 0;
    for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
    for (int slot = 0; slot < getTotalSlotCountLocked(); ++slot) {
        bool isInFreeSlots = mFreeSlots.count(slot) != 0;
        bool isInFreeBuffers =
                std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
+62 −14
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>

#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Trace.h>

@@ -108,9 +109,9 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
        return NO_INIT;
    }

    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
        BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)",
                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
    int maxSlot = mCore->getTotalSlotCountLocked();
    if (slot < 0 || slot >= maxSlot) {
        BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, maxSlot);
        return BAD_VALUE;
    } else if (!mSlots[slot].mBufferState.isDequeued()) {
        BQ_LOGE("requestBuffer: slot %d is not owned by the producer "
@@ -123,6 +124,49 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    return NO_ERROR;
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
status_t BufferQueueProducer::extendSlotCount(int size) {
    ATRACE_CALL();

    sp<IConsumerListener> listener;
    {
        std::lock_guard<std::mutex> lock(mCore->mMutex);
        BQ_LOGV("extendSlotCount: size %d", size);

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

        if (!mCore->mAllowExtendedSlotCount) {
            BQ_LOGE("extendSlotCount: Consumer did not allow unlimited slots");
            return INVALID_OPERATION;
        }

        int maxBeforeExtension = mCore->mMaxBufferCount;

        if (size == maxBeforeExtension) {
            return NO_ERROR;
        }

        if (size < maxBeforeExtension) {
            return BAD_VALUE;
        }

        if (status_t ret = mCore->extendSlotCountLocked(size); ret != OK) {
            return ret;
        }
        listener = mCore->mConsumerListener;
    }

    if (listener) {
        listener->onSlotCountChanged(size);
    }

    return NO_ERROR;
}
#endif

status_t BufferQueueProducer::setMaxDequeuedBufferCount(
        int maxDequeuedBuffers) {
    int maxBufferCount;
@@ -170,9 +214,10 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers,
        int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
        bufferCount += maxDequeuedBuffers;

        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
        if (bufferCount > mCore->getTotalSlotCountLocked()) {
            BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large "
                    "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
                    "(max %d)",
                    bufferCount, mCore->getTotalSlotCountLocked());
            return BAD_VALUE;
        }

@@ -756,9 +801,9 @@ status_t BufferQueueProducer::detachBuffer(int slot) {
            return BAD_VALUE;
        }

        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
        const int totalSlotCount = mCore->getTotalSlotCountLocked();
        if (slot < 0 || slot >= totalSlotCount) {
            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount);
            return BAD_VALUE;
        } else if (!mSlots[slot].mBufferState.isDequeued()) {
            // TODO(http://b/140581935): This message is BQ_LOGW because it
@@ -993,9 +1038,9 @@ status_t BufferQueueProducer::queueBuffer(int slot,
            return NO_INIT;
        }

        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
            BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
        const int totalSlotCount = mCore->getTotalSlotCountLocked();
        if (slot < 0 || slot >= totalSlotCount) {
            BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount);
            return BAD_VALUE;
        } else if (!mSlots[slot].mBufferState.isDequeued()) {
            BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
@@ -1239,9 +1284,9 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
            return BAD_VALUE;
        }

        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
            BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
                    BufferQueueDefs::NUM_BUFFER_SLOTS);
        const int totalSlotCount = mCore->getTotalSlotCountLocked();
        if (slot < 0 || slot >= totalSlotCount) {
            BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount);
            return BAD_VALUE;
        } else if (!mSlots[slot].mBufferState.isDequeued()) {
            BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
@@ -1409,6 +1454,9 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
            output->nextFrameNumber = mCore->mFrameCounter + 1;
            output->bufferReplaced = false;
            output->maxBufferCount = mCore->mMaxBufferCount;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
            output->isSlotExpansionAllowed = mCore->mAllowExtendedSlotCount;
#endif

            if (listener != nullptr) {
                // Set up a death notification so that we can disconnect
+11 −0
Original line number Diff line number Diff line
@@ -254,6 +254,17 @@ void ConsumerBase::onBuffersReleased() {
void ConsumerBase::onSidebandStreamChanged() {
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
void ConsumerBase::onSlotCountChanged(int slotCount) {
    CB_LOGV("onSlotCountChanged: %d", slotCount);
    Mutex::Autolock lock(mMutex);

    if (slotCount > (int)mSlots.size()) {
        mSlots.resize(slotCount);
    }
}
#endif

void ConsumerBase::abandon() {
    CB_LOGV("abandon");
    Mutex::Autolock lock(mMutex);
Loading