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
DisplayModeController()49 DisplayModeController::DisplayModeController() {
50 using namespace std::string_literals;
51 mSupportsHdcp = base::GetBoolProperty("debug.sf.hdcp_support"s, false);
52 }
53
registerDisplay(PhysicalDisplayId displayId,DisplaySnapshotRef snapshotRef,RefreshRateSelectorPtr selectorPtr)54 void DisplayModeController::registerDisplay(PhysicalDisplayId displayId,
55 DisplaySnapshotRef snapshotRef,
56 RefreshRateSelectorPtr selectorPtr) {
57 DisplayPtr displayPtr = std::make_unique<Display>(snapshotRef, selectorPtr);
58 // TODO: b/349703362 - Remove first condition when HDCP aidl APIs are enforced
59 displayPtr->setSecure(!supportsHdcp() ||
60 snapshotRef.get().connectionType() ==
61 ui::DisplayConnectionType::Internal);
62 std::lock_guard lock(mDisplayLock);
63 mDisplays.emplace_or_replace(displayId, std::move(displayPtr));
64 }
65
registerDisplay(DisplaySnapshotRef snapshotRef,DisplayModeId activeModeId,scheduler::RefreshRateSelector::Config config)66 void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
67 DisplayModeId activeModeId,
68 scheduler::RefreshRateSelector::Config config) {
69 const auto& snapshot = snapshotRef.get();
70 const auto displayId = snapshot.displayId();
71 DisplayPtr displayPtr =
72 std::make_unique<Display>(snapshotRef, snapshot.displayModes(), activeModeId, config);
73 // TODO: b/349703362 - Remove first condition when HDCP aidl APIs are enforced
74 displayPtr->setSecure(!supportsHdcp() ||
75 snapshotRef.get().connectionType() ==
76 ui::DisplayConnectionType::Internal);
77 std::lock_guard lock(mDisplayLock);
78 mDisplays.emplace_or_replace(displayId, std::move(displayPtr));
79 }
80
unregisterDisplay(PhysicalDisplayId displayId)81 void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
82 std::lock_guard lock(mDisplayLock);
83 const bool ok = mDisplays.erase(displayId);
84 ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
85 }
86
selectorPtrFor(PhysicalDisplayId displayId) const87 auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
88 -> RefreshRateSelectorPtr {
89 std::lock_guard lock(mDisplayLock);
90 return mDisplays.get(displayId)
91 .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
92 .value_or(nullptr);
93 }
94
setDesiredMode(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode)95 auto DisplayModeController::setDesiredMode(PhysicalDisplayId displayId,
96 DisplayModeRequest&& desiredMode) -> DesiredModeAction {
97 std::lock_guard lock(mDisplayLock);
98 const auto& displayPtr =
99 FTL_EXPECT(mDisplays.get(displayId).ok_or(DesiredModeAction::None)).get();
100
101 {
102 SFTRACE_NAME(displayPtr->concatId(__func__).c_str());
103 ALOGD("%s %s", displayPtr->concatId(__func__).c_str(), to_string(desiredMode).c_str());
104
105 std::scoped_lock lock(displayPtr->desiredModeLock);
106
107 if (auto& desiredModeOpt = displayPtr->desiredModeOpt) {
108 // A mode transition was already scheduled, so just override the desired mode.
109 const bool emitEvent = desiredModeOpt->emitEvent;
110 const bool force = desiredModeOpt->force;
111 desiredModeOpt = std::move(desiredMode);
112 desiredModeOpt->emitEvent |= emitEvent;
113 desiredModeOpt->force |= force;
114 return DesiredModeAction::None;
115 }
116
117 // If the desired mode is already active...
118 const auto activeMode = displayPtr->selectorPtr->getActiveMode();
119 if (const auto& desiredModePtr = desiredMode.mode.modePtr;
120 !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
121 if (activeMode == desiredMode.mode) {
122 return DesiredModeAction::None;
123 }
124
125 // ...but the render rate changed:
126 setActiveModeLocked(displayId, desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
127 desiredMode.mode.fps);
128 return DesiredModeAction::InitiateRenderRateSwitch;
129 }
130
131 // Restore peak render rate to schedule the next frame as soon as possible.
132 setActiveModeLocked(displayId, activeMode.modePtr->getId(),
133 activeMode.modePtr->getVsyncRate(), activeMode.modePtr->getPeakFps());
134
135 // Initiate a mode change.
136 displayPtr->desiredModeOpt = std::move(desiredMode);
137 displayPtr->hasDesiredModeTrace = true;
138 }
139
140 return DesiredModeAction::InitiateDisplayModeSwitch;
141 }
142
getDesiredMode(PhysicalDisplayId displayId) const143 auto DisplayModeController::getDesiredMode(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->desiredModeOpt;
152 }
153 }
154
getPendingMode(PhysicalDisplayId displayId) const155 auto DisplayModeController::getPendingMode(PhysicalDisplayId displayId) const
156 -> DisplayModeRequestOpt {
157 std::lock_guard lock(mDisplayLock);
158 const auto& displayPtr =
159 FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();
160
161 {
162 std::scoped_lock lock(displayPtr->desiredModeLock);
163 return displayPtr->pendingModeOpt;
164 }
165 }
166
isModeSetPending(PhysicalDisplayId displayId) const167 bool DisplayModeController::isModeSetPending(PhysicalDisplayId displayId) const {
168 std::lock_guard lock(mDisplayLock);
169 const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();
170
171 {
172 std::scoped_lock lock(displayPtr->desiredModeLock);
173 return displayPtr->isModeSetPending;
174 }
175 }
176
getActiveMode(PhysicalDisplayId displayId) const177 scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
178 return selectorPtrFor(displayId)->getActiveMode();
179 }
180
clearDesiredMode(PhysicalDisplayId displayId)181 void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) {
182 std::lock_guard lock(mDisplayLock);
183 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
184
185 {
186 std::scoped_lock lock(displayPtr->desiredModeLock);
187 displayPtr->desiredModeOpt.reset();
188 displayPtr->hasDesiredModeTrace = false;
189 }
190 }
191
initiateModeChange(PhysicalDisplayId displayId,DisplayModeRequest && desiredMode,const hal::VsyncPeriodChangeConstraints & constraints,hal::VsyncPeriodChangeTimeline & outTimeline)192 auto DisplayModeController::initiateModeChange(
193 PhysicalDisplayId displayId, DisplayModeRequest&& desiredMode,
194 const hal::VsyncPeriodChangeConstraints& constraints,
195 hal::VsyncPeriodChangeTimeline& outTimeline) -> ModeChangeResult {
196 std::lock_guard lock(mDisplayLock);
197 const auto& displayPtr =
198 FTL_EXPECT(mDisplays.get(displayId).ok_or(ModeChangeResult::Aborted)).get();
199
200 // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states.
201 // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not
202 // cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
203 // consumed at this point, so clear the `force` flag to prevent an endless loop of
204 // `initiateModeChange`.
205 {
206 std::scoped_lock lock(displayPtr->desiredModeLock);
207 if (displayPtr->desiredModeOpt) {
208 displayPtr->desiredModeOpt->force = false;
209 }
210 }
211
212 displayPtr->pendingModeOpt = std::move(desiredMode);
213 displayPtr->isModeSetPending = true;
214
215 const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr;
216
217 const auto error = mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(),
218 constraints, &outTimeline);
219 switch (error) {
220 case FAILED_TRANSACTION:
221 return ModeChangeResult::Rejected;
222 case OK:
223 SFTRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
224 return ModeChangeResult::Changed;
225 default:
226 return ModeChangeResult::Aborted;
227 }
228 }
229
finalizeModeChange(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)230 void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId,
231 Fps vsyncRate, Fps renderFps) {
232 std::lock_guard lock(mDisplayLock);
233 setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
234
235 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
236 displayPtr->isModeSetPending = false;
237 }
238
setActiveMode(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)239 void DisplayModeController::setActiveMode(PhysicalDisplayId displayId, DisplayModeId modeId,
240 Fps vsyncRate, Fps renderFps) {
241 std::lock_guard lock(mDisplayLock);
242 setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
243 }
244
setActiveModeLocked(PhysicalDisplayId displayId,DisplayModeId modeId,Fps vsyncRate,Fps renderFps)245 void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, DisplayModeId modeId,
246 Fps vsyncRate, Fps renderFps) {
247 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
248
249 SFTRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
250 SFTRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());
251
252 displayPtr->selectorPtr->setActiveMode(modeId, renderFps);
253
254 if (mActiveModeListener) {
255 mActiveModeListener(displayId, vsyncRate, renderFps);
256 }
257 }
258
updateKernelIdleTimer(PhysicalDisplayId displayId)259 void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) {
260 std::lock_guard lock(mDisplayLock);
261 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
262
263 const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController();
264 if (!controllerOpt) return;
265
266 using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction;
267
268 switch (displayPtr->selectorPtr->getIdleTimerAction()) {
269 case KernelIdleTimerAction::TurnOff:
270 if (displayPtr->isKernelIdleTimerEnabled) {
271 SFTRACE_INT("KernelIdleTimer", 0);
272 updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt);
273 displayPtr->isKernelIdleTimerEnabled = false;
274 }
275 break;
276 case KernelIdleTimerAction::TurnOn:
277 if (!displayPtr->isKernelIdleTimerEnabled) {
278 SFTRACE_INT("KernelIdleTimer", 1);
279 const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout();
280 updateKernelIdleTimer(displayId, timeout, *controllerOpt);
281 displayPtr->isKernelIdleTimerEnabled = true;
282 }
283 break;
284 }
285 }
286
updateKernelIdleTimer(PhysicalDisplayId displayId,std::chrono::milliseconds timeout,KernelIdleTimerController controller)287 void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId,
288 std::chrono::milliseconds timeout,
289 KernelIdleTimerController controller) {
290 switch (controller) {
291 case KernelIdleTimerController::HwcApi:
292 mComposerPtr->setIdleTimerEnabled(displayId, timeout);
293 break;
294
295 case KernelIdleTimerController::Sysprop:
296 using namespace std::string_literals;
297 base::SetProperty("graphics.display.kernel_idle_timer.enabled"s,
298 timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s);
299 break;
300 }
301 }
302
303 #pragma clang diagnostic push
304 #pragma clang diagnostic ignored "-Wunused-value" // b/369277774
getKernelIdleTimerState(PhysicalDisplayId displayId) const305 auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const
306 -> KernelIdleTimerState {
307 std::lock_guard lock(mDisplayLock);
308 const auto& displayPtr =
309 FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get();
310
311 const auto desiredModeIdOpt =
312 (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt)
313 .transform([](const display::DisplayModeRequest& request) {
314 return request.mode.modePtr->getId();
315 });
316
317 return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled};
318 }
319
supportsHdcp() const320 bool DisplayModeController::supportsHdcp() const {
321 return mSupportsHdcp && FlagManager::getInstance().hdcp_level_hal() &&
322 FlagManager::getInstance().hdcp_negotiation();
323 }
324
startHdcpNegotiation(PhysicalDisplayId displayId)325 void DisplayModeController::startHdcpNegotiation(PhysicalDisplayId displayId) {
326 using aidl::android::hardware::drm::HdcpLevel;
327 using aidl::android::hardware::drm::HdcpLevels;
328 constexpr HdcpLevels kLevels = {.connectedLevel = HdcpLevel::HDCP_V2_1,
329 .maxLevel = HdcpLevel::HDCP_V2_3};
330
331 std::lock_guard lock(mDisplayLock);
332 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
333 if (displayPtr->hdcpState == HdcpState::Desired) {
334 const auto status = mComposerPtr->startHdcpNegotiation(displayId, kLevels);
335 displayPtr->hdcpState = (status == NO_ERROR) ? HdcpState::Enabled : HdcpState::Undesired;
336 }
337 }
338
setSecure(PhysicalDisplayId displayId,bool secure)339 void DisplayModeController::setSecure(PhysicalDisplayId displayId, bool secure) {
340 std::lock_guard lock(mDisplayLock);
341 const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
342 displayPtr->setSecure(secure);
343 }
344
345 #pragma clang diagnostic pop
346 } // namespace android::display
347