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