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

Commit bafbf275 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Add ability to process buffers into the same syncTransaction"

parents 46f3e3b6 0acd33a3
Loading
Loading
Loading
Loading
+64 −32
Original line number Diff line number Diff line
@@ -407,18 +407,9 @@ void BLASTBufferQueue::releaseBufferCallback(

    // Release all buffers that are beyond the ones that we need to hold
    while (mPendingRelease.size() > numPendingBuffersToHold) {
        const auto releaseBuffer = mPendingRelease.front();
        const auto releasedBuffer = mPendingRelease.front();
        mPendingRelease.pop_front();
        auto it = mSubmitted.find(releaseBuffer.callbackId);
        if (it == mSubmitted.end()) {
            BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
                     releaseBuffer.callbackId.to_string().c_str());
            return;
        }
        mNumAcquired--;
        BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str());
        mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
        mSubmitted.erase(it);
        releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
        // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
        // onFrameAvailable handle processing them since it will merge with the syncTransaction.
        if (!mWaitForTransactionCallback) {
@@ -432,6 +423,20 @@ void BLASTBufferQueue::releaseBufferCallback(
    mCallbackCV.notify_all();
}

void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId,
                                     const sp<Fence>& releaseFence) {
    auto it = mSubmitted.find(callbackId);
    if (it == mSubmitted.end()) {
        BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
                 callbackId.to_string().c_str());
        return;
    }
    mNumAcquired--;
    BQA_LOGV("released %s", callbackId.to_string().c_str());
    mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
    mSubmitted.erase(it);
}

void BLASTBufferQueue::acquireNextBufferLocked(
        const std::optional<SurfaceComposerClient::Transaction*> transaction) {
    ATRACE_CALL();
@@ -589,14 +594,8 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() {
    mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
}

void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    ATRACE_CALL();
    std::unique_lock _lock{mMutex};

    const bool syncTransactionSet = mSyncTransaction != nullptr;
    BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));
    if (syncTransactionSet) {
        if (mWaitForTransactionCallback) {
void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
    if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
        // We are waiting on a previous sync's transaction callback so allow another sync
        // transaction to proceed.
        //
@@ -606,7 +605,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
        // on max acquired to make sure we have the capacity to acquire another buffer.
        if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
            BQA_LOGD("waiting to flush shadow queue...");
                mCallbackCV.wait(_lock);
            mCallbackCV.wait(lock);
        }
        while (mNumFrameAvailable > 0) {
            // flush out the shadow queue
@@ -616,7 +615,36 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {

    while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
        BQA_LOGD("waiting for free buffer.");
            mCallbackCV.wait(_lock);
        mCallbackCV.wait(lock);
    }
}

void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    ATRACE_CALL();
    std::unique_lock _lock{mMutex};

    const bool syncTransactionSet = mSyncTransaction != nullptr;
    BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));

    if (syncTransactionSet) {
        bool mayNeedToWaitForBuffer = true;
        // If we are going to re-use the same mSyncTransaction, release the buffer that may already
        // be set in the Transaction. This is to allow us a free slot early to continue processing
        // a new buffer.
        if (!mAcquireSingleBuffer) {
            auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl);
            if (bufferData) {
                BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64,
                         bufferData->frameNumber);
                releaseBuffer(bufferData->releaseCallbackId, bufferData->acquireFence);
                // Because we just released a buffer, we know there's no need to wait for a free
                // buffer.
                mayNeedToWaitForBuffer = false;
            }
        }

        if (mayNeedToWaitForBuffer) {
            flushAndWaitForFreeBuffer(_lock);
        }
    }

@@ -629,8 +657,10 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
             boolToString(syncTransactionSet));

    if (syncTransactionSet) {
        acquireNextBufferLocked(std::move(mSyncTransaction));
        acquireNextBufferLocked(mSyncTransaction);
        if (mAcquireSingleBuffer) {
            mSyncTransaction = nullptr;
        }
        mWaitForTransactionCallback = true;
    } else if (!mWaitForTransactionCallback) {
        acquireNextBufferLocked(std::nullopt);
@@ -652,9 +682,11 @@ void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) {
    mDequeueTimestamps.erase(bufferId);
};

void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t) {
void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t,
                                          bool acquireSingleBuffer) {
    std::lock_guard _lock{mMutex};
    mSyncTransaction = t;
    mAcquireSingleBuffer = mSyncTransaction ? acquireSingleBuffer : true;
}

bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
+30 −0
Original line number Diff line number Diff line
@@ -413,6 +413,14 @@ ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLock
    return callback;
}

void TransactionCompletedListener::removeReleaseBufferCallback(
        const ReleaseCallbackId& callbackId) {
    {
        std::scoped_lock<std::mutex> lock(mMutex);
        popReleaseBufferCallbackLocked(callbackId);
    }
}

// ---------------------------------------------------------------------------

void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId);
@@ -1307,6 +1315,28 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<Surfac
    return *this;
}

