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