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

Commit 72daab65 authored by Pablo Ceballos's avatar Pablo Ceballos
Browse files

BQ: Flexible resizing

- Allow the producer to call setMaxDequeuedBufferCount and the
  consumer to call setMaxAcquiredBufferCount when buffers are
  currently dequeued/acquired as long as the new value is not less
  than the number of dequeued/acquired buffers.

Bug 22768206

Change-Id: I599a4027a6ae9cb0a1c0d5ec60cb5e65b86a345b
parent 9e314337
Loading
Loading
Loading
Loading
+11 −2
Original line number Original line Diff line number Diff line
@@ -206,17 +206,26 @@ public:
    virtual status_t setMaxBufferCount(int bufferCount) = 0;
    virtual status_t setMaxBufferCount(int bufferCount) = 0;


    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
    // be acquired by the consumer at one time (default 1).  This call will
    // be acquired by the consumer at one time (default 1). If this method
    // fail if a producer is connected to the BufferQueue.
    // succeeds, any new buffer slots will be both unallocated and owned by the
    // BufferQueue object (i.e. they are not owned by the producer or consumer).
    // Calling this may also cause some buffer slots to be emptied.
    //
    // This function should not be called with a value of maxAcquiredBuffers
    // that is less than the number of currently acquired buffer slots. Doing so
    // will result in a BAD_VALUE error.
    //
    //
    // maxAcquiredBuffers must be (inclusive) between 1 and
    // maxAcquiredBuffers must be (inclusive) between 1 and
    // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
    // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
    // to be exceeded.
    // to be exceeded.
    //
    //
    // Return of a value other than NO_ERROR means an error has occurred:
    // Return of a value other than NO_ERROR means an error has occurred:
    // * NO_INIT - the buffer queue has been abandoned
    // * BAD_VALUE - one of the below conditions occurred:
    // * BAD_VALUE - one of the below conditions occurred:
    //             * maxAcquiredBuffers was out of range (see above).
    //             * maxAcquiredBuffers was out of range (see above).
    //             * failure to adjust the number of available slots.
    //             * failure to adjust the number of available slots.
    //             * client would have more than the requested number of
    //               acquired buffers after this call
    // * INVALID_OPERATION - attempting to call this after a producer connected.
    // * INVALID_OPERATION - attempting to call this after a producer connected.
    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;


+11 −9
Original line number Original line Diff line number Diff line
@@ -82,15 +82,16 @@ public:
    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;


    // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
    // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
    // dequeued by the producer at one time. If this method succeeds, buffer
    // dequeued by the producer at one time. If this method succeeds, any new
    // slots will be both unallocated and owned by the BufferQueue object (i.e.
    // buffer slots will be both unallocated and owned by the BufferQueue object
    // they are not owned by the producer or consumer). Calling this will also
    // (i.e. they are not owned by the producer or consumer). Calling this may
    // cause all buffer slots to be emptied. If the caller is caching the
    // also cause some buffer slots to be emptied. If the caller is caching the
    // contents of the buffer slots, it should empty that cache after calling
    // contents of the buffer slots, it should empty that cache after calling
    // this method.
    // this method.
    //
    //
    // This function should not be called when there are any currently dequeued
    // This function should not be called with a value of maxDequeuedBuffers
    // buffer slots. Doing so will result in a BAD_VALUE error.
    // that is less than the number of currently dequeued buffer slots. Doing so
    // will result in a BAD_VALUE error.
    //
    //
    // The buffer count should be at least 1 (inclusive), but at most
    // The buffer count should be at least 1 (inclusive), but at most
    // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
    // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
@@ -100,9 +101,10 @@ public:
    // Return of a value other than NO_ERROR means an error has occurred:
    // Return of a value other than NO_ERROR means an error has occurred:
    // * NO_INIT - the buffer queue has been abandoned.
    // * NO_INIT - the buffer queue has been abandoned.
    // * BAD_VALUE - one of the below conditions occurred:
    // * BAD_VALUE - one of the below conditions occurred:
    //     * bufferCount was out of range (see above)
    //     * bufferCount was out of range (see above).
    //     * client has too many buffers dequeued
    //     * client would have more than the requested number of dequeued
    //     * this call would cause the maxBufferCount value to be exceeded
    //       buffers after this call.
    //     * this call would cause the maxBufferCount value to be exceeded.
    //     * failure to adjust the number of available slots.
    //     * failure to adjust the number of available slots.
    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;


