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

Commit fc46c1e6 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

Introduce ASurfaceTransaction_setOnCommit api

Introduce a new callback for SurfaceControl transactions that
fire after we commit a transaction in SurfaceFlinger. This
will help some clients pace when they should apply the next
transaction so it get applied on the next vsync. If they wait for
the existing transaction complete callback, there may not be
enough time between when the client applies the transaction
and surface flinger waking up and apply it on the new vsync.
This would mean the update would arrive a frame late.

This callback is guaranteed to fire before the transaction complete
callback. It includes all the stats as the transaction complete
callback with the exception of jank data, present fence
and the previous buffer release fence.

This callback piggybacks of the oncomplete callback implementation
by modifying the callback id to provide a callback type. The
callbacks are filtered in SurfaceFlinger to invoke them earlier. In
SurfaceComposerClient, they are filtered again to make sure the
callbacks are invoked in order, oncommit before oncomplete.

Bug: 185843251
Test: atest ASurfaceControlTest
Change-Id: I57e85d75214376935e366d3825a6f3f1a8a4e79b
parent 1510dad2
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -147,6 +147,28 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
                                               __INTRODUCED_IN(29);


/**
 * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates
 * are ready to be presented. This callback will be invoked before the
 * ASurfaceTransaction_OnComplete callback.
 *
 * \param context Optional context provided by the client that is passed into the callback.
 *
 * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query
 * information about the transaction. The handle is only valid during the callback.
 * Present and release fences are not available for this callback. Querying them using
 * ASurfaceTransactionStats_getPresentFenceFd and ASurfaceTransactionStats_getPreviousReleaseFenceFd
 * will result in failure.
 *
 * THREADING
 * The transaction committed callback can be invoked on any thread.
 *
 * Available since API level 31.
 */
typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionStats* stats)
                                               __INTRODUCED_IN(31);

/**
 * Returns the timestamp of when the frame was latched by the framework. Once a frame is
 * latched by the framework, it is presented at the following hardware vsync.
@@ -161,6 +183,8 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_
 * The recipient of the callback takes ownership of the fence and is responsible for closing
 * it. If a device does not support present fences, a -1 will be returned.
 *
 * This query is not valid for ASurfaceTransaction_OnCommit callback.
 *
 * Available since API level 29.
 */
int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
@@ -218,6 +242,8 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac
 * The client must ensure that all pending refs on a buffer are released before attempting to reuse
 * this buffer, otherwise synchronization errors may occur.
 *
 * This query is not valid for ASurfaceTransaction_OnCommit callback.
 *
 * Available since API level 29.
 */
int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
@@ -235,6 +261,16 @@ int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
                                       ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);

/**
 * Sets the callback that will be invoked when the updates from this transaction are applied and are
 * ready to be presented. This callback will be invoked before the ASurfaceTransaction_OnComplete
 * callback.
 *
 * Available since API level 31.
 */
void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* context,
                                    ASurfaceTransaction_OnCommit func) __INTRODUCED_IN(31);

