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 <common/FlagManager.h>
26 #include <ftl/concat.h>
27 #include <ftl/expected.h>
28 #include <log/log.h>
29 
30 namespace android::display {
31 
32 template <size_t N>
concatId(const char (& str)[N]) const33 inline std::string DisplayModeController::Display::concatId(const char (&str)[N]) const {
34     return std::string(ftl::Concat(str, ' ', snapshot.get().displayId().value).str());
35 }
36 
Display(DisplaySnapshotRef snapshot,RefreshRateSelectorPtr selectorPtr)37 DisplayModeController::Display::Display(DisplaySnapshotRef snapshot,
38                                         RefreshRateSelectorPtr selectorPtr)
39       : snapshot(snapshot),
40         selectorPtr(std::move(selectorPtr)),
41         pendingModeFpsTrace(concatId("PendingModeFps")),
42         activeModeFpsTrace(concatId("ActiveModeFps")),
43         renderRateFpsTrace(concatId("RenderRateFps")),
44         hasDesiredModeTrace(concatId("HasDesiredMode"), false) {}
45 
registerDisplay(PhysicalDisplayId displayId,DisplaySnapshotRef snapshotRef,RefreshRateSelectorPtr selectorPtr)46 void DisplayModeController::registerDisplay(PhysicalDisplayId displayId,
47                                             DisplaySnapshotRef snapshotRef,
48                                             RefreshRateSelectorPtr selectorPtr) {
49     std::lock_guard lock(mDisplayLock);
50     mDisplays.emplace_or_replace(displayId, std::make_unique<Display>(snapshotRef, selectorPtr));
51 }
52 
registerDisplay(DisplaySnapshotRef snapshotRef,DisplayModeId activeModeId,scheduler::RefreshRateSelector::Config config)53 void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
54                                             DisplayModeId activeModeId,
55                                             scheduler::RefreshRateSelector::Config config) {
56     const auto& snapshot = snapshotRef.get();
57     const auto displayId = snapshot.displayId();
58 
59     std::lock_guard lock(mDisplayLock);
60     mDisplays.emplace_or_replace(displayId,
61                                  std::make_unique<Display>(snapshotRef, snapshot.displayModes(),
62                                                            activeModeId, config));
63 }
64 
unregisterDisplay(PhysicalDisplayId displayId)65 void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
66     std::lock_guard lock(mDisplayLock);
67     const bool ok = mDisplays.erase(displayId);
68     ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
69 }
70 
selectorPtrFor(PhysicalDisplayId displayId) const71 auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
72         -> RefreshRateSelectorPtr {
73     std::lock_guard lock(mDisplayLock);
74     return mDisplays.get(displayId)
75             .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
76             .value_or(nullptr);
77 }
78 
setDesiredMode(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode)79 auto DisplayModeController::setDesiredMode(PhysicalDisplayId displayId,
80                                            DisplayModeRequest&& desiredMode) -> DesiredModeAction {
81     std::lock_guard lock(mDisplayLock);
82     const auto& displayPtr =
83             FTL_EXPECT(mDisplays.get(displayId).ok_or(DesiredModeAction::None)).get();
84 
85     {
86         ATRACE_NAME(displayPtr->concatId(__func__).c_str());
87         ALOGD("%s %s", displayPtr->concatId(__func__).c_str(), to_string(desiredMode).c_str());
88 
89         std::scoped_lock lock(displayPtr->desiredModeLock);
90 
91         if (auto& desiredModeOpt = displayPtr->desiredModeOpt) {
92             // A mode transition was already scheduled, so just override the desired mode.
93             const bool emitEvent = desiredModeOpt->emitEvent;
94             const bool force = desiredModeOpt->force;
95             desiredModeOpt = std::move(desiredMode);
96             desiredModeOpt->emitEvent |= emitEvent;
97             if (FlagManager::getInstance().connected_display()) {
98                 desiredModeOpt->force |= force;
99             }
100             return DesiredModeAction::None;
101         }
102 
103         // If the desired mode is already active...
104         const auto activeMode = displayPtr->selectorPtr->getActiveMode();
105         if (const auto& desiredModePtr = desiredMode.mode.modePtr;
106             !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
107             if (activeMode == desiredMode.mode) {
108                 return DesiredModeAction::None;
109             }
110 
111             // ...but the render rate changed:
112             setActiveModeLocked(displayId, desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
113                                 desiredMode.mode.fps);
114             return DesiredModeAction::InitiateRenderRateSwitch;
115         }
116 
117         // Restore peak render rate to schedule the next frame as soon as possible.
118         setActiveModeLocked(displayId, activeMode.modePtr->getId(),
119                             activeMode.modePtr->getVsyncRate(), activeMode.modePtr->getPeakFps());
120 
121         // Initiate a mode change.
122         displayPtr->desiredModeOpt = std::move(desiredMode);
123         displayPtr->hasDesiredModeTrace = true;
124     }
125 
126     return DesiredModeAction::InitiateDisplayModeSwitch;
127 }
128 
getDesiredMode(PhysicalDisplayId displayId) const129 auto DisplayModeController::getDesiredMode(PhysicalDisplayId displayId) const
130         -> DisplayModeRequestOpt {
131     std::lock_guard lock(mDisplayLock);
132     const auto& displayPtr =
133             FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
134 
135     {
136         std::scoped_lock lock(displayPtr->desiredModeLock);
137         return displayPtr->desiredModeOpt;
138     }
139 }
140 
getPendingMode(PhysicalDisplayId displayId) const141 auto DisplayModeController::getPendingMode(PhysicalDisplayId displayId) const
142         -> DisplayModeRequestOpt {
143     std::lock_guard lock(mDisplayLock);
144     const auto& displayPtr =
145             FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
146 
147     {
148         std::scoped_lock lock(displayPtr->desiredModeLock);
149         return displayPtr->pendingModeOpt;
150     }
151 }
152 
isModeSetPending(PhysicalDisplayId displayId) const153 bool DisplayModeController::isModeSetPending(PhysicalDisplayId displayId) const {
154     std::lock_guard lock(mDisplayLock);
155     const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
156 
157     {
158         std::scoped_lock lock(displayPtr->desiredModeLock);
159         return displayPtr->isModeSetPending;
160     }
161 }
162 
getActiveMode(PhysicalDisplayId displayId) const163 scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
164     return selectorPtrFor(displayId)->getActiveMode();
165 }
166 
clearDesiredMode(PhysicalDisplayId displayId)167 void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) {
168     std::lock_guard lock(mDisplayLock);
169     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
170 
171     {
172         std::scoped_lock lock(displayPtr->desiredModeLock);
173         displayPtr->desiredModeOpt.reset();
174         displayPtr->hasDesiredModeTrace = false;
175     }
176 }
177 
initiateModeChange(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode,const hal::VsyncPeriodChangeConstraints & constraints,hal::VsyncPeriodChangeTimeline & outTimeline)178 bool DisplayModeController::initiateModeChange(PhysicalDisplayId displayId,
179                                                DisplayModeRequest&& desiredMode,
180                                                const hal::VsyncPeriodChangeConstraints& constraints,
181                                                hal::VsyncPeriodChangeTimeline& outTimeline) {
182     std::lock_guard lock(mDisplayLock);
183     const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
184 
185     // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states.
186     // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not
187     // cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
188     // consumed at this point, so clear the `force` flag to prevent an endless loop of
189     // `initiateModeChange`.
190     if (FlagManager::getInstance().connected_display()) {
191         std::scoped_lock lock(displayPtr->desiredModeLock);
192         if (displayPtr->desiredModeOpt) {
193             displayPtr->desiredModeOpt->force = false;
194         }
195     }
196 
197     displayPtr->pendingModeOpt = std::move(desiredMode);
198     displayPtr->isModeSetPending = true;
199 
200     const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr;
201 
202     if (mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(), constraints,
203                                                    &outTimeline) != OK) {
204         return false;
205     }
206 
207     ATRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
208     return true;
209 }
210 
finalizeModeChange(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)211 void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId,
212                                                Fps vsyncRate, Fps renderFps) {
213     std::lock_guard lock(mDisplayLock);
214     setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
215 
216     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
217     displayPtr->isModeSetPending = false;
218 }
219 
setActiveMode(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)220 void DisplayModeController::setActiveMode(PhysicalDisplayId displayId, DisplayModeId modeId,
221                                           Fps vsyncRate, Fps renderFps) {
222     std::lock_guard lock(mDisplayLock);
223     setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
224 }
225 
setActiveModeLocked(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)226 void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, DisplayModeId modeId,
227                                                 Fps vsyncRate, Fps renderFps) {
228     const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
229 
230     ATRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
231     ATRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());
232 
233     displayPtr->selectorPtr->setActiveMode(modeId, renderFps);
234 
235     if (mActiveModeListener) {
236         mActiveModeListener(displayId, vsyncRate, renderFps);
237     }
238 }
239 
240 } // namespace android::display
241