void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
                                                   const sp<Fence>& releaseFence, uint32_t transformHint,
                                                   uint32_t currentMaxAcquiredBufferCount) {
    ...
    // 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(id);
        return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
    }();

    const auto numPendingBuffersToHold =
            isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
    auto rb = ReleasedBuffer{id, releaseFence};
    if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
        mPendingRelease.emplace_back(rb);
    }
    // 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.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", id.to_string().c_str());
        mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
        mSubmitted.erase(it);
        // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
        // onFrameAvailable handle processing them since it will merge with the nextTransaction.
        if (!mWaitForTransactionCallback) {
            acquireNextBufferLocked(std::nullopt);
        }
    }

    ATRACE_INT("PendingRelease", mPendingRelease.size());
    ATRACE_INT(mQueuedBufferTrace.c_str(),
               mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
    mCallbackCV.notify_all();
}