/**
 * Reparents the \a surface_control from its old parent to the \a new_parent surface control.
 * Any children of the reparented \a surface_control will remain children of the \a surface_control.
+2 −2
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ public:
        SAFE_PARCEL(data.writeVectorSize, listenerCallbacks);
        for (const auto& [listener, callbackIds] : listenerCallbacks) {
            SAFE_PARCEL(data.writeStrongBinder, listener);
            SAFE_PARCEL(data.writeInt64Vector, callbackIds);
            SAFE_PARCEL(data.writeParcelableVector, callbackIds);
        }

        SAFE_PARCEL(data.writeUint64, transactionId);
@@ -1246,7 +1246,7 @@ status_t BnSurfaceComposer::onTransact(
            for (int32_t i = 0; i < listenersSize; i++) {
                SAFE_PARCEL(data.readStrongBinder, &tmpBinder);
                std::vector<CallbackId> callbackIds;
                SAFE_PARCEL(data.readInt64Vector, &callbackIds);
                SAFE_PARCEL(data.readParcelableVector, &callbackIds);
                listenerCallbacks.emplace_back(tmpBinder, callbackIds);
            }

+29 −4
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) {
}

status_t TransactionStats::writeToParcel(Parcel* output) const {
    status_t err = output->writeInt64Vector(callbackIds);
    status_t err = output->writeParcelableVector(callbackIds);
    if (err != NO_ERROR) {
        return err;
    }
@@ -176,7 +176,7 @@ status_t TransactionStats::writeToParcel(Parcel* output) const {
}

status_t TransactionStats::readFromParcel(const Parcel* input) {
    status_t err = input->readInt64Vector(&callbackIds);
    status_t err = input->readParcelableVector(&callbackIds);
    if (err != NO_ERROR) {
        return err;
    }
@@ -227,8 +227,9 @@ status_t ListenerStats::readFromParcel(const Parcel* input) {
    return NO_ERROR;
}

ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener,
                                         const std::unordered_set<CallbackId>& callbackIds) {
ListenerStats ListenerStats::createEmpty(
        const sp<IBinder>& listener,
        const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
    ListenerStats listenerStats;
    listenerStats.listener = listener;
    listenerStats.transactionStats.emplace_back(callbackIds);
@@ -278,4 +279,28 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel&
    }
}

ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const {
    std::vector<CallbackId> filteredCallbackIds;
    for (const auto& callbackId : callbackIds) {
        if (callbackId.type == type) {
            filteredCallbackIds.push_back(callbackId);
        }
    }
    return ListenerCallbacks(transactionCompletedListener, filteredCallbackIds);
}

status_t CallbackId::writeToParcel(Parcel* output) const {
    SAFE_PARCEL(output->writeInt64, id);
    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(type));
    return NO_ERROR;
}

status_t CallbackId::readFromParcel(const Parcel* input) {
    SAFE_PARCEL(input->readInt64, &id);
    int32_t typeAsInt;
    SAFE_PARCEL(input->readInt32, &typeAsInt);
    type = static_cast<CallbackId::Type>(typeAsInt);
    return NO_ERROR;
}

}; // namespace android
+2 −2
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ status_t layer_state_t::write(Parcel& output) const

    for (auto listener : listeners) {
        SAFE_PARCEL(output.writeStrongBinder, listener.transactionCompletedListener);
        SAFE_PARCEL(output.writeInt64Vector, listener.callbackIds);
        SAFE_PARCEL(output.writeParcelableVector, listener.callbackIds);
    }
    SAFE_PARCEL(output.writeFloat, shadowRadius);
    SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority);
@@ -258,7 +258,7 @@ status_t layer_state_t::read(const Parcel& input)
        sp<IBinder> listener;
        std::vector<CallbackId> callbackIds;
        SAFE_PARCEL(input.readNullableStrongBinder, &listener);
        SAFE_PARCEL(input.readInt64Vector, &callbackIds);
        SAFE_PARCEL(input.readParcelableVector, &callbackIds);
        listeners.emplace_back(listener, callbackIds);
    }
    SAFE_PARCEL(input.readFloat, &shadowRadius);
+56 −12
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ JankDataListener::~JankDataListener() {
// 0 is an invalid callback id
TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}

CallbackId TransactionCompletedListener::getNextIdLocked() {
int64_t TransactionCompletedListener::getNextIdLocked() {
    return mCallbackIdCounter++;
}

@@ -163,13 +163,13 @@ void TransactionCompletedListener::startListeningLocked() {
CallbackId TransactionCompletedListener::addCallbackFunction(
        const TransactionCompletedCallback& callbackFunction,
        const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
                surfaceControls) {
                surfaceControls,
        CallbackId::Type callbackType) {
    std::lock_guard<std::mutex> lock(mMutex);
    startListeningLocked();

    CallbackId callbackId = getNextIdLocked();
    CallbackId callbackId(getNextIdLocked(), callbackType);
    mCallbacks[callbackId].callbackFunction = callbackFunction;

    auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls;

    for (const auto& surfaceControl : surfaceControls) {
@@ -228,7 +228,7 @@ void TransactionCompletedListener::removeSurfaceStatsListener(void* context, voi

void TransactionCompletedListener::addSurfaceControlToCallbacks(
        const sp<SurfaceControl>& surfaceControl,
        const std::unordered_set<CallbackId>& callbackIds) {
        const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
    std::lock_guard<std::mutex> lock(mMutex);

    for (auto callbackId : callbackIds) {
@@ -240,7 +240,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(
}

void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
    std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
    std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
    std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
    std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
    {
@@ -267,7 +267,36 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
        }
    }
    for (const auto& transactionStats : listenerStats.transactionStats) {
        // handle on commit callbacks
        for (auto callbackId : transactionStats.callbackIds) {
            if (callbackId.type != CallbackId::Type::ON_COMMIT) {
                continue;
            }
            auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
            if (!callbackFunction) {
                ALOGE("cannot call null callback function, skipping");
                continue;
            }
            std::vector<SurfaceControlStats> surfaceControlStats;
            for (const auto& surfaceStats : transactionStats.surfaceStats) {
                surfaceControlStats
                        .emplace_back(callbacksMap[callbackId]
                                              .surfaceControls[surfaceStats.surfaceControl],
                                      transactionStats.latchTime, surfaceStats.acquireTime,
                                      transactionStats.presentFence,
                                      surfaceStats.previousReleaseFence, surfaceStats.transformHint,
                                      surfaceStats.eventStats);
            }

            callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                             surfaceControlStats);
        }

        // handle on complete callbacks
        for (auto callbackId : transactionStats.callbackIds) {
            if (callbackId.type != CallbackId::Type::ON_COMPLETE) {
                continue;
            }
            auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
            if (!callbackFunction) {
                ALOGE("cannot call null callback function, skipping");
@@ -542,7 +571,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
            return BAD_VALUE;
        }
        for (size_t j = 0; j < numCallbackIds; j++) {
            listenerCallbacks[listener].callbackIds.insert(parcel->readInt64());
            CallbackId id;
            parcel->readParcelable(&id);
            listenerCallbacks[listener].callbackIds.insert(id);
        }
        size_t numSurfaces = parcel->readUint32();
        if (numSurfaces > parcel->dataSize()) {
@@ -628,7 +659,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const
        parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener));
        parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size()));
        for (auto callbackId : callbackInfo.callbackIds) {
            parcel->writeInt64(callbackId);
            parcel->writeParcelable(callbackId);
        }
        parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size()));
        for (auto surfaceControl : callbackInfo.surfaceControls) {
@@ -1389,9 +1420,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<Surfa
    return *this;
}

SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback(
        TransactionCompletedCallbackTakesContext callback, void* callbackContext,
        CallbackId::Type callbackType) {
    auto listener = TransactionCompletedListener::getInstance();

    auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
@@ -1399,13 +1430,26 @@ SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
    const auto& surfaceControls =
            mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;

    CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls);
    CallbackId callbackId =
            listener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType);

    mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
            callbackId);
    return *this;
}

SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
    return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE);
}

SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCommittedCallback(
        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
    return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT);
}

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
        const sp<SurfaceControl>& sc) {
    layer_state_t* s = getLayerState(sc);
Loading