1 /*
2  * Copyright 2018 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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #include "Scheduler.h"
20 
21 #include <algorithm>
22 #include <cinttypes>
23 #include <cstdint>
24 #include <memory>
25 #include <numeric>
26 
27 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
28 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
29 #include <configstore/Utils.h>
30 #include <cutils/properties.h>
31 #include <input/InputWindow.h>
32 #include <system/window.h>
33 #include <ui/DisplayStatInfo.h>
34 #include <utils/Timers.h>
35 #include <utils/Trace.h>
36 
37 #include "DispSync.h"
38 #include "DispSyncSource.h"
39 #include "EventControlThread.h"
40 #include "EventThread.h"
41 #include "IdleTimer.h"
42 #include "InjectVSyncSource.h"
43 #include "LayerInfo.h"
44 #include "SchedulerUtils.h"
45 #include "SurfaceFlingerProperties.h"
46 
47 namespace android {
48 
49 using namespace android::hardware::configstore;
50 using namespace android::hardware::configstore::V1_0;
51 using namespace android::sysprop;
52 
53 #define RETURN_VALUE_IF_INVALID(value) \
54     if (handle == nullptr || mConnections.count(handle->id) == 0) return value
55 #define RETURN_IF_INVALID() \
56     if (handle == nullptr || mConnections.count(handle->id) == 0) return
57 
58 std::atomic<int64_t> Scheduler::sNextId = 0;
59 
Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,const scheduler::RefreshRateConfigs & refreshRateConfig)60 Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
61                      const scheduler::RefreshRateConfigs& refreshRateConfig)
62       : mHasSyncFramework(running_without_sync_framework(true)),
63         mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
64         mPrimaryHWVsyncEnabled(false),
65         mHWVsyncAvailable(false),
66         mRefreshRateConfigs(refreshRateConfig) {
67     // Note: We create a local temporary with the real DispSync implementation
68     // type temporarily so we can initialize it with the configured values,
69     // before storing it for more generic use using the interface type.
70     auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
71     primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
72     mPrimaryDispSync = std::move(primaryDispSync);
73     mEventControlThread = std::make_unique<impl::EventControlThread>(function);
74 
75     mSetIdleTimerMs = set_idle_timer_ms(0);
76     mSupportKernelTimer = support_kernel_idle_timer(false);
77 
78     mSetTouchTimerMs = set_touch_timer_ms(0);
79     mSetDisplayPowerTimerMs = set_display_power_timer_ms(0);
80 
81     char value[PROPERTY_VALUE_MAX];
82     property_get("debug.sf.set_idle_timer_ms", value, "0");
83     int int_value = atoi(value);
84     if (int_value) {
85         mSetIdleTimerMs = atoi(value);
86     }
87 
88     if (mSetIdleTimerMs > 0) {
89         if (mSupportKernelTimer) {
90             mIdleTimer =
91                     std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
92                                                                    mSetIdleTimerMs),
93                                                            [this] { resetKernelTimerCallback(); },
94                                                            [this] {
95                                                                expiredKernelTimerCallback();
96                                                            });
97         } else {
98             mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
99                                                                         mSetIdleTimerMs),
100                                                                 [this] { resetTimerCallback(); },
101                                                                 [this] { expiredTimerCallback(); });
102         }
103         mIdleTimer->start();
104     }
105 
106     if (mSetTouchTimerMs > 0) {
107         // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
108         mTouchTimer =
109                 std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs),
110                                                        [this] { resetTouchTimerCallback(); },
111                                                        [this] { expiredTouchTimerCallback(); });
112         mTouchTimer->start();
113     }
114 
115     if (mSetDisplayPowerTimerMs > 0) {
116         mDisplayPowerTimer =
117                 std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
118                                                                mSetDisplayPowerTimerMs),
119                                                        [this] { resetDisplayPowerTimerCallback(); },
120                                                        [this] {
121                                                            expiredDisplayPowerTimerCallback();
122                                                        });
123         mDisplayPowerTimer->start();
124     }
125 }
126 
~Scheduler()127 Scheduler::~Scheduler() {
128     // Ensure the IdleTimer thread is joined before we start destroying state.
129     mDisplayPowerTimer.reset();
130     mTouchTimer.reset();
131     mIdleTimer.reset();
132 }
133 
createConnection(const char * connectionName,nsecs_t phaseOffsetNs,nsecs_t offsetThresholdForNextVsync,impl::EventThread::InterceptVSyncsCallback interceptCallback)134 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
135         const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
136         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
137     const int64_t id = sNextId++;
138     ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
139 
140     std::unique_ptr<EventThread> eventThread =
141             makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
142                             offsetThresholdForNextVsync, std::move(interceptCallback));
143 
144     auto eventThreadConnection =
145             createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
146     mConnections.emplace(id,
147                          std::make_unique<Connection>(new ConnectionHandle(id),
148                                                       eventThreadConnection,
149                                                       std::move(eventThread)));
150     return mConnections[id]->handle;
151 }
152 
makeEventThread(const char * connectionName,DispSync * dispSync,nsecs_t phaseOffsetNs,nsecs_t offsetThresholdForNextVsync,impl::EventThread::InterceptVSyncsCallback interceptCallback)153 std::unique_ptr<EventThread> Scheduler::makeEventThread(
154         const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
155         nsecs_t offsetThresholdForNextVsync,
156         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
157     std::unique_ptr<VSyncSource> eventThreadSource =
158             std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
159                                              true, connectionName);
160     return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
161                                                std::move(interceptCallback), connectionName);
162 }
163 
createConnectionInternal(EventThread * eventThread,ISurfaceComposer::ConfigChanged configChanged)164 sp<EventThreadConnection> Scheduler::createConnectionInternal(
165         EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
166     return eventThread->createEventConnection([&] { resync(); }, configChanged);
167 }
168 
createDisplayEventConnection(const sp<Scheduler::ConnectionHandle> & handle,ISurfaceComposer::ConfigChanged configChanged)169 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
170         const sp<Scheduler::ConnectionHandle>& handle,
171         ISurfaceComposer::ConfigChanged configChanged) {
172     RETURN_VALUE_IF_INVALID(nullptr);
173     return createConnectionInternal(mConnections[handle->id]->thread.get(), configChanged);
174 }
175 
getEventThread(const sp<Scheduler::ConnectionHandle> & handle)176 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
177     RETURN_VALUE_IF_INVALID(nullptr);
178     return mConnections[handle->id]->thread.get();
179 }
180 
getEventConnection(const sp<ConnectionHandle> & handle)181 sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
182     RETURN_VALUE_IF_INVALID(nullptr);
183     return mConnections[handle->id]->eventConnection;
184 }
185 
hotplugReceived(const sp<Scheduler::ConnectionHandle> & handle,PhysicalDisplayId displayId,bool connected)186 void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
187                                 PhysicalDisplayId displayId, bool connected) {
188     RETURN_IF_INVALID();
189     mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
190 }
191 
onScreenAcquired(const sp<Scheduler::ConnectionHandle> & handle)192 void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
193     RETURN_IF_INVALID();
194     mConnections[handle->id]->thread->onScreenAcquired();
195 }
196 
onScreenReleased(const sp<Scheduler::ConnectionHandle> & handle)197 void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
198     RETURN_IF_INVALID();
199     mConnections[handle->id]->thread->onScreenReleased();
200 }
201 
onConfigChanged(const sp<ConnectionHandle> & handle,PhysicalDisplayId displayId,int32_t configId)202 void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
203                                 int32_t configId) {
204     RETURN_IF_INVALID();
205     mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
206 }
207 
dump(const sp<Scheduler::ConnectionHandle> & handle,std::string & result) const208 void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
209     RETURN_IF_INVALID();
210     mConnections.at(handle->id)->thread->dump(result);
211 }
212 
setPhaseOffset(const sp<Scheduler::ConnectionHandle> & handle,nsecs_t phaseOffset)213 void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
214     RETURN_IF_INVALID();
215     mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
216 }
217 
getDisplayStatInfo(DisplayStatInfo * stats)218 void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
219     stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
220     stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
221 }
222 
enableHardwareVsync()223 void Scheduler::enableHardwareVsync() {
224     std::lock_guard<std::mutex> lock(mHWVsyncLock);
225     if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
226         mPrimaryDispSync->beginResync();
227         mEventControlThread->setVsyncEnabled(true);
228         mPrimaryHWVsyncEnabled = true;
229     }
230 }
231 
disableHardwareVsync(bool makeUnavailable)232 void Scheduler::disableHardwareVsync(bool makeUnavailable) {
233     std::lock_guard<std::mutex> lock(mHWVsyncLock);
234     if (mPrimaryHWVsyncEnabled) {
235         mEventControlThread->setVsyncEnabled(false);
236         mPrimaryDispSync->endResync();
237         mPrimaryHWVsyncEnabled = false;
238     }
239     if (makeUnavailable) {
240         mHWVsyncAvailable = false;
241     }
242 }
243 
resyncToHardwareVsync(bool makeAvailable,nsecs_t period)244 void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
245     {
246         std::lock_guard<std::mutex> lock(mHWVsyncLock);
247         if (makeAvailable) {
248             mHWVsyncAvailable = makeAvailable;
249         } else if (!mHWVsyncAvailable) {
250             // Hardware vsync is not currently available, so abort the resync
251             // attempt for now
252             return;
253         }
254     }
255 
256     if (period <= 0) {
257         return;
258     }
259 
260     setVsyncPeriod(period);
261 }
262 
resync()263 void Scheduler::resync() {
264     static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
265 
266     const nsecs_t now = systemTime();
267     const nsecs_t last = mLastResyncTime.exchange(now);
268 
269     if (now - last > kIgnoreDelay) {
270         resyncToHardwareVsync(false,
271                               mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
272     }
273 }
274 
setRefreshSkipCount(int count)275 void Scheduler::setRefreshSkipCount(int count) {
276     mPrimaryDispSync->setRefreshSkipCount(count);
277 }
278 
setVsyncPeriod(const nsecs_t period)279 void Scheduler::setVsyncPeriod(const nsecs_t period) {
280     std::lock_guard<std::mutex> lock(mHWVsyncLock);
281     mPrimaryDispSync->setPeriod(period);
282 
283     if (!mPrimaryHWVsyncEnabled) {
284         mPrimaryDispSync->beginResync();
285         mEventControlThread->setVsyncEnabled(true);
286         mPrimaryHWVsyncEnabled = true;
287     }
288 }
289 
addResyncSample(const nsecs_t timestamp,bool * periodFlushed)290 void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
291     bool needsHwVsync = false;
292     *periodFlushed = false;
293     { // Scope for the lock
294         std::lock_guard<std::mutex> lock(mHWVsyncLock);
295         if (mPrimaryHWVsyncEnabled) {
296             needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
297         }
298     }
299 
300     if (needsHwVsync) {
301         enableHardwareVsync();
302     } else {
303         disableHardwareVsync(false);
304     }
305 }
306 
addPresentFence(const std::shared_ptr<FenceTime> & fenceTime)307 void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
308     if (mPrimaryDispSync->addPresentFence(fenceTime)) {
309         enableHardwareVsync();
310     } else {
311         disableHardwareVsync(false);
312     }
313 }
314 
setIgnorePresentFences(bool ignore)315 void Scheduler::setIgnorePresentFences(bool ignore) {
316     mPrimaryDispSync->setIgnorePresentFences(ignore);
317 }
318 
getDispSyncExpectedPresentTime()319 nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
320     return mPrimaryDispSync->expectedPresentTime();
321 }
322 
dumpPrimaryDispSync(std::string & result) const323 void Scheduler::dumpPrimaryDispSync(std::string& result) const {
324     mPrimaryDispSync->dump(result);
325 }
326 
registerLayer(std::string const & name,int windowType)327 std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
328         std::string const& name, int windowType) {
329     uint32_t defaultFps, performanceFps;
330     if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
331         defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
332         performanceFps =
333                 mRefreshRateConfigs
334                         .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
335                                                         ? RefreshRateType::DEFAULT
336                                                         : RefreshRateType::PERFORMANCE)
337                         .fps;
338     } else {
339         defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
340         performanceFps = defaultFps;
341     }
342     return mLayerHistory.createLayer(name, defaultFps, performanceFps);
343 }
344 
addLayerPresentTimeAndHDR(const std::unique_ptr<scheduler::LayerHistory::LayerHandle> & layerHandle,nsecs_t presentTime,bool isHDR)345 void Scheduler::addLayerPresentTimeAndHDR(
346         const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
347         nsecs_t presentTime, bool isHDR) {
348     mLayerHistory.insert(layerHandle, presentTime, isHDR);
349 }
350 
setLayerVisibility(const std::unique_ptr<scheduler::LayerHistory::LayerHandle> & layerHandle,bool visible)351 void Scheduler::setLayerVisibility(
352         const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
353     mLayerHistory.setVisibility(layerHandle, visible);
354 }
355 
withPrimaryDispSync(std::function<void (DispSync &)> const & fn)356 void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
357     fn(*mPrimaryDispSync);
358 }
359 
updateFpsBasedOnContent()360 void Scheduler::updateFpsBasedOnContent() {
361     auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
362     const uint32_t refreshRateRound = std::round(refreshRate);
363     RefreshRateType newRefreshRateType;
364     {
365         std::lock_guard<std::mutex> lock(mFeatureStateLock);
366         if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
367             return;
368         }
369         mContentRefreshRate = refreshRateRound;
370         ATRACE_INT("ContentFPS", mContentRefreshRate);
371 
372         mIsHDRContent = isHDR;
373         ATRACE_INT("ContentHDR", mIsHDRContent);
374 
375         mCurrentContentFeatureState = refreshRateRound > 0
376                 ? ContentFeatureState::CONTENT_DETECTION_ON
377                 : ContentFeatureState::CONTENT_DETECTION_OFF;
378         newRefreshRateType = calculateRefreshRateType();
379         if (mRefreshRateType == newRefreshRateType) {
380             return;
381         }
382         mRefreshRateType = newRefreshRateType;
383     }
384     changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
385 }
386 
setChangeRefreshRateCallback(const ChangeRefreshRateCallback && changeRefreshRateCallback)387 void Scheduler::setChangeRefreshRateCallback(
388         const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
389     std::lock_guard<std::mutex> lock(mCallbackLock);
390     mChangeRefreshRateCallback = changeRefreshRateCallback;
391 }
392 
updateFrameSkipping(const int64_t skipCount)393 void Scheduler::updateFrameSkipping(const int64_t skipCount) {
394     ATRACE_INT("FrameSkipCount", skipCount);
395     if (mSkipCount != skipCount) {
396         // Only update DispSync if it hasn't been updated yet.
397         mPrimaryDispSync->setRefreshSkipCount(skipCount);
398         mSkipCount = skipCount;
399     }
400 }
401 
resetIdleTimer()402 void Scheduler::resetIdleTimer() {
403     if (mIdleTimer) {
404         mIdleTimer->reset();
405     }
406 }
407 
notifyTouchEvent()408 void Scheduler::notifyTouchEvent() {
409     if (mTouchTimer) {
410         mTouchTimer->reset();
411     }
412 
413     if (mSupportKernelTimer) {
414         resetIdleTimer();
415     }
416 
417     // Touch event will boost the refresh rate to performance.
418     // Clear Layer History to get fresh FPS detection
419     mLayerHistory.clearHistory();
420 }
421 
setDisplayPowerState(bool normal)422 void Scheduler::setDisplayPowerState(bool normal) {
423     {
424         std::lock_guard<std::mutex> lock(mFeatureStateLock);
425         mIsDisplayPowerStateNormal = normal;
426     }
427 
428     if (mDisplayPowerTimer) {
429         mDisplayPowerTimer->reset();
430     }
431 
432     // Display Power event will boost the refresh rate to performance.
433     // Clear Layer History to get fresh FPS detection
434     mLayerHistory.clearHistory();
435 }
436 
resetTimerCallback()437 void Scheduler::resetTimerCallback() {
438     handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false);
439     ATRACE_INT("ExpiredIdleTimer", 0);
440 }
441 
resetKernelTimerCallback()442 void Scheduler::resetKernelTimerCallback() {
443     ATRACE_INT("ExpiredKernelIdleTimer", 0);
444     const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
445     if (refreshRate.first == RefreshRateType::PERFORMANCE) {
446         // If we're not in performance mode then the kernel timer shouldn't do
447         // anything, as the refresh rate during DPU power collapse will be the
448         // same.
449         resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod);
450     }
451 }
452 
expiredTimerCallback()453 void Scheduler::expiredTimerCallback() {
454     handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false);
455     ATRACE_INT("ExpiredIdleTimer", 1);
456 }
457 
resetTouchTimerCallback()458 void Scheduler::resetTouchTimerCallback() {
459     handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true);
460     ATRACE_INT("TouchState", 1);
461 }
462 
expiredTouchTimerCallback()463 void Scheduler::expiredTouchTimerCallback() {
464     handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true);
465     ATRACE_INT("TouchState", 0);
466 }
467 
resetDisplayPowerTimerCallback()468 void Scheduler::resetDisplayPowerTimerCallback() {
469     handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true);
470     ATRACE_INT("ExpiredDisplayPowerTimer", 0);
471 }
472 
expiredDisplayPowerTimerCallback()473 void Scheduler::expiredDisplayPowerTimerCallback() {
474     handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true);
475     ATRACE_INT("ExpiredDisplayPowerTimer", 1);
476 }
477 
expiredKernelTimerCallback()478 void Scheduler::expiredKernelTimerCallback() {
479     ATRACE_INT("ExpiredKernelIdleTimer", 1);
480     const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
481     if (refreshRate.first != RefreshRateType::PERFORMANCE) {
482         // Disable HW Vsync if the timer expired, as we don't need it
483         // enabled if we're not pushing frames, and if we're in PERFORMANCE
484         // mode then we'll need to re-update the DispSync model anyways.
485         disableHardwareVsync(false);
486     }
487 }
488 
doDump()489 std::string Scheduler::doDump() {
490     std::ostringstream stream;
491     stream << "+  Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
492     stream << "+  Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
493     return stream.str();
494 }
495 
496 template <class T>
handleTimerStateChanged(T * currentState,T newState,bool eventOnContentDetection)497 void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
498     ConfigEvent event = ConfigEvent::None;
499     RefreshRateType newRefreshRateType;
500     {
501         std::lock_guard<std::mutex> lock(mFeatureStateLock);
502         if (*currentState == newState) {
503             return;
504         }
505         *currentState = newState;
506         newRefreshRateType = calculateRefreshRateType();
507         if (mRefreshRateType == newRefreshRateType) {
508             return;
509         }
510         mRefreshRateType = newRefreshRateType;
511         if (eventOnContentDetection &&
512             mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
513             event = ConfigEvent::Changed;
514         }
515     }
516     changeRefreshRate(newRefreshRateType, event);
517 }
518 
calculateRefreshRateType()519 Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
520     if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
521         return RefreshRateType::DEFAULT;
522     }
523 
524     // HDR content is not supported on PERFORMANCE mode
525     if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
526         return RefreshRateType::DEFAULT;
527     }
528 
529     // If Display Power is not in normal operation we want to be in performance mode.
530     // When coming back to normal mode, a grace period is given with DisplayPowerTimer
531     if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) {
532         return RefreshRateType::PERFORMANCE;
533     }
534 
535     // As long as touch is active we want to be in performance mode
536     if (mCurrentTouchState == TouchState::ACTIVE) {
537         return RefreshRateType::PERFORMANCE;
538     }
539 
540     // If timer has expired as it means there is no new content on the screen
541     if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
542         return RefreshRateType::DEFAULT;
543     }
544 
545     // If content detection is off we choose performance as we don't know the content fps
546     if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
547         return RefreshRateType::PERFORMANCE;
548     }
549 
550     // Content detection is on, find the appropriate refresh rate with minimal error
551     auto begin = mRefreshRateConfigs.getRefreshRateMap().cbegin();
552 
553     auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRateMap().cend(),
554                             [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
555                                 return std::abs(l.second.fps - static_cast<float>(rate)) <
556                                         std::abs(r.second.fps - static_cast<float>(rate));
557                             });
558     RefreshRateType currRefreshRateType = iter->first;
559 
560     // Some content aligns better on higher refresh rate. For example for 45fps we should choose
561     // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
562     // align well with both
563     constexpr float MARGIN = 0.05f;
564     float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps /
565             float(mContentRefreshRate);
566     if (std::abs(std::round(ratio) - ratio) > MARGIN) {
567         while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
568             ratio = iter->second.fps / float(mContentRefreshRate);
569 
570             if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
571                 currRefreshRateType = iter->first;
572                 break;
573             }
574             ++iter;
575         }
576     }
577 
578     return currRefreshRateType;
579 }
580 
changeRefreshRate(RefreshRateType refreshRateType,ConfigEvent configEvent)581 void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
582     std::lock_guard<std::mutex> lock(mCallbackLock);
583     if (mChangeRefreshRateCallback) {
584         mChangeRefreshRateCallback(refreshRateType, configEvent);
585     }
586 }
587 
588 } // namespace android
589