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

Commit 3ec2b85e authored by Robert Carr's avatar Robert Carr Committed by Rob Carr
Browse files

TransactionCallbackInvoker: Send callbacks on thread

The binder serialization cost and one way method cost can add up
when we have multiple layers. We invoked these callbacks directly
from the main thread in order to reduce latency. Latency requirements
are now loosened by two changes:
     1. Most of the time we have a queue on the server side
     and won't be trying to make the next frame from the callback
     2. In GL comp where frames are back to back, we now have
     release at latch.

Bug: 201436596
Test: Existing tests pass
Change-Id: I1372022b5130e041d6b2429a2e87e2c622086d7a
parent 6cb6100d
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -49,6 +49,31 @@ static bool containsOnCommitCallbacks(const std::vector<CallbackId>& callbacks)
    return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
}

TransactionCallbackInvoker::TransactionCallbackInvoker() {
    mThread = std::thread([&]() {
          std::unique_lock lock(mCallbackThreadMutex);

        while (mKeepRunning) {
          while (mCallbackThreadWork.size() > 0) {
              mCallbackThreadWork.front()();
              mCallbackThreadWork.pop();
          }
          mCallbackConditionVariable.wait(lock);
        }
    });
}

TransactionCallbackInvoker::~TransactionCallbackInvoker() {
    {
          std::unique_lock lock(mCallbackThreadMutex);
          mKeepRunning = false;
          mCallbackConditionVariable.notify_all();
    }
    if (mThread.joinable()) {
        mThread.join();
    }
}

void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
    auto& [listener, callbackIds] = listenerCallbacks;
    auto& transactionStatsDeque = mCompletedTransactions[listener];
@@ -180,8 +205,15 @@ void TransactionCallbackInvoker::sendCallbacks() {
                // keep it as an IBinder due to consistency reasons: if we
                // interface_cast at the IPC boundary when reading a Parcel,
                // we get pointers that compare unequal in the SF process.
                interface_cast<ITransactionCompletedListener>(listenerStats.listener)
                        ->onTransactionCompleted(listenerStats);
                {
                    std::unique_lock lock(mCallbackThreadMutex);
                    mCallbackThreadWork.push(
                        [stats = std::move(listenerStats)]() {
                          interface_cast<ITransactionCompletedListener>(stats.listener)
                              ->onTransactionCompleted(stats);
                    });
                    mCallbackConditionVariable.notify_all();
                }
            }
        }
        completedTransactionsItr++;
+11 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <condition_variable>
#include <deque>
#include <queue>
#include <mutex>
#include <thread>
#include <unordered_map>
@@ -56,6 +57,9 @@ public:

class TransactionCallbackInvoker {
public:
    TransactionCallbackInvoker();
    ~TransactionCallbackInvoker();

    status_t addCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                const std::vector<JankData>& jankData);
    status_t addOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
@@ -88,6 +92,12 @@ private:
        mCompletedTransactions;

    sp<Fence> mPresentFence;

    std::mutex mCallbackThreadMutex;
    std::condition_variable mCallbackConditionVariable;
    std::thread mThread;
    bool mKeepRunning = true;
    std::queue<std::function<void()>> mCallbackThreadWork;
};

} // namespace android