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

Commit 8b30dd11 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

Allow BlastBufferQueue to acquire an additional buffer

We want to be able to send buffers from BlastBufferQueue to the server
as soon as possible. This allows us among other things, dropping the
oldest buffer when multiple buffers with timestamps are queued up.
To support this behavior with BlastBufferQueue, we need to acquire an
additional buffer and send it to SurfaceFlinger.

This requires changing the consumer owned by BlastBufferQueue to
acquire an additional buffer. This change is safe because we will only
acquire the buffer if its not droppable, maintaining the contract
with the producer.

If the buffer is not droppable, i.e. the producer is in sync mode, once
the buffer has been queued, the buffer is owned by the queue until it
is released or acquired by the consumer. By acquiring an additional
buffer, we transfer the ownership to the consumer earlier. The server
has more info to make decisions faster. The producer still has access
the same number of buffers and is unaffected.

If the producer is in async mode, then this buffer may be released by
the producer when trying to queue a buffer. So we check if the buffer is
droppable, and we do not acquire the extra buffer in this scenario.

Test: atest BlastBufferQueueTests android.media.cts.PresentationSyncTest
Bug: b/176507654, b/176967609
Change-Id: I494a9edcbea0b1c297ee75df2b840d8328e59eca
parent dd5bfa93
Loading
Loading
Loading
Loading
+19 −11
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
        mPendingReleaseItem.item = std::move(mSubmitted.front());
        mSubmitted.pop();

        processNextBufferLocked(false);
        processNextBufferLocked(false /* useNextTransaction */);

        currFrameNumber = mPendingReleaseItem.item.mFrameNumber;
        if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) {
@@ -269,9 +269,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
    ATRACE_CALL();
    BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));

    // Wait to acquire a buffer if there are no frames available or we have acquired the max
    // number of buffers.
    if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
    // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
    // include the extra buffer when checking if we can acquire the next buffer.
    const bool includeExtraAcquire = !useNextTransaction;
    if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
        BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
        mCallbackCV.notify_all();
        return;
@@ -295,7 +296,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {

    status_t status =
            mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
    if (status != OK) {
    if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
        BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
        return;
    } else if (status != OK) {
        BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
        return;
    }
@@ -414,7 +418,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
             item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));

    if (nextTransactionSet || mFlushShadowQueue) {
        while (mNumFrameAvailable > 0 || maxBuffersAcquired()) {
        while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
            BQA_LOGV("waiting in onFrameAvailable...");
            mCallbackCV.wait(_lock);
        }
@@ -422,7 +426,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    mFlushShadowQueue = false;
    // add to shadow queue
    mNumFrameAvailable++;
    processNextBufferLocked(true);
    processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
}

void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
@@ -482,9 +486,12 @@ void BLASTBufferQueue::setTransactionCompleteCallback(
// Check if we have acquired the maximum number of buffers.
// As a special case, we wait for the first callback before acquiring the second buffer so we
// can ensure the first buffer is presented if multiple buffers are queued in succession.
bool BLASTBufferQueue::maxBuffersAcquired() const {
    return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
            (!mInitialCallbackReceived && mNumAcquired == 1);
// Consumer can acquire an additional buffer if that buffer is not droppable. Set
// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
    int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1);
    return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1);
}

class BBQSurface : public Surface {
@@ -654,7 +661,8 @@ void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer
    LOG_ALWAYS_FATAL_IF(producer == nullptr,
                        "BLASTBufferQueue: failed to create BBQBufferQueueProducer");

    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
    consumer->setAllowExtraAcquire(true);
    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
                        "BLASTBufferQueue: failed to create BufferQueueConsumer");

+12 −1
Original line number Diff line number Diff line
@@ -94,7 +94,10 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
                ++numAcquiredBuffers;
            }
        }
        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
        const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire &&
                numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1;
        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 &&
            !acquireNonDroppableBuffer) {
            BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                    numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
            return INVALID_OPERATION;
@@ -254,6 +257,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
            outBuffer->mIsStale = false;
            outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
                    mCore->mAutoRefresh;
        } else if (acquireNonDroppableBuffer && front->mIsDroppable) {
            BQ_LOGV("acquireBuffer: front buffer is not droppable");
            return NO_BUFFER_AVAILABLE;
        } else {
            slot = front->mSlot;
            *outBuffer = *front;
@@ -824,4 +830,9 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul
    return NO_ERROR;
}

void BufferQueueConsumer::setAllowExtraAcquire(bool allow) {
    std::lock_guard<std::mutex> lock(mCore->mMutex);
    mCore->mAllowExtraAcquire = allow;
}

} // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ private:
    Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
    // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
    bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
    bool maxBuffersAcquired() const REQUIRES(mMutex);
    bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);

    std::string mName;
    sp<SurfaceControl> mSurfaceControl;
+4 −0
Original line number Diff line number Diff line
@@ -174,6 +174,10 @@ public:
    // Value used to determine if present time is valid.
    constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second

    // This allows the consumer to acquire an additional buffer if that buffer is not droppable and
    // will eventually be released or acquired by the consumer.
    void setAllowExtraAcquire(bool /* allow */);

private:
    sp<BufferQueueCore> mCore;

+3 −0
Original line number Diff line number Diff line
@@ -354,6 +354,9 @@ private:
    // mTransformHintInUse is to cache the mTransformHint used by the producer.
    uint32_t mTransformHintInUse;

    // This allows the consumer to acquire an additional buffer if that buffer is not droppable and
    // will eventually be released or acquired by the consumer.
    bool mAllowExtraAcquire = false;
}; // class BufferQueueCore

} // namespace android