Reland "Create a VsyncSchedule per display"
In order to determine the vsync offsets between displays, keep track of
a VsyncSchedule for each display.
Store the VsyncSchedules in a SmallMap. Update getVsyncSchedule with a
parameter to choose the display. The default parameter uses the leader's
display, which is what many current callers want.
Update VsyncDispatches when the leader changes, so that they are always
listening to the leader.
Enable and disable vsync callbacks per display. Earlier attempts to turn
them on and off together could leave a secondary display on a bad
schedule. Add a method for resyncing all displays at once.
Use std::shared_ptrs for VsyncDispatches. This prevents lifetime issues
if a VsyncSchedule gets removed while its VsyncDispatch is still in use.
Same for VsyncTracker, which is referenced by VsyncDispatch.
When the leader VsyncSchedule changes, call cancel on
VsyncCallbackRegistrations and replace them with new ones using the new
VsyncDispatches. If a callback was scheduled, schedule a new one.
Update VsyncSchedule's members' traces so that there is a separate track
for each display.
For refresh rate changes, modulate vsync config based on the leader
display. When switching leaders, force a period transition to ensure
that a potential refresh rate change is completed.
This reverts commit db16a2be4054d0dd7d940f4fa0a2ced0575fd2e7 aka
I0757a7df540fad316b2db42e4c77f1c73bc49420, which reverted the original
CL, If60218e85292c786b9fa70ecb33ee374d3a385e0. Notable differences from
the original CL:
- Logical pieces have been separated and landed in the following CLs:
- I21be76e20776d8a3f49e5bd295a0042de9e2dde9
- I062002245db8fd817e145a3aaf197bb874b00636
- I54a1304a3428968134cc707b24d5b325927c31df
- Remove IEventThreadCallback changes. These are ultimately orthogonal
to the motivation of this CL.
- Store the ID instead of the name and use ftl::Concat, as tracked in
b/266817103.
- Rename MessageQueue::updateVsyncRegistration to onNewVsyncSchedule, to
match the name in EventThread. These methods do essentially the same
thing, so use the same name.
- Crucially, I54a1304a3428968134cc707b24d5b325927c31df restores the
pending HWC Vsync state, which was originally removed in
If60218e85292c786b9fa70ecb33ee374d3a385e0. The removal seems to have
been responsible for b/267562341.
Bug: 255601557
Bug: 256196556
Bug: 241285473
Bug: 241286146
Bug: 268366385
Fixes: 266817103
Test: libsurfaceflinger_unittest
Test: manual (look at perfetto traces)
Change-Id: Icdb80253436b4d0034fc20fcae8583efb7c30292
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 67f4daa..7374054 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -114,8 +114,6 @@
void run();
- void createVsyncSchedule(FeatureFlags);
-
using Impl::initVsync;
using Impl::getScheduledFrameTime;
@@ -169,9 +167,21 @@
const VsyncModulator& vsyncModulator() const { return *mVsyncModulator; }
+ // In some cases, we should only modulate for the leader display. In those
+ // cases, the caller should pass in the relevant display, and the method
+ // will no-op if it's not the leader. Other cases are not specific to a
+ // display.
template <typename... Args,
typename Handler = std::optional<VsyncConfig> (VsyncModulator::*)(Args...)>
- void modulateVsync(Handler handler, Args... args) {
+ void modulateVsync(std::optional<PhysicalDisplayId> id, Handler handler, Args... args) {
+ if (id) {
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+ if (id != mLeaderDisplayId) {
+ return;
+ }
+ }
+
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
setVsyncConfig(*config, getLeaderVsyncPeriod());
}
@@ -180,24 +190,32 @@
void setVsyncConfigSet(const VsyncConfigSet&, Period vsyncPeriod);
// Sets the render rate for the scheduler to run at.
- void setRenderRate(Fps);
+ void setRenderRate(PhysicalDisplayId, Fps);
- void enableHardwareVsync();
- void disableHardwareVsync(bool disallow);
+ void enableHardwareVsync(PhysicalDisplayId);
+ void disableHardwareVsync(PhysicalDisplayId, bool disallow);
// Resyncs the scheduler to hardware vsync.
// If allowToEnable is true, then hardware vsync will be turned on.
// Otherwise, if hardware vsync is not already enabled then this method will
// no-op.
- void resyncToHardwareVsync(bool allowToEnable, Fps refreshRate);
+ // If refreshRate is nullopt, use the existing refresh rate of the display.
+ void resyncToHardwareVsync(PhysicalDisplayId id, bool allowToEnable,
+ std::optional<Fps> refreshRate = std::nullopt)
+ EXCLUDES(mDisplayLock) {
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+ resyncToHardwareVsyncLocked(id, allowToEnable, refreshRate);
+ }
void resync() EXCLUDES(mDisplayLock);
void forceNextResync() { mLastResyncTime = 0; }
// Passes a vsync sample to VsyncController. Returns true if
// VsyncController detected that the vsync period changed and false
// otherwise.
- bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod);
- void addPresentFence(std::shared_ptr<FenceTime>);
+ bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp,
+ std::optional<nsecs_t> hwcVsyncPeriod);
+ void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock);
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
@@ -215,20 +233,26 @@
// Indicates that touch interaction is taking place.
void onTouchHint();
- void setDisplayPowerMode(hal::PowerMode powerMode);
+ void setDisplayPowerMode(PhysicalDisplayId, hal::PowerMode powerMode)
+ REQUIRES(kMainThreadContext);
- VsyncSchedule& getVsyncSchedule() { return *mVsyncSchedule; }
+ std::shared_ptr<const VsyncSchedule> getVsyncSchedule(
+ std::optional<PhysicalDisplayId> idOpt = std::nullopt) const EXCLUDES(mDisplayLock);
+ std::shared_ptr<VsyncSchedule> getVsyncSchedule(
+ std::optional<PhysicalDisplayId> idOpt = std::nullopt) EXCLUDES(mDisplayLock) {
+ return std::const_pointer_cast<VsyncSchedule>(
+ static_cast<const Scheduler*>(this)->getVsyncSchedule(idOpt));
+ }
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
- // Checks if a vsync timestamp is in phase for a frame rate
- bool isVsyncInPhase(TimePoint timePoint, const Fps frameRate) const;
+ bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const;
void dump(utils::Dumper&) const;
void dump(ConnectionHandle, std::string&) const;
- void dumpVsync(std::string&) const;
+ void dumpVsync(std::string&) const EXCLUDES(mDisplayLock);
// Returns the preferred refresh rate and frame rate for the leader display.
FrameRateMode getPreferredDisplayMode();
@@ -288,6 +312,10 @@
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
+ void resyncToHardwareVsyncLocked(PhysicalDisplayId, bool allowToEnable,
+ std::optional<Fps> refreshRate = std::nullopt)
+ REQUIRES(kMainThreadContext, mDisplayLock);
+ void resyncAllToHardwareVsync(bool allowToEnable) EXCLUDES(mDisplayLock);
void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod);
// Chooses a leader among the registered displays, unless `leaderIdOpt` is specified. The new
@@ -299,6 +327,10 @@
// caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
void demoteLeaderDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
+ void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr,
+ std::shared_ptr<VsyncSchedule>) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
+
struct Policy;
// Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
@@ -355,7 +387,6 @@
std::atomic<nsecs_t> mLastResyncTime = 0;
const FeatureFlags mFeatures;
- std::unique_ptr<VsyncSchedule> mVsyncSchedule;
// Shifts the VSYNC phase during certain transactions and refresh rate changes.
const sp<VsyncModulator> mVsyncModulator;
@@ -380,6 +411,10 @@
display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors
GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
+ // TODO (b/266715559): Store in the same map as mRefreshRateSelectors.
+ display::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<VsyncSchedule>> mVsyncSchedules
+ GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
+
ftl::Optional<PhysicalDisplayId> mLeaderDisplayId GUARDED_BY(mDisplayLock)
GUARDED_BY(kMainThreadContext);
@@ -399,6 +434,14 @@
.value_or(std::cref(noLeader));
}
+ std::shared_ptr<const VsyncSchedule> getVsyncScheduleLocked(
+ std::optional<PhysicalDisplayId> idOpt = std::nullopt) const REQUIRES(mDisplayLock);
+ std::shared_ptr<VsyncSchedule> getVsyncScheduleLocked(
+ std::optional<PhysicalDisplayId> idOpt = std::nullopt) REQUIRES(mDisplayLock) {
+ return std::const_pointer_cast<VsyncSchedule>(
+ static_cast<const Scheduler*>(this)->getVsyncScheduleLocked(idOpt));
+ }
+
struct Policy {
// Policy for choosing the display mode.
LayerHistory::Summary contentRequirements;