Loading services/surfaceflinger/Scheduler/Scheduler.cpp +63 −16 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading Loading @@ -171,21 +172,43 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(), const FrameTargeter::BeginFrameArgs beginFrameArgs = {.frameBeginTime = SchedulerClock::now(), .vsyncId = vsyncId, // TODO(b/255601557): Calculate per display. .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}, *getVsyncSchedule()); .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}; if (!compositor.commit(mPacesetterFrameTargeter.target())) { return; 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 { Loading Loading @@ -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 { Loading Loading @@ -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 { Loading services/surfaceflinger/Scheduler/Scheduler.h +24 −7 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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>); Loading Loading @@ -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; }; Loading @@ -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)); }); Loading services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +9 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <atomic> #include <memory> #include <ui/DisplayId.h> #include <ui/Fence.h> #include <ui/FenceTime.h> Loading Loading @@ -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; Loading @@ -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; } Loading services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ #pragma once #include <ui/DisplayId.h> #include <ui/DisplayMap.h> #include <scheduler/interface/CompositionCoverage.h> namespace android { Loading @@ -24,4 +27,6 @@ struct CompositeResult { CompositionCoverageFlags compositionCoverage; }; using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>; } // namespace android services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <cstdint> #include <ftl/flags.h> #include <ui/DisplayId.h> #include <ui/DisplayMap.h> namespace android { Loading @@ -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 Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +63 −16 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading Loading @@ -171,21 +172,43 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(), const FrameTargeter::BeginFrameArgs beginFrameArgs = {.frameBeginTime = SchedulerClock::now(), .vsyncId = vsyncId, // TODO(b/255601557): Calculate per display. .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}, *getVsyncSchedule()); .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}; if (!compositor.commit(mPacesetterFrameTargeter.target())) { return; 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 { Loading Loading @@ -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 { Loading Loading @@ -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 { Loading
services/surfaceflinger/Scheduler/Scheduler.h +24 −7 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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>); Loading Loading @@ -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; }; Loading @@ -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)); }); Loading
services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +9 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <atomic> #include <memory> #include <ui/DisplayId.h> #include <ui/Fence.h> #include <ui/FenceTime.h> Loading Loading @@ -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; Loading @@ -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; } Loading
services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ #pragma once #include <ui/DisplayId.h> #include <ui/DisplayMap.h> #include <scheduler/interface/CompositionCoverage.h> namespace android { Loading @@ -24,4 +27,6 @@ struct CompositeResult { CompositionCoverageFlags compositionCoverage; }; using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>; } // namespace android
services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <cstdint> #include <ftl/flags.h> #include <ui/DisplayId.h> #include <ui/DisplayMap.h> namespace android { Loading @@ -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