+48 −24
Original line number Original line Diff line number Diff line
@@ -611,35 +611,59 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


    sp<IConsumerListener> listener;
    { // Autolock scope
        Mutex::Autolock lock(mCore->mMutex);
        Mutex::Autolock lock(mCore->mMutex);
        mCore->waitWhileAllocatingLocked();


    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
        if (mCore->mIsAbandoned) {
        BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected");
            BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned");
        return INVALID_OPERATION;
            return NO_INIT;
        }

        // The new maxAcquiredBuffers count should not be violated by the number
        // of currently acquired buffers
        int acquiredCount = 0;
        for (int slot : mCore->mActiveBuffers) {
            if (mSlots[slot].mBufferState.isAcquired()) {
                acquiredCount++;
            }
        }
        if (acquiredCount > maxAcquiredBuffers) {
            BQ_LOGE("setMaxAcquiredBufferCount: the requested maxAcquiredBuffer"
                    "count (%d) exceeds the current acquired buffer count (%d)",
                    maxAcquiredBuffers, acquiredCount);
            return BAD_VALUE;
        }
        }


        if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
        if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
            (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
                (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0))
            mCore->mMaxBufferCount) {
                > mCore->mMaxBufferCount) {
        BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed "
            BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would "
                "the maxBufferCount (%d) (maxDequeued %d async %d)",
                    "exceed the maxBufferCount (%d) (maxDequeued %d async %d)",
                    maxAcquiredBuffers, mCore->mMaxBufferCount,
                    maxAcquiredBuffers, mCore->mMaxBufferCount,
                    mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
                    mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
                    mCore->mDequeueBufferCannotBlock);
                    mCore->mDequeueBufferCannotBlock);
            return BAD_VALUE;
            return BAD_VALUE;
        }
        }


    if (!mCore->adjustAvailableSlotsLocked(
        int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
            maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount)) {
        if (!mCore->adjustAvailableSlotsLocked(delta)) {
        BQ_LOGE("setMaxAcquiredBufferCount: BufferQueue failed to adjust the "
                "number of available slots. Delta = %d",
                maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount);
            return BAD_VALUE;
            return BAD_VALUE;
        }
        }


        BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
        BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
        mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
        mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
        VALIDATE_CONSISTENCY();
        VALIDATE_CONSISTENCY();
        if (delta < 0) {
            listener = mCore->mConsumerListener;
        }
    }
    // Call back without lock held
    if (listener != NULL) {
        listener->onBuffersReleased();
    }

    return NO_ERROR;
    return NO_ERROR;
}
}


+9 −0
Original line number Original line Diff line number Diff line
@@ -227,6 +227,10 @@ void BufferQueueCore::freeAllBuffersLocked() {


bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
    if (delta >= 0) {
    if (delta >= 0) {
        // If we're going to fail, do so before modifying anything
        if (delta > static_cast<int>(mUnusedSlots.size())) {
            return false;
        }
        while (delta > 0) {
        while (delta > 0) {
            if (mUnusedSlots.empty()) {
            if (mUnusedSlots.empty()) {
                return false;
                return false;
@@ -237,6 +241,11 @@ bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
            delta--;
            delta--;
        }
        }
    } else {
    } else {
        // If we're going to fail, do so before modifying anything
        if (-delta > static_cast<int>(mFreeSlots.size() +
                mFreeBuffers.size())) {
            return false;
        }
        while (delta < 0) {
        while (delta < 0) {
            if (!mFreeSlots.empty()) {
            if (!mFreeSlots.empty()) {
                auto slot = mFreeSlots.begin();
                auto slot = mFreeSlots.begin();
+15 −13
Original line number Original line Diff line number Diff line
@@ -101,13 +101,20 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(
            return NO_INIT;
            return NO_INIT;
        }
        }


        // There must be no dequeued buffers when changing the buffer count.
        // The new maxDequeuedBuffer count should not be violated by the number
        // of currently dequeued buffers
        int dequeuedCount = 0;
        for (int s : mCore->mActiveBuffers) {
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isDequeued()) {
            if (mSlots[s].mBufferState.isDequeued()) {
                BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
                dequeuedCount++;
                return BAD_VALUE;
            }
            }
        }
        }
        if (dequeuedCount > maxDequeuedBuffers) {
            BQ_LOGE("setMaxDequeuedBufferCount: the requested maxDequeuedBuffer"
                    "count (%d) exceeds the current dequeued buffer count (%d)",
                    maxDequeuedBuffers, dequeuedCount);
            return BAD_VALUE;
        }


        int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
        int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
        bufferCount += maxDequeuedBuffers;
        bufferCount += maxDequeuedBuffers;
@@ -134,21 +141,16 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(
            return BAD_VALUE;
            return BAD_VALUE;
        }
        }


        // Here we are guaranteed that the producer doesn't have any dequeued
        int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
        // buffers and will release all of its buffer references. We don't
        if (!mCore->adjustAvailableSlotsLocked(delta)) {
        // clear the queue, however, so that currently queued buffers still
        // get displayed.
        if (!mCore->adjustAvailableSlotsLocked(
                maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount)) {
            BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue failed to adjust "
                    "the number of available slots. Delta = %d",
                    maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount);
            return BAD_VALUE;
            return BAD_VALUE;
        }
        }
        mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
        mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
        VALIDATE_CONSISTENCY();
        VALIDATE_CONSISTENCY();
        mCore->mDequeueCondition.broadcast();
        if (delta < 0) {
            listener = mCore->mConsumerListener;
            listener = mCore->mConsumerListener;
        }
        mCore->mDequeueCondition.broadcast();
    } // Autolock scope
    } // Autolock scope


    // Call back without lock held
    // Call back without lock held
Loading