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

Commit 899dcdb6 authored by Ady Abraham's avatar Ady Abraham
Browse files

SF: change acquired buffers based on the current refresh rate

BLASTBufferQueue set the max acquired buffers based on SF
vsync configuration (sf.duration and app.duration). This is calculated
based on the max supported refresh rate on the device, and it turn
is propogated to apps via min_undequeued_buffers to the app could
allocate enough buffers for maintaining the pipeline SF expects.

This leads to a higher latency when the device is running in a lower
refresh rate as there are more buffers on the buffer queue then required.
In this change we are holding on the these "extra buffers" and not
releasing them back to the buffer queue so the app would use the number
of buffers it needs based on the current refresh rate, and to avoid having
unnecessary long latency.

Bug: 188553729
Test: Run backpressure based game on 60Hz and 120Hz and collect systraces
Change-Id: I9d4e6278f0ddd28008ac437ab0576aa79d05166a
parent 0bde6b5a
Loading
Loading
Loading
Loading
+37 −15
Original line number Diff line number Diff line
@@ -159,9 +159,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
    mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
    mBufferItemConsumer->setBlastBufferQueue(this);

    int extraBufferCount = 0;
    ComposerService::getComposerService()->getExtraBufferCount(&extraBufferCount);
    mMaxAcquiredBuffers = 1 + extraBufferCount;
    ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
    mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);

    mTransformHint = mSurfaceControl->getTransformHint();
@@ -308,18 +306,20 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
// Otherwise, this is a no-op.
static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId,
                                       const sp<Fence>& releaseFence, uint32_t transformHint) {
                                       const sp<Fence>& releaseFence, uint32_t transformHint,
                                       uint32_t currentMaxAcquiredBufferCount) {
    sp<BLASTBufferQueue> blastBufferQueue = context.promote();
    ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s",
          graphicBufferId, blastBufferQueue ? "alive" : "dead");
    if (blastBufferQueue) {
        blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint);
        blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint,
                                                currentMaxAcquiredBufferCount);
    }
}

void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
                                             const sp<Fence>& releaseFence,
                                             uint32_t transformHint) {
                                             const sp<Fence>& releaseFence, uint32_t transformHint,
                                             uint32_t currentMaxAcquiredBufferCount) {
    ATRACE_CALL();
    std::unique_lock _lock{mMutex};
    BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId);
@@ -330,15 +330,36 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
        mBufferItemConsumer->setTransformHint(mTransformHint);
    }

    auto it = mSubmitted.find(graphicBufferId);
    // Calculate how many buffers we need to hold before we release them back
    // to the buffer queue. This will prevent higher latency when we are running
    // on a lower refresh rate than the max supported. We only do that for EGL
    // clients as others don't care about latency
    const bool isEGL = [&] {
        const auto it = mSubmitted.find(graphicBufferId);
        return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
    }();

    const auto numPendingBuffersToHold =
            isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
    mPendingRelease.emplace_back(ReleasedBuffer{graphicBufferId, releaseFence});

    // Release all buffers that are beyond the ones that we need to hold
    while (mPendingRelease.size() > numPendingBuffersToHold) {
        const auto releaseBuffer = mPendingRelease.front();
        mPendingRelease.pop_front();
        auto it = mSubmitted.find(releaseBuffer.bufferId);
        if (it == mSubmitted.end()) {
            BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
                     graphicBufferId);
            return;
        }

    mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
        mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
        mSubmitted.erase(it);
    }

    ATRACE_INT("PendingRelease", mPendingRelease.size());

    mNumAcquired--;
    processNextBufferLocked(false /* useNextTransaction */);
    mCallbackCV.notify_all();
@@ -420,7 +441,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {

    auto releaseBufferCallback =
            std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
                      std::placeholders::_4);
    t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback);
    t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
    t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
+9 −8
Original line number Diff line number Diff line
@@ -1215,16 +1215,17 @@ public:
        return reply.readInt32();
    }

    status_t getExtraBufferCount(int* extraBuffers) const override {
    status_t getMaxAcquiredBufferCount(int* buffers) const override {
        Parcel data, reply;
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply);
        status_t err =
                remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
        if (err != NO_ERROR) {
            ALOGE("getExtraBufferCount failed to read data:  %s (%d)", strerror(-err), err);
            ALOGE("getMaxAcquiredBufferCount failed to read data:  %s (%d)", strerror(-err), err);
            return err;
        }

        return reply.readInt32(extraBuffers);
        return reply.readInt32(buffers);
    }
};

