xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Display/DisplayModeController.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2024 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 "DisplayModeController"
19*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include "Display/DisplayModeController.h"
22*38e8c45fSAndroid Build Coastguard Worker #include "Display/DisplaySnapshot.h"
23*38e8c45fSAndroid Build Coastguard Worker #include "DisplayHardware/HWComposer.h"
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker #include <android-base/properties.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <common/FlagManager.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <ftl/concat.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <ftl/expected.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <utils/Errors.h>
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker namespace android::display {
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker template <size_t N>
concatId(const char (& str)[N]) const36*38e8c45fSAndroid Build Coastguard Worker inline std::string DisplayModeController::Display::concatId(const char (&str)[N]) const {
37*38e8c45fSAndroid Build Coastguard Worker     return std::string(ftl::Concat(str, ' ', snapshot.get().displayId().value).str());
38*38e8c45fSAndroid Build Coastguard Worker }
39*38e8c45fSAndroid Build Coastguard Worker 
Display(DisplaySnapshotRef snapshot,RefreshRateSelectorPtr selectorPtr)40*38e8c45fSAndroid Build Coastguard Worker DisplayModeController::Display::Display(DisplaySnapshotRef snapshot,
41*38e8c45fSAndroid Build Coastguard Worker                                         RefreshRateSelectorPtr selectorPtr)
42*38e8c45fSAndroid Build Coastguard Worker       : snapshot(snapshot),
43*38e8c45fSAndroid Build Coastguard Worker         selectorPtr(std::move(selectorPtr)),
44*38e8c45fSAndroid Build Coastguard Worker         pendingModeFpsTrace(concatId("PendingModeFps")),
45*38e8c45fSAndroid Build Coastguard Worker         activeModeFpsTrace(concatId("ActiveModeFps")),
46*38e8c45fSAndroid Build Coastguard Worker         renderRateFpsTrace(concatId("RenderRateFps")),
47*38e8c45fSAndroid Build Coastguard Worker         hasDesiredModeTrace(concatId("HasDesiredMode"), false) {}
48*38e8c45fSAndroid Build Coastguard Worker 
registerDisplay(PhysicalDisplayId displayId,DisplaySnapshotRef snapshotRef,RefreshRateSelectorPtr selectorPtr)49*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::registerDisplay(PhysicalDisplayId displayId,
50*38e8c45fSAndroid Build Coastguard Worker                                             DisplaySnapshotRef snapshotRef,
51*38e8c45fSAndroid Build Coastguard Worker                                             RefreshRateSelectorPtr selectorPtr) {
52*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
53*38e8c45fSAndroid Build Coastguard Worker     mDisplays.emplace_or_replace(displayId, std::make_unique<Display>(snapshotRef, selectorPtr));
54*38e8c45fSAndroid Build Coastguard Worker }
55*38e8c45fSAndroid Build Coastguard Worker 
registerDisplay(DisplaySnapshotRef snapshotRef,DisplayModeId activeModeId,scheduler::RefreshRateSelector::Config config)56*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
57*38e8c45fSAndroid Build Coastguard Worker                                             DisplayModeId activeModeId,
58*38e8c45fSAndroid Build Coastguard Worker                                             scheduler::RefreshRateSelector::Config config) {
59*38e8c45fSAndroid Build Coastguard Worker     const auto& snapshot = snapshotRef.get();
60*38e8c45fSAndroid Build Coastguard Worker     const auto displayId = snapshot.displayId();
61*38e8c45fSAndroid Build Coastguard Worker 
62*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
63*38e8c45fSAndroid Build Coastguard Worker     mDisplays.emplace_or_replace(displayId,
64*38e8c45fSAndroid Build Coastguard Worker                                  std::make_unique<Display>(snapshotRef, snapshot.displayModes(),
65*38e8c45fSAndroid Build Coastguard Worker                                                            activeModeId, config));
66*38e8c45fSAndroid Build Coastguard Worker }
67*38e8c45fSAndroid Build Coastguard Worker 
unregisterDisplay(PhysicalDisplayId displayId)68*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
69*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
70*38e8c45fSAndroid Build Coastguard Worker     const bool ok = mDisplays.erase(displayId);
71*38e8c45fSAndroid Build Coastguard Worker     ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
72*38e8c45fSAndroid Build Coastguard Worker }
73*38e8c45fSAndroid Build Coastguard Worker 
selectorPtrFor(PhysicalDisplayId displayId) const74*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
75*38e8c45fSAndroid Build Coastguard Worker         -> RefreshRateSelectorPtr {
76*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
77*38e8c45fSAndroid Build Coastguard Worker     return mDisplays.get(displayId)
78*38e8c45fSAndroid Build Coastguard Worker             .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
79*38e8c45fSAndroid Build Coastguard Worker             .value_or(nullptr);
80*38e8c45fSAndroid Build Coastguard Worker }
81*38e8c45fSAndroid Build Coastguard Worker 
setDesiredMode(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode)82*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::setDesiredMode(PhysicalDisplayId displayId,
83*38e8c45fSAndroid Build Coastguard Worker                                            DisplayModeRequest&& desiredMode) -> DesiredModeAction {
84*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
85*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr =
86*38e8c45fSAndroid Build Coastguard Worker             FTL_EXPECT(mDisplays.get(displayId).ok_or(DesiredModeAction::None)).get();
87*38e8c45fSAndroid Build Coastguard Worker 
88*38e8c45fSAndroid Build Coastguard Worker     {
89*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_NAME(displayPtr->concatId(__func__).c_str());
90*38e8c45fSAndroid Build Coastguard Worker         ALOGD("%s %s", displayPtr->concatId(__func__).c_str(), to_string(desiredMode).c_str());
91*38e8c45fSAndroid Build Coastguard Worker 
92*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
93*38e8c45fSAndroid Build Coastguard Worker 
94*38e8c45fSAndroid Build Coastguard Worker         if (auto& desiredModeOpt = displayPtr->desiredModeOpt) {
95*38e8c45fSAndroid Build Coastguard Worker             // A mode transition was already scheduled, so just override the desired mode.
96*38e8c45fSAndroid Build Coastguard Worker             const bool emitEvent = desiredModeOpt->emitEvent;
97*38e8c45fSAndroid Build Coastguard Worker             const bool force = desiredModeOpt->force;
98*38e8c45fSAndroid Build Coastguard Worker             desiredModeOpt = std::move(desiredMode);
99*38e8c45fSAndroid Build Coastguard Worker             desiredModeOpt->emitEvent |= emitEvent;
100*38e8c45fSAndroid Build Coastguard Worker             if (FlagManager::getInstance().connected_display()) {
101*38e8c45fSAndroid Build Coastguard Worker                 desiredModeOpt->force |= force;
102*38e8c45fSAndroid Build Coastguard Worker             }
103*38e8c45fSAndroid Build Coastguard Worker             return DesiredModeAction::None;
104*38e8c45fSAndroid Build Coastguard Worker         }
105*38e8c45fSAndroid Build Coastguard Worker 
106*38e8c45fSAndroid Build Coastguard Worker         // If the desired mode is already active...
107*38e8c45fSAndroid Build Coastguard Worker         const auto activeMode = displayPtr->selectorPtr->getActiveMode();
108*38e8c45fSAndroid Build Coastguard Worker         if (const auto& desiredModePtr = desiredMode.mode.modePtr;
109*38e8c45fSAndroid Build Coastguard Worker             !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
110*38e8c45fSAndroid Build Coastguard Worker             if (activeMode == desiredMode.mode) {
111*38e8c45fSAndroid Build Coastguard Worker                 return DesiredModeAction::None;
112*38e8c45fSAndroid Build Coastguard Worker             }
113*38e8c45fSAndroid Build Coastguard Worker 
114*38e8c45fSAndroid Build Coastguard Worker             // ...but the render rate changed:
115*38e8c45fSAndroid Build Coastguard Worker             setActiveModeLocked(displayId, desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
116*38e8c45fSAndroid Build Coastguard Worker                                 desiredMode.mode.fps);
117*38e8c45fSAndroid Build Coastguard Worker             return DesiredModeAction::InitiateRenderRateSwitch;
118*38e8c45fSAndroid Build Coastguard Worker         }
119*38e8c45fSAndroid Build Coastguard Worker 
120*38e8c45fSAndroid Build Coastguard Worker         // Restore peak render rate to schedule the next frame as soon as possible.
121*38e8c45fSAndroid Build Coastguard Worker         setActiveModeLocked(displayId, activeMode.modePtr->getId(),
122*38e8c45fSAndroid Build Coastguard Worker                             activeMode.modePtr->getVsyncRate(), activeMode.modePtr->getPeakFps());
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker         // Initiate a mode change.
125*38e8c45fSAndroid Build Coastguard Worker         displayPtr->desiredModeOpt = std::move(desiredMode);
126*38e8c45fSAndroid Build Coastguard Worker         displayPtr->hasDesiredModeTrace = true;
127*38e8c45fSAndroid Build Coastguard Worker     }
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker     return DesiredModeAction::InitiateDisplayModeSwitch;
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker 
getDesiredMode(PhysicalDisplayId displayId) const132*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::getDesiredMode(PhysicalDisplayId displayId) const
133*38e8c45fSAndroid Build Coastguard Worker         -> DisplayModeRequestOpt {
134*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
135*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr =
136*38e8c45fSAndroid Build Coastguard Worker             FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
137*38e8c45fSAndroid Build Coastguard Worker 
138*38e8c45fSAndroid Build Coastguard Worker     {
139*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
140*38e8c45fSAndroid Build Coastguard Worker         return displayPtr->desiredModeOpt;
141*38e8c45fSAndroid Build Coastguard Worker     }
142*38e8c45fSAndroid Build Coastguard Worker }
143*38e8c45fSAndroid Build Coastguard Worker 
getPendingMode(PhysicalDisplayId displayId) const144*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::getPendingMode(PhysicalDisplayId displayId) const
145*38e8c45fSAndroid Build Coastguard Worker         -> DisplayModeRequestOpt {
146*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
147*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr =
148*38e8c45fSAndroid Build Coastguard Worker             FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
149*38e8c45fSAndroid Build Coastguard Worker 
150*38e8c45fSAndroid Build Coastguard Worker     {
151*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
152*38e8c45fSAndroid Build Coastguard Worker         return displayPtr->pendingModeOpt;
153*38e8c45fSAndroid Build Coastguard Worker     }
154*38e8c45fSAndroid Build Coastguard Worker }
155*38e8c45fSAndroid Build Coastguard Worker 
isModeSetPending(PhysicalDisplayId displayId) const156*38e8c45fSAndroid Build Coastguard Worker bool DisplayModeController::isModeSetPending(PhysicalDisplayId displayId) const {
157*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
158*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker     {
161*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
162*38e8c45fSAndroid Build Coastguard Worker         return displayPtr->isModeSetPending;
163*38e8c45fSAndroid Build Coastguard Worker     }
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker 
getActiveMode(PhysicalDisplayId displayId) const166*38e8c45fSAndroid Build Coastguard Worker scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
167*38e8c45fSAndroid Build Coastguard Worker     return selectorPtrFor(displayId)->getActiveMode();
168*38e8c45fSAndroid Build Coastguard Worker }
169*38e8c45fSAndroid Build Coastguard Worker 
clearDesiredMode(PhysicalDisplayId displayId)170*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) {
171*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
172*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
173*38e8c45fSAndroid Build Coastguard Worker 
174*38e8c45fSAndroid Build Coastguard Worker     {
175*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
176*38e8c45fSAndroid Build Coastguard Worker         displayPtr->desiredModeOpt.reset();
177*38e8c45fSAndroid Build Coastguard Worker         displayPtr->hasDesiredModeTrace = false;
178*38e8c45fSAndroid Build Coastguard Worker     }
179*38e8c45fSAndroid Build Coastguard Worker }
180*38e8c45fSAndroid Build Coastguard Worker 
initiateModeChange(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode,const hal::VsyncPeriodChangeConstraints & constraints,hal::VsyncPeriodChangeTimeline & outTimeline)181*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::initiateModeChange(
182*38e8c45fSAndroid Build Coastguard Worker         PhysicalDisplayId displayId, DisplayModeRequest&& desiredMode,
183*38e8c45fSAndroid Build Coastguard Worker         const hal::VsyncPeriodChangeConstraints& constraints,
184*38e8c45fSAndroid Build Coastguard Worker         hal::VsyncPeriodChangeTimeline& outTimeline) -> ModeChangeResult {
185*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
186*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr =
187*38e8c45fSAndroid Build Coastguard Worker             FTL_EXPECT(mDisplays.get(displayId).ok_or(ModeChangeResult::Aborted)).get();
188*38e8c45fSAndroid Build Coastguard Worker 
189*38e8c45fSAndroid Build Coastguard Worker     // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states.
190*38e8c45fSAndroid Build Coastguard Worker     // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not
191*38e8c45fSAndroid Build Coastguard Worker     // cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
192*38e8c45fSAndroid Build Coastguard Worker     // consumed at this point, so clear the `force` flag to prevent an endless loop of
193*38e8c45fSAndroid Build Coastguard Worker     // `initiateModeChange`.
194*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().connected_display()) {
195*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock lock(displayPtr->desiredModeLock);
196*38e8c45fSAndroid Build Coastguard Worker         if (displayPtr->desiredModeOpt) {
197*38e8c45fSAndroid Build Coastguard Worker             displayPtr->desiredModeOpt->force = false;
198*38e8c45fSAndroid Build Coastguard Worker         }
199*38e8c45fSAndroid Build Coastguard Worker     }
200*38e8c45fSAndroid Build Coastguard Worker 
201*38e8c45fSAndroid Build Coastguard Worker     displayPtr->pendingModeOpt = std::move(desiredMode);
202*38e8c45fSAndroid Build Coastguard Worker     displayPtr->isModeSetPending = true;
203*38e8c45fSAndroid Build Coastguard Worker 
204*38e8c45fSAndroid Build Coastguard Worker     const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr;
205*38e8c45fSAndroid Build Coastguard Worker 
206*38e8c45fSAndroid Build Coastguard Worker     const auto error = mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(),
207*38e8c45fSAndroid Build Coastguard Worker                                                                   constraints, &outTimeline);
208*38e8c45fSAndroid Build Coastguard Worker     switch (error) {
209*38e8c45fSAndroid Build Coastguard Worker         case FAILED_TRANSACTION:
210*38e8c45fSAndroid Build Coastguard Worker             return ModeChangeResult::Rejected;
211*38e8c45fSAndroid Build Coastguard Worker         case OK:
212*38e8c45fSAndroid Build Coastguard Worker             SFTRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
213*38e8c45fSAndroid Build Coastguard Worker             return ModeChangeResult::Changed;
214*38e8c45fSAndroid Build Coastguard Worker         default:
215*38e8c45fSAndroid Build Coastguard Worker             return ModeChangeResult::Aborted;
216*38e8c45fSAndroid Build Coastguard Worker     }
217*38e8c45fSAndroid Build Coastguard Worker }
218*38e8c45fSAndroid Build Coastguard Worker 
finalizeModeChange(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)219*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId,
220*38e8c45fSAndroid Build Coastguard Worker                                                Fps vsyncRate, Fps renderFps) {
221*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
222*38e8c45fSAndroid Build Coastguard Worker     setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
225*38e8c45fSAndroid Build Coastguard Worker     displayPtr->isModeSetPending = false;
226*38e8c45fSAndroid Build Coastguard Worker }
227*38e8c45fSAndroid Build Coastguard Worker 
setActiveMode(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)228*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::setActiveMode(PhysicalDisplayId displayId, DisplayModeId modeId,
229*38e8c45fSAndroid Build Coastguard Worker                                           Fps vsyncRate, Fps renderFps) {
230*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
231*38e8c45fSAndroid Build Coastguard Worker     setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
232*38e8c45fSAndroid Build Coastguard Worker }
233*38e8c45fSAndroid Build Coastguard Worker 
setActiveModeLocked(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)234*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, DisplayModeId modeId,
235*38e8c45fSAndroid Build Coastguard Worker                                                 Fps vsyncRate, Fps renderFps) {
236*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
237*38e8c45fSAndroid Build Coastguard Worker 
238*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
239*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());
240*38e8c45fSAndroid Build Coastguard Worker 
241*38e8c45fSAndroid Build Coastguard Worker     displayPtr->selectorPtr->setActiveMode(modeId, renderFps);
242*38e8c45fSAndroid Build Coastguard Worker 
243*38e8c45fSAndroid Build Coastguard Worker     if (mActiveModeListener) {
244*38e8c45fSAndroid Build Coastguard Worker         mActiveModeListener(displayId, vsyncRate, renderFps);
245*38e8c45fSAndroid Build Coastguard Worker     }
246*38e8c45fSAndroid Build Coastguard Worker }
247*38e8c45fSAndroid Build Coastguard Worker 
updateKernelIdleTimer(PhysicalDisplayId displayId)248*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) {
249*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
250*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
251*38e8c45fSAndroid Build Coastguard Worker 
252*38e8c45fSAndroid Build Coastguard Worker     const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController();
253*38e8c45fSAndroid Build Coastguard Worker     if (!controllerOpt) return;
254*38e8c45fSAndroid Build Coastguard Worker 
255*38e8c45fSAndroid Build Coastguard Worker     using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction;
256*38e8c45fSAndroid Build Coastguard Worker 
257*38e8c45fSAndroid Build Coastguard Worker     switch (displayPtr->selectorPtr->getIdleTimerAction()) {
258*38e8c45fSAndroid Build Coastguard Worker         case KernelIdleTimerAction::TurnOff:
259*38e8c45fSAndroid Build Coastguard Worker             if (displayPtr->isKernelIdleTimerEnabled) {
260*38e8c45fSAndroid Build Coastguard Worker                 SFTRACE_INT("KernelIdleTimer", 0);
261*38e8c45fSAndroid Build Coastguard Worker                 updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt);
262*38e8c45fSAndroid Build Coastguard Worker                 displayPtr->isKernelIdleTimerEnabled = false;
263*38e8c45fSAndroid Build Coastguard Worker             }
264*38e8c45fSAndroid Build Coastguard Worker             break;
265*38e8c45fSAndroid Build Coastguard Worker         case KernelIdleTimerAction::TurnOn:
266*38e8c45fSAndroid Build Coastguard Worker             if (!displayPtr->isKernelIdleTimerEnabled) {
267*38e8c45fSAndroid Build Coastguard Worker                 SFTRACE_INT("KernelIdleTimer", 1);
268*38e8c45fSAndroid Build Coastguard Worker                 const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout();
269*38e8c45fSAndroid Build Coastguard Worker                 updateKernelIdleTimer(displayId, timeout, *controllerOpt);
270*38e8c45fSAndroid Build Coastguard Worker                 displayPtr->isKernelIdleTimerEnabled = true;
271*38e8c45fSAndroid Build Coastguard Worker             }
272*38e8c45fSAndroid Build Coastguard Worker             break;
273*38e8c45fSAndroid Build Coastguard Worker     }
274*38e8c45fSAndroid Build Coastguard Worker }
275*38e8c45fSAndroid Build Coastguard Worker 
updateKernelIdleTimer(PhysicalDisplayId displayId,std::chrono::milliseconds timeout,KernelIdleTimerController controller)276*38e8c45fSAndroid Build Coastguard Worker void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId,
277*38e8c45fSAndroid Build Coastguard Worker                                                   std::chrono::milliseconds timeout,
278*38e8c45fSAndroid Build Coastguard Worker                                                   KernelIdleTimerController controller) {
279*38e8c45fSAndroid Build Coastguard Worker     switch (controller) {
280*38e8c45fSAndroid Build Coastguard Worker         case KernelIdleTimerController::HwcApi:
281*38e8c45fSAndroid Build Coastguard Worker             mComposerPtr->setIdleTimerEnabled(displayId, timeout);
282*38e8c45fSAndroid Build Coastguard Worker             break;
283*38e8c45fSAndroid Build Coastguard Worker 
284*38e8c45fSAndroid Build Coastguard Worker         case KernelIdleTimerController::Sysprop:
285*38e8c45fSAndroid Build Coastguard Worker             using namespace std::string_literals;
286*38e8c45fSAndroid Build Coastguard Worker             base::SetProperty("graphics.display.kernel_idle_timer.enabled"s,
287*38e8c45fSAndroid Build Coastguard Worker                               timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s);
288*38e8c45fSAndroid Build Coastguard Worker             break;
289*38e8c45fSAndroid Build Coastguard Worker     }
290*38e8c45fSAndroid Build Coastguard Worker }
291*38e8c45fSAndroid Build Coastguard Worker 
292*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
293*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-value" // b/369277774
getKernelIdleTimerState(PhysicalDisplayId displayId) const294*38e8c45fSAndroid Build Coastguard Worker auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const
295*38e8c45fSAndroid Build Coastguard Worker         -> KernelIdleTimerState {
296*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mDisplayLock);
297*38e8c45fSAndroid Build Coastguard Worker     const auto& displayPtr =
298*38e8c45fSAndroid Build Coastguard Worker             FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get();
299*38e8c45fSAndroid Build Coastguard Worker 
300*38e8c45fSAndroid Build Coastguard Worker     const auto desiredModeIdOpt =
301*38e8c45fSAndroid Build Coastguard Worker             (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt)
302*38e8c45fSAndroid Build Coastguard Worker                     .transform([](const display::DisplayModeRequest& request) {
303*38e8c45fSAndroid Build Coastguard Worker                         return request.mode.modePtr->getId();
304*38e8c45fSAndroid Build Coastguard Worker                     });
305*38e8c45fSAndroid Build Coastguard Worker 
306*38e8c45fSAndroid Build Coastguard Worker     return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled};
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker 
309*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
310*38e8c45fSAndroid Build Coastguard Worker } // namespace android::display
311