• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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