@@ -2069,14 +2070,14 @@ status_t BnSurfaceComposer::onTransact(
            SAFE_PARCEL(reply->writeInt32, priority);
            return NO_ERROR;
        }
        case GET_EXTRA_BUFFER_COUNT: {
        case GET_MAX_ACQUIRED_BUFFER_COUNT: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            int extraBuffers = 0;
            int err = getExtraBufferCount(&extraBuffers);
            int buffers = 0;
            int err = getMaxAcquiredBufferCount(&buffers);
            if (err != NO_ERROR) {
                return err;
            }
            SAFE_PARCEL(reply->writeInt32, extraBuffers);
            SAFE_PARCEL(reply->writeInt32, buffers);
            return NO_ERROR;
        }
        case OVERRIDE_HDR_TYPES: {
+7 −3
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const {
        SAFE_PARCEL(output->writeBool, false);
    }
    SAFE_PARCEL(output->writeUint32, transformHint);
    SAFE_PARCEL(output->writeUint32, currentMaxAcquiredBufferCount);
    SAFE_PARCEL(output->writeParcelable, eventStats);
    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
    for (const auto& data : jankData) {
@@ -138,6 +139,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) {
        SAFE_PARCEL(input->read, *previousReleaseFence);
    }
    SAFE_PARCEL(input->readUint32, &transformHint);
    SAFE_PARCEL(input->readUint32, &currentMaxAcquiredBufferCount);
    SAFE_PARCEL(input->readParcelable, &eventStats);

    int32_t jankData_size = 0;
@@ -251,11 +253,13 @@ public:
                                                                  stats);
    }

    void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
                         uint32_t transformHint) override {
    void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence, uint32_t transformHint,
                         uint32_t currentMaxAcquiredBufferCount) override {
        callRemoteAsync<decltype(
                &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
                graphicBufferId, releaseFence, transformHint);
                                                                  graphicBufferId, releaseFence,
                                                                  transformHint,
                                                                  currentMaxAcquiredBufferCount);
    }
};

+6 −5
Original line number Diff line number Diff line
@@ -328,7 +328,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
                                 surfaceStats.previousReleaseFence
                                         ? surfaceStats.previousReleaseFence
                                         : Fence::NO_FENCE,
                                 surfaceStats.transformHint);
                                 surfaceStats.transformHint,
                                 surfaceStats.currentMaxAcquiredBufferCount);
                    }
                }
            }
@@ -364,9 +365,9 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
    }
}

void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
                                                   sp<Fence> releaseFence,
                                                   uint32_t transformHint) {
void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
                                                   uint32_t transformHint,
                                                   uint32_t currentMaxAcquiredBufferCount) {
    ReleaseBufferCallback callback;
    {
        std::scoped_lock<std::mutex> lock(mMutex);
@@ -376,7 +377,7 @@ void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
        ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId);
        return;
    }
    callback(graphicBufferId, releaseFence, transformHint);
    callback(graphicBufferId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
}

ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
+10 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ public:
    void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
            const std::vector<SurfaceControlStats>& stats);
    void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence,
                               uint32_t transformHint);
                               uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
    void setNextTransaction(SurfaceComposerClient::Transaction *t);
    void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
    void setTransactionCompleteCallback(uint64_t frameNumber,
@@ -141,6 +141,15 @@ private:
    // buffer or the buffer has been presented and a new buffer is ready to be presented.
    std::unordered_map<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex);

    // Keep a queue of the released buffers instead of immediately releasing
    // the buffers back to the buffer queue. This would be controlled by SF
    // setting the max acquired buffer count.
    struct ReleasedBuffer {
        uint64_t bufferId;
        sp<Fence> releaseFence;
    };
    std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);

    ui::Size mSize GUARDED_BY(mMutex);
    ui::Size mRequestedSize GUARDED_BY(mMutex);
    int32_t mFormat GUARDED_BY(mMutex);
Loading