std::optional<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer(
        const sp<SurfaceControl>& sc) {
    layer_state_t* s = getLayerState(sc);
    if (!s) {
        return std::nullopt;
    }
    if (!(s->what & layer_state_t::eBufferChanged)) {
        return std::nullopt;
    }

    BufferData bufferData = s->bufferData;

    TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(
            bufferData.releaseCallbackId);
    BufferData emptyBufferData;
    s->what &= ~layer_state_t::eBufferChanged;
    s->bufferData = emptyBufferData;

    mContainsBuffer = false;
    return bufferData;
}

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
        const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
        const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
+9 −2
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ public:
                                     const std::vector<SurfaceControlStats>& stats);
    void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
                               std::optional<uint32_t> currentMaxAcquiredBufferCount);
    void setSyncTransaction(SurfaceComposerClient::Transaction* t);
    void setSyncTransaction(SurfaceComposerClient::Transaction* t, bool acquireSingleBuffer = true);
    void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
    void applyPendingTransactions(uint64_t frameNumber);

@@ -132,6 +132,9 @@ private:

    void flushShadowQueue() REQUIRES(mMutex);
    void acquireAndReleaseBuffer() REQUIRES(mMutex);
    void releaseBuffer(const ReleaseCallbackId& callbackId, const sp<Fence>& releaseFence)
            REQUIRES(mMutex);
    void flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock);

    std::string mName;
    // Represents the queued buffer count from buffer queue,
@@ -239,7 +242,11 @@ private:
    std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);

    uint32_t mCurrentMaxAcquiredBufferCount;
    bool mWaitForTransactionCallback = false;
    bool mWaitForTransactionCallback GUARDED_BY(mMutex) = false;

    // Flag to determine if syncTransaction should only acquire a single buffer and then clear or
    // continue to acquire buffers until explicitly cleared
    bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true;
};

} // namespace android
+3 −0
Original line number Diff line number Diff line
@@ -493,6 +493,7 @@ public:
                               const std::optional<uint64_t>& frameNumber = std::nullopt,
                               const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID,
                               ReleaseBufferCallback callback = nullptr);
        std::optional<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc);
        Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
        Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
        Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
@@ -751,6 +752,8 @@ public:
    void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
                         uint32_t currentMaxAcquiredBufferCount) override;

    void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId);

    // For Testing Only
    static void setInstance(const sp<TransactionCompletedListener>&);

+48 −4
Original line number Diff line number Diff line
@@ -109,8 +109,8 @@ public:
        mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888);
    }

    void setSyncTransaction(Transaction* sync) {
        mBlastBufferQueueAdapter->setSyncTransaction(sync);
    void setSyncTransaction(Transaction* next, bool acquireSingleBuffer = true) {
        mBlastBufferQueueAdapter->setSyncTransaction(next, acquireSingleBuffer);
    }

    int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
@@ -143,6 +143,11 @@ public:
        mBlastBufferQueueAdapter->waitForCallback(frameNumber);
    }

    void validateNumFramesSubmitted(int64_t numFramesSubmitted) {
        std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
        ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
    }

private:
    sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
};
@@ -298,7 +303,7 @@ protected:
        auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
                                       PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
                                       nullptr, nullptr);
        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
        ASSERT_TRUE(ret == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || ret == NO_ERROR);
        ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf));

        uint32_t* bufData;
@@ -818,7 +823,7 @@ TEST_F(BLASTBufferQueueTest, SyncThenNoSync) {
    CallbackData callbackData;
    transactionCallback.getCallbackData(&callbackData);

    // capture screen and verify that it is red
    // capture screen and verify that it is green
    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -1025,6 +1030,45 @@ TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) {
            checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}

TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) {
    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);

    sp<IGraphicBufferProducer> igbProducer;
    setUpProducer(adapter, igbProducer);

    Transaction next;
    adapter.setSyncTransaction(&next, false);
    queueBuffer(igbProducer, 0, 255, 0, 0);
    queueBuffer(igbProducer, 0, 0, 255, 0);
    // There should only be one frame submitted since the first frame will be released.
    adapter.validateNumFramesSubmitted(1);
    adapter.setSyncTransaction(nullptr);

    // queue non sync buffer, so this one should get blocked
    // Add a present delay to allow the first screenshot to get taken.
    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
    queueBuffer(igbProducer, 255, 0, 0, presentTimeDelay);

    CallbackHelper transactionCallback;
    next.addTransactionCompletedCallback(transactionCallback.function,
                                         transactionCallback.getContext())
            .apply();

    CallbackData callbackData;
    transactionCallback.getCallbackData(&callbackData);

    // capture screen and verify that it is blue
    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));

    mProducerListener->waitOnNumberReleased(2);
    // capture screen and verify that it is red
    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}

class TestProducerListener : public BnProducerListener {
public:
    sp<IGraphicBufferProducer> mIgbp;