blob: 0e9218cb93570e23decf313397a34dcf1406b3a5 [file] [log] [blame]
Dominik Laskowski6e465152022-09-28 11:00:25 -04001/*
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"
Dominik Laskowski5c989f52024-04-11 13:57:14 -040023#include "DisplayHardware/HWComposer.h"
Dominik Laskowski6e465152022-09-28 11:00:25 -040024
Dominik Laskowski43839672024-08-04 02:01:48 -040025#include <android-base/properties.h>
Dominik Laskowski5c989f52024-04-11 13:57:14 -040026#include <common/FlagManager.h>
Dominik Laskowski43839672024-08-04 02:01:48 -040027#include <common/trace.h>
Dominik Laskowski5c989f52024-04-11 13:57:14 -040028#include <ftl/concat.h>
29#include <ftl/expected.h>
Dominik Laskowski6e465152022-09-28 11:00:25 -040030#include <log/log.h>
31
32namespace android::display {
33
Dominik Laskowski5c989f52024-04-11 13:57:14 -040034template <size_t N>
35inline std::string DisplayModeController::Display::concatId(const char (&str)[N]) const {
36 return std::string(ftl::Concat(str, ' ', snapshot.get().displayId().value).str());
37}
38
39DisplayModeController::Display::Display(DisplaySnapshotRef snapshot,
40 RefreshRateSelectorPtr selectorPtr)
41 : snapshot(snapshot),
42 selectorPtr(std::move(selectorPtr)),
43 pendingModeFpsTrace(concatId("PendingModeFps")),
44 activeModeFpsTrace(concatId("ActiveModeFps")),
45 renderRateFpsTrace(concatId("RenderRateFps")),
46 hasDesiredModeTrace(concatId("HasDesiredMode"), false) {}
47
48void DisplayModeController::registerDisplay(PhysicalDisplayId displayId,
49 DisplaySnapshotRef snapshotRef,
50 RefreshRateSelectorPtr selectorPtr) {
51 std::lock_guard lock(mDisplayLock);
52 mDisplays.emplace_or_replace(displayId, std::make_unique<Display>(snapshotRef, selectorPtr));
53}
54
Dominik Laskowski6e465152022-09-28 11:00:25 -040055void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
56 DisplayModeId activeModeId,
57 scheduler::RefreshRateSelector::Config config) {
58 const auto& snapshot = snapshotRef.get();
59 const auto displayId = snapshot.displayId();
60
Dominik Laskowski5c989f52024-04-11 13:57:14 -040061 std::lock_guard lock(mDisplayLock);
62 mDisplays.emplace_or_replace(displayId,
63 std::make_unique<Display>(snapshotRef, snapshot.displayModes(),
64 activeModeId, config));
Dominik Laskowski6e465152022-09-28 11:00:25 -040065}
66
67void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
Dominik Laskowski5c989f52024-04-11 13:57:14 -040068 std::lock_guard lock(mDisplayLock);
Dominik Laskowski6e465152022-09-28 11:00:25 -040069 const bool ok = mDisplays.erase(displayId);
70 ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
71}
72
Dominik Laskowski5c989f52024-04-11 13:57:14 -040073auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
74 -> RefreshRateSelectorPtr {
75 std::lock_guard lock(mDisplayLock);
Dominik Laskowski6e465152022-09-28 11:00:25 -040076 return mDisplays.get(displayId)
Dominik Laskowski5c989f52024-04-11 13:57:14 -040077 .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
Dominik Laskowski6e465152022-09-28 11:00:25 -040078 .value_or(nullptr);
79}
80
Dominik Laskowski5c989f52024-04-11 13:57:14 -040081auto DisplayModeController::setDesiredMode(PhysicalDisplayId displayId,
82 DisplayModeRequest&& desiredMode) -> DesiredModeAction {
83 std::lock_guard lock(mDisplayLock);
84 const auto& displayPtr =
85 FTL_EXPECT(mDisplays.get(displayId).ok_or(DesiredModeAction::None)).get();
86
87 {
Vishnu Nairbe0ad902024-06-27 23:38:43 +000088 SFTRACE_NAME(displayPtr->concatId(__func__).c_str());
Dominik Laskowski5c989f52024-04-11 13:57:14 -040089 ALOGD("%s %s", displayPtr->concatId(__func__).c_str(), to_string(desiredMode).c_str());
90
91 std::scoped_lock lock(displayPtr->desiredModeLock);
92
93 if (auto& desiredModeOpt = displayPtr->desiredModeOpt) {
94 // A mode transition was already scheduled, so just override the desired mode.
95 const bool emitEvent = desiredModeOpt->emitEvent;
96 const bool force = desiredModeOpt->force;
97 desiredModeOpt = std::move(desiredMode);
98 desiredModeOpt->emitEvent |= emitEvent;
99 if (FlagManager::getInstance().connected_display()) {
100 desiredModeOpt->force |= force;
101 }
102 return DesiredModeAction::None;
103 }
104
105 // If the desired mode is already active...
106 const auto activeMode = displayPtr->selectorPtr->getActiveMode();
107 if (const auto& desiredModePtr = desiredMode.mode.modePtr;
108 !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
109 if (activeMode == desiredMode.mode) {
110 return DesiredModeAction::None;
111 }
112
113 // ...but the render rate changed:
114 setActiveModeLocked(displayId, desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
115 desiredMode.mode.fps);
116 return DesiredModeAction::InitiateRenderRateSwitch;
117 }
118
119 // Restore peak render rate to schedule the next frame as soon as possible.
120 setActiveModeLocked(displayId, activeMode.modePtr->getId(),
121 activeMode.modePtr->getVsyncRate(), activeMode.modePtr->getPeakFps());
122
123 // Initiate a mode change.
124 displayPtr->desiredModeOpt = std::move(desiredMode);
125 displayPtr->hasDesiredModeTrace = true;
126 }
127
128 return DesiredModeAction::InitiateDisplayModeSwitch;
129}
130
131auto DisplayModeController::getDesiredMode(PhysicalDisplayId displayId) const
132 -> DisplayModeRequestOpt {
133 std::lock_guard lock(mDisplayLock);
134 const auto& displayPtr =
135 FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
136
137 {
138 std::scoped_lock lock(displayPtr->desiredModeLock);
139 return displayPtr->desiredModeOpt;
140 }
141}
142
143auto DisplayModeController::getPendingMode(PhysicalDisplayId displayId) const
144 -> DisplayModeRequestOpt {
145 std::lock_guard lock(mDisplayLock);
146 const auto& displayPtr =
147 FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
148
149 {
150 std::scoped_lock lock(displayPtr->desiredModeLock);
151 return displayPtr->pendingModeOpt;
152 }
153}
154
155bool DisplayModeController::isModeSetPending(PhysicalDisplayId displayId) const {
156 std::lock_guard lock(mDisplayLock);
157 const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
158
159 {
160 std::scoped_lock lock(displayPtr->desiredModeLock);
161 return displayPtr->isModeSetPending;
162 }
163}
164
165scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
166 return selectorPtrFor(displayId)->getActiveMode();
167}
168
169void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) {
170 std::lock_guard lock(mDisplayLock);
171 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
172
173 {
174 std::scoped_lock lock(displayPtr->desiredModeLock);
175 displayPtr->desiredModeOpt.reset();
176 displayPtr->hasDesiredModeTrace = false;
177 }
178}
179
180bool DisplayModeController::initiateModeChange(PhysicalDisplayId displayId,
181 DisplayModeRequest&& desiredMode,
182 const hal::VsyncPeriodChangeConstraints& constraints,
183 hal::VsyncPeriodChangeTimeline& outTimeline) {
184 std::lock_guard lock(mDisplayLock);
185 const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
186
187 // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states.
188 // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not
189 // cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
190 // consumed at this point, so clear the `force` flag to prevent an endless loop of
191 // `initiateModeChange`.
192 if (FlagManager::getInstance().connected_display()) {
193 std::scoped_lock lock(displayPtr->desiredModeLock);
194 if (displayPtr->desiredModeOpt) {
195 displayPtr->desiredModeOpt->force = false;
196 }
197 }
198
199 displayPtr->pendingModeOpt = std::move(desiredMode);
200 displayPtr->isModeSetPending = true;
201
202 const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr;
203
204 if (mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(), constraints,
205 &outTimeline) != OK) {
206 return false;
207 }
208
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000209 SFTRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400210 return true;
211}
212
213void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId,
214 Fps vsyncRate, Fps renderFps) {
215 std::lock_guard lock(mDisplayLock);
216 setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
217
218 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
219 displayPtr->isModeSetPending = false;
220}
221
222void DisplayModeController::setActiveMode(PhysicalDisplayId displayId, DisplayModeId modeId,
223 Fps vsyncRate, Fps renderFps) {
224 std::lock_guard lock(mDisplayLock);
225 setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
226}
227
228void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, DisplayModeId modeId,
229 Fps vsyncRate, Fps renderFps) {
230 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
231
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000232 SFTRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
233 SFTRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400234
235 displayPtr->selectorPtr->setActiveMode(modeId, renderFps);
236
237 if (mActiveModeListener) {
238 mActiveModeListener(displayId, vsyncRate, renderFps);
239 }
240}
241
Dominik Laskowski43839672024-08-04 02:01:48 -0400242void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) {
243 std::lock_guard lock(mDisplayLock);
244 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
245
246 const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController();
247 if (!controllerOpt) return;
248
249 using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction;
250
251 switch (displayPtr->selectorPtr->getIdleTimerAction()) {
252 case KernelIdleTimerAction::TurnOff:
253 if (displayPtr->isKernelIdleTimerEnabled) {
254 SFTRACE_INT("KernelIdleTimer", 0);
255 updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt);
256 displayPtr->isKernelIdleTimerEnabled = false;
257 }
258 break;
259 case KernelIdleTimerAction::TurnOn:
260 if (!displayPtr->isKernelIdleTimerEnabled) {
261 SFTRACE_INT("KernelIdleTimer", 1);
262 const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout();
263 updateKernelIdleTimer(displayId, timeout, *controllerOpt);
264 displayPtr->isKernelIdleTimerEnabled = true;
265 }
266 break;
267 }
268}
269
270void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId,
271 std::chrono::milliseconds timeout,
272 KernelIdleTimerController controller) {
273 switch (controller) {
274 case KernelIdleTimerController::HwcApi:
275 mComposerPtr->setIdleTimerEnabled(displayId, timeout);
276 break;
277
278 case KernelIdleTimerController::Sysprop:
279 using namespace std::string_literals;
280 base::SetProperty("graphics.display.kernel_idle_timer.enabled"s,
281 timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s);
282 break;
283 }
284}
285
286auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const
287 -> KernelIdleTimerState {
288 std::lock_guard lock(mDisplayLock);
289 const auto& displayPtr =
290 FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get();
291
292 const auto desiredModeIdOpt =
293 (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt)
294 .transform([](const display::DisplayModeRequest& request) {
295 return request.mode.modePtr->getId();
296 });
297
298 return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled};
299}
300
Dominik Laskowski6e465152022-09-28 11:00:25 -0400301} // namespace android::display