blob: e2a880a7fe301a8352b265788f7410188403ad35 [file] [log] [blame]
Ana Krulec98b5b242018-08-10 15:03:23 -07001/*
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
Dominik Laskowski98041832019-08-01 18:35:59 -070017#undef LOG_TAG
18#define LOG_TAG "Scheduler"
Ana Krulec7ab56032018-11-02 20:51:06 +010019#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
Ana Krulec98b5b242018-08-10 15:03:23 -070021#include "Scheduler.h"
22
Ana Krulec434c22d2018-11-28 13:48:36 +010023#include <algorithm>
Ana Krulec98b5b242018-08-10 15:03:23 -070024#include <cinttypes>
25#include <cstdint>
Dominik Laskowski98041832019-08-01 18:35:59 -070026#include <functional>
Ana Krulec98b5b242018-08-10 15:03:23 -070027#include <memory>
Ana Krulec7ab56032018-11-02 20:51:06 +010028#include <numeric>
Ana Krulec98b5b242018-08-10 15:03:23 -070029
Ana Krulece588e312018-09-18 12:32:24 -070030#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
31#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
Ana Krulece588e312018-09-18 12:32:24 -070032#include <configstore/Utils.h>
Ana Krulecfb772822018-11-30 10:44:07 +010033#include <cutils/properties.h>
Ady Abraham8f1ee7f2019-04-05 10:32:50 -070034#include <input/InputWindow.h>
Ana Krulecfefd6ae2019-02-13 17:53:08 -080035#include <system/window.h>
Ana Krulece588e312018-09-18 12:32:24 -070036#include <ui/DisplayStatInfo.h>
Ana Krulec3084c052018-11-21 20:27:17 +010037#include <utils/Timers.h>
Ana Krulec7ab56032018-11-02 20:51:06 +010038#include <utils/Trace.h>
Ana Krulec98b5b242018-08-10 15:03:23 -070039
40#include "DispSync.h"
41#include "DispSyncSource.h"
Ana Krulece588e312018-09-18 12:32:24 -070042#include "EventControlThread.h"
Ana Krulec98b5b242018-08-10 15:03:23 -070043#include "EventThread.h"
Ana Krulecf2c006d2019-06-21 15:37:07 -070044#include "OneShotTimer.h"
Ana Krulec434c22d2018-11-28 13:48:36 +010045#include "SchedulerUtils.h"
Sundong Ahnd5e08f62018-12-12 20:27:28 +090046#include "SurfaceFlingerProperties.h"
Ana Krulec98b5b242018-08-10 15:03:23 -070047
Dominik Laskowski98041832019-08-01 18:35:59 -070048#define RETURN_IF_INVALID_HANDLE(handle, ...) \
49 do { \
50 if (mConnections.count(handle) == 0) { \
51 ALOGE("Invalid connection handle %" PRIuPTR, handle.id); \
52 return __VA_ARGS__; \
53 } \
54 } while (false)
55
Ana Krulec98b5b242018-08-10 15:03:23 -070056namespace android {
57
Ady Abraham09bd3922019-04-08 10:44:56 -070058Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
59 const scheduler::RefreshRateConfigs& refreshRateConfig)
Dominik Laskowski98041832019-08-01 18:35:59 -070060 : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync",
61 sysprop::running_without_sync_framework(true))),
62 mEventControlThread(new impl::EventControlThread(std::move(function))),
63 mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
Ady Abraham09bd3922019-04-08 10:44:56 -070064 mRefreshRateConfigs(refreshRateConfig) {
Dominik Laskowski98041832019-08-01 18:35:59 -070065 using namespace sysprop;
Ady Abraham8532d012019-05-08 14:50:56 -070066
Ana Krulecfb772822018-11-30 10:44:07 +010067 char value[PROPERTY_VALUE_MAX];
Ana Kruleca5bdd9d2019-01-29 19:00:58 -080068 property_get("debug.sf.set_idle_timer_ms", value, "0");
Dominik Laskowski98041832019-08-01 18:35:59 -070069 const int setIdleTimerMs = atoi(value);
Ana Krulecfb772822018-11-30 10:44:07 +010070
Dominik Laskowski98041832019-08-01 18:35:59 -070071 if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
72 const auto callback = mSupportKernelTimer ? &Scheduler::kernelIdleTimerCallback
73 : &Scheduler::idleTimerCallback;
74
75 mIdleTimer.emplace(
76 std::chrono::milliseconds(millis),
77 [this, callback] { std::invoke(callback, this, TimerState::Reset); },
78 [this, callback] { std::invoke(callback, this, TimerState::Expired); });
Ana Krulecfb772822018-11-30 10:44:07 +010079 mIdleTimer->start();
80 }
Ady Abraham8532d012019-05-08 14:50:56 -070081
Dominik Laskowski98041832019-08-01 18:35:59 -070082 if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
Ady Abraham8532d012019-05-08 14:50:56 -070083 // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
Dominik Laskowski98041832019-08-01 18:35:59 -070084 mTouchTimer.emplace(
85 std::chrono::milliseconds(millis),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -070086 [this] { touchTimerCallback(TimerState::Reset); },
87 [this] { touchTimerCallback(TimerState::Expired); });
Ady Abraham8532d012019-05-08 14:50:56 -070088 mTouchTimer->start();
89 }
Ady Abraham6fe2c172019-07-12 12:37:57 -070090
Dominik Laskowski98041832019-08-01 18:35:59 -070091 if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
92 mDisplayPowerTimer.emplace(
93 std::chrono::milliseconds(millis),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -070094 [this] { displayPowerTimerCallback(TimerState::Reset); },
95 [this] { displayPowerTimerCallback(TimerState::Expired); });
Ady Abraham6fe2c172019-07-12 12:37:57 -070096 mDisplayPowerTimer->start();
97 }
Ana Krulece588e312018-09-18 12:32:24 -070098}
99
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700100Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
101 std::unique_ptr<EventControlThread> eventControlThread,
102 const scheduler::RefreshRateConfigs& configs)
Dominik Laskowski98041832019-08-01 18:35:59 -0700103 : mPrimaryDispSync(std::move(primaryDispSync)),
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700104 mEventControlThread(std::move(eventControlThread)),
Dominik Laskowski98041832019-08-01 18:35:59 -0700105 mSupportKernelTimer(false),
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700106 mRefreshRateConfigs(configs) {}
107
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800108Scheduler::~Scheduler() {
Ana Krulecf2c006d2019-06-21 15:37:07 -0700109 // Ensure the OneShotTimer threads are joined before we start destroying state.
Ady Abraham6fe2c172019-07-12 12:37:57 -0700110 mDisplayPowerTimer.reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700111 mTouchTimer.reset();
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800112 mIdleTimer.reset();
113}
Ana Krulec0c8cd522018-08-31 12:27:28 -0700114
Dominik Laskowski98041832019-08-01 18:35:59 -0700115DispSync& Scheduler::getPrimaryDispSync() {
116 return *mPrimaryDispSync;
117}
118
119Scheduler::ConnectionHandle Scheduler::createConnection(
Ady Abraham45e4e362019-06-07 18:20:51 -0700120 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
121 ResyncCallback resyncCallback,
Ana Krulec98b5b242018-08-10 15:03:23 -0700122 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700123 auto eventThread = makeEventThread(connectionName, phaseOffsetNs, offsetThresholdForNextVsync,
124 std::move(interceptCallback));
125 return createConnection(std::move(eventThread), std::move(resyncCallback));
126}
Ana Krulec98b5b242018-08-10 15:03:23 -0700127
Dominik Laskowski98041832019-08-01 18:35:59 -0700128Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread,
129 ResyncCallback&& resyncCallback) {
130 const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
131 ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
Dominik Laskowskif654d572018-12-20 11:03:06 -0800132
Dominik Laskowski98041832019-08-01 18:35:59 -0700133 auto connection = createConnectionInternal(eventThread.get(), std::move(resyncCallback),
134 ISurfaceComposer::eConfigChangedSuppress);
135
136 mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
137 return handle;
Ana Krulec98b5b242018-08-10 15:03:23 -0700138}
139
Ana Krulec0c8cd522018-08-31 12:27:28 -0700140std::unique_ptr<EventThread> Scheduler::makeEventThread(
Dominik Laskowski98041832019-08-01 18:35:59 -0700141 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
142 impl::EventThread::InterceptVSyncsCallback&& interceptCallback) {
143 auto source = std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs,
144 offsetThresholdForNextVsync,
145 true /* traceVsync */, connectionName);
146 return std::make_unique<impl::EventThread>(std::move(source), std::move(interceptCallback),
147 connectionName);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800148}
149
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700150sp<EventThreadConnection> Scheduler::createConnectionInternal(
151 EventThread* eventThread, ResyncCallback&& resyncCallback,
152 ISurfaceComposer::ConfigChanged configChanged) {
153 return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
Ana Krulec0c8cd522018-08-31 12:27:28 -0700154}
155
Ana Krulec98b5b242018-08-10 15:03:23 -0700156sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
Dominik Laskowski98041832019-08-01 18:35:59 -0700157 ConnectionHandle handle, ResyncCallback resyncCallback,
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700158 ISurfaceComposer::ConfigChanged configChanged) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700159 RETURN_IF_INVALID_HANDLE(handle, nullptr);
160 return createConnectionInternal(mConnections[handle].thread.get(), std::move(resyncCallback),
161 configChanged);
Ana Krulec98b5b242018-08-10 15:03:23 -0700162}
163
Dominik Laskowski98041832019-08-01 18:35:59 -0700164EventThread* Scheduler::getEventThread(ConnectionHandle handle) {
165 RETURN_IF_INVALID_HANDLE(handle, nullptr);
166 return mConnections[handle].thread.get();
Ana Krulec98b5b242018-08-10 15:03:23 -0700167}
168
Dominik Laskowski98041832019-08-01 18:35:59 -0700169sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
170 RETURN_IF_INVALID_HANDLE(handle, nullptr);
171 return mConnections[handle].connection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700172}
173
Dominik Laskowski98041832019-08-01 18:35:59 -0700174void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
175 bool connected) {
176 RETURN_IF_INVALID_HANDLE(handle);
177 mConnections[handle].thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700178}
179
Dominik Laskowski98041832019-08-01 18:35:59 -0700180void Scheduler::onScreenAcquired(ConnectionHandle handle) {
181 RETURN_IF_INVALID_HANDLE(handle);
182 mConnections[handle].thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700183}
184
Dominik Laskowski98041832019-08-01 18:35:59 -0700185void Scheduler::onScreenReleased(ConnectionHandle handle) {
186 RETURN_IF_INVALID_HANDLE(handle);
187 mConnections[handle].thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700188}
189
Dominik Laskowski98041832019-08-01 18:35:59 -0700190void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
Ady Abraham447052e2019-02-13 16:07:27 -0800191 int32_t configId) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700192 RETURN_IF_INVALID_HANDLE(handle);
193 mConnections[handle].thread->onConfigChanged(displayId, configId);
Ady Abraham447052e2019-02-13 16:07:27 -0800194}
195
Dominik Laskowski98041832019-08-01 18:35:59 -0700196void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
197 RETURN_IF_INVALID_HANDLE(handle);
198 mConnections.at(handle).thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700199}
200
Dominik Laskowski98041832019-08-01 18:35:59 -0700201void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
202 RETURN_IF_INVALID_HANDLE(handle);
203 mConnections[handle].thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700204}
Ana Krulece588e312018-09-18 12:32:24 -0700205
206void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
207 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
208 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
209}
210
211void Scheduler::enableHardwareVsync() {
212 std::lock_guard<std::mutex> lock(mHWVsyncLock);
213 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
214 mPrimaryDispSync->beginResync();
215 mEventControlThread->setVsyncEnabled(true);
216 mPrimaryHWVsyncEnabled = true;
217 }
218}
219
220void Scheduler::disableHardwareVsync(bool makeUnavailable) {
221 std::lock_guard<std::mutex> lock(mHWVsyncLock);
222 if (mPrimaryHWVsyncEnabled) {
223 mEventControlThread->setVsyncEnabled(false);
224 mPrimaryDispSync->endResync();
225 mPrimaryHWVsyncEnabled = false;
226 }
227 if (makeUnavailable) {
228 mHWVsyncAvailable = false;
229 }
230}
231
Ana Krulecc2870422019-01-29 19:00:58 -0800232void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
233 {
234 std::lock_guard<std::mutex> lock(mHWVsyncLock);
235 if (makeAvailable) {
236 mHWVsyncAvailable = makeAvailable;
237 } else if (!mHWVsyncAvailable) {
238 // Hardware vsync is not currently available, so abort the resync
239 // attempt for now
240 return;
241 }
242 }
243
244 if (period <= 0) {
245 return;
246 }
247
248 setVsyncPeriod(period);
249}
250
251ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
252 std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
253 return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
254 if (const auto vsync = ptr.lock()) {
255 vsync->resync(getVsyncPeriod);
256 }
257 };
258}
259
260void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
261 static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
262
263 const nsecs_t now = systemTime();
264 const nsecs_t last = lastResyncTime.exchange(now);
265
266 if (now - last > kIgnoreDelay) {
267 scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
268 }
269}
270
Dominik Laskowski98041832019-08-01 18:35:59 -0700271void Scheduler::setVsyncPeriod(nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800272 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700273 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800274
275 if (!mPrimaryHWVsyncEnabled) {
276 mPrimaryDispSync->beginResync();
277 mEventControlThread->setVsyncEnabled(true);
278 mPrimaryHWVsyncEnabled = true;
279 }
Ana Krulece588e312018-09-18 12:32:24 -0700280}
281
Dominik Laskowski98041832019-08-01 18:35:59 -0700282void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700283 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700284 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700285 { // Scope for the lock
286 std::lock_guard<std::mutex> lock(mHWVsyncLock);
287 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700288 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700289 }
290 }
291
292 if (needsHwVsync) {
293 enableHardwareVsync();
294 } else {
295 disableHardwareVsync(false);
296 }
297}
298
299void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
300 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
301 enableHardwareVsync();
302 } else {
303 disableHardwareVsync(false);
304 }
305}
306
307void Scheduler::setIgnorePresentFences(bool ignore) {
308 mPrimaryDispSync->setIgnorePresentFences(ignore);
309}
310
Ady Abraham8fe11022019-06-12 17:11:12 -0700311nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800312 return mPrimaryDispSync->expectedPresentTime();
313}
314
Ady Abraham09bd3922019-04-08 10:44:56 -0700315std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700316 std::string const& name, int windowType) {
317 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
318 ? RefreshRateType::DEFAULT
319 : RefreshRateType::PERFORMANCE;
Ady Abraham09bd3922019-04-08 10:44:56 -0700320
321 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
Ana Krulecad083c42019-06-26 16:28:08 -0700322 const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
323
324 const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
325 const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
326 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700327}
328
Ady Abrahama315ce72019-04-24 14:35:20 -0700329void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700330 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700331 nsecs_t presentTime, bool isHDR) {
332 mLayerHistory.insert(layerHandle, presentTime, isHDR);
333}
334
335void Scheduler::setLayerVisibility(
336 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
337 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100338}
339
Ady Abraham09bd3922019-04-08 10:44:56 -0700340void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700341 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
342 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700343 RefreshRateType newRefreshRateType;
344 {
345 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700346 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700347 return;
348 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700349 mFeatures.contentRefreshRate = refreshRateRound;
350 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700351
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700352 mFeatures.isHDRContent = isHDR;
353 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700354
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700355 mFeatures.contentDetection =
356 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700357 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700358 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700359 return;
360 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700361 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800362 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700363 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100364}
365
Dominik Laskowski98041832019-08-01 18:35:59 -0700366void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800367 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700368 mChangeRefreshRateCallback = std::move(callback);
Ady Abrahama1a49af2019-02-07 14:36:55 -0800369}
370
Dominik Laskowski98041832019-08-01 18:35:59 -0700371void Scheduler::setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&& callback) {
Alec Mouri7f015182019-07-11 13:56:22 -0700372 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700373 mGetCurrentRefreshRateTypeCallback = std::move(callback);
Alec Mouri7f015182019-07-11 13:56:22 -0700374}
375
Dominik Laskowski98041832019-08-01 18:35:59 -0700376void Scheduler::setGetVsyncPeriodCallback(GetVsyncPeriod&& callback) {
Alec Mouridc28b372019-04-18 21:17:13 -0700377 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700378 mGetVsyncPeriod = std::move(callback);
Ana Krulec3084c052018-11-21 20:27:17 +0100379}
380
Ana Krulecfb772822018-11-30 10:44:07 +0100381void Scheduler::resetIdleTimer() {
382 if (mIdleTimer) {
383 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800384 }
385}
386
Ady Abraham8532d012019-05-08 14:50:56 -0700387void Scheduler::notifyTouchEvent() {
388 if (mTouchTimer) {
389 mTouchTimer->reset();
390 }
391
Dominik Laskowski98041832019-08-01 18:35:59 -0700392 if (mSupportKernelTimer && mIdleTimer) {
393 mIdleTimer->reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700394 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700395
396 // Touch event will boost the refresh rate to performance.
397 // Clear Layer History to get fresh FPS detection
398 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700399}
400
Ady Abraham6fe2c172019-07-12 12:37:57 -0700401void Scheduler::setDisplayPowerState(bool normal) {
402 {
403 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700404 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700405 }
406
407 if (mDisplayPowerTimer) {
408 mDisplayPowerTimer->reset();
409 }
410
411 // Display Power event will boost the refresh rate to performance.
412 // Clear Layer History to get fresh FPS detection
413 mLayerHistory.clearHistory();
414}
415
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700416void Scheduler::kernelIdleTimerCallback(TimerState state) {
417 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100418
Alec Mouridc28b372019-04-18 21:17:13 -0700419 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700420 if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
421
422 const auto type = mGetCurrentRefreshRateTypeCallback();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700423 if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700424 // If we're not in performance mode then the kernel timer shouldn't do
425 // anything, as the refresh rate during DPU power collapse will be the
426 // same.
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700427 resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700428 } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700429 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
430 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
431 // need to update the DispSync model anyway.
432 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700433 }
434}
435
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700436void Scheduler::idleTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700437 handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700438 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100439}
440
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700441void Scheduler::touchTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700442 const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
443 handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700444 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700445}
446
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700447void Scheduler::displayPowerTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700448 handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
449 true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700450 ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
Alec Mouridc28b372019-04-18 21:17:13 -0700451}
452
Dominik Laskowski98041832019-08-01 18:35:59 -0700453void Scheduler::dump(std::string& result) const {
Ana Krulecb43429d2019-01-09 14:28:51 -0800454 std::ostringstream stream;
Dominik Laskowski98041832019-08-01 18:35:59 -0700455 if (mIdleTimer) {
456 stream << "+ Idle timer interval: " << mIdleTimer->interval().count() << " ms\n";
457 }
458 if (mTouchTimer) {
459 stream << "+ Touch timer interval: " << mTouchTimer->interval().count() << " ms\n";
460 }
461
462 result.append(stream.str());
Ana Krulecb43429d2019-01-09 14:28:51 -0800463}
464
Ady Abraham6fe2c172019-07-12 12:37:57 -0700465template <class T>
466void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
Ady Abraham8532d012019-05-08 14:50:56 -0700467 ConfigEvent event = ConfigEvent::None;
468 RefreshRateType newRefreshRateType;
469 {
470 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6fe2c172019-07-12 12:37:57 -0700471 if (*currentState == newState) {
Ady Abraham8532d012019-05-08 14:50:56 -0700472 return;
473 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700474 *currentState = newState;
Ady Abraham8532d012019-05-08 14:50:56 -0700475 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700476 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham8532d012019-05-08 14:50:56 -0700477 return;
478 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700479 mFeatures.refreshRateType = newRefreshRateType;
480 if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
Ady Abraham8532d012019-05-08 14:50:56 -0700481 event = ConfigEvent::Changed;
482 }
483 }
484 changeRefreshRate(newRefreshRateType, event);
485}
486
Ady Abraham09bd3922019-04-08 10:44:56 -0700487Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700488 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700489 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700490 return RefreshRateType::DEFAULT;
491 }
492
Ady Abraham6fe2c172019-07-12 12:37:57 -0700493 // If Display Power is not in normal operation we want to be in performance mode.
494 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700495 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700496 return RefreshRateType::PERFORMANCE;
497 }
498
Ady Abraham8532d012019-05-08 14:50:56 -0700499 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700500 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700501 return RefreshRateType::PERFORMANCE;
502 }
503
504 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700505 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700506 return RefreshRateType::DEFAULT;
507 }
508
Ady Abraham09bd3922019-04-08 10:44:56 -0700509 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700510 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700511 return RefreshRateType::PERFORMANCE;
512 }
513
Wei Wang09be73f2019-07-02 14:29:18 -0700514 // Content detection is on, find the appropriate refresh rate with minimal error
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700515 // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700516 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Ady Abraham67968802019-09-06 13:05:40 -0700517 auto begin = mRefreshRateConfigs.getRefreshRates().cbegin();
518
519 // Skip POWER_SAVING config as it is not a real config
520 if (begin->first == RefreshRateType::POWER_SAVING) {
521 ++begin;
522 }
523 auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700524 [rate](const auto& lhs, const auto& rhs) -> bool {
525 return std::abs(lhs.second->fps - rate) <
526 std::abs(rhs.second->fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700527 });
528 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700529
Ady Abraham85b3f012019-04-08 11:04:14 -0700530 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
531 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
532 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700533 constexpr float MARGIN = 0.05f;
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700534 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700535 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
536 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700537 ratio = iter->second->fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700538
Ady Abraham85b3f012019-04-08 11:04:14 -0700539 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
540 currRefreshRateType = iter->first;
541 break;
542 }
543 ++iter;
544 }
545 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700546
547 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800548}
549
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700550Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
551 std::lock_guard<std::mutex> lock(mFeatureStateLock);
552 return mFeatures.refreshRateType;
553}
554
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800555void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
556 std::lock_guard<std::mutex> lock(mCallbackLock);
557 if (mChangeRefreshRateCallback) {
558 mChangeRefreshRateCallback(refreshRateType, configEvent);
559 }
560}
561
Ana Krulec98b5b242018-08-10 15:03:23 -0700562} // namespace android