blob: 7f1fb3bcd45e2ab782e64cb08d019b25122c552b [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
271void Scheduler::setRefreshSkipCount(int count) {
272 mPrimaryDispSync->setRefreshSkipCount(count);
273}
274
Dominik Laskowski98041832019-08-01 18:35:59 -0700275void Scheduler::setVsyncPeriod(nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800276 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700277 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800278
279 if (!mPrimaryHWVsyncEnabled) {
280 mPrimaryDispSync->beginResync();
281 mEventControlThread->setVsyncEnabled(true);
282 mPrimaryHWVsyncEnabled = true;
283 }
Ana Krulece588e312018-09-18 12:32:24 -0700284}
285
Dominik Laskowski98041832019-08-01 18:35:59 -0700286void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700287 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700288 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700289 { // Scope for the lock
290 std::lock_guard<std::mutex> lock(mHWVsyncLock);
291 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700292 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700293 }
294 }
295
296 if (needsHwVsync) {
297 enableHardwareVsync();
298 } else {
299 disableHardwareVsync(false);
300 }
301}
302
303void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
304 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
305 enableHardwareVsync();
306 } else {
307 disableHardwareVsync(false);
308 }
309}
310
311void Scheduler::setIgnorePresentFences(bool ignore) {
312 mPrimaryDispSync->setIgnorePresentFences(ignore);
313}
314
Ady Abraham8fe11022019-06-12 17:11:12 -0700315nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800316 return mPrimaryDispSync->expectedPresentTime();
317}
318
Ady Abraham09bd3922019-04-08 10:44:56 -0700319std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700320 std::string const& name, int windowType) {
321 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
322 ? RefreshRateType::DEFAULT
323 : RefreshRateType::PERFORMANCE;
Ady Abraham09bd3922019-04-08 10:44:56 -0700324
325 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
Ana Krulecad083c42019-06-26 16:28:08 -0700326 const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
327
328 const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
329 const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
330 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700331}
332
Ady Abrahama315ce72019-04-24 14:35:20 -0700333void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700334 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700335 nsecs_t presentTime, bool isHDR) {
336 mLayerHistory.insert(layerHandle, presentTime, isHDR);
337}
338
339void Scheduler::setLayerVisibility(
340 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
341 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100342}
343
Ady Abraham09bd3922019-04-08 10:44:56 -0700344void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700345 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
346 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700347 RefreshRateType newRefreshRateType;
348 {
349 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700350 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700351 return;
352 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700353 mFeatures.contentRefreshRate = refreshRateRound;
354 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700355
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700356 mFeatures.isHDRContent = isHDR;
357 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700358
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700359 mFeatures.contentDetection =
360 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700361 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700362 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700363 return;
364 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700365 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800366 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700367 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100368}
369
Dominik Laskowski98041832019-08-01 18:35:59 -0700370void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800371 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700372 mChangeRefreshRateCallback = std::move(callback);
Ady Abrahama1a49af2019-02-07 14:36:55 -0800373}
374
Dominik Laskowski98041832019-08-01 18:35:59 -0700375void Scheduler::setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&& callback) {
Alec Mouri7f015182019-07-11 13:56:22 -0700376 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700377 mGetCurrentRefreshRateTypeCallback = std::move(callback);
Alec Mouri7f015182019-07-11 13:56:22 -0700378}
379
Dominik Laskowski98041832019-08-01 18:35:59 -0700380void Scheduler::setGetVsyncPeriodCallback(GetVsyncPeriod&& callback) {
Alec Mouridc28b372019-04-18 21:17:13 -0700381 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700382 mGetVsyncPeriod = std::move(callback);
Ana Krulec3084c052018-11-21 20:27:17 +0100383}
384
Ana Krulecfb772822018-11-30 10:44:07 +0100385void Scheduler::resetIdleTimer() {
386 if (mIdleTimer) {
387 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800388 }
389}
390
Ady Abraham8532d012019-05-08 14:50:56 -0700391void Scheduler::notifyTouchEvent() {
392 if (mTouchTimer) {
393 mTouchTimer->reset();
394 }
395
Dominik Laskowski98041832019-08-01 18:35:59 -0700396 if (mSupportKernelTimer && mIdleTimer) {
397 mIdleTimer->reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700398 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700399
400 // Touch event will boost the refresh rate to performance.
401 // Clear Layer History to get fresh FPS detection
402 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700403}
404
Ady Abraham6fe2c172019-07-12 12:37:57 -0700405void Scheduler::setDisplayPowerState(bool normal) {
406 {
407 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700408 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700409 }
410
411 if (mDisplayPowerTimer) {
412 mDisplayPowerTimer->reset();
413 }
414
415 // Display Power event will boost the refresh rate to performance.
416 // Clear Layer History to get fresh FPS detection
417 mLayerHistory.clearHistory();
418}
419
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700420void Scheduler::kernelIdleTimerCallback(TimerState state) {
421 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100422
Alec Mouridc28b372019-04-18 21:17:13 -0700423 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700424 if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
425
426 const auto type = mGetCurrentRefreshRateTypeCallback();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700427 if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700428 // If we're not in performance mode then the kernel timer shouldn't do
429 // anything, as the refresh rate during DPU power collapse will be the
430 // same.
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700431 resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700432 } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700433 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
434 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
435 // need to update the DispSync model anyway.
436 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700437 }
438}
439
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700440void Scheduler::idleTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700441 handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700442 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100443}
444
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700445void Scheduler::touchTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700446 const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
447 handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700448 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700449}
450
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700451void Scheduler::displayPowerTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700452 handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
453 true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700454 ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
Alec Mouridc28b372019-04-18 21:17:13 -0700455}
456
Dominik Laskowski98041832019-08-01 18:35:59 -0700457void Scheduler::dump(std::string& result) const {
Ana Krulecb43429d2019-01-09 14:28:51 -0800458 std::ostringstream stream;
Dominik Laskowski98041832019-08-01 18:35:59 -0700459 if (mIdleTimer) {
460 stream << "+ Idle timer interval: " << mIdleTimer->interval().count() << " ms\n";
461 }
462 if (mTouchTimer) {
463 stream << "+ Touch timer interval: " << mTouchTimer->interval().count() << " ms\n";
464 }
465
466 result.append(stream.str());
Ana Krulecb43429d2019-01-09 14:28:51 -0800467}
468
Ady Abraham6fe2c172019-07-12 12:37:57 -0700469template <class T>
470void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
Ady Abraham8532d012019-05-08 14:50:56 -0700471 ConfigEvent event = ConfigEvent::None;
472 RefreshRateType newRefreshRateType;
473 {
474 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6fe2c172019-07-12 12:37:57 -0700475 if (*currentState == newState) {
Ady Abraham8532d012019-05-08 14:50:56 -0700476 return;
477 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700478 *currentState = newState;
Ady Abraham8532d012019-05-08 14:50:56 -0700479 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700480 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham8532d012019-05-08 14:50:56 -0700481 return;
482 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700483 mFeatures.refreshRateType = newRefreshRateType;
484 if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
Ady Abraham8532d012019-05-08 14:50:56 -0700485 event = ConfigEvent::Changed;
486 }
487 }
488 changeRefreshRate(newRefreshRateType, event);
489}
490
Ady Abraham09bd3922019-04-08 10:44:56 -0700491Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700492 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700493 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700494 return RefreshRateType::DEFAULT;
495 }
496
Ady Abraham6fe2c172019-07-12 12:37:57 -0700497 // If Display Power is not in normal operation we want to be in performance mode.
498 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700499 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700500 return RefreshRateType::PERFORMANCE;
501 }
502
Ady Abraham8532d012019-05-08 14:50:56 -0700503 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700504 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700505 return RefreshRateType::PERFORMANCE;
506 }
507
508 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700509 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700510 return RefreshRateType::DEFAULT;
511 }
512
Ady Abraham09bd3922019-04-08 10:44:56 -0700513 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700514 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700515 return RefreshRateType::PERFORMANCE;
516 }
517
Wei Wang09be73f2019-07-02 14:29:18 -0700518 // Content detection is on, find the appropriate refresh rate with minimal error
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700519 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Wei Wang09be73f2019-07-02 14:29:18 -0700520 auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
521 mRefreshRateConfigs.getRefreshRates().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700522 [rate](const auto& lhs, const auto& rhs) -> bool {
523 return std::abs(lhs.second->fps - rate) <
524 std::abs(rhs.second->fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700525 });
526 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700527
Ady Abraham85b3f012019-04-08 11:04:14 -0700528 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
529 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
530 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700531 constexpr float MARGIN = 0.05f;
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700532 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700533 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
534 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700535 ratio = iter->second->fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700536
Ady Abraham85b3f012019-04-08 11:04:14 -0700537 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
538 currRefreshRateType = iter->first;
539 break;
540 }
541 ++iter;
542 }
543 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700544
545 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800546}
547
548void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
549 std::lock_guard<std::mutex> lock(mCallbackLock);
550 if (mChangeRefreshRateCallback) {
551 mChangeRefreshRateCallback(refreshRateType, configEvent);
552 }
553}
554
Ana Krulec98b5b242018-08-10 15:03:23 -0700555} // namespace android