xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2018 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
18*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "Scheduler"
19*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include "Scheduler.h"
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker #include <android-base/properties.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <configstore/Utils.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <ftl/concat.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <ftl/enum.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <ftl/fake_guard.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <ftl/small_map.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <gui/WindowInfo.h>
34*38e8c45fSAndroid Build Coastguard Worker #include <system/window.h>
35*38e8c45fSAndroid Build Coastguard Worker #include <ui/DisplayMap.h>
36*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker #include <FrameTimeline/FrameTimeline.h>
39*38e8c45fSAndroid Build Coastguard Worker #include <scheduler/interface/ICompositor.h>
40*38e8c45fSAndroid Build Coastguard Worker 
41*38e8c45fSAndroid Build Coastguard Worker #include <cinttypes>
42*38e8c45fSAndroid Build Coastguard Worker #include <cstdint>
43*38e8c45fSAndroid Build Coastguard Worker #include <functional>
44*38e8c45fSAndroid Build Coastguard Worker #include <memory>
45*38e8c45fSAndroid Build Coastguard Worker #include <numeric>
46*38e8c45fSAndroid Build Coastguard Worker 
47*38e8c45fSAndroid Build Coastguard Worker #include <common/FlagManager.h>
48*38e8c45fSAndroid Build Coastguard Worker #include "EventThread.h"
49*38e8c45fSAndroid Build Coastguard Worker #include "FrameRateOverrideMappings.h"
50*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/LayerHandle.h"
51*38e8c45fSAndroid Build Coastguard Worker #include "Layer.h"
52*38e8c45fSAndroid Build Coastguard Worker #include "OneShotTimer.h"
53*38e8c45fSAndroid Build Coastguard Worker #include "RefreshRateStats.h"
54*38e8c45fSAndroid Build Coastguard Worker #include "SurfaceFlingerFactory.h"
55*38e8c45fSAndroid Build Coastguard Worker #include "SurfaceFlingerProperties.h"
56*38e8c45fSAndroid Build Coastguard Worker #include "TimeStats/TimeStats.h"
57*38e8c45fSAndroid Build Coastguard Worker #include "VsyncConfiguration.h"
58*38e8c45fSAndroid Build Coastguard Worker #include "VsyncController.h"
59*38e8c45fSAndroid Build Coastguard Worker #include "VsyncSchedule.h"
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker namespace android::scheduler {
62*38e8c45fSAndroid Build Coastguard Worker 
Scheduler(ICompositor & compositor,ISchedulerCallback & callback,FeatureFlags features,surfaceflinger::Factory & factory,Fps activeRefreshRate,TimeStats & timeStats)63*38e8c45fSAndroid Build Coastguard Worker Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features,
64*38e8c45fSAndroid Build Coastguard Worker                      surfaceflinger::Factory& factory, Fps activeRefreshRate, TimeStats& timeStats)
65*38e8c45fSAndroid Build Coastguard Worker       : android::impl::MessageQueue(compositor),
66*38e8c45fSAndroid Build Coastguard Worker         mFeatures(features),
67*38e8c45fSAndroid Build Coastguard Worker         mVsyncConfiguration(factory.createVsyncConfiguration(activeRefreshRate)),
68*38e8c45fSAndroid Build Coastguard Worker         mVsyncModulator(sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs())),
69*38e8c45fSAndroid Build Coastguard Worker         mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate)),
70*38e8c45fSAndroid Build Coastguard Worker         mSchedulerCallback(callback) {}
71*38e8c45fSAndroid Build Coastguard Worker 
~Scheduler()72*38e8c45fSAndroid Build Coastguard Worker Scheduler::~Scheduler() {
73*38e8c45fSAndroid Build Coastguard Worker     // MessageQueue depends on VsyncSchedule, so first destroy it.
74*38e8c45fSAndroid Build Coastguard Worker     // Otherwise, MessageQueue will get destroyed after Scheduler's dtor,
75*38e8c45fSAndroid Build Coastguard Worker     // which will cause a use-after-free issue.
76*38e8c45fSAndroid Build Coastguard Worker     Impl::destroyVsync();
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker     // Stop timers and wait for their threads to exit.
79*38e8c45fSAndroid Build Coastguard Worker     mDisplayPowerTimer.reset();
80*38e8c45fSAndroid Build Coastguard Worker     mTouchTimer.reset();
81*38e8c45fSAndroid Build Coastguard Worker 
82*38e8c45fSAndroid Build Coastguard Worker     // Stop idle timer and clear callbacks, as the RefreshRateSelector may outlive the Scheduler.
83*38e8c45fSAndroid Build Coastguard Worker     demotePacesetterDisplay({.toggleIdleTimer = true});
84*38e8c45fSAndroid Build Coastguard Worker }
85*38e8c45fSAndroid Build Coastguard Worker 
initVsync(frametimeline::TokenManager & tokenManager,std::chrono::nanoseconds workDuration)86*38e8c45fSAndroid Build Coastguard Worker void Scheduler::initVsync(frametimeline::TokenManager& tokenManager,
87*38e8c45fSAndroid Build Coastguard Worker                           std::chrono::nanoseconds workDuration) {
88*38e8c45fSAndroid Build Coastguard Worker     Impl::initVsyncInternal(getVsyncSchedule()->getDispatch(), tokenManager, workDuration);
89*38e8c45fSAndroid Build Coastguard Worker }
90*38e8c45fSAndroid Build Coastguard Worker 
startTimers()91*38e8c45fSAndroid Build Coastguard Worker void Scheduler::startTimers() {
92*38e8c45fSAndroid Build Coastguard Worker     using namespace sysprop;
93*38e8c45fSAndroid Build Coastguard Worker     using namespace std::string_literals;
94*38e8c45fSAndroid Build Coastguard Worker 
95*38e8c45fSAndroid Build Coastguard Worker     const int32_t defaultTouchTimerValue =
96*38e8c45fSAndroid Build Coastguard Worker             FlagManager::getInstance().enable_fro_dependent_features() &&
97*38e8c45fSAndroid Build Coastguard Worker                     sysprop::enable_frame_rate_override(true)
98*38e8c45fSAndroid Build Coastguard Worker             ? 200
99*38e8c45fSAndroid Build Coastguard Worker             : 0;
100*38e8c45fSAndroid Build Coastguard Worker     if (const int32_t millis = set_touch_timer_ms(defaultTouchTimerValue); millis > 0) {
101*38e8c45fSAndroid Build Coastguard Worker         // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
102*38e8c45fSAndroid Build Coastguard Worker         mTouchTimer.emplace(
103*38e8c45fSAndroid Build Coastguard Worker                 "TouchTimer", std::chrono::milliseconds(millis),
104*38e8c45fSAndroid Build Coastguard Worker                 [this] { touchTimerCallback(TimerState::Reset); },
105*38e8c45fSAndroid Build Coastguard Worker                 [this] { touchTimerCallback(TimerState::Expired); });
106*38e8c45fSAndroid Build Coastguard Worker         mTouchTimer->start();
107*38e8c45fSAndroid Build Coastguard Worker     }
108*38e8c45fSAndroid Build Coastguard Worker 
109*38e8c45fSAndroid Build Coastguard Worker     if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
110*38e8c45fSAndroid Build Coastguard Worker         mDisplayPowerTimer.emplace(
111*38e8c45fSAndroid Build Coastguard Worker                 "DisplayPowerTimer", std::chrono::milliseconds(millis),
112*38e8c45fSAndroid Build Coastguard Worker                 [this] { displayPowerTimerCallback(TimerState::Reset); },
113*38e8c45fSAndroid Build Coastguard Worker                 [this] { displayPowerTimerCallback(TimerState::Expired); });
114*38e8c45fSAndroid Build Coastguard Worker         mDisplayPowerTimer->start();
115*38e8c45fSAndroid Build Coastguard Worker     }
116*38e8c45fSAndroid Build Coastguard Worker }
117*38e8c45fSAndroid Build Coastguard Worker 
setPacesetterDisplay(PhysicalDisplayId pacesetterId)118*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) {
119*38e8c45fSAndroid Build Coastguard Worker     constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = true};
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker     demotePacesetterDisplay(kPromotionParams);
122*38e8c45fSAndroid Build Coastguard Worker     promotePacesetterDisplay(pacesetterId, kPromotionParams);
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker     // Cancel the pending refresh rate change, if any, before updating the phase configuration.
125*38e8c45fSAndroid Build Coastguard Worker     mVsyncModulator->cancelRefreshRateChange();
126*38e8c45fSAndroid Build Coastguard Worker 
127*38e8c45fSAndroid Build Coastguard Worker     mVsyncConfiguration->reset();
128*38e8c45fSAndroid Build Coastguard Worker     updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps);
129*38e8c45fSAndroid Build Coastguard Worker }
130*38e8c45fSAndroid Build Coastguard Worker 
registerDisplay(PhysicalDisplayId displayId,RefreshRateSelectorPtr selectorPtr,PhysicalDisplayId activeDisplayId)131*38e8c45fSAndroid Build Coastguard Worker void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
132*38e8c45fSAndroid Build Coastguard Worker                                 PhysicalDisplayId activeDisplayId) {
133*38e8c45fSAndroid Build Coastguard Worker     auto schedulePtr =
134*38e8c45fSAndroid Build Coastguard Worker             std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
135*38e8c45fSAndroid Build Coastguard Worker                                             [this](PhysicalDisplayId id, bool enable) {
136*38e8c45fSAndroid Build Coastguard Worker                                                 onHardwareVsyncRequest(id, enable);
137*38e8c45fSAndroid Build Coastguard Worker                                             });
138*38e8c45fSAndroid Build Coastguard Worker 
139*38e8c45fSAndroid Build Coastguard Worker     registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr),
140*38e8c45fSAndroid Build Coastguard Worker                             activeDisplayId);
141*38e8c45fSAndroid Build Coastguard Worker }
142*38e8c45fSAndroid Build Coastguard Worker 
registerDisplayInternal(PhysicalDisplayId displayId,RefreshRateSelectorPtr selectorPtr,VsyncSchedulePtr schedulePtr,PhysicalDisplayId activeDisplayId)143*38e8c45fSAndroid Build Coastguard Worker void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
144*38e8c45fSAndroid Build Coastguard Worker                                         RefreshRateSelectorPtr selectorPtr,
145*38e8c45fSAndroid Build Coastguard Worker                                         VsyncSchedulePtr schedulePtr,
146*38e8c45fSAndroid Build Coastguard Worker                                         PhysicalDisplayId activeDisplayId) {
147*38e8c45fSAndroid Build Coastguard Worker     const bool isPrimary = (ftl::FakeGuard(mDisplayLock), !mPacesetterDisplayId);
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker     // Start the idle timer for the first registered (i.e. primary) display.
150*38e8c45fSAndroid Build Coastguard Worker     const PromotionParams promotionParams = {.toggleIdleTimer = isPrimary};
151*38e8c45fSAndroid Build Coastguard Worker 
152*38e8c45fSAndroid Build Coastguard Worker     demotePacesetterDisplay(promotionParams);
153*38e8c45fSAndroid Build Coastguard Worker 
154*38e8c45fSAndroid Build Coastguard Worker     auto [pacesetterVsyncSchedule, isNew] = [&]() REQUIRES(kMainThreadContext) {
155*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
156*38e8c45fSAndroid Build Coastguard Worker         const bool isNew = mDisplays
157*38e8c45fSAndroid Build Coastguard Worker                                    .emplace_or_replace(displayId, displayId, std::move(selectorPtr),
158*38e8c45fSAndroid Build Coastguard Worker                                                        std::move(schedulePtr), mFeatures)
159*38e8c45fSAndroid Build Coastguard Worker                                    .second;
160*38e8c45fSAndroid Build Coastguard Worker 
161*38e8c45fSAndroid Build Coastguard Worker         return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId, promotionParams),
162*38e8c45fSAndroid Build Coastguard Worker                               isNew);
163*38e8c45fSAndroid Build Coastguard Worker     }();
164*38e8c45fSAndroid Build Coastguard Worker 
165*38e8c45fSAndroid Build Coastguard Worker     applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
166*38e8c45fSAndroid Build Coastguard Worker 
167*38e8c45fSAndroid Build Coastguard Worker     // Disable hardware VSYNC if the registration is new, as opposed to a renewal.
168*38e8c45fSAndroid Build Coastguard Worker     if (isNew) {
169*38e8c45fSAndroid Build Coastguard Worker         onHardwareVsyncRequest(displayId, false);
170*38e8c45fSAndroid Build Coastguard Worker     }
171*38e8c45fSAndroid Build Coastguard Worker 
172*38e8c45fSAndroid Build Coastguard Worker     dispatchHotplug(displayId, Hotplug::Connected);
173*38e8c45fSAndroid Build Coastguard Worker }
174*38e8c45fSAndroid Build Coastguard Worker 
unregisterDisplay(PhysicalDisplayId displayId,PhysicalDisplayId activeDisplayId)175*38e8c45fSAndroid Build Coastguard Worker void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId activeDisplayId) {
176*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(displayId == activeDisplayId, "Cannot unregister the active display!");
177*38e8c45fSAndroid Build Coastguard Worker 
178*38e8c45fSAndroid Build Coastguard Worker     dispatchHotplug(displayId, Hotplug::Disconnected);
179*38e8c45fSAndroid Build Coastguard Worker 
180*38e8c45fSAndroid Build Coastguard Worker     constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = false};
181*38e8c45fSAndroid Build Coastguard Worker     demotePacesetterDisplay(kPromotionParams);
182*38e8c45fSAndroid Build Coastguard Worker 
183*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
184*38e8c45fSAndroid Build Coastguard Worker     {
185*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
186*38e8c45fSAndroid Build Coastguard Worker         mDisplays.erase(displayId);
187*38e8c45fSAndroid Build Coastguard Worker 
188*38e8c45fSAndroid Build Coastguard Worker         // Do not allow removing the final display. Code in the scheduler expects
189*38e8c45fSAndroid Build Coastguard Worker         // there to be at least one display. (This may be relaxed in the future with
190*38e8c45fSAndroid Build Coastguard Worker         // headless virtual display.)
191*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");
192*38e8c45fSAndroid Build Coastguard Worker 
193*38e8c45fSAndroid Build Coastguard Worker         pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId, kPromotionParams);
194*38e8c45fSAndroid Build Coastguard Worker     }
195*38e8c45fSAndroid Build Coastguard Worker     applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
196*38e8c45fSAndroid Build Coastguard Worker }
197*38e8c45fSAndroid Build Coastguard Worker 
run()198*38e8c45fSAndroid Build Coastguard Worker void Scheduler::run() {
199*38e8c45fSAndroid Build Coastguard Worker     while (true) {
200*38e8c45fSAndroid Build Coastguard Worker         waitMessage();
201*38e8c45fSAndroid Build Coastguard Worker     }
202*38e8c45fSAndroid Build Coastguard Worker }
203*38e8c45fSAndroid Build Coastguard Worker 
onFrameSignal(ICompositor & compositor,VsyncId vsyncId,TimePoint expectedVsyncTime)204*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
205*38e8c45fSAndroid Build Coastguard Worker                               TimePoint expectedVsyncTime) {
206*38e8c45fSAndroid Build Coastguard Worker     const auto debugPresentDelay = mDebugPresentDelay.load();
207*38e8c45fSAndroid Build Coastguard Worker     mDebugPresentDelay.store(std::nullopt);
208*38e8c45fSAndroid Build Coastguard Worker 
209*38e8c45fSAndroid Build Coastguard Worker     const FrameTargeter::BeginFrameArgs beginFrameArgs =
210*38e8c45fSAndroid Build Coastguard Worker             {.frameBeginTime = SchedulerClock::now(),
211*38e8c45fSAndroid Build Coastguard Worker              .vsyncId = vsyncId,
212*38e8c45fSAndroid Build Coastguard Worker              .expectedVsyncTime = expectedVsyncTime,
213*38e8c45fSAndroid Build Coastguard Worker              .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration,
214*38e8c45fSAndroid Build Coastguard Worker              .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration,
215*38e8c45fSAndroid Build Coastguard Worker              .debugPresentTimeDelay = debugPresentDelay};
216*38e8c45fSAndroid Build Coastguard Worker 
217*38e8c45fSAndroid Build Coastguard Worker     ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked();
218*38e8c45fSAndroid Build Coastguard Worker     pacesetterPtr->targeterPtr->beginFrame(beginFrameArgs, *pacesetterPtr->schedulePtr);
219*38e8c45fSAndroid Build Coastguard Worker 
220*38e8c45fSAndroid Build Coastguard Worker     {
221*38e8c45fSAndroid Build Coastguard Worker         FrameTargets targets;
222*38e8c45fSAndroid Build Coastguard Worker         targets.try_emplace(pacesetterPtr->displayId, &pacesetterPtr->targeterPtr->target());
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker         // TODO (b/256196556): Followers should use the next VSYNC after the frontrunner, not the
225*38e8c45fSAndroid Build Coastguard Worker         // pacesetter.
226*38e8c45fSAndroid Build Coastguard Worker         // Update expectedVsyncTime, which may have been adjusted by beginFrame.
227*38e8c45fSAndroid Build Coastguard Worker         expectedVsyncTime = pacesetterPtr->targeterPtr->target().expectedPresentTime();
228*38e8c45fSAndroid Build Coastguard Worker 
229*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [id, display] : mDisplays) {
230*38e8c45fSAndroid Build Coastguard Worker             if (id == pacesetterPtr->displayId) continue;
231*38e8c45fSAndroid Build Coastguard Worker 
232*38e8c45fSAndroid Build Coastguard Worker             auto followerBeginFrameArgs = beginFrameArgs;
233*38e8c45fSAndroid Build Coastguard Worker             followerBeginFrameArgs.expectedVsyncTime =
234*38e8c45fSAndroid Build Coastguard Worker                     display.schedulePtr->vsyncDeadlineAfter(expectedVsyncTime);
235*38e8c45fSAndroid Build Coastguard Worker 
236*38e8c45fSAndroid Build Coastguard Worker             FrameTargeter& targeter = *display.targeterPtr;
237*38e8c45fSAndroid Build Coastguard Worker             targeter.beginFrame(followerBeginFrameArgs, *display.schedulePtr);
238*38e8c45fSAndroid Build Coastguard Worker             targets.try_emplace(id, &targeter.target());
239*38e8c45fSAndroid Build Coastguard Worker         }
240*38e8c45fSAndroid Build Coastguard Worker 
241*38e8c45fSAndroid Build Coastguard Worker         if (!compositor.commit(pacesetterPtr->displayId, targets)) {
242*38e8c45fSAndroid Build Coastguard Worker             if (FlagManager::getInstance().vrr_config()) {
243*38e8c45fSAndroid Build Coastguard Worker                 compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
244*38e8c45fSAndroid Build Coastguard Worker             }
245*38e8c45fSAndroid Build Coastguard Worker             mSchedulerCallback.onCommitNotComposited();
246*38e8c45fSAndroid Build Coastguard Worker             return;
247*38e8c45fSAndroid Build Coastguard Worker         }
248*38e8c45fSAndroid Build Coastguard Worker     }
249*38e8c45fSAndroid Build Coastguard Worker 
250*38e8c45fSAndroid Build Coastguard Worker     // The pacesetter may have changed or been registered anew during commit.
251*38e8c45fSAndroid Build Coastguard Worker     pacesetterPtr = pacesetterPtrLocked();
252*38e8c45fSAndroid Build Coastguard Worker 
253*38e8c45fSAndroid Build Coastguard Worker     // TODO(b/256196556): Choose the frontrunner display.
254*38e8c45fSAndroid Build Coastguard Worker     FrameTargeters targeters;
255*38e8c45fSAndroid Build Coastguard Worker     targeters.try_emplace(pacesetterPtr->displayId, pacesetterPtr->targeterPtr.get());
256*38e8c45fSAndroid Build Coastguard Worker 
257*38e8c45fSAndroid Build Coastguard Worker     for (auto& [id, display] : mDisplays) {
258*38e8c45fSAndroid Build Coastguard Worker         if (id == pacesetterPtr->displayId) continue;
259*38e8c45fSAndroid Build Coastguard Worker 
260*38e8c45fSAndroid Build Coastguard Worker         FrameTargeter& targeter = *display.targeterPtr;
261*38e8c45fSAndroid Build Coastguard Worker         targeters.try_emplace(id, &targeter);
262*38e8c45fSAndroid Build Coastguard Worker     }
263*38e8c45fSAndroid Build Coastguard Worker 
264*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().vrr_config() &&
265*38e8c45fSAndroid Build Coastguard Worker         CC_UNLIKELY(mPacesetterFrameDurationFractionToSkip > 0.f)) {
266*38e8c45fSAndroid Build Coastguard Worker         const auto period = pacesetterPtr->targeterPtr->target().expectedFrameDuration();
267*38e8c45fSAndroid Build Coastguard Worker         const auto skipDuration = Duration::fromNs(
268*38e8c45fSAndroid Build Coastguard Worker                 static_cast<nsecs_t>(period.ns() * mPacesetterFrameDurationFractionToSkip));
269*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT("Injecting jank for %f%% of the frame (%" PRId64 " ns)",
270*38e8c45fSAndroid Build Coastguard Worker                        mPacesetterFrameDurationFractionToSkip * 100, skipDuration.ns());
271*38e8c45fSAndroid Build Coastguard Worker         std::this_thread::sleep_for(skipDuration);
272*38e8c45fSAndroid Build Coastguard Worker         mPacesetterFrameDurationFractionToSkip = 0.f;
273*38e8c45fSAndroid Build Coastguard Worker     }
274*38e8c45fSAndroid Build Coastguard Worker 
275*38e8c45fSAndroid Build Coastguard Worker     const auto resultsPerDisplay = compositor.composite(pacesetterPtr->displayId, targeters);
276*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().vrr_config()) {
277*38e8c45fSAndroid Build Coastguard Worker         compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
278*38e8c45fSAndroid Build Coastguard Worker     }
279*38e8c45fSAndroid Build Coastguard Worker     compositor.sample();
280*38e8c45fSAndroid Build Coastguard Worker 
281*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, targeter] : targeters) {
282*38e8c45fSAndroid Build Coastguard Worker         const auto resultOpt = resultsPerDisplay.get(id);
283*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!resultOpt);
284*38e8c45fSAndroid Build Coastguard Worker         targeter->endFrame(*resultOpt);
285*38e8c45fSAndroid Build Coastguard Worker     }
286*38e8c45fSAndroid Build Coastguard Worker }
287*38e8c45fSAndroid Build Coastguard Worker 
getFrameRateOverride(uid_t uid) const288*38e8c45fSAndroid Build Coastguard Worker std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
289*38e8c45fSAndroid Build Coastguard Worker     const bool supportsFrameRateOverrideByContent =
290*38e8c45fSAndroid Build Coastguard Worker             pacesetterSelectorPtr()->supportsAppFrameRateOverrideByContent();
291*38e8c45fSAndroid Build Coastguard Worker     return mFrameRateOverrideMappings
292*38e8c45fSAndroid Build Coastguard Worker             .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
293*38e8c45fSAndroid Build Coastguard Worker }
294*38e8c45fSAndroid Build Coastguard Worker 
isVsyncValid(TimePoint expectedVsyncTime,uid_t uid) const295*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::isVsyncValid(TimePoint expectedVsyncTime, uid_t uid) const {
296*38e8c45fSAndroid Build Coastguard Worker     const auto frameRate = getFrameRateOverride(uid);
297*38e8c45fSAndroid Build Coastguard Worker     if (!frameRate.has_value()) {
298*38e8c45fSAndroid Build Coastguard Worker         return true;
299*38e8c45fSAndroid Build Coastguard Worker     }
300*38e8c45fSAndroid Build Coastguard Worker 
301*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_FORMAT("%s uid: %d frameRate: %s", __func__, uid, to_string(*frameRate).c_str());
302*38e8c45fSAndroid Build Coastguard Worker     return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), *frameRate);
303*38e8c45fSAndroid Build Coastguard Worker }
304*38e8c45fSAndroid Build Coastguard Worker 
isVsyncInPhase(TimePoint expectedVsyncTime,Fps frameRate) const305*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const {
306*38e8c45fSAndroid Build Coastguard Worker     return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), frameRate);
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker 
throttleVsync(android::TimePoint expectedPresentTime,uid_t uid)309*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::throttleVsync(android::TimePoint expectedPresentTime, uid_t uid) {
310*38e8c45fSAndroid Build Coastguard Worker     return !isVsyncValid(expectedPresentTime, uid);
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker 
getVsyncPeriod(uid_t uid)313*38e8c45fSAndroid Build Coastguard Worker Period Scheduler::getVsyncPeriod(uid_t uid) {
314*38e8c45fSAndroid Build Coastguard Worker     const auto [refreshRate, period] = [this] {
315*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
316*38e8c45fSAndroid Build Coastguard Worker         const auto pacesetterOpt = pacesetterDisplayLocked();
317*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!pacesetterOpt);
318*38e8c45fSAndroid Build Coastguard Worker         const Display& pacesetter = *pacesetterOpt;
319*38e8c45fSAndroid Build Coastguard Worker         const FrameRateMode& frameRateMode = pacesetter.selectorPtr->getActiveMode();
320*38e8c45fSAndroid Build Coastguard Worker         const auto refreshRate = frameRateMode.fps;
321*38e8c45fSAndroid Build Coastguard Worker         const auto displayVsync = frameRateMode.modePtr->getVsyncRate();
322*38e8c45fSAndroid Build Coastguard Worker         const auto numPeriod = RefreshRateSelector::getFrameRateDivisor(displayVsync, refreshRate);
323*38e8c45fSAndroid Build Coastguard Worker         return std::make_pair(refreshRate, numPeriod * pacesetter.schedulePtr->period());
324*38e8c45fSAndroid Build Coastguard Worker     }();
325*38e8c45fSAndroid Build Coastguard Worker 
326*38e8c45fSAndroid Build Coastguard Worker     const Period currentPeriod = period != Period::zero() ? period : refreshRate.getPeriod();
327*38e8c45fSAndroid Build Coastguard Worker 
328*38e8c45fSAndroid Build Coastguard Worker     const auto frameRate = getFrameRateOverride(uid);
329*38e8c45fSAndroid Build Coastguard Worker     if (!frameRate.has_value()) {
330*38e8c45fSAndroid Build Coastguard Worker         return currentPeriod;
331*38e8c45fSAndroid Build Coastguard Worker     }
332*38e8c45fSAndroid Build Coastguard Worker 
333*38e8c45fSAndroid Build Coastguard Worker     const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate);
334*38e8c45fSAndroid Build Coastguard Worker     if (divisor <= 1) {
335*38e8c45fSAndroid Build Coastguard Worker         return currentPeriod;
336*38e8c45fSAndroid Build Coastguard Worker     }
337*38e8c45fSAndroid Build Coastguard Worker 
338*38e8c45fSAndroid Build Coastguard Worker     // TODO(b/299378819): the casting is not needed, but we need a flag as it might change
339*38e8c45fSAndroid Build Coastguard Worker     // behaviour.
340*38e8c45fSAndroid Build Coastguard Worker     return Period::fromNs(currentPeriod.ns() * divisor);
341*38e8c45fSAndroid Build Coastguard Worker }
onExpectedPresentTimePosted(TimePoint expectedPresentTime)342*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onExpectedPresentTimePosted(TimePoint expectedPresentTime) {
343*38e8c45fSAndroid Build Coastguard Worker     const auto frameRateMode = [this] {
344*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
345*38e8c45fSAndroid Build Coastguard Worker         const auto pacesetterOpt = pacesetterDisplayLocked();
346*38e8c45fSAndroid Build Coastguard Worker         const Display& pacesetter = *pacesetterOpt;
347*38e8c45fSAndroid Build Coastguard Worker         return pacesetter.selectorPtr->getActiveMode();
348*38e8c45fSAndroid Build Coastguard Worker     }();
349*38e8c45fSAndroid Build Coastguard Worker 
350*38e8c45fSAndroid Build Coastguard Worker     if (frameRateMode.modePtr->getVrrConfig()) {
351*38e8c45fSAndroid Build Coastguard Worker         mSchedulerCallback.onExpectedPresentTimePosted(expectedPresentTime, frameRateMode.modePtr,
352*38e8c45fSAndroid Build Coastguard Worker                                                        frameRateMode.fps);
353*38e8c45fSAndroid Build Coastguard Worker     }
354*38e8c45fSAndroid Build Coastguard Worker }
355*38e8c45fSAndroid Build Coastguard Worker 
createEventThread(Cycle cycle,frametimeline::TokenManager * tokenManager,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)356*38e8c45fSAndroid Build Coastguard Worker void Scheduler::createEventThread(Cycle cycle, frametimeline::TokenManager* tokenManager,
357*38e8c45fSAndroid Build Coastguard Worker                                   std::chrono::nanoseconds workDuration,
358*38e8c45fSAndroid Build Coastguard Worker                                   std::chrono::nanoseconds readyDuration) {
359*38e8c45fSAndroid Build Coastguard Worker     auto eventThread =
360*38e8c45fSAndroid Build Coastguard Worker             std::make_unique<android::impl::EventThread>(cycle == Cycle::Render ? "app" : "appSf",
361*38e8c45fSAndroid Build Coastguard Worker                                                          getVsyncSchedule(), tokenManager, *this,
362*38e8c45fSAndroid Build Coastguard Worker                                                          workDuration, readyDuration);
363*38e8c45fSAndroid Build Coastguard Worker 
364*38e8c45fSAndroid Build Coastguard Worker     if (cycle == Cycle::Render) {
365*38e8c45fSAndroid Build Coastguard Worker         mRenderEventThread = std::move(eventThread);
366*38e8c45fSAndroid Build Coastguard Worker     } else {
367*38e8c45fSAndroid Build Coastguard Worker         mLastCompositeEventThread = std::move(eventThread);
368*38e8c45fSAndroid Build Coastguard Worker     }
369*38e8c45fSAndroid Build Coastguard Worker }
370*38e8c45fSAndroid Build Coastguard Worker 
createDisplayEventConnection(Cycle cycle,EventRegistrationFlags eventRegistration,const sp<IBinder> & layerHandle)371*38e8c45fSAndroid Build Coastguard Worker sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
372*38e8c45fSAndroid Build Coastguard Worker         Cycle cycle, EventRegistrationFlags eventRegistration, const sp<IBinder>& layerHandle) {
373*38e8c45fSAndroid Build Coastguard Worker     const auto connection = eventThreadFor(cycle).createEventConnection(eventRegistration);
374*38e8c45fSAndroid Build Coastguard Worker     const auto layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
375*38e8c45fSAndroid Build Coastguard Worker 
376*38e8c45fSAndroid Build Coastguard Worker     if (layerId != static_cast<int32_t>(UNASSIGNED_LAYER_ID)) {
377*38e8c45fSAndroid Build Coastguard Worker         // TODO(b/290409668): Moving the choreographer attachment to be a transaction that will be
378*38e8c45fSAndroid Build Coastguard Worker         // processed on the main thread.
379*38e8c45fSAndroid Build Coastguard Worker         mSchedulerCallback.onChoreographerAttached();
380*38e8c45fSAndroid Build Coastguard Worker 
381*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mChoreographerLock);
382*38e8c45fSAndroid Build Coastguard Worker         const auto [iter, emplaced] =
383*38e8c45fSAndroid Build Coastguard Worker                 mAttachedChoreographers.emplace(layerId,
384*38e8c45fSAndroid Build Coastguard Worker                                                 AttachedChoreographers{Fps(), {connection}});
385*38e8c45fSAndroid Build Coastguard Worker         if (!emplaced) {
386*38e8c45fSAndroid Build Coastguard Worker             iter->second.connections.emplace(connection);
387*38e8c45fSAndroid Build Coastguard Worker             connection->frameRate = iter->second.frameRate;
388*38e8c45fSAndroid Build Coastguard Worker         }
389*38e8c45fSAndroid Build Coastguard Worker     }
390*38e8c45fSAndroid Build Coastguard Worker     return connection;
391*38e8c45fSAndroid Build Coastguard Worker }
392*38e8c45fSAndroid Build Coastguard Worker 
dispatchHotplug(PhysicalDisplayId displayId,Hotplug hotplug)393*38e8c45fSAndroid Build Coastguard Worker void Scheduler::dispatchHotplug(PhysicalDisplayId displayId, Hotplug hotplug) {
394*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
395*38e8c45fSAndroid Build Coastguard Worker         const bool connected = hotplug == Hotplug::Connected;
396*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onHotplugReceived(displayId, connected);
397*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::LastComposite).onHotplugReceived(displayId, connected);
398*38e8c45fSAndroid Build Coastguard Worker     }
399*38e8c45fSAndroid Build Coastguard Worker }
400*38e8c45fSAndroid Build Coastguard Worker 
dispatchHotplugError(int32_t errorCode)401*38e8c45fSAndroid Build Coastguard Worker void Scheduler::dispatchHotplugError(int32_t errorCode) {
402*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
403*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onHotplugConnectionError(errorCode);
404*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::LastComposite).onHotplugConnectionError(errorCode);
405*38e8c45fSAndroid Build Coastguard Worker     }
406*38e8c45fSAndroid Build Coastguard Worker }
407*38e8c45fSAndroid Build Coastguard Worker 
enableSyntheticVsync(bool enable)408*38e8c45fSAndroid Build Coastguard Worker void Scheduler::enableSyntheticVsync(bool enable) {
409*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(Cycle::Render).enableSyntheticVsync(enable);
410*38e8c45fSAndroid Build Coastguard Worker }
411*38e8c45fSAndroid Build Coastguard Worker 
omitVsyncDispatching(bool omitted)412*38e8c45fSAndroid Build Coastguard Worker void Scheduler::omitVsyncDispatching(bool omitted) {
413*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(Cycle::Render).omitVsyncDispatching(omitted);
414*38e8c45fSAndroid Build Coastguard Worker     // Note: If we don't couple Cycle::LastComposite event thread, there is a black screen
415*38e8c45fSAndroid Build Coastguard Worker     // after boot. This is most likely sysui or system_server dependency on sf instance
416*38e8c45fSAndroid Build Coastguard Worker     // Choreographer
417*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(Cycle::LastComposite).omitVsyncDispatching(omitted);
418*38e8c45fSAndroid Build Coastguard Worker }
419*38e8c45fSAndroid Build Coastguard Worker 
onFrameRateOverridesChanged()420*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onFrameRateOverridesChanged() {
421*38e8c45fSAndroid Build Coastguard Worker     const auto [pacesetterId, supportsFrameRateOverrideByContent] = [this] {
422*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
423*38e8c45fSAndroid Build Coastguard Worker         const auto pacesetterOpt = pacesetterDisplayLocked();
424*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!pacesetterOpt);
425*38e8c45fSAndroid Build Coastguard Worker         const Display& pacesetter = *pacesetterOpt;
426*38e8c45fSAndroid Build Coastguard Worker         return std::make_pair(FTL_FAKE_GUARD(kMainThreadContext, *mPacesetterDisplayId),
427*38e8c45fSAndroid Build Coastguard Worker                               pacesetter.selectorPtr->supportsAppFrameRateOverrideByContent());
428*38e8c45fSAndroid Build Coastguard Worker     }();
429*38e8c45fSAndroid Build Coastguard Worker 
430*38e8c45fSAndroid Build Coastguard Worker     std::vector<FrameRateOverride> overrides =
431*38e8c45fSAndroid Build Coastguard Worker             mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
432*38e8c45fSAndroid Build Coastguard Worker 
433*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(Cycle::Render).onFrameRateOverridesChanged(pacesetterId, std::move(overrides));
434*38e8c45fSAndroid Build Coastguard Worker }
435*38e8c45fSAndroid Build Coastguard Worker 
onHdcpLevelsChanged(Cycle cycle,PhysicalDisplayId displayId,int32_t connectedLevel,int32_t maxLevel)436*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onHdcpLevelsChanged(Cycle cycle, PhysicalDisplayId displayId,
437*38e8c45fSAndroid Build Coastguard Worker                                     int32_t connectedLevel, int32_t maxLevel) {
438*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(cycle).onHdcpLevelsChanged(displayId, connectedLevel, maxLevel);
439*38e8c45fSAndroid Build Coastguard Worker }
440*38e8c45fSAndroid Build Coastguard Worker 
441*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
442*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-value" // b/369277774
onDisplayModeChanged(PhysicalDisplayId displayId,const FrameRateMode & mode,bool clearContentRequirements)443*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRateMode& mode,
444*38e8c45fSAndroid Build Coastguard Worker                                      bool clearContentRequirements) {
445*38e8c45fSAndroid Build Coastguard Worker     const bool isPacesetter =
446*38e8c45fSAndroid Build Coastguard Worker             FTL_FAKE_GUARD(kMainThreadContext,
447*38e8c45fSAndroid Build Coastguard Worker                            (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId));
448*38e8c45fSAndroid Build Coastguard Worker 
449*38e8c45fSAndroid Build Coastguard Worker     if (isPacesetter) {
450*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lock(mPolicyLock);
451*38e8c45fSAndroid Build Coastguard Worker         mPolicy.emittedModeOpt = mode;
452*38e8c45fSAndroid Build Coastguard Worker 
453*38e8c45fSAndroid Build Coastguard Worker         if (clearContentRequirements) {
454*38e8c45fSAndroid Build Coastguard Worker             // Invalidate content based refresh rate selection so it could be calculated
455*38e8c45fSAndroid Build Coastguard Worker             // again for the new refresh rate.
456*38e8c45fSAndroid Build Coastguard Worker             mPolicy.contentRequirements.clear();
457*38e8c45fSAndroid Build Coastguard Worker         }
458*38e8c45fSAndroid Build Coastguard Worker     }
459*38e8c45fSAndroid Build Coastguard Worker 
460*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
461*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onModeChanged(mode);
462*38e8c45fSAndroid Build Coastguard Worker     }
463*38e8c45fSAndroid Build Coastguard Worker 
464*38e8c45fSAndroid Build Coastguard Worker     return isPacesetter;
465*38e8c45fSAndroid Build Coastguard Worker }
466*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
467*38e8c45fSAndroid Build Coastguard Worker 
onDisplayModeRejected(PhysicalDisplayId displayId,DisplayModeId modeId)468*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onDisplayModeRejected(PhysicalDisplayId displayId, DisplayModeId modeId) {
469*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
470*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onModeRejected(displayId, modeId);
471*38e8c45fSAndroid Build Coastguard Worker     }
472*38e8c45fSAndroid Build Coastguard Worker }
473*38e8c45fSAndroid Build Coastguard Worker 
emitModeChangeIfNeeded()474*38e8c45fSAndroid Build Coastguard Worker void Scheduler::emitModeChangeIfNeeded() {
475*38e8c45fSAndroid Build Coastguard Worker     if (!mPolicy.modeOpt || !mPolicy.emittedModeOpt) {
476*38e8c45fSAndroid Build Coastguard Worker         ALOGW("No mode change to emit");
477*38e8c45fSAndroid Build Coastguard Worker         return;
478*38e8c45fSAndroid Build Coastguard Worker     }
479*38e8c45fSAndroid Build Coastguard Worker 
480*38e8c45fSAndroid Build Coastguard Worker     const auto& mode = *mPolicy.modeOpt;
481*38e8c45fSAndroid Build Coastguard Worker 
482*38e8c45fSAndroid Build Coastguard Worker     if (mode != pacesetterSelectorPtr()->getActiveMode()) {
483*38e8c45fSAndroid Build Coastguard Worker         // A mode change is pending. The event will be emitted when the mode becomes active.
484*38e8c45fSAndroid Build Coastguard Worker         return;
485*38e8c45fSAndroid Build Coastguard Worker     }
486*38e8c45fSAndroid Build Coastguard Worker 
487*38e8c45fSAndroid Build Coastguard Worker     if (mode == *mPolicy.emittedModeOpt) {
488*38e8c45fSAndroid Build Coastguard Worker         // The event was already emitted.
489*38e8c45fSAndroid Build Coastguard Worker         return;
490*38e8c45fSAndroid Build Coastguard Worker     }
491*38e8c45fSAndroid Build Coastguard Worker 
492*38e8c45fSAndroid Build Coastguard Worker     mPolicy.emittedModeOpt = mode;
493*38e8c45fSAndroid Build Coastguard Worker 
494*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
495*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onModeChanged(mode);
496*38e8c45fSAndroid Build Coastguard Worker     }
497*38e8c45fSAndroid Build Coastguard Worker }
498*38e8c45fSAndroid Build Coastguard Worker 
dump(Cycle cycle,std::string & result) const499*38e8c45fSAndroid Build Coastguard Worker void Scheduler::dump(Cycle cycle, std::string& result) const {
500*38e8c45fSAndroid Build Coastguard Worker     eventThreadFor(cycle).dump(result);
501*38e8c45fSAndroid Build Coastguard Worker }
502*38e8c45fSAndroid Build Coastguard Worker 
setDuration(Cycle cycle,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)503*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setDuration(Cycle cycle, std::chrono::nanoseconds workDuration,
504*38e8c45fSAndroid Build Coastguard Worker                             std::chrono::nanoseconds readyDuration) {
505*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
506*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(cycle).setDuration(workDuration, readyDuration);
507*38e8c45fSAndroid Build Coastguard Worker     }
508*38e8c45fSAndroid Build Coastguard Worker }
509*38e8c45fSAndroid Build Coastguard Worker 
510*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
511*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-value" // b/369277774
updatePhaseConfiguration(PhysicalDisplayId displayId,Fps refreshRate)512*38e8c45fSAndroid Build Coastguard Worker void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refreshRate) {
513*38e8c45fSAndroid Build Coastguard Worker     const bool isPacesetter =
514*38e8c45fSAndroid Build Coastguard Worker             FTL_FAKE_GUARD(kMainThreadContext,
515*38e8c45fSAndroid Build Coastguard Worker                            (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId));
516*38e8c45fSAndroid Build Coastguard Worker     if (!isPacesetter) return;
517*38e8c45fSAndroid Build Coastguard Worker 
518*38e8c45fSAndroid Build Coastguard Worker     mRefreshRateStats->setRefreshRate(refreshRate);
519*38e8c45fSAndroid Build Coastguard Worker     mVsyncConfiguration->setRefreshRateFps(refreshRate);
520*38e8c45fSAndroid Build Coastguard Worker     setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()),
521*38e8c45fSAndroid Build Coastguard Worker                    refreshRate.getPeriod());
522*38e8c45fSAndroid Build Coastguard Worker }
523*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
524*38e8c45fSAndroid Build Coastguard Worker 
setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode)525*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode) {
526*38e8c45fSAndroid Build Coastguard Worker     mRefreshRateStats->setPowerMode(powerMode);
527*38e8c45fSAndroid Build Coastguard Worker }
528*38e8c45fSAndroid Build Coastguard Worker 
setVsyncConfig(const VsyncConfig & config,Period vsyncPeriod)529*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) {
530*38e8c45fSAndroid Build Coastguard Worker     setDuration(Cycle::Render,
531*38e8c45fSAndroid Build Coastguard Worker                 /* workDuration */ config.appWorkDuration,
532*38e8c45fSAndroid Build Coastguard Worker                 /* readyDuration */ config.sfWorkDuration);
533*38e8c45fSAndroid Build Coastguard Worker     setDuration(Cycle::LastComposite,
534*38e8c45fSAndroid Build Coastguard Worker                 /* workDuration */ vsyncPeriod,
535*38e8c45fSAndroid Build Coastguard Worker                 /* readyDuration */ config.sfWorkDuration);
536*38e8c45fSAndroid Build Coastguard Worker     setDuration(config.sfWorkDuration);
537*38e8c45fSAndroid Build Coastguard Worker }
538*38e8c45fSAndroid Build Coastguard Worker 
enableHardwareVsync(PhysicalDisplayId id)539*38e8c45fSAndroid Build Coastguard Worker void Scheduler::enableHardwareVsync(PhysicalDisplayId id) {
540*38e8c45fSAndroid Build Coastguard Worker     auto schedule = getVsyncSchedule(id);
541*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!schedule);
542*38e8c45fSAndroid Build Coastguard Worker     schedule->enableHardwareVsync();
543*38e8c45fSAndroid Build Coastguard Worker }
544*38e8c45fSAndroid Build Coastguard Worker 
disableHardwareVsync(PhysicalDisplayId id,bool disallow)545*38e8c45fSAndroid Build Coastguard Worker void Scheduler::disableHardwareVsync(PhysicalDisplayId id, bool disallow) {
546*38e8c45fSAndroid Build Coastguard Worker     auto schedule = getVsyncSchedule(id);
547*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!schedule);
548*38e8c45fSAndroid Build Coastguard Worker     schedule->disableHardwareVsync(disallow);
549*38e8c45fSAndroid Build Coastguard Worker }
550*38e8c45fSAndroid Build Coastguard Worker 
resyncAllToHardwareVsync(bool allowToEnable)551*38e8c45fSAndroid Build Coastguard Worker void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
552*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
553*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
554*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
555*38e8c45fSAndroid Build Coastguard Worker 
556*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, display] : mDisplays) {
557*38e8c45fSAndroid Build Coastguard Worker         if (display.powerMode != hal::PowerMode::OFF ||
558*38e8c45fSAndroid Build Coastguard Worker             !FlagManager::getInstance().multithreaded_present()) {
559*38e8c45fSAndroid Build Coastguard Worker             resyncToHardwareVsyncLocked(id, allowToEnable);
560*38e8c45fSAndroid Build Coastguard Worker         }
561*38e8c45fSAndroid Build Coastguard Worker     }
562*38e8c45fSAndroid Build Coastguard Worker }
563*38e8c45fSAndroid Build Coastguard Worker 
resyncToHardwareVsyncLocked(PhysicalDisplayId id,bool allowToEnable,DisplayModePtr modePtr)564*38e8c45fSAndroid Build Coastguard Worker void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable,
565*38e8c45fSAndroid Build Coastguard Worker                                             DisplayModePtr modePtr) {
566*38e8c45fSAndroid Build Coastguard Worker     const auto displayOpt = mDisplays.get(id);
567*38e8c45fSAndroid Build Coastguard Worker     if (!displayOpt) {
568*38e8c45fSAndroid Build Coastguard Worker         ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
569*38e8c45fSAndroid Build Coastguard Worker         return;
570*38e8c45fSAndroid Build Coastguard Worker     }
571*38e8c45fSAndroid Build Coastguard Worker     const Display& display = *displayOpt;
572*38e8c45fSAndroid Build Coastguard Worker 
573*38e8c45fSAndroid Build Coastguard Worker     if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
574*38e8c45fSAndroid Build Coastguard Worker         if (!modePtr) {
575*38e8c45fSAndroid Build Coastguard Worker             modePtr = display.selectorPtr->getActiveMode().modePtr.get();
576*38e8c45fSAndroid Build Coastguard Worker         }
577*38e8c45fSAndroid Build Coastguard Worker         if (modePtr->getVsyncRate().isValid()) {
578*38e8c45fSAndroid Build Coastguard Worker             constexpr bool kForce = false;
579*38e8c45fSAndroid Build Coastguard Worker             display.schedulePtr->onDisplayModeChanged(ftl::as_non_null(modePtr), kForce);
580*38e8c45fSAndroid Build Coastguard Worker         }
581*38e8c45fSAndroid Build Coastguard Worker     }
582*38e8c45fSAndroid Build Coastguard Worker }
583*38e8c45fSAndroid Build Coastguard Worker 
onHardwareVsyncRequest(PhysicalDisplayId id,bool enabled)584*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onHardwareVsyncRequest(PhysicalDisplayId id, bool enabled) {
585*38e8c45fSAndroid Build Coastguard Worker     static const auto& whence = __func__;
586*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_NAME(ftl::Concat(whence, ' ', id.value, ' ', enabled).c_str());
587*38e8c45fSAndroid Build Coastguard Worker 
588*38e8c45fSAndroid Build Coastguard Worker     // On main thread to serialize reads/writes of pending hardware VSYNC state.
589*38e8c45fSAndroid Build Coastguard Worker     static_cast<void>(
590*38e8c45fSAndroid Build Coastguard Worker             schedule([=, this]() FTL_FAKE_GUARD(mDisplayLock) FTL_FAKE_GUARD(kMainThreadContext) {
591*38e8c45fSAndroid Build Coastguard Worker                 SFTRACE_NAME(ftl::Concat(whence, ' ', id.value, ' ', enabled).c_str());
592*38e8c45fSAndroid Build Coastguard Worker 
593*38e8c45fSAndroid Build Coastguard Worker                 if (const auto displayOpt = mDisplays.get(id)) {
594*38e8c45fSAndroid Build Coastguard Worker                     auto& display = displayOpt->get();
595*38e8c45fSAndroid Build Coastguard Worker                     display.schedulePtr->setPendingHardwareVsyncState(enabled);
596*38e8c45fSAndroid Build Coastguard Worker 
597*38e8c45fSAndroid Build Coastguard Worker                     if (display.powerMode != hal::PowerMode::OFF) {
598*38e8c45fSAndroid Build Coastguard Worker                         mSchedulerCallback.requestHardwareVsync(id, enabled);
599*38e8c45fSAndroid Build Coastguard Worker                     }
600*38e8c45fSAndroid Build Coastguard Worker                 }
601*38e8c45fSAndroid Build Coastguard Worker             }));
602*38e8c45fSAndroid Build Coastguard Worker }
603*38e8c45fSAndroid Build Coastguard Worker 
setRenderRate(PhysicalDisplayId id,Fps renderFrameRate,bool applyImmediately)604*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate, bool applyImmediately) {
605*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
606*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
607*38e8c45fSAndroid Build Coastguard Worker 
608*38e8c45fSAndroid Build Coastguard Worker     const auto displayOpt = mDisplays.get(id);
609*38e8c45fSAndroid Build Coastguard Worker     if (!displayOpt) {
610*38e8c45fSAndroid Build Coastguard Worker         ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
611*38e8c45fSAndroid Build Coastguard Worker         return;
612*38e8c45fSAndroid Build Coastguard Worker     }
613*38e8c45fSAndroid Build Coastguard Worker     const Display& display = *displayOpt;
614*38e8c45fSAndroid Build Coastguard Worker     const auto mode = display.selectorPtr->getActiveMode();
615*38e8c45fSAndroid Build Coastguard Worker 
616*38e8c45fSAndroid Build Coastguard Worker     using fps_approx_ops::operator!=;
617*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(renderFrameRate != mode.fps,
618*38e8c45fSAndroid Build Coastguard Worker                         "Mismatch in render frame rates. Selector: %s, Scheduler: %s, Display: "
619*38e8c45fSAndroid Build Coastguard Worker                         "%" PRIu64,
620*38e8c45fSAndroid Build Coastguard Worker                         to_string(mode.fps).c_str(), to_string(renderFrameRate).c_str(), id.value);
621*38e8c45fSAndroid Build Coastguard Worker 
622*38e8c45fSAndroid Build Coastguard Worker     ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
623*38e8c45fSAndroid Build Coastguard Worker           to_string(mode.modePtr->getVsyncRate()).c_str());
624*38e8c45fSAndroid Build Coastguard Worker 
625*38e8c45fSAndroid Build Coastguard Worker     display.schedulePtr->getTracker().setRenderRate(renderFrameRate, applyImmediately);
626*38e8c45fSAndroid Build Coastguard Worker }
627*38e8c45fSAndroid Build Coastguard Worker 
getNextFrameInterval(PhysicalDisplayId id,TimePoint currentExpectedPresentTime) const628*38e8c45fSAndroid Build Coastguard Worker Fps Scheduler::getNextFrameInterval(PhysicalDisplayId id,
629*38e8c45fSAndroid Build Coastguard Worker                                     TimePoint currentExpectedPresentTime) const {
630*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
631*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
632*38e8c45fSAndroid Build Coastguard Worker 
633*38e8c45fSAndroid Build Coastguard Worker     const auto displayOpt = mDisplays.get(id);
634*38e8c45fSAndroid Build Coastguard Worker     if (!displayOpt) {
635*38e8c45fSAndroid Build Coastguard Worker         ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
636*38e8c45fSAndroid Build Coastguard Worker         return Fps{};
637*38e8c45fSAndroid Build Coastguard Worker     }
638*38e8c45fSAndroid Build Coastguard Worker     const Display& display = *displayOpt;
639*38e8c45fSAndroid Build Coastguard Worker     const Duration threshold =
640*38e8c45fSAndroid Build Coastguard Worker             display.selectorPtr->getActiveMode().modePtr->getVsyncRate().getPeriod() / 2;
641*38e8c45fSAndroid Build Coastguard Worker     const TimePoint nextVsyncTime =
642*38e8c45fSAndroid Build Coastguard Worker             display.schedulePtr->vsyncDeadlineAfter(currentExpectedPresentTime + threshold,
643*38e8c45fSAndroid Build Coastguard Worker                                                     currentExpectedPresentTime);
644*38e8c45fSAndroid Build Coastguard Worker     const Duration frameInterval = nextVsyncTime - currentExpectedPresentTime;
645*38e8c45fSAndroid Build Coastguard Worker     return Fps::fromPeriodNsecs(frameInterval.ns());
646*38e8c45fSAndroid Build Coastguard Worker }
647*38e8c45fSAndroid Build Coastguard Worker 
resync()648*38e8c45fSAndroid Build Coastguard Worker void Scheduler::resync() {
649*38e8c45fSAndroid Build Coastguard Worker     static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
650*38e8c45fSAndroid Build Coastguard Worker 
651*38e8c45fSAndroid Build Coastguard Worker     const nsecs_t now = systemTime();
652*38e8c45fSAndroid Build Coastguard Worker     const nsecs_t last = mLastResyncTime.exchange(now);
653*38e8c45fSAndroid Build Coastguard Worker 
654*38e8c45fSAndroid Build Coastguard Worker     if (now - last > kIgnoreDelay) {
655*38e8c45fSAndroid Build Coastguard Worker         resyncAllToHardwareVsync(false /* allowToEnable */);
656*38e8c45fSAndroid Build Coastguard Worker     }
657*38e8c45fSAndroid Build Coastguard Worker }
658*38e8c45fSAndroid Build Coastguard Worker 
addResyncSample(PhysicalDisplayId id,nsecs_t timestamp,std::optional<nsecs_t> hwcVsyncPeriodIn)659*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::addResyncSample(PhysicalDisplayId id, nsecs_t timestamp,
660*38e8c45fSAndroid Build Coastguard Worker                                 std::optional<nsecs_t> hwcVsyncPeriodIn) {
661*38e8c45fSAndroid Build Coastguard Worker     const auto hwcVsyncPeriod = ftl::Optional(hwcVsyncPeriodIn).transform([](nsecs_t nanos) {
662*38e8c45fSAndroid Build Coastguard Worker         return Period::fromNs(nanos);
663*38e8c45fSAndroid Build Coastguard Worker     });
664*38e8c45fSAndroid Build Coastguard Worker     auto schedule = getVsyncSchedule(id);
665*38e8c45fSAndroid Build Coastguard Worker     if (!schedule) {
666*38e8c45fSAndroid Build Coastguard Worker         ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
667*38e8c45fSAndroid Build Coastguard Worker         return false;
668*38e8c45fSAndroid Build Coastguard Worker     }
669*38e8c45fSAndroid Build Coastguard Worker     return schedule->addResyncSample(TimePoint::fromNs(timestamp), hwcVsyncPeriod);
670*38e8c45fSAndroid Build Coastguard Worker }
671*38e8c45fSAndroid Build Coastguard Worker 
addPresentFence(PhysicalDisplayId id,std::shared_ptr<FenceTime> fence)672*38e8c45fSAndroid Build Coastguard Worker void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) {
673*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_NAME(ftl::Concat(__func__, ' ', id.value).c_str());
674*38e8c45fSAndroid Build Coastguard Worker     const auto scheduleOpt =
675*38e8c45fSAndroid Build Coastguard Worker             (ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) {
676*38e8c45fSAndroid Build Coastguard Worker                 return display.powerMode == hal::PowerMode::OFF
677*38e8c45fSAndroid Build Coastguard Worker                         ? std::nullopt
678*38e8c45fSAndroid Build Coastguard Worker                         : std::make_optional(display.schedulePtr);
679*38e8c45fSAndroid Build Coastguard Worker             });
680*38e8c45fSAndroid Build Coastguard Worker 
681*38e8c45fSAndroid Build Coastguard Worker     if (!scheduleOpt) return;
682*38e8c45fSAndroid Build Coastguard Worker     const auto& schedule = scheduleOpt->get();
683*38e8c45fSAndroid Build Coastguard Worker 
684*38e8c45fSAndroid Build Coastguard Worker     const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence));
685*38e8c45fSAndroid Build Coastguard Worker     if (needMoreSignals) {
686*38e8c45fSAndroid Build Coastguard Worker         schedule->enableHardwareVsync();
687*38e8c45fSAndroid Build Coastguard Worker     } else {
688*38e8c45fSAndroid Build Coastguard Worker         constexpr bool kDisallow = false;
689*38e8c45fSAndroid Build Coastguard Worker         schedule->disableHardwareVsync(kDisallow);
690*38e8c45fSAndroid Build Coastguard Worker     }
691*38e8c45fSAndroid Build Coastguard Worker }
692*38e8c45fSAndroid Build Coastguard Worker 
registerLayer(Layer * layer,FrameRateCompatibility frameRateCompatibility)693*38e8c45fSAndroid Build Coastguard Worker void Scheduler::registerLayer(Layer* layer, FrameRateCompatibility frameRateCompatibility) {
694*38e8c45fSAndroid Build Coastguard Worker     // If the content detection feature is off, we still keep the layer history,
695*38e8c45fSAndroid Build Coastguard Worker     // since we use it for other features (like Frame Rate API), so layers
696*38e8c45fSAndroid Build Coastguard Worker     // still need to be registered.
697*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection),
698*38e8c45fSAndroid Build Coastguard Worker                                 frameRateCompatibility);
699*38e8c45fSAndroid Build Coastguard Worker }
700*38e8c45fSAndroid Build Coastguard Worker 
deregisterLayer(Layer * layer)701*38e8c45fSAndroid Build Coastguard Worker void Scheduler::deregisterLayer(Layer* layer) {
702*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.deregisterLayer(layer);
703*38e8c45fSAndroid Build Coastguard Worker }
704*38e8c45fSAndroid Build Coastguard Worker 
onLayerDestroyed(Layer * layer)705*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onLayerDestroyed(Layer* layer) {
706*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mChoreographerLock);
707*38e8c45fSAndroid Build Coastguard Worker     mAttachedChoreographers.erase(layer->getSequence());
708*38e8c45fSAndroid Build Coastguard Worker }
709*38e8c45fSAndroid Build Coastguard Worker 
recordLayerHistory(int32_t id,const LayerProps & layerProps,nsecs_t presentTime,nsecs_t now,LayerHistory::LayerUpdateType updateType)710*38e8c45fSAndroid Build Coastguard Worker void Scheduler::recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
711*38e8c45fSAndroid Build Coastguard Worker                                    nsecs_t now, LayerHistory::LayerUpdateType updateType) {
712*38e8c45fSAndroid Build Coastguard Worker     if (pacesetterSelectorPtr()->canSwitch()) {
713*38e8c45fSAndroid Build Coastguard Worker         mLayerHistory.record(id, layerProps, presentTime, now, updateType);
714*38e8c45fSAndroid Build Coastguard Worker     }
715*38e8c45fSAndroid Build Coastguard Worker }
716*38e8c45fSAndroid Build Coastguard Worker 
setModeChangePending(bool pending)717*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setModeChangePending(bool pending) {
718*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.setModeChangePending(pending);
719*38e8c45fSAndroid Build Coastguard Worker }
720*38e8c45fSAndroid Build Coastguard Worker 
setDefaultFrameRateCompatibility(int32_t id,scheduler::FrameRateCompatibility frameRateCompatibility)721*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setDefaultFrameRateCompatibility(
722*38e8c45fSAndroid Build Coastguard Worker         int32_t id, scheduler::FrameRateCompatibility frameRateCompatibility) {
723*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.setDefaultFrameRateCompatibility(id, frameRateCompatibility,
724*38e8c45fSAndroid Build Coastguard Worker                                                    mFeatures.test(Feature::kContentDetection));
725*38e8c45fSAndroid Build Coastguard Worker }
726*38e8c45fSAndroid Build Coastguard Worker 
setLayerProperties(int32_t id,const android::scheduler::LayerProps & properties)727*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setLayerProperties(int32_t id, const android::scheduler::LayerProps& properties) {
728*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.setLayerProperties(id, properties);
729*38e8c45fSAndroid Build Coastguard Worker }
730*38e8c45fSAndroid Build Coastguard Worker 
chooseRefreshRateForContent(const surfaceflinger::frontend::LayerHierarchy * hierarchy,bool updateAttachedChoreographer)731*38e8c45fSAndroid Build Coastguard Worker void Scheduler::chooseRefreshRateForContent(
732*38e8c45fSAndroid Build Coastguard Worker         const surfaceflinger::frontend::LayerHierarchy* hierarchy,
733*38e8c45fSAndroid Build Coastguard Worker         bool updateAttachedChoreographer) {
734*38e8c45fSAndroid Build Coastguard Worker     const auto selectorPtr = pacesetterSelectorPtr();
735*38e8c45fSAndroid Build Coastguard Worker     if (!selectorPtr->canSwitch()) return;
736*38e8c45fSAndroid Build Coastguard Worker 
737*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
738*38e8c45fSAndroid Build Coastguard Worker 
739*38e8c45fSAndroid Build Coastguard Worker     LayerHistory::Summary summary = mLayerHistory.summarize(*selectorPtr, systemTime());
740*38e8c45fSAndroid Build Coastguard Worker     applyPolicy(&Policy::contentRequirements, std::move(summary));
741*38e8c45fSAndroid Build Coastguard Worker 
742*38e8c45fSAndroid Build Coastguard Worker     if (updateAttachedChoreographer) {
743*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!hierarchy);
744*38e8c45fSAndroid Build Coastguard Worker 
745*38e8c45fSAndroid Build Coastguard Worker         // update the attached choreographers after we selected the render rate.
746*38e8c45fSAndroid Build Coastguard Worker         const ftl::Optional<FrameRateMode> modeOpt = [&] {
747*38e8c45fSAndroid Build Coastguard Worker             std::scoped_lock lock(mPolicyLock);
748*38e8c45fSAndroid Build Coastguard Worker             return mPolicy.modeOpt;
749*38e8c45fSAndroid Build Coastguard Worker         }();
750*38e8c45fSAndroid Build Coastguard Worker 
751*38e8c45fSAndroid Build Coastguard Worker         if (modeOpt) {
752*38e8c45fSAndroid Build Coastguard Worker             updateAttachedChoreographers(*hierarchy, modeOpt->fps);
753*38e8c45fSAndroid Build Coastguard Worker         }
754*38e8c45fSAndroid Build Coastguard Worker     }
755*38e8c45fSAndroid Build Coastguard Worker }
756*38e8c45fSAndroid Build Coastguard Worker 
resetIdleTimer()757*38e8c45fSAndroid Build Coastguard Worker void Scheduler::resetIdleTimer() {
758*38e8c45fSAndroid Build Coastguard Worker     pacesetterSelectorPtr()->resetIdleTimer();
759*38e8c45fSAndroid Build Coastguard Worker }
760*38e8c45fSAndroid Build Coastguard Worker 
onTouchHint()761*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onTouchHint() {
762*38e8c45fSAndroid Build Coastguard Worker     if (mTouchTimer) {
763*38e8c45fSAndroid Build Coastguard Worker         mTouchTimer->reset();
764*38e8c45fSAndroid Build Coastguard Worker         pacesetterSelectorPtr()->resetKernelIdleTimer();
765*38e8c45fSAndroid Build Coastguard Worker     }
766*38e8c45fSAndroid Build Coastguard Worker }
767*38e8c45fSAndroid Build Coastguard Worker 
setDisplayPowerMode(PhysicalDisplayId id,hal::PowerMode powerMode)768*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setDisplayPowerMode(PhysicalDisplayId id, hal::PowerMode powerMode) {
769*38e8c45fSAndroid Build Coastguard Worker     const bool isPacesetter = [this, id]() REQUIRES(kMainThreadContext) {
770*38e8c45fSAndroid Build Coastguard Worker         ftl::FakeGuard guard(mDisplayLock);
771*38e8c45fSAndroid Build Coastguard Worker         return id == mPacesetterDisplayId;
772*38e8c45fSAndroid Build Coastguard Worker     }();
773*38e8c45fSAndroid Build Coastguard Worker     if (isPacesetter) {
774*38e8c45fSAndroid Build Coastguard Worker         // TODO (b/255657128): This needs to be handled per display.
775*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lock(mPolicyLock);
776*38e8c45fSAndroid Build Coastguard Worker         mPolicy.displayPowerMode = powerMode;
777*38e8c45fSAndroid Build Coastguard Worker     }
778*38e8c45fSAndroid Build Coastguard Worker     {
779*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
780*38e8c45fSAndroid Build Coastguard Worker 
781*38e8c45fSAndroid Build Coastguard Worker         const auto displayOpt = mDisplays.get(id);
782*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!displayOpt);
783*38e8c45fSAndroid Build Coastguard Worker         auto& display = displayOpt->get();
784*38e8c45fSAndroid Build Coastguard Worker 
785*38e8c45fSAndroid Build Coastguard Worker         display.powerMode = powerMode;
786*38e8c45fSAndroid Build Coastguard Worker         display.schedulePtr->getController().setDisplayPowerMode(powerMode);
787*38e8c45fSAndroid Build Coastguard Worker     }
788*38e8c45fSAndroid Build Coastguard Worker     if (!isPacesetter) return;
789*38e8c45fSAndroid Build Coastguard Worker 
790*38e8c45fSAndroid Build Coastguard Worker     if (mDisplayPowerTimer) {
791*38e8c45fSAndroid Build Coastguard Worker         mDisplayPowerTimer->reset();
792*38e8c45fSAndroid Build Coastguard Worker     }
793*38e8c45fSAndroid Build Coastguard Worker 
794*38e8c45fSAndroid Build Coastguard Worker     // Display Power event will boost the refresh rate to performance.
795*38e8c45fSAndroid Build Coastguard Worker     // Clear Layer History to get fresh FPS detection
796*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.clear();
797*38e8c45fSAndroid Build Coastguard Worker }
798*38e8c45fSAndroid Build Coastguard Worker 
getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt) const799*38e8c45fSAndroid Build Coastguard Worker auto Scheduler::getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt) const
800*38e8c45fSAndroid Build Coastguard Worker         -> ConstVsyncSchedulePtr {
801*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
802*38e8c45fSAndroid Build Coastguard Worker     return getVsyncScheduleLocked(idOpt);
803*38e8c45fSAndroid Build Coastguard Worker }
804*38e8c45fSAndroid Build Coastguard Worker 
getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt) const805*38e8c45fSAndroid Build Coastguard Worker auto Scheduler::getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt) const
806*38e8c45fSAndroid Build Coastguard Worker         -> ConstVsyncSchedulePtr {
807*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
808*38e8c45fSAndroid Build Coastguard Worker 
809*38e8c45fSAndroid Build Coastguard Worker     if (!idOpt) {
810*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId, "Missing a pacesetter!");
811*38e8c45fSAndroid Build Coastguard Worker         idOpt = mPacesetterDisplayId;
812*38e8c45fSAndroid Build Coastguard Worker     }
813*38e8c45fSAndroid Build Coastguard Worker 
814*38e8c45fSAndroid Build Coastguard Worker     const auto displayOpt = mDisplays.get(*idOpt);
815*38e8c45fSAndroid Build Coastguard Worker     if (!displayOpt) {
816*38e8c45fSAndroid Build Coastguard Worker         return nullptr;
817*38e8c45fSAndroid Build Coastguard Worker     }
818*38e8c45fSAndroid Build Coastguard Worker     return displayOpt->get().schedulePtr;
819*38e8c45fSAndroid Build Coastguard Worker }
820*38e8c45fSAndroid Build Coastguard Worker 
kernelIdleTimerCallback(TimerState state)821*38e8c45fSAndroid Build Coastguard Worker void Scheduler::kernelIdleTimerCallback(TimerState state) {
822*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
823*38e8c45fSAndroid Build Coastguard Worker 
824*38e8c45fSAndroid Build Coastguard Worker     // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
825*38e8c45fSAndroid Build Coastguard Worker     // magic number
826*38e8c45fSAndroid Build Coastguard Worker     const Fps refreshRate = pacesetterSelectorPtr()->getActiveMode().modePtr->getPeakFps();
827*38e8c45fSAndroid Build Coastguard Worker 
828*38e8c45fSAndroid Build Coastguard Worker     constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
829*38e8c45fSAndroid Build Coastguard Worker     using namespace fps_approx_ops;
830*38e8c45fSAndroid Build Coastguard Worker 
831*38e8c45fSAndroid Build Coastguard Worker     if (state == TimerState::Reset && refreshRate > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
832*38e8c45fSAndroid Build Coastguard Worker         // If we're not in performance mode then the kernel timer shouldn't do
833*38e8c45fSAndroid Build Coastguard Worker         // anything, as the refresh rate during DPU power collapse will be the
834*38e8c45fSAndroid Build Coastguard Worker         // same.
835*38e8c45fSAndroid Build Coastguard Worker         resyncAllToHardwareVsync(true /* allowToEnable */);
836*38e8c45fSAndroid Build Coastguard Worker     } else if (state == TimerState::Expired && refreshRate <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
837*38e8c45fSAndroid Build Coastguard Worker         // Disable HW VSYNC if the timer expired, as we don't need it enabled if
838*38e8c45fSAndroid Build Coastguard Worker         // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
839*38e8c45fSAndroid Build Coastguard Worker         // need to update the VsyncController model anyway.
840*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
841*38e8c45fSAndroid Build Coastguard Worker         ftl::FakeGuard guard(kMainThreadContext);
842*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [_, display] : mDisplays) {
843*38e8c45fSAndroid Build Coastguard Worker             constexpr bool kDisallow = false;
844*38e8c45fSAndroid Build Coastguard Worker             display.schedulePtr->disableHardwareVsync(kDisallow);
845*38e8c45fSAndroid Build Coastguard Worker         }
846*38e8c45fSAndroid Build Coastguard Worker     }
847*38e8c45fSAndroid Build Coastguard Worker 
848*38e8c45fSAndroid Build Coastguard Worker     mSchedulerCallback.kernelTimerChanged(state == TimerState::Expired);
849*38e8c45fSAndroid Build Coastguard Worker }
850*38e8c45fSAndroid Build Coastguard Worker 
idleTimerCallback(TimerState state)851*38e8c45fSAndroid Build Coastguard Worker void Scheduler::idleTimerCallback(TimerState state) {
852*38e8c45fSAndroid Build Coastguard Worker     applyPolicy(&Policy::idleTimer, state);
853*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
854*38e8c45fSAndroid Build Coastguard Worker }
855*38e8c45fSAndroid Build Coastguard Worker 
touchTimerCallback(TimerState state)856*38e8c45fSAndroid Build Coastguard Worker void Scheduler::touchTimerCallback(TimerState state) {
857*38e8c45fSAndroid Build Coastguard Worker     const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
858*38e8c45fSAndroid Build Coastguard Worker     // Touch event will boost the refresh rate to performance.
859*38e8c45fSAndroid Build Coastguard Worker     // Clear layer history to get fresh FPS detection.
860*38e8c45fSAndroid Build Coastguard Worker     // NOTE: Instead of checking all the layers, we should be checking the layer
861*38e8c45fSAndroid Build Coastguard Worker     // that is currently on top. b/142507166 will give us this capability.
862*38e8c45fSAndroid Build Coastguard Worker     if (applyPolicy(&Policy::touch, touch).touch) {
863*38e8c45fSAndroid Build Coastguard Worker         mLayerHistory.clear();
864*38e8c45fSAndroid Build Coastguard Worker     }
865*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("TouchState", static_cast<int>(touch));
866*38e8c45fSAndroid Build Coastguard Worker }
867*38e8c45fSAndroid Build Coastguard Worker 
displayPowerTimerCallback(TimerState state)868*38e8c45fSAndroid Build Coastguard Worker void Scheduler::displayPowerTimerCallback(TimerState state) {
869*38e8c45fSAndroid Build Coastguard Worker     applyPolicy(&Policy::displayPowerTimer, state);
870*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
871*38e8c45fSAndroid Build Coastguard Worker }
872*38e8c45fSAndroid Build Coastguard Worker 
dump(utils::Dumper & dumper) const873*38e8c45fSAndroid Build Coastguard Worker void Scheduler::dump(utils::Dumper& dumper) const {
874*38e8c45fSAndroid Build Coastguard Worker     using namespace std::string_view_literals;
875*38e8c45fSAndroid Build Coastguard Worker 
876*38e8c45fSAndroid Build Coastguard Worker     {
877*38e8c45fSAndroid Build Coastguard Worker         utils::Dumper::Section section(dumper, "Features"sv);
878*38e8c45fSAndroid Build Coastguard Worker 
879*38e8c45fSAndroid Build Coastguard Worker         for (Feature feature : ftl::enum_range<Feature>()) {
880*38e8c45fSAndroid Build Coastguard Worker             if (const auto flagOpt = ftl::flag_name(feature)) {
881*38e8c45fSAndroid Build Coastguard Worker                 dumper.dump(flagOpt->substr(1), mFeatures.test(feature));
882*38e8c45fSAndroid Build Coastguard Worker             }
883*38e8c45fSAndroid Build Coastguard Worker         }
884*38e8c45fSAndroid Build Coastguard Worker     }
885*38e8c45fSAndroid Build Coastguard Worker     {
886*38e8c45fSAndroid Build Coastguard Worker         utils::Dumper::Section section(dumper, "Policy"sv);
887*38e8c45fSAndroid Build Coastguard Worker         {
888*38e8c45fSAndroid Build Coastguard Worker             std::scoped_lock lock(mDisplayLock);
889*38e8c45fSAndroid Build Coastguard Worker             ftl::FakeGuard guard(kMainThreadContext);
890*38e8c45fSAndroid Build Coastguard Worker             dumper.dump("pacesetterDisplayId"sv, mPacesetterDisplayId);
891*38e8c45fSAndroid Build Coastguard Worker         }
892*38e8c45fSAndroid Build Coastguard Worker         dumper.dump("layerHistory"sv, mLayerHistory.dump());
893*38e8c45fSAndroid Build Coastguard Worker         dumper.dump("touchTimer"sv, mTouchTimer.transform(&OneShotTimer::interval));
894*38e8c45fSAndroid Build Coastguard Worker         dumper.dump("displayPowerTimer"sv, mDisplayPowerTimer.transform(&OneShotTimer::interval));
895*38e8c45fSAndroid Build Coastguard Worker     }
896*38e8c45fSAndroid Build Coastguard Worker 
897*38e8c45fSAndroid Build Coastguard Worker     mFrameRateOverrideMappings.dump(dumper);
898*38e8c45fSAndroid Build Coastguard Worker     dumper.eol();
899*38e8c45fSAndroid Build Coastguard Worker 
900*38e8c45fSAndroid Build Coastguard Worker     mVsyncConfiguration->dump(dumper.out());
901*38e8c45fSAndroid Build Coastguard Worker     dumper.eol();
902*38e8c45fSAndroid Build Coastguard Worker 
903*38e8c45fSAndroid Build Coastguard Worker     mRefreshRateStats->dump(dumper.out());
904*38e8c45fSAndroid Build Coastguard Worker     dumper.eol();
905*38e8c45fSAndroid Build Coastguard Worker 
906*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
907*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
908*38e8c45fSAndroid Build Coastguard Worker 
909*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, display] : mDisplays) {
910*38e8c45fSAndroid Build Coastguard Worker         utils::Dumper::Section
911*38e8c45fSAndroid Build Coastguard Worker                 section(dumper,
912*38e8c45fSAndroid Build Coastguard Worker                         id == mPacesetterDisplayId
913*38e8c45fSAndroid Build Coastguard Worker                                 ? ftl::Concat("Pacesetter Display ", id.value).c_str()
914*38e8c45fSAndroid Build Coastguard Worker                                 : ftl::Concat("Follower Display ", id.value).c_str());
915*38e8c45fSAndroid Build Coastguard Worker 
916*38e8c45fSAndroid Build Coastguard Worker         display.selectorPtr->dump(dumper);
917*38e8c45fSAndroid Build Coastguard Worker         display.targeterPtr->dump(dumper);
918*38e8c45fSAndroid Build Coastguard Worker         dumper.eol();
919*38e8c45fSAndroid Build Coastguard Worker     }
920*38e8c45fSAndroid Build Coastguard Worker }
921*38e8c45fSAndroid Build Coastguard Worker 
dumpVsync(std::string & out) const922*38e8c45fSAndroid Build Coastguard Worker void Scheduler::dumpVsync(std::string& out) const {
923*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mDisplayLock);
924*38e8c45fSAndroid Build Coastguard Worker     ftl::FakeGuard guard(kMainThreadContext);
925*38e8c45fSAndroid Build Coastguard Worker     if (mPacesetterDisplayId) {
926*38e8c45fSAndroid Build Coastguard Worker         base::StringAppendF(&out, "VsyncSchedule for pacesetter %s:\n",
927*38e8c45fSAndroid Build Coastguard Worker                             to_string(*mPacesetterDisplayId).c_str());
928*38e8c45fSAndroid Build Coastguard Worker         getVsyncScheduleLocked()->dump(out);
929*38e8c45fSAndroid Build Coastguard Worker     }
930*38e8c45fSAndroid Build Coastguard Worker     for (auto& [id, display] : mDisplays) {
931*38e8c45fSAndroid Build Coastguard Worker         if (id == mPacesetterDisplayId) {
932*38e8c45fSAndroid Build Coastguard Worker             continue;
933*38e8c45fSAndroid Build Coastguard Worker         }
934*38e8c45fSAndroid Build Coastguard Worker         base::StringAppendF(&out, "VsyncSchedule for follower %s:\n", to_string(id).c_str());
935*38e8c45fSAndroid Build Coastguard Worker         display.schedulePtr->dump(out);
936*38e8c45fSAndroid Build Coastguard Worker     }
937*38e8c45fSAndroid Build Coastguard Worker }
938*38e8c45fSAndroid Build Coastguard Worker 
939*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
940*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-value" // b/369277774
updateFrameRateOverrides(GlobalSignals consideredSignals,Fps displayRefreshRate)941*38e8c45fSAndroid Build Coastguard Worker void Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
942*38e8c45fSAndroid Build Coastguard Worker     const bool changed = (std::scoped_lock(mPolicyLock),
943*38e8c45fSAndroid Build Coastguard Worker                           updateFrameRateOverridesLocked(consideredSignals, displayRefreshRate));
944*38e8c45fSAndroid Build Coastguard Worker 
945*38e8c45fSAndroid Build Coastguard Worker     if (changed) {
946*38e8c45fSAndroid Build Coastguard Worker         onFrameRateOverridesChanged();
947*38e8c45fSAndroid Build Coastguard Worker     }
948*38e8c45fSAndroid Build Coastguard Worker }
949*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
950*38e8c45fSAndroid Build Coastguard Worker 
updateFrameRateOverridesLocked(GlobalSignals consideredSignals,Fps displayRefreshRate)951*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals,
952*38e8c45fSAndroid Build Coastguard Worker                                                Fps displayRefreshRate) {
953*38e8c45fSAndroid Build Coastguard Worker     if (consideredSignals.idle) return false;
954*38e8c45fSAndroid Build Coastguard Worker 
955*38e8c45fSAndroid Build Coastguard Worker     const auto frameRateOverrides =
956*38e8c45fSAndroid Build Coastguard Worker             pacesetterSelectorPtr()->getFrameRateOverrides(mPolicy.contentRequirements,
957*38e8c45fSAndroid Build Coastguard Worker                                                            displayRefreshRate, consideredSignals);
958*38e8c45fSAndroid Build Coastguard Worker 
959*38e8c45fSAndroid Build Coastguard Worker     // Note that RefreshRateSelector::supportsFrameRateOverrideByContent is checked when querying
960*38e8c45fSAndroid Build Coastguard Worker     // the FrameRateOverrideMappings rather than here.
961*38e8c45fSAndroid Build Coastguard Worker     return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
962*38e8c45fSAndroid Build Coastguard Worker }
963*38e8c45fSAndroid Build Coastguard Worker 
addBufferStuffedUids(BufferStuffingMap bufferStuffedUids)964*38e8c45fSAndroid Build Coastguard Worker void Scheduler::addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) {
965*38e8c45fSAndroid Build Coastguard Worker     if (!mRenderEventThread) return;
966*38e8c45fSAndroid Build Coastguard Worker     mRenderEventThread->addBufferStuffedUids(std::move(bufferStuffedUids));
967*38e8c45fSAndroid Build Coastguard Worker }
968*38e8c45fSAndroid Build Coastguard Worker 
promotePacesetterDisplay(PhysicalDisplayId pacesetterId,PromotionParams params)969*38e8c45fSAndroid Build Coastguard Worker void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams params) {
970*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
971*38e8c45fSAndroid Build Coastguard Worker     {
972*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mDisplayLock);
973*38e8c45fSAndroid Build Coastguard Worker         pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterId, params);
974*38e8c45fSAndroid Build Coastguard Worker     }
975*38e8c45fSAndroid Build Coastguard Worker 
976*38e8c45fSAndroid Build Coastguard Worker     applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
977*38e8c45fSAndroid Build Coastguard Worker }
978*38e8c45fSAndroid Build Coastguard Worker 
promotePacesetterDisplayLocked(PhysicalDisplayId pacesetterId,PromotionParams params)979*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
980*38e8c45fSAndroid Build Coastguard Worker         PhysicalDisplayId pacesetterId, PromotionParams params) {
981*38e8c45fSAndroid Build Coastguard Worker     // TODO: b/241286431 - Choose the pacesetter among mDisplays.
982*38e8c45fSAndroid Build Coastguard Worker     mPacesetterDisplayId = pacesetterId;
983*38e8c45fSAndroid Build Coastguard Worker     ALOGI("Display %s is the pacesetter", to_string(pacesetterId).c_str());
984*38e8c45fSAndroid Build Coastguard Worker 
985*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr;
986*38e8c45fSAndroid Build Coastguard Worker     if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
987*38e8c45fSAndroid Build Coastguard Worker         const Display& pacesetter = *pacesetterOpt;
988*38e8c45fSAndroid Build Coastguard Worker 
989*38e8c45fSAndroid Build Coastguard Worker         if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
990*38e8c45fSAndroid Build Coastguard Worker             pacesetter.selectorPtr->setIdleTimerCallbacks(
991*38e8c45fSAndroid Build Coastguard Worker                     {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
992*38e8c45fSAndroid Build Coastguard Worker                                   .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
993*38e8c45fSAndroid Build Coastguard Worker                      .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
994*38e8c45fSAndroid Build Coastguard Worker                                 .onExpired =
995*38e8c45fSAndroid Build Coastguard Worker                                         [this] { kernelIdleTimerCallback(TimerState::Expired); }},
996*38e8c45fSAndroid Build Coastguard Worker                      .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); },
997*38e8c45fSAndroid Build Coastguard Worker                              .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}});
998*38e8c45fSAndroid Build Coastguard Worker 
999*38e8c45fSAndroid Build Coastguard Worker             pacesetter.selectorPtr->startIdleTimer();
1000*38e8c45fSAndroid Build Coastguard Worker         }
1001*38e8c45fSAndroid Build Coastguard Worker 
1002*38e8c45fSAndroid Build Coastguard Worker         newVsyncSchedulePtr = pacesetter.schedulePtr;
1003*38e8c45fSAndroid Build Coastguard Worker 
1004*38e8c45fSAndroid Build Coastguard Worker         constexpr bool kForce = true;
1005*38e8c45fSAndroid Build Coastguard Worker         newVsyncSchedulePtr->onDisplayModeChanged(pacesetter.selectorPtr->getActiveMode().modePtr,
1006*38e8c45fSAndroid Build Coastguard Worker                                                   kForce);
1007*38e8c45fSAndroid Build Coastguard Worker     }
1008*38e8c45fSAndroid Build Coastguard Worker     return newVsyncSchedulePtr;
1009*38e8c45fSAndroid Build Coastguard Worker }
1010*38e8c45fSAndroid Build Coastguard Worker 
applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule)1011*38e8c45fSAndroid Build Coastguard Worker void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) {
1012*38e8c45fSAndroid Build Coastguard Worker     onNewVsyncSchedule(vsyncSchedule->getDispatch());
1013*38e8c45fSAndroid Build Coastguard Worker 
1014*38e8c45fSAndroid Build Coastguard Worker     if (hasEventThreads()) {
1015*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::Render).onNewVsyncSchedule(vsyncSchedule);
1016*38e8c45fSAndroid Build Coastguard Worker         eventThreadFor(Cycle::LastComposite).onNewVsyncSchedule(vsyncSchedule);
1017*38e8c45fSAndroid Build Coastguard Worker     }
1018*38e8c45fSAndroid Build Coastguard Worker }
1019*38e8c45fSAndroid Build Coastguard Worker 
demotePacesetterDisplay(PromotionParams params)1020*38e8c45fSAndroid Build Coastguard Worker void Scheduler::demotePacesetterDisplay(PromotionParams params) {
1021*38e8c45fSAndroid Build Coastguard Worker     if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
1022*38e8c45fSAndroid Build Coastguard Worker         // No need to lock for reads on kMainThreadContext.
1023*38e8c45fSAndroid Build Coastguard Worker         if (const auto pacesetterPtr =
1024*38e8c45fSAndroid Build Coastguard Worker                     FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
1025*38e8c45fSAndroid Build Coastguard Worker             pacesetterPtr->stopIdleTimer();
1026*38e8c45fSAndroid Build Coastguard Worker             pacesetterPtr->clearIdleTimerCallbacks();
1027*38e8c45fSAndroid Build Coastguard Worker         }
1028*38e8c45fSAndroid Build Coastguard Worker     }
1029*38e8c45fSAndroid Build Coastguard Worker 
1030*38e8c45fSAndroid Build Coastguard Worker     // Clear state that depends on the pacesetter's RefreshRateSelector.
1031*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mPolicyLock);
1032*38e8c45fSAndroid Build Coastguard Worker     mPolicy = {};
1033*38e8c45fSAndroid Build Coastguard Worker }
1034*38e8c45fSAndroid Build Coastguard Worker 
updateAttachedChoreographersFrameRate(const surfaceflinger::frontend::RequestedLayerState & layer,Fps fps)1035*38e8c45fSAndroid Build Coastguard Worker void Scheduler::updateAttachedChoreographersFrameRate(
1036*38e8c45fSAndroid Build Coastguard Worker         const surfaceflinger::frontend::RequestedLayerState& layer, Fps fps) {
1037*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(mChoreographerLock);
1038*38e8c45fSAndroid Build Coastguard Worker 
1039*38e8c45fSAndroid Build Coastguard Worker     const auto layerId = static_cast<int32_t>(layer.id);
1040*38e8c45fSAndroid Build Coastguard Worker     const auto choreographers = mAttachedChoreographers.find(layerId);
1041*38e8c45fSAndroid Build Coastguard Worker     if (choreographers == mAttachedChoreographers.end()) {
1042*38e8c45fSAndroid Build Coastguard Worker         return;
1043*38e8c45fSAndroid Build Coastguard Worker     }
1044*38e8c45fSAndroid Build Coastguard Worker 
1045*38e8c45fSAndroid Build Coastguard Worker     auto& layerChoreographers = choreographers->second;
1046*38e8c45fSAndroid Build Coastguard Worker 
1047*38e8c45fSAndroid Build Coastguard Worker     layerChoreographers.frameRate = fps;
1048*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_FORMAT_INSTANT("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str());
1049*38e8c45fSAndroid Build Coastguard Worker     ALOGV("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str());
1050*38e8c45fSAndroid Build Coastguard Worker 
1051*38e8c45fSAndroid Build Coastguard Worker     auto it = layerChoreographers.connections.begin();
1052*38e8c45fSAndroid Build Coastguard Worker     while (it != layerChoreographers.connections.end()) {
1053*38e8c45fSAndroid Build Coastguard Worker         sp<EventThreadConnection> choreographerConnection = it->promote();
1054*38e8c45fSAndroid Build Coastguard Worker         if (choreographerConnection) {
1055*38e8c45fSAndroid Build Coastguard Worker             choreographerConnection->frameRate = fps;
1056*38e8c45fSAndroid Build Coastguard Worker             it++;
1057*38e8c45fSAndroid Build Coastguard Worker         } else {
1058*38e8c45fSAndroid Build Coastguard Worker             it = choreographers->second.connections.erase(it);
1059*38e8c45fSAndroid Build Coastguard Worker         }
1060*38e8c45fSAndroid Build Coastguard Worker     }
1061*38e8c45fSAndroid Build Coastguard Worker 
1062*38e8c45fSAndroid Build Coastguard Worker     if (layerChoreographers.connections.empty()) {
1063*38e8c45fSAndroid Build Coastguard Worker         mAttachedChoreographers.erase(choreographers);
1064*38e8c45fSAndroid Build Coastguard Worker     }
1065*38e8c45fSAndroid Build Coastguard Worker }
1066*38e8c45fSAndroid Build Coastguard Worker 
updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy & layerHierarchy,Fps displayRefreshRate,int parentDivisor)1067*38e8c45fSAndroid Build Coastguard Worker int Scheduler::updateAttachedChoreographersInternal(
1068*38e8c45fSAndroid Build Coastguard Worker         const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate,
1069*38e8c45fSAndroid Build Coastguard Worker         int parentDivisor) {
1070*38e8c45fSAndroid Build Coastguard Worker     const char* name = layerHierarchy.getLayer() ? layerHierarchy.getLayer()->name.c_str() : "Root";
1071*38e8c45fSAndroid Build Coastguard Worker 
1072*38e8c45fSAndroid Build Coastguard Worker     int divisor = 0;
1073*38e8c45fSAndroid Build Coastguard Worker     if (layerHierarchy.getLayer()) {
1074*38e8c45fSAndroid Build Coastguard Worker         const auto frameRateCompatibility = layerHierarchy.getLayer()->frameRateCompatibility;
1075*38e8c45fSAndroid Build Coastguard Worker         const auto frameRate = Fps::fromValue(layerHierarchy.getLayer()->frameRate);
1076*38e8c45fSAndroid Build Coastguard Worker         ALOGV("%s: %s frameRate %s parentDivisor=%d", __func__, name, to_string(frameRate).c_str(),
1077*38e8c45fSAndroid Build Coastguard Worker               parentDivisor);
1078*38e8c45fSAndroid Build Coastguard Worker 
1079*38e8c45fSAndroid Build Coastguard Worker         if (frameRate.isValid()) {
1080*38e8c45fSAndroid Build Coastguard Worker             if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE ||
1081*38e8c45fSAndroid Build Coastguard Worker                 frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_EXACT) {
1082*38e8c45fSAndroid Build Coastguard Worker                 // Since this layer wants an exact match, we would only set a frame rate if the
1083*38e8c45fSAndroid Build Coastguard Worker                 // desired rate is a divisor of the display refresh rate.
1084*38e8c45fSAndroid Build Coastguard Worker                 divisor = RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate);
1085*38e8c45fSAndroid Build Coastguard Worker             } else if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
1086*38e8c45fSAndroid Build Coastguard Worker                 // find the closest frame rate divisor for the desired frame rate.
1087*38e8c45fSAndroid Build Coastguard Worker                 divisor = static_cast<int>(
1088*38e8c45fSAndroid Build Coastguard Worker                         std::round(displayRefreshRate.getValue() / frameRate.getValue()));
1089*38e8c45fSAndroid Build Coastguard Worker             }
1090*38e8c45fSAndroid Build Coastguard Worker         }
1091*38e8c45fSAndroid Build Coastguard Worker     }
1092*38e8c45fSAndroid Build Coastguard Worker 
1093*38e8c45fSAndroid Build Coastguard Worker     // We start by traversing the children, updating their choreographers, and getting back the
1094*38e8c45fSAndroid Build Coastguard Worker     // aggregated frame rate.
1095*38e8c45fSAndroid Build Coastguard Worker     int childrenDivisor = 0;
1096*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [child, _] : layerHierarchy.mChildren) {
1097*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(child == nullptr || child->getLayer() == nullptr);
1098*38e8c45fSAndroid Build Coastguard Worker 
1099*38e8c45fSAndroid Build Coastguard Worker         ALOGV("%s: %s traversing child %s", __func__, name, child->getLayer()->name.c_str());
1100*38e8c45fSAndroid Build Coastguard Worker 
1101*38e8c45fSAndroid Build Coastguard Worker         const int childDivisor =
1102*38e8c45fSAndroid Build Coastguard Worker                 updateAttachedChoreographersInternal(*child, displayRefreshRate, divisor);
1103*38e8c45fSAndroid Build Coastguard Worker         childrenDivisor = childrenDivisor > 0 ? childrenDivisor : childDivisor;
1104*38e8c45fSAndroid Build Coastguard Worker         if (childDivisor > 0) {
1105*38e8c45fSAndroid Build Coastguard Worker             childrenDivisor = std::gcd(childrenDivisor, childDivisor);
1106*38e8c45fSAndroid Build Coastguard Worker         }
1107*38e8c45fSAndroid Build Coastguard Worker         ALOGV("%s: %s childrenDivisor=%d", __func__, name, childrenDivisor);
1108*38e8c45fSAndroid Build Coastguard Worker     }
1109*38e8c45fSAndroid Build Coastguard Worker 
1110*38e8c45fSAndroid Build Coastguard Worker     ALOGV("%s: %s divisor=%d", __func__, name, divisor);
1111*38e8c45fSAndroid Build Coastguard Worker 
1112*38e8c45fSAndroid Build Coastguard Worker     // If there is no explicit vote for this layer. Use the children's vote if exists
1113*38e8c45fSAndroid Build Coastguard Worker     divisor = (divisor == 0) ? childrenDivisor : divisor;
1114*38e8c45fSAndroid Build Coastguard Worker     ALOGV("%s: %s divisor=%d with children", __func__, name, divisor);
1115*38e8c45fSAndroid Build Coastguard Worker 
1116*38e8c45fSAndroid Build Coastguard Worker     // If there is no explicit vote for this layer or its children, Use the parent vote if exists
1117*38e8c45fSAndroid Build Coastguard Worker     divisor = (divisor == 0) ? parentDivisor : divisor;
1118*38e8c45fSAndroid Build Coastguard Worker     ALOGV("%s: %s divisor=%d with parent", __func__, name, divisor);
1119*38e8c45fSAndroid Build Coastguard Worker 
1120*38e8c45fSAndroid Build Coastguard Worker     if (layerHierarchy.getLayer()) {
1121*38e8c45fSAndroid Build Coastguard Worker         Fps fps = divisor > 1 ? displayRefreshRate / (unsigned int)divisor : Fps();
1122*38e8c45fSAndroid Build Coastguard Worker         updateAttachedChoreographersFrameRate(*layerHierarchy.getLayer(), fps);
1123*38e8c45fSAndroid Build Coastguard Worker     }
1124*38e8c45fSAndroid Build Coastguard Worker 
1125*38e8c45fSAndroid Build Coastguard Worker     return divisor;
1126*38e8c45fSAndroid Build Coastguard Worker }
1127*38e8c45fSAndroid Build Coastguard Worker 
updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy & layerHierarchy,Fps displayRefreshRate)1128*38e8c45fSAndroid Build Coastguard Worker void Scheduler::updateAttachedChoreographers(
1129*38e8c45fSAndroid Build Coastguard Worker         const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate) {
1130*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
1131*38e8c45fSAndroid Build Coastguard Worker     updateAttachedChoreographersInternal(layerHierarchy, displayRefreshRate, 0);
1132*38e8c45fSAndroid Build Coastguard Worker }
1133*38e8c45fSAndroid Build Coastguard Worker 
1134*38e8c45fSAndroid Build Coastguard Worker template <typename S, typename T>
applyPolicy(S Policy::* statePtr,T && newState)1135*38e8c45fSAndroid Build Coastguard Worker auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
1136*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
1137*38e8c45fSAndroid Build Coastguard Worker     std::vector<display::DisplayModeRequest> modeRequests;
1138*38e8c45fSAndroid Build Coastguard Worker     GlobalSignals consideredSignals;
1139*38e8c45fSAndroid Build Coastguard Worker 
1140*38e8c45fSAndroid Build Coastguard Worker     bool refreshRateChanged = false;
1141*38e8c45fSAndroid Build Coastguard Worker     bool frameRateOverridesChanged;
1142*38e8c45fSAndroid Build Coastguard Worker 
1143*38e8c45fSAndroid Build Coastguard Worker     {
1144*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mPolicyLock);
1145*38e8c45fSAndroid Build Coastguard Worker 
1146*38e8c45fSAndroid Build Coastguard Worker         auto& currentState = mPolicy.*statePtr;
1147*38e8c45fSAndroid Build Coastguard Worker         if (currentState == newState) return {};
1148*38e8c45fSAndroid Build Coastguard Worker         currentState = std::forward<T>(newState);
1149*38e8c45fSAndroid Build Coastguard Worker 
1150*38e8c45fSAndroid Build Coastguard Worker         DisplayModeChoiceMap modeChoices;
1151*38e8c45fSAndroid Build Coastguard Worker         ftl::Optional<FrameRateMode> modeOpt;
1152*38e8c45fSAndroid Build Coastguard Worker         {
1153*38e8c45fSAndroid Build Coastguard Worker             std::scoped_lock lock(mDisplayLock);
1154*38e8c45fSAndroid Build Coastguard Worker             ftl::FakeGuard guard(kMainThreadContext);
1155*38e8c45fSAndroid Build Coastguard Worker 
1156*38e8c45fSAndroid Build Coastguard Worker             modeChoices = chooseDisplayModes();
1157*38e8c45fSAndroid Build Coastguard Worker 
1158*38e8c45fSAndroid Build Coastguard Worker             // TODO(b/240743786): The pacesetter display's mode must change for any
1159*38e8c45fSAndroid Build Coastguard Worker             // DisplayModeRequest to go through. Fix this by tracking per-display Scheduler::Policy
1160*38e8c45fSAndroid Build Coastguard Worker             // and timers.
1161*38e8c45fSAndroid Build Coastguard Worker             std::tie(modeOpt, consideredSignals) =
1162*38e8c45fSAndroid Build Coastguard Worker                     modeChoices.get(*mPacesetterDisplayId)
1163*38e8c45fSAndroid Build Coastguard Worker                             .transform([](const DisplayModeChoice& choice) {
1164*38e8c45fSAndroid Build Coastguard Worker                                 return std::make_pair(choice.mode, choice.consideredSignals);
1165*38e8c45fSAndroid Build Coastguard Worker                             })
1166*38e8c45fSAndroid Build Coastguard Worker                             .value();
1167*38e8c45fSAndroid Build Coastguard Worker         }
1168*38e8c45fSAndroid Build Coastguard Worker 
1169*38e8c45fSAndroid Build Coastguard Worker         modeRequests.reserve(modeChoices.size());
1170*38e8c45fSAndroid Build Coastguard Worker         for (auto& [id, choice] : modeChoices) {
1171*38e8c45fSAndroid Build Coastguard Worker             modeRequests.emplace_back(
1172*38e8c45fSAndroid Build Coastguard Worker                     display::DisplayModeRequest{.mode = std::move(choice.mode),
1173*38e8c45fSAndroid Build Coastguard Worker                                                 .emitEvent = choice.consideredSignals
1174*38e8c45fSAndroid Build Coastguard Worker                                                                      .shouldEmitEvent()});
1175*38e8c45fSAndroid Build Coastguard Worker         }
1176*38e8c45fSAndroid Build Coastguard Worker 
1177*38e8c45fSAndroid Build Coastguard Worker         if (!FlagManager::getInstance().vrr_bugfix_dropped_frame()) {
1178*38e8c45fSAndroid Build Coastguard Worker             frameRateOverridesChanged =
1179*38e8c45fSAndroid Build Coastguard Worker                     updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps);
1180*38e8c45fSAndroid Build Coastguard Worker         }
1181*38e8c45fSAndroid Build Coastguard Worker         if (mPolicy.modeOpt != modeOpt) {
1182*38e8c45fSAndroid Build Coastguard Worker             mPolicy.modeOpt = modeOpt;
1183*38e8c45fSAndroid Build Coastguard Worker             refreshRateChanged = true;
1184*38e8c45fSAndroid Build Coastguard Worker         } else if (consideredSignals.shouldEmitEvent()) {
1185*38e8c45fSAndroid Build Coastguard Worker             // The mode did not change, but we may need to emit if DisplayModeRequest::emitEvent was
1186*38e8c45fSAndroid Build Coastguard Worker             // previously false.
1187*38e8c45fSAndroid Build Coastguard Worker             emitModeChangeIfNeeded();
1188*38e8c45fSAndroid Build Coastguard Worker         }
1189*38e8c45fSAndroid Build Coastguard Worker     }
1190*38e8c45fSAndroid Build Coastguard Worker     if (refreshRateChanged) {
1191*38e8c45fSAndroid Build Coastguard Worker         mSchedulerCallback.requestDisplayModes(std::move(modeRequests));
1192*38e8c45fSAndroid Build Coastguard Worker     }
1193*38e8c45fSAndroid Build Coastguard Worker 
1194*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().vrr_bugfix_dropped_frame()) {
1195*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(mPolicyLock);
1196*38e8c45fSAndroid Build Coastguard Worker         frameRateOverridesChanged =
1197*38e8c45fSAndroid Build Coastguard Worker                 updateFrameRateOverridesLocked(consideredSignals, mPolicy.modeOpt->fps);
1198*38e8c45fSAndroid Build Coastguard Worker     }
1199*38e8c45fSAndroid Build Coastguard Worker     if (frameRateOverridesChanged) {
1200*38e8c45fSAndroid Build Coastguard Worker         onFrameRateOverridesChanged();
1201*38e8c45fSAndroid Build Coastguard Worker     }
1202*38e8c45fSAndroid Build Coastguard Worker     return consideredSignals;
1203*38e8c45fSAndroid Build Coastguard Worker }
1204*38e8c45fSAndroid Build Coastguard Worker 
chooseDisplayModes() const1205*38e8c45fSAndroid Build Coastguard Worker auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {
1206*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
1207*38e8c45fSAndroid Build Coastguard Worker 
1208*38e8c45fSAndroid Build Coastguard Worker     DisplayModeChoiceMap modeChoices;
1209*38e8c45fSAndroid Build Coastguard Worker     const auto globalSignals = makeGlobalSignals();
1210*38e8c45fSAndroid Build Coastguard Worker 
1211*38e8c45fSAndroid Build Coastguard Worker     const Fps pacesetterFps = [&]() REQUIRES(mPolicyLock, mDisplayLock, kMainThreadContext) {
1212*38e8c45fSAndroid Build Coastguard Worker         auto rankedFrameRates =
1213*38e8c45fSAndroid Build Coastguard Worker                 pacesetterSelectorPtrLocked()->getRankedFrameRates(mPolicy.contentRequirements,
1214*38e8c45fSAndroid Build Coastguard Worker                                                                    globalSignals);
1215*38e8c45fSAndroid Build Coastguard Worker 
1216*38e8c45fSAndroid Build Coastguard Worker         const Fps pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;
1217*38e8c45fSAndroid Build Coastguard Worker 
1218*38e8c45fSAndroid Build Coastguard Worker         modeChoices.try_emplace(*mPacesetterDisplayId,
1219*38e8c45fSAndroid Build Coastguard Worker                                 DisplayModeChoice::from(std::move(rankedFrameRates)));
1220*38e8c45fSAndroid Build Coastguard Worker         return pacesetterFps;
1221*38e8c45fSAndroid Build Coastguard Worker     }();
1222*38e8c45fSAndroid Build Coastguard Worker 
1223*38e8c45fSAndroid Build Coastguard Worker     // Choose a mode for powered-on follower displays.
1224*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, display] : mDisplays) {
1225*38e8c45fSAndroid Build Coastguard Worker         if (id == *mPacesetterDisplayId) continue;
1226*38e8c45fSAndroid Build Coastguard Worker         if (display.powerMode != hal::PowerMode::ON) continue;
1227*38e8c45fSAndroid Build Coastguard Worker 
1228*38e8c45fSAndroid Build Coastguard Worker         auto rankedFrameRates =
1229*38e8c45fSAndroid Build Coastguard Worker                 display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals,
1230*38e8c45fSAndroid Build Coastguard Worker                                                          pacesetterFps);
1231*38e8c45fSAndroid Build Coastguard Worker 
1232*38e8c45fSAndroid Build Coastguard Worker         modeChoices.try_emplace(id, DisplayModeChoice::from(std::move(rankedFrameRates)));
1233*38e8c45fSAndroid Build Coastguard Worker     }
1234*38e8c45fSAndroid Build Coastguard Worker 
1235*38e8c45fSAndroid Build Coastguard Worker     return modeChoices;
1236*38e8c45fSAndroid Build Coastguard Worker }
1237*38e8c45fSAndroid Build Coastguard Worker 
makeGlobalSignals() const1238*38e8c45fSAndroid Build Coastguard Worker GlobalSignals Scheduler::makeGlobalSignals() const {
1239*38e8c45fSAndroid Build Coastguard Worker     const bool powerOnImminent = mDisplayPowerTimer &&
1240*38e8c45fSAndroid Build Coastguard Worker             (mPolicy.displayPowerMode != hal::PowerMode::ON ||
1241*38e8c45fSAndroid Build Coastguard Worker              mPolicy.displayPowerTimer == TimerState::Reset);
1242*38e8c45fSAndroid Build Coastguard Worker 
1243*38e8c45fSAndroid Build Coastguard Worker     return {.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
1244*38e8c45fSAndroid Build Coastguard Worker             .idle = mPolicy.idleTimer == TimerState::Expired,
1245*38e8c45fSAndroid Build Coastguard Worker             .powerOnImminent = powerOnImminent};
1246*38e8c45fSAndroid Build Coastguard Worker }
1247*38e8c45fSAndroid Build Coastguard Worker 
getPreferredDisplayMode()1248*38e8c45fSAndroid Build Coastguard Worker FrameRateMode Scheduler::getPreferredDisplayMode() {
1249*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mPolicyLock);
1250*38e8c45fSAndroid Build Coastguard Worker     const auto frameRateMode =
1251*38e8c45fSAndroid Build Coastguard Worker             pacesetterSelectorPtr()
1252*38e8c45fSAndroid Build Coastguard Worker                     ->getRankedFrameRates(mPolicy.contentRequirements, makeGlobalSignals())
1253*38e8c45fSAndroid Build Coastguard Worker                     .ranking.front()
1254*38e8c45fSAndroid Build Coastguard Worker                     .frameRateMode;
1255*38e8c45fSAndroid Build Coastguard Worker 
1256*38e8c45fSAndroid Build Coastguard Worker     // Make sure the stored mode is up to date.
1257*38e8c45fSAndroid Build Coastguard Worker     mPolicy.modeOpt = frameRateMode;
1258*38e8c45fSAndroid Build Coastguard Worker 
1259*38e8c45fSAndroid Build Coastguard Worker     return frameRateMode;
1260*38e8c45fSAndroid Build Coastguard Worker }
1261*38e8c45fSAndroid Build Coastguard Worker 
onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline & timeline)1262*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
1263*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
1264*38e8c45fSAndroid Build Coastguard Worker     mLastVsyncPeriodChangeTimeline = std::make_optional(timeline);
1265*38e8c45fSAndroid Build Coastguard Worker 
1266*38e8c45fSAndroid Build Coastguard Worker     const auto maxAppliedTime = systemTime() + MAX_VSYNC_APPLIED_TIME.count();
1267*38e8c45fSAndroid Build Coastguard Worker     if (timeline.newVsyncAppliedTimeNanos > maxAppliedTime) {
1268*38e8c45fSAndroid Build Coastguard Worker         mLastVsyncPeriodChangeTimeline->newVsyncAppliedTimeNanos = maxAppliedTime;
1269*38e8c45fSAndroid Build Coastguard Worker     }
1270*38e8c45fSAndroid Build Coastguard Worker }
1271*38e8c45fSAndroid Build Coastguard Worker 
onCompositionPresented(nsecs_t presentTime)1272*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::onCompositionPresented(nsecs_t presentTime) {
1273*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
1274*38e8c45fSAndroid Build Coastguard Worker     if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
1275*38e8c45fSAndroid Build Coastguard Worker         if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
1276*38e8c45fSAndroid Build Coastguard Worker             // We need to composite again as refreshTimeNanos is still in the future.
1277*38e8c45fSAndroid Build Coastguard Worker             return true;
1278*38e8c45fSAndroid Build Coastguard Worker         }
1279*38e8c45fSAndroid Build Coastguard Worker 
1280*38e8c45fSAndroid Build Coastguard Worker         mLastVsyncPeriodChangeTimeline->refreshRequired = false;
1281*38e8c45fSAndroid Build Coastguard Worker     }
1282*38e8c45fSAndroid Build Coastguard Worker     return false;
1283*38e8c45fSAndroid Build Coastguard Worker }
1284*38e8c45fSAndroid Build Coastguard Worker 
onActiveDisplayAreaChanged(uint32_t displayArea)1285*38e8c45fSAndroid Build Coastguard Worker void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
1286*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.setDisplayArea(displayArea);
1287*38e8c45fSAndroid Build Coastguard Worker }
1288*38e8c45fSAndroid Build Coastguard Worker 
setGameModeFrameRateForUid(FrameRateOverride frameRateOverride)1289*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setGameModeFrameRateForUid(FrameRateOverride frameRateOverride) {
1290*38e8c45fSAndroid Build Coastguard Worker     if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
1291*38e8c45fSAndroid Build Coastguard Worker         return;
1292*38e8c45fSAndroid Build Coastguard Worker     }
1293*38e8c45fSAndroid Build Coastguard Worker 
1294*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().game_default_frame_rate()) {
1295*38e8c45fSAndroid Build Coastguard Worker         // update the frame rate override mapping in LayerHistory
1296*38e8c45fSAndroid Build Coastguard Worker         mLayerHistory.updateGameModeFrameRateOverride(frameRateOverride);
1297*38e8c45fSAndroid Build Coastguard Worker     } else {
1298*38e8c45fSAndroid Build Coastguard Worker         mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride);
1299*38e8c45fSAndroid Build Coastguard Worker     }
1300*38e8c45fSAndroid Build Coastguard Worker 
1301*38e8c45fSAndroid Build Coastguard Worker     onFrameRateOverridesChanged();
1302*38e8c45fSAndroid Build Coastguard Worker }
1303*38e8c45fSAndroid Build Coastguard Worker 
setGameDefaultFrameRateForUid(FrameRateOverride frameRateOverride)1304*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setGameDefaultFrameRateForUid(FrameRateOverride frameRateOverride) {
1305*38e8c45fSAndroid Build Coastguard Worker     if (!FlagManager::getInstance().game_default_frame_rate() ||
1306*38e8c45fSAndroid Build Coastguard Worker         (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f)) {
1307*38e8c45fSAndroid Build Coastguard Worker         return;
1308*38e8c45fSAndroid Build Coastguard Worker     }
1309*38e8c45fSAndroid Build Coastguard Worker 
1310*38e8c45fSAndroid Build Coastguard Worker     // update the frame rate override mapping in LayerHistory
1311*38e8c45fSAndroid Build Coastguard Worker     mLayerHistory.updateGameDefaultFrameRateOverride(frameRateOverride);
1312*38e8c45fSAndroid Build Coastguard Worker }
1313*38e8c45fSAndroid Build Coastguard Worker 
setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride)1314*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
1315*38e8c45fSAndroid Build Coastguard Worker     if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
1316*38e8c45fSAndroid Build Coastguard Worker         return;
1317*38e8c45fSAndroid Build Coastguard Worker     }
1318*38e8c45fSAndroid Build Coastguard Worker 
1319*38e8c45fSAndroid Build Coastguard Worker     mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride);
1320*38e8c45fSAndroid Build Coastguard Worker     onFrameRateOverridesChanged();
1321*38e8c45fSAndroid Build Coastguard Worker }
1322*38e8c45fSAndroid Build Coastguard Worker 
updateSmallAreaDetection(std::vector<std::pair<int32_t,float>> & uidThresholdMappings)1323*38e8c45fSAndroid Build Coastguard Worker void Scheduler::updateSmallAreaDetection(
1324*38e8c45fSAndroid Build Coastguard Worker         std::vector<std::pair<int32_t, float>>& uidThresholdMappings) {
1325*38e8c45fSAndroid Build Coastguard Worker     mSmallAreaDetectionAllowMappings.update(uidThresholdMappings);
1326*38e8c45fSAndroid Build Coastguard Worker }
1327*38e8c45fSAndroid Build Coastguard Worker 
setSmallAreaDetectionThreshold(int32_t appId,float threshold)1328*38e8c45fSAndroid Build Coastguard Worker void Scheduler::setSmallAreaDetectionThreshold(int32_t appId, float threshold) {
1329*38e8c45fSAndroid Build Coastguard Worker     mSmallAreaDetectionAllowMappings.setThresholdForAppId(appId, threshold);
1330*38e8c45fSAndroid Build Coastguard Worker }
1331*38e8c45fSAndroid Build Coastguard Worker 
isSmallDirtyArea(int32_t appId,uint32_t dirtyArea)1332*38e8c45fSAndroid Build Coastguard Worker bool Scheduler::isSmallDirtyArea(int32_t appId, uint32_t dirtyArea) {
1333*38e8c45fSAndroid Build Coastguard Worker     std::optional<float> oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForAppId(appId);
1334*38e8c45fSAndroid Build Coastguard Worker     if (oThreshold) {
1335*38e8c45fSAndroid Build Coastguard Worker         return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value());
1336*38e8c45fSAndroid Build Coastguard Worker     }
1337*38e8c45fSAndroid Build Coastguard Worker     return false;
1338*38e8c45fSAndroid Build Coastguard Worker }
1339*38e8c45fSAndroid Build Coastguard Worker 
1340*38e8c45fSAndroid Build Coastguard Worker } // namespace android::scheduler
1341