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

Commit 4d9cef90 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

[sf] update transaction handler filter to use new front end

Instead of looking at drawing state, get the data from
RequestedLayerState.

Bug: 238781169
Test: presubmit

Change-Id: I760900ca23c8d8717b1a0bc5afa8cfee36013a0b
parent 3d367380
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#undef LOG_TAG
#define LOG_TAG "SurfaceFlinger"

#include <gui/TraceUtils.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <sys/types.h>
@@ -507,6 +508,51 @@ bool RequestedLayerState::willReleaseBufferOnLatch() const {
    return changes.test(Changes::Buffer) && !externalTexture;
}

bool RequestedLayerState::backpressureEnabled() const {
    return flags & layer_state_t::eEnableBackpressure;
}

bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const {
    static constexpr uint64_t requiredFlags = layer_state_t::eBufferChanged;
    if ((s.what & requiredFlags) != requiredFlags) {
        ATRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
                              (s.what | requiredFlags) & ~s.what);
        return false;
    }

    static constexpr uint64_t deniedFlags = layer_state_t::eProducerDisconnect |
            layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged |
            layer_state_t::eTransparentRegionChanged | layer_state_t::eFlagsChanged |
            layer_state_t::eBlurRegionsChanged | layer_state_t::eLayerStackChanged |
            layer_state_t::eAutoRefreshChanged | layer_state_t::eReparent;
    if (s.what & deniedFlags) {
        ATRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
                              s.what & deniedFlags);
        return false;
    }

    bool changedFlags = diff(s);
    static constexpr auto deniedChanges = layer_state_t::ePositionChanged |
            layer_state_t::eAlphaChanged | layer_state_t::eColorTransformChanged |
            layer_state_t::eBackgroundColorChanged | layer_state_t::eMatrixChanged |
            layer_state_t::eCornerRadiusChanged | layer_state_t::eBackgroundBlurRadiusChanged |
            layer_state_t::eBufferTransformChanged |
            layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
            layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged |
            layer_state_t::eSidebandStreamChanged | layer_state_t::eColorSpaceAgnosticChanged |
            layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged |
            layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged |
            layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged |
            layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged;
    if (changedFlags & deniedChanges) {
        ATRACE_FORMAT_INSTANT("%s: false [has denied changes flags 0x%" PRIx64 "]", __func__,
                              s.what & deniedChanges);
        return false;
    }

    return true;
}

void RequestedLayerState::clearChanges() {
    what = 0;
    changes.clear();
+2 −0
Original line number Diff line number Diff line
@@ -82,6 +82,8 @@ struct RequestedLayerState : layer_state_t {
    bool hasReadyFrame() const;
    bool hasSidebandStreamFrame() const;
    bool willReleaseBufferOnLatch() const;
    bool backpressureEnabled() const;
    bool isSimpleBufferUpdate(const layer_state_t&) const;

    // Layer serial number.  This gives layers an explicit ordering, so we
    // have a stable sort order when their layer stack and Z-order are
+3 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ void TransactionHandler::queueTransaction(TransactionState&& state) {
    ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
}

std::vector<TransactionState> TransactionHandler::flushTransactions() {
void TransactionHandler::collectTransactions() {
    while (!mLocklessTransactionQueue.isEmpty()) {
        auto maybeTransaction = mLocklessTransactionQueue.pop();
        if (!maybeTransaction.has_value()) {
@@ -42,7 +42,9 @@ std::vector<TransactionState> TransactionHandler::flushTransactions() {
        auto transaction = maybeTransaction.value();
        mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction));
    }
}

std::vector<TransactionState> TransactionHandler::flushTransactions() {
    // Collect transaction that are ready to be applied.
    std::vector<TransactionState> transactions;
    TransactionFlushState flushState;
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ public:
    using TransactionFilter = std::function<TransactionReadiness(const TransactionFlushState&)>;

    bool hasPendingTransactions();
    // Moves transactions from the lockless queue.
    void collectTransactions();
    std::vector<TransactionState> flushTransactions();
    void addTransactionReadyFilter(TransactionFilter&&);
    void queueTransaction(TransactionState&&);
+179 −42
Original line number Diff line number Diff line
@@ -2054,12 +2054,22 @@ void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) {
    }
}

bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
                                                bool transactionsFlushed,
bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTimeNs,
                                                bool flushTransactions,
                                                bool& outTransactionsAreEmpty) {
    ATRACE_CALL();
    frontend::Update update;
    if (flushTransactions) {
        update = flushLifecycleUpdates();
        if (mTransactionTracing) {
            mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs,
                                                          update, mFrontEndDisplayInfos,
                                                          mFrontEndDisplayInfosChanged);
        }
    }

    bool needsTraversal = false;
    if (transactionsFlushed) {
    if (flushTransactions) {
        needsTraversal |= commitMirrorDisplays(vsyncId);
        needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates);
        needsTraversal |= applyTransactions(update.transactions, vsyncId);
@@ -2107,12 +2117,43 @@ void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot)
    }
}

bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update,
                                          bool transactionsFlushed, bool& outTransactionsAreEmpty) {
bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs,
                                          bool flushTransactions, bool& outTransactionsAreEmpty) {
    using Changes = frontend::RequestedLayerState::Changes;
    ATRACE_CALL();
    frontend::Update update;
    if (flushTransactions) {
        ATRACE_NAME("TransactionHandler:flushTransactions");
        // Locking:
        // 1. to prevent onHandleDestroyed from being called while the state lock is held,
        // we must keep a copy of the transactions (specifically the composer
        // states) around outside the scope of the lock.
        // 2. Transactions and created layers do not share a lock. To prevent applying
        // transactions with layers still in the createdLayer queue, collect the transactions
        // before committing the created layers.
        // 3. Transactions can only be flushed after adding layers, since the layer can be a newly
        // created one
        mTransactionHandler.collectTransactions();
        {
            // TODO(b/238781169) lockless queue this and keep order.
            std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
            update.layerCreatedStates = std::move(mCreatedLayers);
            mCreatedLayers.clear();
            update.newLayers = std::move(mNewLayers);
            mNewLayers.clear();
            update.layerCreationArgs = std::move(mNewLayerArgs);
            mNewLayerArgs.clear();
            update.destroyedHandles = std::move(mDestroyedHandles);
            mDestroyedHandles.clear();
        }

        mLayerLifecycleManager.addLayers(std::move(update.newLayers));
        update.transactions = mTransactionHandler.flushTransactions();
        if (mTransactionTracing) {
            mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs,
                                                          update, mFrontEndDisplayInfos,
                                                          mFrontEndDisplayInfosChanged);
        }
        mLayerLifecycleManager.applyTransactions(update.transactions);
        mLayerLifecycleManager.onHandlesDestroyed(update.destroyedHandles);
        for (auto& legacyLayer : update.layerCreatedStates) {
@@ -2121,12 +2162,12 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
                mLegacyLayers[layer->sequence] = layer;
            }
        }
    }
        if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) {
            ATRACE_NAME("LayerHierarchyBuilder:update");
            mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(),
                                          mLayerLifecycleManager.getDestroyedLayers());
        }
    }

    bool mustComposite = false;
    mustComposite |= applyAndCommitDisplayTransactionStates(update.transactions);
@@ -2299,25 +2340,16 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget)
                                    Fps::fromPeriodNsecs(vsyncPeriod.ns()));

        const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
        frontend::Update updates;
        if (flushTransactions) {
            updates = flushLifecycleUpdates();
            if (mTransactionTracing) {
                mTransactionTracing
                        ->addCommittedTransactions(ftl::to_underlying(vsyncId),
                                                   pacesetterFrameTarget.frameBeginTime().ns(),
                                                   updates, mFrontEndDisplayInfos,
                                                   mFrontEndDisplayInfosChanged);
            }
        }
        bool transactionsAreEmpty;
        if (mConfig->legacyFrontEndEnabled) {
            mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions,
                                                        transactionsAreEmpty);
            mustComposite |=
                    updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
                                               flushTransactions, transactionsAreEmpty);
        }
        if (mConfig->layerLifecycleManagerEnabled) {
            mustComposite |=
                    updateLayerSnapshots(vsyncId, updates, flushTransactions, transactionsAreEmpty);
                    updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
                                         flushTransactions, transactionsAreEmpty);
        }

        if (transactionFlushNeeded()) {
@@ -4123,18 +4155,16 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin
    return TransactionReadiness::Ready;
}

TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheckLegacy(
        const TransactionHandler::TransactionFlushState& flushState) {
    using TransactionReadiness = TransactionHandler::TransactionReadiness;
    auto ready = TransactionReadiness::Ready;
    flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s,
                                                                   const std::shared_ptr<
                                                                           renderengine::
                                                                                   ExternalTexture>&
                                                                           externalTexture)
                                                                       -> bool {
        sp<Layer> layer = LayerHandle::getLayer(s.surface);
    flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState&
                                                                           resolvedState) -> bool {
        sp<Layer> layer = LayerHandle::getLayer(resolvedState.state.surface);

        const auto& transaction = *flushState.transaction;
        const auto& s = resolvedState.state;
        // check for barrier frames
        if (s.bufferData->hasBarrier) {
            // The current producerId is already a newer producer than the buffer that has a
@@ -4142,7 +4172,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
            // don't wait on the barrier since we know that's stale information.
            if (layer->getDrawingState().barrierProducerId > s.bufferData->producerId) {
                layer->callReleaseBufferCallback(s.bufferData->releaseBufferListener,
                                                 externalTexture->getBuffer(),
                                                 resolvedState.externalTexture->getBuffer(),
                                                 s.bufferData->frameNumber,
                                                 s.bufferData->acquireFence);
                // Delete the entire state at this point and not just release the buffer because
@@ -4188,9 +4218,10 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
                s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled;
        if (!fenceSignaled) {
            // check fence status
            const bool allowLatchUnsignaled =
                    shouldLatchUnsignaled(layer, s, transaction.states.size(),
                                          flushState.firstTransaction);
            const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(),
                                                                    flushState.firstTransaction) &&
                    layer->isSimpleBufferUpdate(s);

            if (allowLatchUnsignaled) {
                ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s",
                              layer->getDebugName());
@@ -4215,15 +4246,120 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
    return ready;
}

TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
        const TransactionHandler::TransactionFlushState& flushState) {
    using TransactionReadiness = TransactionHandler::TransactionReadiness;
    auto ready = TransactionReadiness::Ready;
    flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState&
                                                                           resolvedState) -> bool {
        const frontend::RequestedLayerState* layer =
                mLayerLifecycleManager.getLayerFromId(resolvedState.layerId);
        const auto& transaction = *flushState.transaction;
        const auto& s = resolvedState.state;
        // check for barrier frames
        if (s.bufferData->hasBarrier) {
            // The current producerId is already a newer producer than the buffer that has a
            // barrier. This means the incoming buffer is older and we can release it here. We
            // don't wait on the barrier since we know that's stale information.
            if (layer->barrierProducerId > s.bufferData->producerId) {
                if (s.bufferData->releaseBufferListener) {
                    uint32_t currentMaxAcquiredBufferCount =
                            getMaxAcquiredBufferCountForCurrentRefreshRate(layer->ownerUid.val());
                    ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64,
                                          layer->name.c_str(), s.bufferData->frameNumber);
                    s.bufferData->releaseBufferListener
                            ->onReleaseBuffer({resolvedState.externalTexture->getBuffer()->getId(),
                                               s.bufferData->frameNumber},
                                              s.bufferData->acquireFence
                                                      ? s.bufferData->acquireFence
                                                      : Fence::NO_FENCE,
                                              currentMaxAcquiredBufferCount);
                }

                // Delete the entire state at this point and not just release the buffer because
                // everything associated with the Layer in this Transaction is now out of date.
                ATRACE_FORMAT("DeleteStaleBuffer %s barrierProducerId:%d > %d", layer->name.c_str(),
                              layer->barrierProducerId, s.bufferData->producerId);
                return TraverseBuffersReturnValues::DELETE_AND_CONTINUE_TRAVERSAL;
            }

            if (layer->barrierFrameNumber < s.bufferData->barrierFrameNumber) {
                const bool willApplyBarrierFrame =
                        flushState.bufferLayersReadyToPresent.contains(s.surface.get()) &&
                        ((flushState.bufferLayersReadyToPresent.get(s.surface.get()) >=
                          s.bufferData->barrierFrameNumber));
                if (!willApplyBarrierFrame) {
                    ATRACE_FORMAT("NotReadyBarrier %s barrierFrameNumber:%" PRId64 " > %" PRId64,
                                  layer->name.c_str(), layer->barrierFrameNumber,
                                  s.bufferData->barrierFrameNumber);
                    ready = TransactionReadiness::NotReadyBarrier;
                    return TraverseBuffersReturnValues::STOP_TRAVERSAL;
                }
            }
        }

        // If backpressure is enabled and we already have a buffer to commit, keep
        // the transaction in the queue.
        const bool hasPendingBuffer =
                flushState.bufferLayersReadyToPresent.contains(s.surface.get());
        if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) {
            ATRACE_FORMAT("hasPendingBuffer %s", layer->name.c_str());
            ready = TransactionReadiness::NotReady;
            return TraverseBuffersReturnValues::STOP_TRAVERSAL;
        }

        // ignore the acquire fence if LatchUnsignaledConfig::Always is set.
        const bool checkAcquireFence = enableLatchUnsignaledConfig != LatchUnsignaledConfig::Always;
        const bool acquireFenceAvailable = s.bufferData &&
                s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
                s.bufferData->acquireFence;
        const bool fenceSignaled = !checkAcquireFence || !acquireFenceAvailable ||
                s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled;
        if (!fenceSignaled) {
            // check fence status
            const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(),
                                                                    flushState.firstTransaction) &&
                    layer->isSimpleBufferUpdate(s);
            if (allowLatchUnsignaled) {
                ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s", layer->name.c_str());
                ready = TransactionReadiness::NotReadyUnsignaled;
            } else {
                ready = TransactionReadiness::NotReady;
                auto& listener = s.bufferData->releaseBufferListener;
                if (listener &&
                    (flushState.queueProcessTime - transaction.postTime) >
                            std::chrono::nanoseconds(4s).count()) {
                    mTransactionHandler
                            .onTransactionQueueStalled(transaction.id, listener,
                                                       "Buffer processing hung up due to stuck "
                                                       "fence. Indicates GPU hang");
                }
                ATRACE_FORMAT("fence unsignaled %s", layer->name.c_str());
                return TraverseBuffersReturnValues::STOP_TRAVERSAL;
            }
        }
        return TraverseBuffersReturnValues::CONTINUE_TRAVERSAL;
    });
    return ready;
}

