blob: a086aee84713f7854a318c41461dd9252f1d26d5 [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>
Manasi Navarefc2a4a72024-11-12 23:59:21 +000031#include <utils/Errors.h>
Dominik Laskowski6e465152022-09-28 11:00:25 -040032
33namespace android::display {
34
Dominik Laskowski5c989f52024-04-11 13:57:14 -040035template <size_t N>
36inline std::string DisplayModeController::Display::concatId(const char (&str)[N]) const {
37 return std::string(ftl::Concat(str, ' ', snapshot.get().displayId().value).str());
38}
39
40DisplayModeController::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
49void 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
Dominik Laskowski6e465152022-09-28 11:00:25 -040056void 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
Dominik Laskowski5c989f52024-04-11 13:57:14 -040062 std::lock_guard lock(mDisplayLock);
63 mDisplays.emplace_or_replace(displayId,
64 std::make_unique<Display>(snapshotRef, snapshot.displayModes(),
65 activeModeId, config));
Dominik Laskowski6e465152022-09-28 11:00:25 -040066}
67
68void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
Dominik Laskowski5c989f52024-04-11 13:57:14 -040069 std::lock_guard lock(mDisplayLock);
Dominik Laskowski6e465152022-09-28 11:00:25 -040070 const bool ok = mDisplays.erase(displayId);
71 ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
72}
73
Dominik Laskowski5c989f52024-04-11 13:57:14 -040074auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
75 -> RefreshRateSelectorPtr {
76 std::lock_guard lock(mDisplayLock);
Dominik Laskowski6e465152022-09-28 11:00:25 -040077 return mDisplays.get(displayId)
Dominik Laskowski5c989f52024-04-11 13:57:14 -040078 .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
Dominik Laskowski6e465152022-09-28 11:00:25 -040079 .value_or(nullptr);
80}
81
Dominik Laskowski5c989f52024-04-11 13:57:14 -040082auto 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 {
Vishnu Nairbe0ad902024-06-27 23:38:43 +000089 SFTRACE_NAME(displayPtr->concatId(__func__).c_str());
Dominik Laskowski5c989f52024-04-11 13:57:14 -040090 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
132auto 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
144auto 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
156bool 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
166scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
167 return selectorPtrFor(displayId)->getActiveMode();
168}
169
170void 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
Manasi Navarefc2a4a72024-11-12 23:59:21 +0000181auto DisplayModeController::initiateModeChange(
182 PhysicalDisplayId displayId, DisplayModeRequest&& desiredMode,
183 const hal::VsyncPeriodChangeConstraints& constraints,
184 hal::VsyncPeriodChangeTimeline& outTimeline) -> ModeChangeResult {
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400185 std::lock_guard lock(mDisplayLock);
Manasi Navarefc2a4a72024-11-12 23:59:21 +0000186 const auto& displayPtr =
187 FTL_EXPECT(mDisplays.get(displayId).ok_or(ModeChangeResult::Aborted)).get();
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400188
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
Manasi Navarefc2a4a72024-11-12 23:59:21 +0000206 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;
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400216 }
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400217}
218
219void 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
228void 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
234void 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
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000238 SFTRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
239 SFTRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());
Dominik Laskowski5c989f52024-04-11 13:57:14 -0400240
241 displayPtr->selectorPtr->setActiveMode(modeId, renderFps);
242
243 if (mActiveModeListener) {
244 mActiveModeListener(displayId, vsyncRate, renderFps);
245 }
246}
247
Dominik Laskowski43839672024-08-04 02:01:48 -0400248void 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
276void 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
Aditya Kumar4648b7e2024-09-26 20:44:18 +0000292#pragma clang diagnostic push
293#pragma clang diagnostic ignored "-Wunused-value" // b/369277774
Dominik Laskowski43839672024-08-04 02:01:48 -0400294auto 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
Aditya Kumar4648b7e2024-09-26 20:44:18 +0000309#pragma clang diagnostic pop
Dominik Laskowski6e465152022-09-28 11:00:25 -0400310} // namespace android::display