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

Commit 914b97eb authored by Wenhui Yang's avatar Wenhui Yang Committed by Android (Google) Code Review
Browse files

Merge changes I9b98a243,I5125ab78 into main

* changes:
  Offload Virtual Display composition from SF main thread
  Add flag offload_gpu_composition
parents 9d8e8aa6 b34ab806
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -95,6 +95,9 @@ public:

    bool isVirtual() const;
    bool isPrimary() const { return mIsPrimary; }
    bool isGpuVirtualDisplay() const {
        return std::holds_alternative<GpuVirtualDisplayId>(getDisplayIdVariant());
    }

    // isSecure indicates whether this display can be trusted to display
    // secure surfaces.
+3 −3
Original line number Diff line number Diff line
@@ -1350,11 +1350,11 @@ void LayerSnapshotBuilder::forEachVisibleSnapshot(const Visitor& visitor) {
    }
}

void LayerSnapshotBuilder::forEachSnapshot(const Visitor& visitor,
void LayerSnapshotBuilder::forEachNonNullSnapshot(const Visitor& visitor,
                                                  const ConstPredicate& predicate) {
    for (int i = 0; i < mNumInterestingSnapshots; i++) {
        std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
        if (!predicate(*snapshot)) continue;
        if (!snapshot || !predicate(*snapshot)) continue;
        visitor(snapshot);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ public:
    typedef std::function<bool(const LayerSnapshot& snapshot)> ConstPredicate;
    // Visit each snapshot that satisfies the predicate and move the snapshot if needed with visible
    // snapshots in z-order
    void forEachSnapshot(const Visitor& visitor, const ConstPredicate& predicate);
    void forEachNonNullSnapshot(const Visitor& visitor, const ConstPredicate& predicate);

    // Visit each snapshot
    void forEachSnapshot(const ConstVisitor& visitor) const;
+165 −63
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@
#include <ftl/concat.h>
#include <ftl/fake_guard.h>
#include <ftl/future.h>
#include <ftl/small_vector.h>
#include <ftl/unit.h>
#include <gui/AidlUtil.h>
#include <gui/BufferQueue.h>
@@ -437,6 +438,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
        mFrameTracer(mFactory.createFrameTracer()),
        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
        mCompositionEngine(mFactory.createCompositionEngine()),
        mOffloadedCompositionEngine(mFactory.createCompositionEngine()),
        mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
        mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()),
        mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
@@ -935,6 +937,7 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
    chooseRenderEngineType(builder);
    mRenderEngine = renderengine::RenderEngine::create(builder.build());
    mCompositionEngine->setRenderEngine(mRenderEngine.get());
    mOffloadedCompositionEngine->setRenderEngine(mRenderEngine.get());
    mMaxRenderTargetSize =
            std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims());

@@ -947,6 +950,7 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {

    mHWComposer = getFactory().createHWComposer(mHwcServiceName);
    mCompositionEngine->setHwComposer(mHWComposer.get());
    mOffloadedCompositionEngine->setHwComposer(mHWComposer.get());
    auto& composer = mCompositionEngine->getHwComposer();
    composer.setCallback(*this);
    mDisplayModeController.setHwComposer(&composer);
@@ -2905,20 +2909,15 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
    return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}

CompositeResultsPerDisplay SurfaceFlinger::composite(
        PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) {
    SFTRACE_ASYNC_FOR_TRACK_BEGIN(WorkloadTracer::TRACK_NAME, "Composition",
                                  WorkloadTracer::COMPOSITION_TRACE_COOKIE);
    const scheduler::FrameTarget& pacesetterTarget =
            frameTargeters.get(pacesetterId)->get()->target();

    const VsyncId vsyncId = pacesetterTarget.vsyncId();
    SFTRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
SurfaceFlinger::RefreshArgsPartition SurfaceFlinger::addOutputsToRefreshArgs(
        PhysicalDisplayId pacesetterId,
        const compositionengine::CompositionRefreshArgs& refreshArgs,
        const scheduler::FrameTargeters& frameTargeters) {
    compositionengine::CompositionRefreshArgs mainThreadRefreshArgs = refreshArgs;
    compositionengine::CompositionRefreshArgs offloadedRefreshArgs = refreshArgs;

    compositionengine::CompositionRefreshArgs refreshArgs;
    refreshArgs.powerCallback = this;
    const auto& pacesetterTarget = frameTargeters.get(pacesetterId)->get()->target();
    const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
    refreshArgs.outputs.reserve(displays.size());

    // Track layer stacks of physical displays that might be added to CompositionEngine
    // output. Layer stacks are not tracked in Display when we iterate through
@@ -2946,36 +2945,98 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
        return true;
    };

    // Add outputs for physical displays.
    // Partition displays: physical for main thread, virtual for offloaded.
    for (const auto& [id, targeter] : frameTargeters) {
        ftl::FakeGuard guard(mStateLock);

        if (const auto display = getCompositionDisplayLocked(id)) {
            const auto layerStack = physicalDisplayLayerStacks.get(id)->get();
            if (isUniqueOutputLayerStack(display->getId(), layerStack)) {
                refreshArgs.outputs.push_back(display);
                mainThreadRefreshArgs.outputs.push_back(display);
            }
        }

        refreshArgs.frameTargets.try_emplace(id, &targeter->target());
        mainThreadRefreshArgs.frameTargets.try_emplace(id, &targeter->target());
    }

    std::vector<DisplayId> displayIds;
    const bool canOffloadGpuComposition =
            FlagManager::getInstance().offload_gpu_composition() && mRenderEngine->isThreaded();
    for (const auto& [_, display] : displays) {
        displayIds.push_back(display->getId());
        display->tracePowerMode();
        if (!display->isVirtual()) {
            continue;
        }

        // Add outputs for virtual displays.
        if (display->isVirtual()) {
        const Fps refreshRate = display->getAdjustedRefreshRate();
        if (refreshRate.isValid() &&
            !mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) {
            continue;
        }

            if (!refreshRate.isValid() ||
                mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) {
                if (isUniqueOutputLayerStack(display->getId(), display->getLayerStack())) {
                    refreshArgs.outputs.push_back(display->getCompositionDisplay());
        if (!isUniqueOutputLayerStack(display->getId(), display->getLayerStack())) {
            continue;
        }

        // Offload GPU backed display to background thread
        if (canOffloadGpuComposition && display->isGpuVirtualDisplay()) {
            offloadedRefreshArgs.outputs.push_back(display->getCompositionDisplay());
        } else {
            mainThreadRefreshArgs.outputs.push_back(display->getCompositionDisplay());
        }
    }

    // Populate properties for offload thread
    if (offloadedRefreshArgs.outputs.empty()) {
        return {.mainThreadRefreshArgs = std::move(mainThreadRefreshArgs),
                .offloadedRefreshArgs = std::nullopt};
    }
    offloadedRefreshArgs.hasTrustedPresentationListener = false;
    offloadedRefreshArgs.bufferIdsToUncache = {};

    return {.mainThreadRefreshArgs = std::move(mainThreadRefreshArgs),
            .offloadedRefreshArgs = offloadedRefreshArgs};
}

std::future<void> SurfaceFlinger::offloadGpuCompositedDisplays(
        compositionengine::CompositionRefreshArgs offloadedRefreshArgs,
        std::vector<std::pair<Layer*, LayerFE*>> offloadedLayers) {
    auto offloadedCompositionPromise = std::make_shared<std::promise<void>>();
    auto offloadedCompositionFuture = offloadedCompositionPromise->get_future();

    for (auto& [layer, layerFE] : offloadedLayers) {
        layer->onPreComposition(offloadedRefreshArgs.refreshStartTime);
        attachReleaseFenceFutureToLayer(layer, layerFE,
                                        layerFE->mSnapshot->outputFilter.layerStack);
    }

    BackgroundExecutor::getInstance().sendCallbacks(
            {[offloadedRefreshArgs = std::move(offloadedRefreshArgs),
              promise = std::move(offloadedCompositionPromise), this]() mutable {
                mOffloadedCompositionEngine->present(offloadedRefreshArgs);
                promise->set_value();
            }});
    return offloadedCompositionFuture;
}

CompositeResultsPerDisplay SurfaceFlinger::composite(
        PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) {
    SFTRACE_ASYNC_FOR_TRACK_BEGIN(WorkloadTracer::TRACK_NAME, "Composition",
                                  WorkloadTracer::COMPOSITION_TRACE_COOKIE);
    const scheduler::FrameTarget& pacesetterTarget =
            frameTargeters.get(pacesetterId)->get()->target();

    const VsyncId vsyncId = pacesetterTarget.vsyncId();
    SFTRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());

    compositionengine::CompositionRefreshArgs refreshArgs;
    // adpf load up hint
    refreshArgs.powerCallback = this;
    const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
    refreshArgs.outputs.reserve(displays.size());

    std::vector<DisplayId> displayIds;
    for (const auto& [_, display] : displays) {
        displayIds.push_back(display->getId());
        display->tracePowerMode();
    }
    mPowerAdvisor->setDisplays(displayIds);

@@ -3015,51 +3076,33 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
    // Store the present time just before calling to the composition engine so we could notify
    // the scheduler.
    const auto presentTime = systemTime();
    refreshArgs.refreshStartTime = presentTime;

    constexpr bool kCursorOnly = false;
    const auto layers = moveSnapshotsToCompositionArgs(refreshArgs, kCursorOnly);

    if (!mVisibleRegionsDirty) {
        for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
            auto compositionDisplay = display->getCompositionDisplay();
            if (!compositionDisplay->getState().isEnabled) continue;
            for (const auto* outputLayer : compositionDisplay->getOutputLayersOrderedByZ()) {
                if (outputLayer->getLayerFE().getCompositionState() == nullptr) {
                    // This is unexpected but instead of crashing, capture traces to disk
                    // and recover gracefully by forcing CE to rebuild layer stack.
                    ALOGE("Output layer %s for display %s %" PRIu64 " has a null "
                          "snapshot. Forcing mVisibleRegionsDirty",
                          outputLayer->getLayerFE().getDebugName(),
                          compositionDisplay->getName().c_str(), compositionDisplay->getId().value);
    auto [mainThreadRefreshArgs, optionalOffloadedRefreshArgs] =
            addOutputsToRefreshArgs(pacesetterId, refreshArgs, frameTargeters);

                    TransactionTraceWriter::getInstance().invoke(__func__, /* overwrite= */ false);
                    mVisibleRegionsDirty = true;
                    refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
                    refreshArgs.updatingGeometryThisFrame = mVisibleRegionsDirty;
                }
            }
        }
    }
    refreshArgs.refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
    constexpr bool kCursorOnly = false;
    const auto layers = addLayerSnapshotsToCompositionArgs(mainThreadRefreshArgs, kCursorOnly);
    setVisibleRegionDirtyIfNeeded(mainThreadRefreshArgs);

    for (auto& [layer, layerFE] : layers) {
        layer->onPreComposition(refreshArgs.refreshStartTime);
        layer->onPreComposition(mainThreadRefreshArgs.refreshStartTime);

        validateForReadback(layerFE);
    }

    setupOutputsForReadback(refreshArgs.outputs);
    setupOutputsForReadback(mainThreadRefreshArgs.outputs);

    for (auto& [layer, layerFE] : layers) {
        attachReleaseFenceFutureToLayer(layer, layerFE,
                                        layerFE->mSnapshot->outputFilter.layerStack);
    }

    refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
    mainThreadRefreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
    for (auto& [layer, _] : mLayersWithQueuedFrames) {
        if (const auto& layerFE =
                    layer->getCompositionEngineLayerFE({static_cast<uint32_t>(layer->sequence)})) {
            refreshArgs.layersWithQueuedFrames.push_back(layerFE);
            mainThreadRefreshArgs.layersWithQueuedFrames.push_back(layerFE);
            // Some layers are not displayed and do not yet have a future release fence
            if (layerFE->getReleaseFencePromiseStatus() ==
                        LayerFE::ReleaseFencePromiseStatus::UNINITIALIZED ||
@@ -3072,12 +3115,25 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
        }
    }

    mCompositionEngine->present(refreshArgs);
    std::optional<std::future<void>> offloadedCompositionFuture;
    std::vector<std::pair<Layer*, LayerFE*>> offloadedLayers;
    if (optionalOffloadedRefreshArgs) {
        setVisibleRegionDirtyIfNeeded(*optionalOffloadedRefreshArgs);

        offloadedLayers =
                addLayerSnapshotsToCompositionArgs(*optionalOffloadedRefreshArgs, kCursorOnly);
        offloadedCompositionFuture =
                offloadGpuCompositedDisplays(std::move(*optionalOffloadedRefreshArgs),
                                             offloadedLayers);
    }

    finalizeReadback(refreshArgs.outputs);
    mCompositionEngine->present(mainThreadRefreshArgs);

    finalizeReadback(mainThreadRefreshArgs.outputs);

    ftl::Flags<adpf::Workload> compositedWorkload;
    if (refreshArgs.updatingGeometryThisFrame || refreshArgs.updatingOutputGeometryThisFrame) {
    if (mainThreadRefreshArgs.updatingGeometryThisFrame ||
        mainThreadRefreshArgs.updatingOutputGeometryThisFrame) {
        compositedWorkload |= adpf::Workload::VISIBLE_REGION;
    }
    if (mFrontEndDisplayInfosChanged) {
@@ -3172,7 +3228,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
        }
    }

    moveSnapshotsFromCompositionArgs(refreshArgs, layers);
    moveSnapshotsFromCompositionArgs(mainThreadRefreshArgs, layers);
    if (optionalOffloadedRefreshArgs) {
        offloadedCompositionFuture->wait();
        moveSnapshotsFromCompositionArgs(*optionalOffloadedRefreshArgs, offloadedLayers);
    }
    mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime());

    // Send a power hint after presentation is finished.
@@ -3203,7 +3263,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(

    TimeStats::ClientCompositionRecord clientCompositionRecord;

    for (const auto& [_, display] : displays) {
    for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
        const auto& state = display->getCompositionDisplay()->getState();
        CompositionCoverageFlags& flags =
                mCompositionCoverage.try_emplace(display->getDisplayIdVariant()).first->second;
@@ -4500,7 +4560,7 @@ void SurfaceFlinger::updateCursorAsync() {
    }

    constexpr bool kCursorOnly = true;
    const auto layers = moveSnapshotsToCompositionArgs(refreshArgs, kCursorOnly);
    const auto layers = addLayerSnapshotsToCompositionArgs(refreshArgs, kCursorOnly);
    mCompositionEngine->updateCursorAsync(refreshArgs);
    moveSnapshotsFromCompositionArgs(refreshArgs, layers);
}
@@ -8836,6 +8896,38 @@ std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextur
    return nullptr;
}

void SurfaceFlinger::setVisibleRegionDirtyIfNeeded(
        compositionengine::CompositionRefreshArgs& refreshArgs) {
    if (mVisibleRegionsDirty) {
        refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
        refreshArgs.updatingGeometryThisFrame = mVisibleRegionsDirty;
        return;
    }

    for (const auto& output : refreshArgs.outputs) {
        if (!output->getState().isEnabled) {
            continue;
        }

        for (const auto* outputLayer : output->getOutputLayersOrderedByZ()) {
            if (outputLayer->getLayerFE().getCompositionState() == nullptr) {
                // This is unexpected but instead of crashing, capture traces to disk
                // and recover gracefully by forcing CE to rebuild layer stack.
                ALOGE("Output layer %s for display %s %" PRIu64
                      " has a null snapshot. Forcing mVisibleRegionsDirty",
                      outputLayer->getLayerFE().getDebugName(), output->getName().c_str(),
                      output->getDisplayId()->value);

                TransactionTraceWriter::getInstance().invoke(__func__, /* overwrite= */ false);
                mVisibleRegionsDirty = true;
                refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
                refreshArgs.updatingGeometryThisFrame = mVisibleRegionsDirty;
                return;
            }
        }
    }
}

void SurfaceFlinger::moveSnapshotsFromCompositionArgs(
        compositionengine::CompositionRefreshArgs& refreshArgs,
        const std::vector<std::pair<Layer*, LayerFE*>>& layers) {
@@ -8847,13 +8939,18 @@ void SurfaceFlinger::moveSnapshotsFromCompositionArgs(
    }
}

std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::moveSnapshotsToCompositionArgs(
std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::addLayerSnapshotsToCompositionArgs(
        compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly) {
    ui::DisplayVector<ui::LayerStack> expectedLayerStacks;
    for (auto& output : refreshArgs.outputs) {
        expectedLayerStacks.push_back(output->getState().layerFilter.layerStack);
    }

    std::vector<std::pair<Layer*, LayerFE*>> layers;
    nsecs_t currentTime = systemTime();
    const bool needsMetadata = mCompositionEngine->getFeatureFlags().test(
            compositionengine::Feature::kSnapshotLayerMetadata);
    mLayerSnapshotBuilder.forEachSnapshot(
    mLayerSnapshotBuilder.forEachNonNullSnapshot(
            [&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) FTL_FAKE_GUARD(
                    kMainThreadContext) {
                if (cursorOnly &&
@@ -8866,6 +8963,11 @@ std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::moveSnapshotsToComposit
                    return;
                }

                if (std::find(expectedLayerStacks.begin(), expectedLayerStacks.end(),
                              snapshot->outputFilter.layerStack) == expectedLayerStacks.end()) {
                    return;
                }

                auto it = mLegacyLayers.find(snapshot->sequence);
                LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
                                                "Couldnt find layer object for %s",
+22 −2
Original line number Diff line number Diff line
@@ -769,9 +769,10 @@ private:
            REQUIRES(mStateLock, kMainThreadContext);
    void doCommitTransactions() REQUIRES(mStateLock);

    std::vector<std::pair<Layer*, LayerFE*>> moveSnapshotsToCompositionArgs(
    std::vector<std::pair<Layer*, LayerFE*>> addLayerSnapshotsToCompositionArgs(
            compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly)
            REQUIRES(kMainThreadContext);

    void moveSnapshotsFromCompositionArgs(compositionengine::CompositionRefreshArgs& refreshArgs,
                                          const std::vector<std::pair<Layer*, LayerFE*>>& layers)
            REQUIRES(kMainThreadContext);
@@ -1547,6 +1548,8 @@ private:
    std::atomic<int> mNumTrustedPresentationListeners = 0;

    std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
    // Dedicated composition engine instance for the virtual displays offloaded from main thread.
    std::unique_ptr<compositionengine::CompositionEngine> mOffloadedCompositionEngine;
    std::unique_ptr<HWComposer> mHWComposer;

    CompositionCoveragePerDisplay mCompositionCoverage;
@@ -1688,6 +1691,22 @@ private:
    void sfdo_forceClientComposition(bool enabled);
    status_t sfdo_forcePacesetter(PhysicalDisplayId displayId);
    void sfdo_resetForcedPacesetter();

    // Partition displays: physical for main thread, virtual for offloaded.
    struct RefreshArgsPartition {
        compositionengine::CompositionRefreshArgs mainThreadRefreshArgs;
        std::optional<compositionengine::CompositionRefreshArgs> offloadedRefreshArgs;
    };
    RefreshArgsPartition addOutputsToRefreshArgs(
            PhysicalDisplayId pacesetterId,
            const compositionengine::CompositionRefreshArgs& refreshArgs,
            const scheduler::FrameTargeters& frameTargeters);
    std::future<void> offloadGpuCompositedDisplays(
            compositionengine::CompositionRefreshArgs offloadedRefreshArgs,
            std::vector<std::pair<Layer*, LayerFE*>> offloadedLayers);
    // TODO(b/431836223): Workaround to capture traces to disk and recover gracefully by forcing CE
    //  to rebuild layer stack instead of crashing.
    void setVisibleRegionDirtyIfNeeded(compositionengine::CompositionRefreshArgs& refreshArgs);
};

class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
@@ -1841,6 +1860,7 @@ private:
    status_t checkObservePictureProfilesPermission();
    static void getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& info,
                                              gui::DynamicDisplayInfo*& outInfo);
    bool isBackedByGpu() const;

private:
    const sp<SurfaceFlinger> mFlinger;
Loading