void SurfaceFlinger::addTransactionReadyFilters() {
    mTransactionHandler.addTransactionReadyFilter(
            std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1));
    if (mConfig->layerLifecycleManagerEnabled) {
        mTransactionHandler.addTransactionReadyFilter(
            std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1));
                std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this,
                          std::placeholders::_1));
    } else {
        mTransactionHandler.addTransactionReadyFilter(
                std::bind(&SurfaceFlinger::transactionReadyBufferCheckLegacy, this,
                          std::placeholders::_1));
    }
}

// For tests only
bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
    mTransactionHandler.collectTransactions();
    std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
    return applyTransactions(transactions, vsyncId);
}
@@ -4276,8 +4412,8 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId
            predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}

bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
                                           size_t numStates, bool firstTransaction) const {
bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t numStates,
                                           bool firstTransaction) const {
    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
        ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
        return false;
@@ -4314,7 +4450,7 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s
        }
    }

    return layer->isSimpleBufferUpdate(state);
    return true;
}

status_t SurfaceFlinger::setTransactionState(
@@ -8158,6 +8294,7 @@ frontend::Update SurfaceFlinger::flushLifecycleUpdates() {
    // 2. Transactions and created layers do not share a lock. To prevent applying
    // transactions with layers still in the createdLayer queue, flush the transactions
    // before committing the created layers.
    mTransactionHandler.collectTransactions();
    update.transactions = mTransactionHandler.flushTransactions();
    {
        // TODO(b/238781169) lockless queue this and keep order.
Loading