diff options
15 files changed, 295 insertions, 134 deletions
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 08667bfdec..eeae93211e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -25,6 +25,7 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> +#include <ftl/concat.h> #include <ftl/enum.h> #include <ftl/fake_guard.h> #include <ftl/small_map.h> @@ -130,8 +131,8 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId, auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) { std::scoped_lock lock(mDisplayLock); const bool isNew = mDisplays - .emplace_or_replace(displayId, std::move(selectorPtr), - std::move(schedulePtr)) + .emplace_or_replace(displayId, displayId, std::move(selectorPtr), + std::move(schedulePtr), mFeatures) .second; return std::make_pair(promotePacesetterDisplayLocked(), isNew); @@ -171,21 +172,43 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { - mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(), - .vsyncId = vsyncId, - .expectedVsyncTime = expectedVsyncTime, - .sfWorkDuration = - mVsyncModulator->getVsyncConfig().sfWorkDuration}, - *getVsyncSchedule()); - - if (!compositor.commit(mPacesetterFrameTargeter.target())) { - return; + const FrameTargeter::BeginFrameArgs beginFrameArgs = + {.frameBeginTime = SchedulerClock::now(), + .vsyncId = vsyncId, + // TODO(b/255601557): Calculate per display. + .expectedVsyncTime = expectedVsyncTime, + .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}; + + LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId); + const auto pacesetterId = *mPacesetterDisplayId; + const auto pacesetterOpt = mDisplays.get(pacesetterId); + + FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr; + pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr); + + if (!compositor.commit(pacesetterTargeter.target())) return; + + // TODO(b/256196556): Choose the frontrunner display. + FrameTargeters targeters; + targeters.try_emplace(pacesetterId, &pacesetterTargeter); + + for (auto& [id, display] : mDisplays) { + if (id == pacesetterId) continue; + + FrameTargeter& targeter = *display.targeterPtr; + targeter.beginFrame(beginFrameArgs, *display.schedulePtr); + + targeters.try_emplace(id, &targeter); } - const auto compositeResult = compositor.composite(mPacesetterFrameTargeter); + const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); - mPacesetterFrameTargeter.endFrame(compositeResult); + for (const auto& [id, targeter] : targeters) { + const auto resultOpt = resultsPerDisplay.get(id); + LOG_ALWAYS_FATAL_IF(!resultOpt); + targeter->endFrame(*resultOpt); + } } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { @@ -539,8 +562,16 @@ bool Scheduler::addResyncSample(PhysicalDisplayId id, nsecs_t timestamp, } void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) { - auto schedule = getVsyncSchedule(id); - LOG_ALWAYS_FATAL_IF(!schedule); + const auto scheduleOpt = + (ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) { + return display.powerMode == hal::PowerMode::OFF + ? std::nullopt + : std::make_optional(display.schedulePtr); + }); + + if (!scheduleOpt) return; + const auto& schedule = scheduleOpt->get(); + if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) { schedule->enableHardwareVsync(); } else { @@ -750,7 +781,23 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); - mPacesetterFrameTargeter.dump(dumper); + { + utils::Dumper::Section section(dumper, "Frame Targeting"sv); + + std::scoped_lock lock(mDisplayLock); + ftl::FakeGuard guard(kMainThreadContext); + + for (const auto& [id, display] : mDisplays) { + utils::Dumper::Section + section(dumper, + id == mPacesetterDisplayId + ? ftl::Concat("Pacesetter Display ", id.value).c_str() + : ftl::Concat("Follower Display ", id.value).c_str()); + + display.targeterPtr->dump(dumper); + dumper.eol(); + } + } } void Scheduler::dumpVsync(std::string& out) const { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 0ffa2d2022..8f51e5d7ee 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -222,7 +222,7 @@ public: // otherwise. bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod); - void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock) + void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) REQUIRES(kMainThreadContext); // Layers are registered on creation, and unregistered when the weak reference expires. @@ -254,7 +254,14 @@ public: return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt)); } - const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); } + TimePoint expectedPresentTimeForPacesetter() const EXCLUDES(mDisplayLock) { + std::scoped_lock lock(mDisplayLock); + return pacesetterDisplayLocked() + .transform([](const Display& display) { + return display.targeterPtr->target().expectedPresentTime(); + }) + .value_or(TimePoint()); + } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -308,7 +315,8 @@ private: enum class TouchState { Inactive, Active }; // impl::MessageQueue overrides: - void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override; + void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override + REQUIRES(kMainThreadContext, mDisplayLock); // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); @@ -434,13 +442,24 @@ private: // must lock for writes but not reads. See also mPolicyLock for locking order. mutable std::mutex mDisplayLock; + using FrameTargeterPtr = std::unique_ptr<FrameTargeter>; + struct Display { - Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr) - : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {} + Display(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr, + VsyncSchedulePtr schedulePtr, FeatureFlags features) + : displayId(displayId), + selectorPtr(std::move(selectorPtr)), + schedulePtr(std::move(schedulePtr)), + targeterPtr(std::make_unique< + FrameTargeter>(displayId, + features.test(Feature::kBackpressureGpuComposition))) {} + + const PhysicalDisplayId displayId; // Effectively const except in move constructor. RefreshRateSelectorPtr selectorPtr; VsyncSchedulePtr schedulePtr; + FrameTargeterPtr targeterPtr; hal::PowerMode powerMode = hal::PowerMode::OFF; }; @@ -454,8 +473,6 @@ private: ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext); - FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)}; - ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) { return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform( [](const Display& display) { return std::ref(const_cast<Display&>(display)); }); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index 85f2e64faa..ae74205720 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -20,6 +20,7 @@ #include <atomic> #include <memory> +#include <ui/DisplayId.h> #include <ui/Fence.h> #include <ui/FenceTime.h> @@ -75,16 +76,17 @@ public: bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; } protected: + explicit FrameTarget(const std::string& displayLabel); ~FrameTarget() = default; VsyncId mVsyncId; TimePoint mFrameBeginTime; TimePoint mExpectedPresentTime; - TracedOrdinal<bool> mFramePending{"PrevFramePending", false}; - TracedOrdinal<bool> mFrameMissed{"PrevFrameMissed", false}; - TracedOrdinal<bool> mHwcFrameMissed{"PrevHwcFrameMissed", false}; - TracedOrdinal<bool> mGpuFrameMissed{"PrevGpuFrameMissed", false}; + TracedOrdinal<bool> mFramePending; + TracedOrdinal<bool> mFrameMissed; + TracedOrdinal<bool> mHwcFrameMissed; + TracedOrdinal<bool> mGpuFrameMissed; struct FenceWithFenceTime { sp<Fence> fence = Fence::NO_FENCE; @@ -103,8 +105,9 @@ private: // Computes a display's per-frame metrics about past/upcoming targeting of present deadlines. class FrameTargeter final : private FrameTarget { public: - explicit FrameTargeter(bool backpressureGpuComposition) - : mBackpressureGpuComposition(backpressureGpuComposition) {} + FrameTargeter(PhysicalDisplayId displayId, bool backpressureGpuComposition) + : FrameTarget(to_string(displayId)), + mBackpressureGpuComposition(backpressureGpuComposition) {} const FrameTarget& target() const { return *this; } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h index f795f1f09d..87c704ece3 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h @@ -16,6 +16,9 @@ #pragma once +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> + #include <scheduler/interface/CompositionCoverage.h> namespace android { @@ -24,4 +27,6 @@ struct CompositeResult { CompositionCoverageFlags compositionCoverage; }; +using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>; + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h index 3d0f1a9d33..767462dfce 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h @@ -19,6 +19,8 @@ #include <cstdint> #include <ftl/flags.h> +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> namespace android { @@ -34,4 +36,14 @@ enum class CompositionCoverage : std::uint8_t { using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>; +using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayId, CompositionCoverageFlags>; + +inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) { + CompositionCoverageFlags coverage; + for (const auto& [id, flags] : displays) { + coverage |= flags; + } + return coverage; +} + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h index 26960766e5..6fe813a181 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h @@ -16,6 +16,9 @@ #pragma once +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> + #include <scheduler/Time.h> #include <scheduler/VsyncId.h> #include <scheduler/interface/CompositeResult.h> @@ -26,6 +29,8 @@ namespace scheduler { class FrameTarget; class FrameTargeter; +using FrameTargeters = ui::PhysicalDisplayMap<PhysicalDisplayId, scheduler::FrameTargeter*>; + } // namespace scheduler struct ICompositor { @@ -38,7 +43,8 @@ struct ICompositor { // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition // via RenderEngine and the Composer HAL, respectively. - virtual CompositeResult composite(scheduler::FrameTargeter&) = 0; + virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) = 0; // Samples the composited frame via RegionSamplingThread. virtual void sample() = 0; diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp index 7138afdf8b..7a18654346 100644 --- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp +++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp @@ -21,6 +21,12 @@ namespace android::scheduler { +FrameTarget::FrameTarget(const std::string& displayLabel) + : mFramePending("PrevFramePending " + displayLabel, false), + mFrameMissed("PrevFrameMissed " + displayLabel, false), + mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false), + mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {} + TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const { // TODO(b/267315508): Generalize to N VSYNCs. const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod)); @@ -130,10 +136,6 @@ FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr } void FrameTargeter::dump(utils::Dumper& dumper) const { - using namespace std::string_view_literals; - - utils::Dumper::Section section(dumper, "Frame Targeting"sv); - // There are scripts and tests that expect this (rather than "name=value") format. dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount)); dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount)); diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp index 908f214e85..1e038d1753 100644 --- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp +++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp @@ -96,7 +96,7 @@ private: FenceToFenceTimeMap mFenceMap; static constexpr bool kBackpressureGpuComposition = true; - FrameTargeter mTargeter{kBackpressureGpuComposition}; + FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition}; }; TEST_F(FrameTargeterTest, targetsFrames) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9a1d80830..711bea56bf 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2181,7 +2181,7 @@ void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData } } -void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { +void SurfaceFlinger::configure() { Mutex::Autolock lock(mStateLock); if (configureLocked()) { setTransactionFlags(eDisplayTransactionNeeded); @@ -2401,8 +2401,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, return mustComposite; } -bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) - FTL_FAKE_GUARD(kMainThreadContext) { +bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) { const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); @@ -2538,31 +2537,42 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFrameTargeter) - FTL_FAKE_GUARD(kMainThreadContext) { - const scheduler::FrameTarget& pacesetterFrameTarget = pacesetterFrameTargeter.target(); +CompositeResultsPerDisplay SurfaceFlinger::composite( + PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) { + const scheduler::FrameTarget& pacesetterTarget = + frameTargeters.get(pacesetterId)->get()->target(); - const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); + const VsyncId vsyncId = pacesetterTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); compositionengine::CompositionRefreshArgs refreshArgs; refreshArgs.powerCallback = this; const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); + + // Add outputs for physical displays. + for (const auto& [id, targeter] : frameTargeters) { + ftl::FakeGuard guard(mStateLock); + + if (const auto display = getCompositionDisplayLocked(id)) { + refreshArgs.outputs.push_back(display); + } + } + std::vector<DisplayId> displayIds; for (const auto& [_, display] : displays) { displayIds.push_back(display->getId()); display->tracePowerMode(); + // Add outputs for virtual displays. if (display->isVirtual()) { const Fps refreshRate = display->getAdjustedRefreshRate(); - if (refreshRate.isValid() && - !mScheduler->isVsyncInPhase(pacesetterFrameTarget.frameBeginTime(), refreshRate)) { - continue; + + if (!refreshRate.isValid() || + mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } - - refreshArgs.outputs.push_back(display->getCompositionDisplay()); } mPowerAdvisor->setDisplays(displayIds); @@ -2622,15 +2632,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr if (!getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && - pacesetterFrameTarget.wouldPresentEarly(vsyncPeriod)) { + pacesetterTarget.wouldPresentEarly(vsyncPeriod)) { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; + // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget. refreshArgs.earliestPresentTime = - pacesetterFrameTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; + pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; } refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); - refreshArgs.expectedPresentTime = pacesetterFrameTarget.expectedPresentTime().ns(); + refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; // Store the present time just before calling to the composition engine so we could notify @@ -2656,14 +2667,14 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr } } - mTimeStats->recordFrameDuration(pacesetterFrameTarget.frameBeginTime().ns(), systemTime()); + mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime()); // Send a power hint after presentation is finished. if (mPowerHintSessionEnabled) { // Now that the current frame has been presented above, PowerAdvisor needs the present time // of the previous frame (whose fence is signaled by now) to determine how long the HWC had // waited on that fence to retire before presenting. - const auto& previousPresentFence = pacesetterFrameTarget.presentFenceForPreviousFrame(); + const auto& previousPresentFence = pacesetterTarget.presentFenceForPreviousFrame(); mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()), TimePoint::now()); @@ -2674,23 +2685,27 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr scheduleComposite(FrameHint::kNone); } - postComposition(pacesetterFrameTargeter, presentTime); + postComposition(pacesetterId, frameTargeters, presentTime); - const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const bool hadGpuComposited = + multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu); mCompositionCoverage.clear(); TimeStats::ClientCompositionRecord clientCompositionRecord; + for (const auto& [_, display] : displays) { const auto& state = display->getCompositionDisplay()->getState(); + CompositionCoverageFlags& flags = + mCompositionCoverage.try_emplace(display->getId()).first->second; if (state.usesDeviceComposition) { - mCompositionCoverage |= CompositionCoverage::Hwc; + flags |= CompositionCoverage::Hwc; } if (state.reusedClientComposition) { - mCompositionCoverage |= CompositionCoverage::GpuReuse; + flags |= CompositionCoverage::GpuReuse; } else if (state.usesClientComposition) { - mCompositionCoverage |= CompositionCoverage::Gpu; + flags |= CompositionCoverage::Gpu; } clientCompositionRecord.predicted |= @@ -2699,10 +2714,11 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS); } - const bool hasGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const auto coverage = multiDisplayUnion(mCompositionCoverage); + const bool hasGpuComposited = coverage.test(CompositionCoverage::Gpu); clientCompositionRecord.hadClientComposition = hasGpuComposited; - clientCompositionRecord.reused = mCompositionCoverage.test(CompositionCoverage::GpuReuse); + clientCompositionRecord.reused = coverage.test(CompositionCoverage::GpuReuse); clientCompositionRecord.changed = hadGpuComposited != hasGpuComposited; mTimeStats->pushCompositionStrategyState(clientCompositionRecord); @@ -2711,16 +2727,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr // TODO(b/160583065): Enable skip validation when SF caches all client composition layers. const bool hasGpuUseOrReuse = - mCompositionCoverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); + coverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse); mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId); + addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId); } - updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + updateInputFlinger(vsyncId, pacesetterTarget.frameBeginTime()); if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; @@ -2733,7 +2749,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr mPowerAdvisor->setCompositeEnd(TimePoint::now()); } - return {mCompositionCoverage}; + CompositeResultsPerDisplay resultsPerDisplay; + + // Filter out virtual displays. + for (const auto& [id, coverage] : mCompositionCoverage) { + if (const auto idOpt = PhysicalDisplayId::tryCast(id)) { + resultsPerDisplay.try_emplace(*idOpt, CompositeResult{coverage}); + } + } + + return resultsPerDisplay; } void SurfaceFlinger::updateLayerGeometry() { @@ -2817,35 +2842,56 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, return ui::ROTATION_0; } -void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTargeter, +void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters& frameTargeters, nsecs_t presentStartTime) { ATRACE_CALL(); ALOGV(__func__); - const auto* defaultDisplay = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); + ui::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<FenceTime>> presentFences; + ui::PhysicalDisplayMap<PhysicalDisplayId, const sp<Fence>> gpuCompositionDoneFences; - std::shared_ptr<FenceTime> glCompositionDoneFenceTime; - if (defaultDisplay && - defaultDisplay->getCompositionDisplay()->getState().usesClientComposition) { - glCompositionDoneFenceTime = - std::make_shared<FenceTime>(defaultDisplay->getCompositionDisplay() - ->getRenderSurface() - ->getClientTargetAcquireFence()); - } else { - glCompositionDoneFenceTime = FenceTime::NO_FENCE; + for (const auto& [id, targeter] : frameTargeters) { + auto presentFence = getHwComposer().getPresentFence(id); + + if (id == pacesetterId) { + mTransactionCallbackInvoker.addPresentFence(presentFence); + } + + if (auto fenceTime = targeter->setPresentFence(std::move(presentFence)); + fenceTime->isValid()) { + presentFences.try_emplace(id, std::move(fenceTime)); + } + + ftl::FakeGuard guard(mStateLock); + if (const auto display = getCompositionDisplayLocked(id); + display && display->getState().usesClientComposition) { + gpuCompositionDoneFences + .try_emplace(id, display->getRenderSurface()->getClientTargetAcquireFence()); + } } - auto presentFence = defaultDisplay - ? getHwComposer().getPresentFence(defaultDisplay->getPhysicalId()) - : Fence::NO_FENCE; + const auto pacesetterDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(pacesetterId)); + + std::shared_ptr<FenceTime> pacesetterPresentFenceTime = + presentFences.get(pacesetterId) + .transform([](const FenceTimePtr& ptr) { return ptr; }) + .value_or(FenceTime::NO_FENCE); + + std::shared_ptr<FenceTime> pacesetterGpuCompositionDoneFenceTime = + gpuCompositionDoneFences.get(pacesetterId) + .transform([](sp<Fence> fence) { + return std::make_shared<FenceTime>(std::move(fence)); + }) + .value_or(FenceTime::NO_FENCE); - auto presentFenceTime = pacesetterFrameTargeter.setPresentFence(presentFence); const TimePoint presentTime = TimePoint::now(); // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime); + mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime, + pacesetterGpuCompositionDoneFenceTime); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -2853,9 +2899,9 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa const TimePoint compositeTime = TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp()); const Duration presentLatency = - !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) - ? mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime) - : Duration::zero(); + getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) + ? Duration::zero() + : mPresentLatencyTracker.trackPendingFrame(compositeTime, pacesetterPresentFenceTime); const auto schedule = mScheduler->getVsyncSchedule(); const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime); @@ -2892,8 +2938,8 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mLayersWithBuffersRemoved.clear(); for (const auto& layer: mLayersWithQueuedFrames) { - layer->onPostComposition(defaultDisplay, glCompositionDoneFenceTime, presentFenceTime, - compositorTiming); + layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime, + pacesetterPresentFenceTime, compositorTiming); layer->releasePendingBuffer(presentTime.ns()); } @@ -2980,38 +3026,32 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mHdrLayerInfoChanged = false; - mTransactionCallbackInvoker.addPresentFence(std::move(presentFence)); mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); mTimeStats->incrementTotalFrames(); - mTimeStats->setPresentFenceGlobal(presentFenceTime); + mTimeStats->setPresentFenceGlobal(pacesetterPresentFenceTime); - { + for (auto&& [id, presentFence] : presentFences) { ftl::FakeGuard guard(mStateLock); - for (const auto& [id, physicalDisplay] : mPhysicalDisplays) { - if (auto displayDevice = getDisplayDeviceLocked(id); - displayDevice && displayDevice->isPoweredOn() && physicalDisplay.isInternal()) { - auto presentFenceTimeI = defaultDisplay && defaultDisplay->getPhysicalId() == id - ? std::move(presentFenceTime) - : std::make_shared<FenceTime>(getHwComposer().getPresentFence(id)); - if (presentFenceTimeI->isValid()) { - mScheduler->addPresentFence(id, std::move(presentFenceTimeI)); - } - } + const bool isInternalDisplay = + mPhysicalDisplays.get(id).transform(&PhysicalDisplay::isInternal).value_or(false); + + if (isInternalDisplay) { + mScheduler->addPresentFence(id, std::move(presentFence)); } } - const bool isDisplayConnected = - defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId()); + const bool hasPacesetterDisplay = + pacesetterDisplay && getHwComposer().isConnected(pacesetterId); if (!hasSyncFramework) { - if (isDisplayConnected && defaultDisplay->isPoweredOn()) { - mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId()); + if (hasPacesetterDisplay && pacesetterDisplay->isPoweredOn()) { + mScheduler->enableHardwareVsync(pacesetterId); } } - if (isDisplayConnected && !defaultDisplay->isPoweredOn()) { + if (hasPacesetterDisplay && !pacesetterDisplay->isPoweredOn()) { getRenderEngine().cleanupPostRender(); return; } @@ -4298,7 +4338,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin const auto& transaction = *flushState.transaction; const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); - const TimePoint expectedPresentTime = mScheduler->pacesetterFrameTarget().expectedPresentTime(); + const TimePoint expectedPresentTime = mScheduler->expectedPresentTimeForPacesetter(); using TransactionReadiness = TransactionHandler::TransactionReadiness; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index aeaeb47210..3d46239759 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -636,9 +636,12 @@ private: void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override; // ICompositor overrides: - void configure() override; - bool commit(const scheduler::FrameTarget&) override; - CompositeResult composite(scheduler::FrameTargeter&) override; + void configure() override REQUIRES(kMainThreadContext); + bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext); + CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) override + REQUIRES(kMainThreadContext); + void sample() override; // ISchedulerCallback overrides: @@ -891,6 +894,14 @@ private: return findDisplay([id](const auto& display) { return display.getId() == id; }); } + std::shared_ptr<compositionengine::Display> getCompositionDisplayLocked(DisplayId id) const + REQUIRES(mStateLock) { + if (const auto display = getDisplayDeviceLocked(id)) { + return display->getCompositionDisplay(); + } + return nullptr; + } + // Returns the primary display or (for foldables) the active display, assuming that the inner // and outer displays have mutually exclusive power states. sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { @@ -964,8 +975,8 @@ private: /* * Compositing */ - void postComposition(scheduler::FrameTargeter&, nsecs_t presentStartTime) - REQUIRES(kMainThreadContext); + void postComposition(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&, + nsecs_t presentStartTime) REQUIRES(kMainThreadContext); /* * Display management @@ -1298,7 +1309,7 @@ private: std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; - CompositionCoverageFlags mCompositionCoverage; + CompositionCoveragePerDisplay mCompositionCoverage; // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by // any mutex. diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 00e92a18ff..28ac664ba3 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -287,7 +287,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} // MessageQueue overrides: @@ -474,25 +477,25 @@ public: &outWideColorGamutPixelFormat); } - void overrideHdrTypes(sp<IBinder> &display, FuzzedDataProvider *fdp) { + void overrideHdrTypes(const sp<IBinder>& display, FuzzedDataProvider* fdp) { std::vector<ui::Hdr> hdrTypes; hdrTypes.push_back(fdp->PickValueInArray(kHdrTypes)); mFlinger->overrideHdrTypes(display, hdrTypes); } - void getDisplayedContentSample(sp<IBinder> &display, FuzzedDataProvider *fdp) { + void getDisplayedContentSample(const sp<IBinder>& display, FuzzedDataProvider* fdp) { DisplayedFrameStats outDisplayedFrameStats; mFlinger->getDisplayedContentSample(display, fdp->ConsumeIntegral<uint64_t>(), fdp->ConsumeIntegral<uint64_t>(), &outDisplayedFrameStats); } - void getDisplayStats(sp<IBinder> &display) { + void getDisplayStats(const sp<IBinder>& display) { android::DisplayStatInfo stats; mFlinger->getDisplayStats(display, &stats); } - void getDisplayState(sp<IBinder> &display) { + void getDisplayState(const sp<IBinder>& display) { ui::DisplayState displayState; mFlinger->getDisplayState(display, &displayState); } @@ -506,12 +509,12 @@ public: android::ui::DynamicDisplayInfo dynamicDisplayInfo; mFlinger->getDynamicDisplayInfoFromId(displayId, &dynamicDisplayInfo); } - void getDisplayNativePrimaries(sp<IBinder> &display) { + void getDisplayNativePrimaries(const sp<IBinder>& display) { android::ui::DisplayPrimaries displayPrimaries; mFlinger->getDisplayNativePrimaries(display, displayPrimaries); } - void getDesiredDisplayModeSpecs(sp<IBinder> &display) { + void getDesiredDisplayModeSpecs(const sp<IBinder>& display) { gui::DisplayModeSpecs _; mFlinger->getDesiredDisplayModeSpecs(display, &_); } @@ -523,7 +526,7 @@ public: return ids.front(); } - std::pair<sp<IBinder>, int64_t> fuzzBoot(FuzzedDataProvider *fdp) { + std::pair<sp<IBinder>, PhysicalDisplayId> fuzzBoot(FuzzedDataProvider* fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); const sp<Client> client = sp<Client>::make(mFlinger); @@ -550,13 +553,13 @@ public: mFlinger->bootFinished(); - return {display, physicalDisplayId.value}; + return {display, physicalDisplayId}; } void fuzzSurfaceFlinger(const uint8_t *data, size_t size) { FuzzedDataProvider mFdp(data, size); - auto [display, displayId] = fuzzBoot(&mFdp); + const auto [display, displayId] = fuzzBoot(&mFdp); sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make(); @@ -564,8 +567,8 @@ public: getDisplayStats(display); getDisplayState(display); - getStaticDisplayInfo(displayId); - getDynamicDisplayInfo(displayId); + getStaticDisplayInfo(displayId.value); + getDynamicDisplayInfo(displayId.value); getDisplayNativePrimaries(display); mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool()); @@ -605,8 +608,9 @@ public: mFlinger->commitTransactions(); mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)); - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); - mFlinger->postComposition(frameTargeter, mFdp.ConsumeIntegral<nsecs_t>()); + scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool()); + mFlinger->postComposition(displayId, ftl::init::map(displayId, &frameTargeter), + mFdp.ConsumeIntegral<nsecs_t>()); } mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>()); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index b1fd06f998..4d1a5ffa67 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -50,7 +50,7 @@ constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode:: constexpr uint16_t kRandomStringLength = 256; constexpr std::chrono::duration kSyncPeriod(16ms); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +constexpr PhysicalDisplayId kDisplayId = PhysicalDisplayId::fromPort(42u); template <typename T> void dump(T* component, FuzzedDataProvider* fdp) { @@ -177,9 +177,8 @@ void SchedulerFuzzer::fuzzVSyncPredictor() { uint16_t now = mFdp.ConsumeIntegral<uint16_t>(); uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX); uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX); - scheduler::VSyncPredictor tracker{DEFAULT_DISPLAY_ID, - mFdp.ConsumeIntegral<uint16_t>() /*period*/, historySize, - minimumSamplesForPrediction, + scheduler::VSyncPredictor tracker{kDisplayId, mFdp.ConsumeIntegral<uint16_t>() /*period*/, + historySize, minimumSamplesForPrediction, mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/}; uint16_t period = mFdp.ConsumeIntegral<uint16_t>(); tracker.setPeriod(period); @@ -251,7 +250,7 @@ void SchedulerFuzzer::fuzzLayerHistory() { void SchedulerFuzzer::fuzzVSyncReactor() { std::shared_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_shared<FuzzImplVSyncTracker>(); - scheduler::VSyncReactor reactor(DEFAULT_DISPLAY_ID, + scheduler::VSyncReactor reactor(kDisplayId, std::make_unique<ClockWrapper>( std::make_shared<FuzzImplClock>()), *vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/, @@ -408,7 +407,7 @@ void SchedulerFuzzer::fuzzPresentLatencyTracker() { } void SchedulerFuzzer::fuzzFrameTargeter() { - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); + scheduler::FrameTargeter frameTargeter(kDisplayId, mFdp.ConsumeBool()); const struct VsyncSource final : scheduler::IVsyncSource { explicit VsyncSource(FuzzedDataProvider& fuzzer) : fuzzer(fuzzer) {} diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 359e2ab7fb..1dcf222834 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -36,7 +36,10 @@ using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} } gNoOpCompositor; diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index fa7a94735f..f3c9d0dd44 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -181,7 +181,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 909b8b8964..9b3a893409 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -359,7 +359,10 @@ public: * Forwarding for functions being tested */ - void configure() { mFlinger->configure(); } + void configure() { + ftl::FakeGuard guard(kMainThreadContext); + mFlinger->configure(); + } void configureAndCommit() { configure(); @@ -368,8 +371,14 @@ public: void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime, bool composite = false) { + ftl::FakeGuard guard(kMainThreadContext); + + const auto displayIdOpt = mScheduler->pacesetterDisplayId(); + LOG_ALWAYS_FATAL_IF(!displayIdOpt); + const auto displayId = *displayIdOpt; + constexpr bool kBackpressureGpuComposition = true; - scheduler::FrameTargeter frameTargeter(kBackpressureGpuComposition); + scheduler::FrameTargeter frameTargeter(displayId, kBackpressureGpuComposition); frameTargeter.beginFrame({.frameBeginTime = frameTime, .vsyncId = vsyncId, @@ -380,7 +389,7 @@ public: mFlinger->commit(frameTargeter.target()); if (composite) { - mFlinger->composite(frameTargeter); + mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter)); } } |