blob: d60e101fb437de50201010503a3903d4ad13b302 [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"
Dominik Laskowski6505f792019-09-18 11:10:05 -070044#include "InjectVSyncSource.h"
Ana Krulecf2c006d2019-06-21 15:37:07 -070045#include "OneShotTimer.h"
Ana Krulec434c22d2018-11-28 13:48:36 +010046#include "SchedulerUtils.h"
Sundong Ahnd5e08f62018-12-12 20:27:28 +090047#include "SurfaceFlingerProperties.h"
Ana Krulec98b5b242018-08-10 15:03:23 -070048
Dominik Laskowski98041832019-08-01 18:35:59 -070049#define RETURN_IF_INVALID_HANDLE(handle, ...) \
50 do { \
51 if (mConnections.count(handle) == 0) { \
52 ALOGE("Invalid connection handle %" PRIuPTR, handle.id); \
53 return __VA_ARGS__; \
54 } \
55 } while (false)
56
Ana Krulec98b5b242018-08-10 15:03:23 -070057namespace android {
58
Ady Abraham09bd3922019-04-08 10:44:56 -070059Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
60 const scheduler::RefreshRateConfigs& refreshRateConfig)
Dominik Laskowski98041832019-08-01 18:35:59 -070061 : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync",
62 sysprop::running_without_sync_framework(true))),
63 mEventControlThread(new impl::EventControlThread(std::move(function))),
64 mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
Ady Abraham09bd3922019-04-08 10:44:56 -070065 mRefreshRateConfigs(refreshRateConfig) {
Dominik Laskowski98041832019-08-01 18:35:59 -070066 using namespace sysprop;
Ady Abraham8532d012019-05-08 14:50:56 -070067
Ana Krulecfb772822018-11-30 10:44:07 +010068 char value[PROPERTY_VALUE_MAX];
Ana Kruleca5bdd9d2019-01-29 19:00:58 -080069 property_get("debug.sf.set_idle_timer_ms", value, "0");
Dominik Laskowski98041832019-08-01 18:35:59 -070070 const int setIdleTimerMs = atoi(value);
Ana Krulecfb772822018-11-30 10:44:07 +010071
Dominik Laskowski98041832019-08-01 18:35:59 -070072 if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
73 const auto callback = mSupportKernelTimer ? &Scheduler::kernelIdleTimerCallback
74 : &Scheduler::idleTimerCallback;
75
76 mIdleTimer.emplace(
77 std::chrono::milliseconds(millis),
78 [this, callback] { std::invoke(callback, this, TimerState::Reset); },
79 [this, callback] { std::invoke(callback, this, TimerState::Expired); });
Ana Krulecfb772822018-11-30 10:44:07 +010080 mIdleTimer->start();
81 }
Ady Abraham8532d012019-05-08 14:50:56 -070082
Dominik Laskowski98041832019-08-01 18:35:59 -070083 if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
Ady Abraham8532d012019-05-08 14:50:56 -070084 // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
Dominik Laskowski98041832019-08-01 18:35:59 -070085 mTouchTimer.emplace(
86 std::chrono::milliseconds(millis),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -070087 [this] { touchTimerCallback(TimerState::Reset); },
88 [this] { touchTimerCallback(TimerState::Expired); });
Ady Abraham8532d012019-05-08 14:50:56 -070089 mTouchTimer->start();
90 }
Ady Abraham6fe2c172019-07-12 12:37:57 -070091
Dominik Laskowski98041832019-08-01 18:35:59 -070092 if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
93 mDisplayPowerTimer.emplace(
94 std::chrono::milliseconds(millis),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -070095 [this] { displayPowerTimerCallback(TimerState::Reset); },
96 [this] { displayPowerTimerCallback(TimerState::Expired); });
Ady Abraham6fe2c172019-07-12 12:37:57 -070097 mDisplayPowerTimer->start();
98 }
Ana Krulece588e312018-09-18 12:32:24 -070099}
100
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700101Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
102 std::unique_ptr<EventControlThread> eventControlThread,
103 const scheduler::RefreshRateConfigs& configs)
Dominik Laskowski98041832019-08-01 18:35:59 -0700104 : mPrimaryDispSync(std::move(primaryDispSync)),
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700105 mEventControlThread(std::move(eventControlThread)),
Dominik Laskowski98041832019-08-01 18:35:59 -0700106 mSupportKernelTimer(false),
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700107 mRefreshRateConfigs(configs) {}
108
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800109Scheduler::~Scheduler() {
Ana Krulecf2c006d2019-06-21 15:37:07 -0700110 // Ensure the OneShotTimer threads are joined before we start destroying state.
Ady Abraham6fe2c172019-07-12 12:37:57 -0700111 mDisplayPowerTimer.reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700112 mTouchTimer.reset();
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800113 mIdleTimer.reset();
114}
Ana Krulec0c8cd522018-08-31 12:27:28 -0700115
Dominik Laskowski98041832019-08-01 18:35:59 -0700116DispSync& Scheduler::getPrimaryDispSync() {
117 return *mPrimaryDispSync;
118}
119
Dominik Laskowski6505f792019-09-18 11:10:05 -0700120std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
121 const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync) {
122 return std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs,
123 offsetThresholdForNextVsync, true /* traceVsync */,
124 name);
125}
126
Dominik Laskowski98041832019-08-01 18:35:59 -0700127Scheduler::ConnectionHandle Scheduler::createConnection(
Ady Abraham45e4e362019-06-07 18:20:51 -0700128 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
Ana Krulec98b5b242018-08-10 15:03:23 -0700129 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
Dominik Laskowski6505f792019-09-18 11:10:05 -0700130 auto vsyncSource =
131 makePrimaryDispSyncSource(connectionName, phaseOffsetNs, offsetThresholdForNextVsync);
132 auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
133 std::move(interceptCallback));
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700134 return createConnection(std::move(eventThread));
Dominik Laskowski98041832019-08-01 18:35:59 -0700135}
Ana Krulec98b5b242018-08-10 15:03:23 -0700136
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700137Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700138 const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
139 ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
Dominik Laskowskif654d572018-12-20 11:03:06 -0800140
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700141 auto connection =
142 createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
Dominik Laskowski98041832019-08-01 18:35:59 -0700143
144 mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
145 return handle;
Ana Krulec98b5b242018-08-10 15:03:23 -0700146}
147
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700148sp<EventThreadConnection> Scheduler::createConnectionInternal(
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700149 EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
150 return eventThread->createEventConnection([&] { resync(); }, configChanged);
Ana Krulec0c8cd522018-08-31 12:27:28 -0700151}
152
Ana Krulec98b5b242018-08-10 15:03:23 -0700153sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700154 ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700155 RETURN_IF_INVALID_HANDLE(handle, nullptr);
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700156 return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
Ana Krulec98b5b242018-08-10 15:03:23 -0700157}
158
Dominik Laskowski98041832019-08-01 18:35:59 -0700159sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
160 RETURN_IF_INVALID_HANDLE(handle, nullptr);
161 return mConnections[handle].connection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700162}
163
Dominik Laskowski98041832019-08-01 18:35:59 -0700164void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
165 bool connected) {
166 RETURN_IF_INVALID_HANDLE(handle);
167 mConnections[handle].thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700168}
169
Dominik Laskowski98041832019-08-01 18:35:59 -0700170void Scheduler::onScreenAcquired(ConnectionHandle handle) {
171 RETURN_IF_INVALID_HANDLE(handle);
172 mConnections[handle].thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700173}
174
Dominik Laskowski98041832019-08-01 18:35:59 -0700175void Scheduler::onScreenReleased(ConnectionHandle handle) {
176 RETURN_IF_INVALID_HANDLE(handle);
177 mConnections[handle].thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700178}
179
Dominik Laskowski98041832019-08-01 18:35:59 -0700180void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
Ady Abraham447052e2019-02-13 16:07:27 -0800181 int32_t configId) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700182 RETURN_IF_INVALID_HANDLE(handle);
183 mConnections[handle].thread->onConfigChanged(displayId, configId);
Ady Abraham447052e2019-02-13 16:07:27 -0800184}
185
Dominik Laskowski98041832019-08-01 18:35:59 -0700186void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
187 RETURN_IF_INVALID_HANDLE(handle);
188 mConnections.at(handle).thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700189}
190
Dominik Laskowski98041832019-08-01 18:35:59 -0700191void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
192 RETURN_IF_INVALID_HANDLE(handle);
193 mConnections[handle].thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700194}
Ana Krulece588e312018-09-18 12:32:24 -0700195
196void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
197 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
198 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
199}
200
Dominik Laskowski6505f792019-09-18 11:10:05 -0700201Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
202 if (mInjectVSyncs == enable) {
203 return {};
204 }
205
206 ALOGV("%s VSYNC injection", enable ? "Enabling" : "Disabling");
207
208 if (!mInjectorConnectionHandle) {
209 auto vsyncSource = std::make_unique<InjectVSyncSource>();
210 mVSyncInjector = vsyncSource.get();
211
212 auto eventThread =
213 std::make_unique<impl::EventThread>(std::move(vsyncSource),
214 impl::EventThread::InterceptVSyncsCallback());
215
216 mInjectorConnectionHandle = createConnection(std::move(eventThread));
217 }
218
219 mInjectVSyncs = enable;
220 return mInjectorConnectionHandle;
221}
222
223bool Scheduler::injectVSync(nsecs_t when) {
224 if (!mInjectVSyncs || !mVSyncInjector) {
225 return false;
226 }
227
228 mVSyncInjector->onInjectSyncEvent(when);
229 return true;
230}
231
Ana Krulece588e312018-09-18 12:32:24 -0700232void Scheduler::enableHardwareVsync() {
233 std::lock_guard<std::mutex> lock(mHWVsyncLock);
234 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
235 mPrimaryDispSync->beginResync();
236 mEventControlThread->setVsyncEnabled(true);
237 mPrimaryHWVsyncEnabled = true;
238 }
239}
240
241void Scheduler::disableHardwareVsync(bool makeUnavailable) {
242 std::lock_guard<std::mutex> lock(mHWVsyncLock);
243 if (mPrimaryHWVsyncEnabled) {
244 mEventControlThread->setVsyncEnabled(false);
245 mPrimaryDispSync->endResync();
246 mPrimaryHWVsyncEnabled = false;
247 }
248 if (makeUnavailable) {
249 mHWVsyncAvailable = false;
250 }
251}
252
Ana Krulecc2870422019-01-29 19:00:58 -0800253void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
254 {
255 std::lock_guard<std::mutex> lock(mHWVsyncLock);
256 if (makeAvailable) {
257 mHWVsyncAvailable = makeAvailable;
258 } else if (!mHWVsyncAvailable) {
259 // Hardware vsync is not currently available, so abort the resync
260 // attempt for now
261 return;
262 }
263 }
264
265 if (period <= 0) {
266 return;
267 }
268
269 setVsyncPeriod(period);
270}
271
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700272void Scheduler::resync() {
Long Ling457bef92019-09-11 14:43:11 -0700273 static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
Ana Krulecc2870422019-01-29 19:00:58 -0800274
275 const nsecs_t now = systemTime();
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700276 const nsecs_t last = mLastResyncTime.exchange(now);
Ana Krulecc2870422019-01-29 19:00:58 -0800277
278 if (now - last > kIgnoreDelay) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700279 resyncToHardwareVsync(false,
280 mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
Ana Krulecc2870422019-01-29 19:00:58 -0800281 }
282}
283
Dominik Laskowski98041832019-08-01 18:35:59 -0700284void Scheduler::setVsyncPeriod(nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800285 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700286 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800287
288 if (!mPrimaryHWVsyncEnabled) {
289 mPrimaryDispSync->beginResync();
290 mEventControlThread->setVsyncEnabled(true);
291 mPrimaryHWVsyncEnabled = true;
292 }
Ana Krulece588e312018-09-18 12:32:24 -0700293}
294
Dominik Laskowski98041832019-08-01 18:35:59 -0700295void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700296 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700297 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700298 { // Scope for the lock
299 std::lock_guard<std::mutex> lock(mHWVsyncLock);
300 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700301 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700302 }
303 }
304
305 if (needsHwVsync) {
306 enableHardwareVsync();
307 } else {
308 disableHardwareVsync(false);
309 }
310}
311
312void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
313 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
314 enableHardwareVsync();
315 } else {
316 disableHardwareVsync(false);
317 }
318}
319
320void Scheduler::setIgnorePresentFences(bool ignore) {
321 mPrimaryDispSync->setIgnorePresentFences(ignore);
322}
323
Ady Abraham8fe11022019-06-12 17:11:12 -0700324nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800325 return mPrimaryDispSync->expectedPresentTime();
326}
327
Ady Abraham09bd3922019-04-08 10:44:56 -0700328std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700329 std::string const& name, int windowType) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700330 uint32_t defaultFps, performanceFps;
331 if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
332 defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
333 performanceFps =
334 mRefreshRateConfigs
335 .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
336 ? RefreshRateType::DEFAULT
337 : RefreshRateType::PERFORMANCE)
338 .fps;
339 } else {
340 defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
341 performanceFps = defaultFps;
342 }
Ana Krulecad083c42019-06-26 16:28:08 -0700343 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700344}
345
Ady Abrahama315ce72019-04-24 14:35:20 -0700346void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700347 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700348 nsecs_t presentTime, bool isHDR) {
349 mLayerHistory.insert(layerHandle, presentTime, isHDR);
350}
351
352void Scheduler::setLayerVisibility(
353 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
354 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100355}
356
Ady Abraham09bd3922019-04-08 10:44:56 -0700357void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700358 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
359 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700360 RefreshRateType newRefreshRateType;
361 {
362 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700363 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700364 return;
365 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700366 mFeatures.contentRefreshRate = refreshRateRound;
367 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700368
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700369 mFeatures.isHDRContent = isHDR;
370 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700371
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700372 mFeatures.contentDetection =
373 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700374 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700375 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700376 return;
377 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700378 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800379 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700380 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100381}
382
Dominik Laskowski98041832019-08-01 18:35:59 -0700383void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800384 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700385 mChangeRefreshRateCallback = std::move(callback);
Ady Abrahama1a49af2019-02-07 14:36:55 -0800386}
387
Ana Krulecfb772822018-11-30 10:44:07 +0100388void Scheduler::resetIdleTimer() {
389 if (mIdleTimer) {
390 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800391 }
392}
393
Ady Abraham8532d012019-05-08 14:50:56 -0700394void Scheduler::notifyTouchEvent() {
395 if (mTouchTimer) {
396 mTouchTimer->reset();
397 }
398
Dominik Laskowski98041832019-08-01 18:35:59 -0700399 if (mSupportKernelTimer && mIdleTimer) {
400 mIdleTimer->reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700401 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700402
403 // Touch event will boost the refresh rate to performance.
404 // Clear Layer History to get fresh FPS detection
405 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700406}
407
Ady Abraham6fe2c172019-07-12 12:37:57 -0700408void Scheduler::setDisplayPowerState(bool normal) {
409 {
410 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700411 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700412 }
413
414 if (mDisplayPowerTimer) {
415 mDisplayPowerTimer->reset();
416 }
417
418 // Display Power event will boost the refresh rate to performance.
419 // Clear Layer History to get fresh FPS detection
420 mLayerHistory.clearHistory();
421}
422
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700423void Scheduler::kernelIdleTimerCallback(TimerState state) {
424 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100425
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700426 const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
427 if (state == TimerState::Reset && refreshRate.first == 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.
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700431 resyncToHardwareVsync(true /* makeAvailable */, refreshRate.second.vsyncPeriod);
432 } else if (state == TimerState::Expired && refreshRate.first != 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() {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700492 if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
493 return RefreshRateType::DEFAULT;
494 }
495
Ady Abraham8532d012019-05-08 14:50:56 -0700496 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700497 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700498 return RefreshRateType::DEFAULT;
499 }
500
Ady Abraham6fe2c172019-07-12 12:37:57 -0700501 // If Display Power is not in normal operation we want to be in performance mode.
502 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700503 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700504 return RefreshRateType::PERFORMANCE;
505 }
506
Ady Abraham8532d012019-05-08 14:50:56 -0700507 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700508 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700509 return RefreshRateType::PERFORMANCE;
510 }
511
512 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700513 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700514 return RefreshRateType::DEFAULT;
515 }
516
Ady Abraham09bd3922019-04-08 10:44:56 -0700517 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700518 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700519 return RefreshRateType::PERFORMANCE;
520 }
521
Wei Wang09be73f2019-07-02 14:29:18 -0700522 // Content detection is on, find the appropriate refresh rate with minimal error
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700523 // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700524 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700525 auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(),
526 mRefreshRateConfigs.getRefreshRateMap().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700527 [rate](const auto& lhs, const auto& rhs) -> bool {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700528 return std::abs(lhs.second.fps - rate) <
529 std::abs(rhs.second.fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700530 });
531 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700532
Ady Abraham85b3f012019-04-08 11:04:14 -0700533 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
534 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
535 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700536 constexpr float MARGIN = 0.05f;
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700537 float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700538 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700539 while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
540 ratio = iter->second.fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700541
Ady Abraham85b3f012019-04-08 11:04:14 -0700542 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
543 currRefreshRateType = iter->first;
544 break;
545 }
546 ++iter;
547 }
548 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700549
550 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800551}
552
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700553Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
554 std::lock_guard<std::mutex> lock(mFeatureStateLock);
555 return mFeatures.refreshRateType;
556}
557
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800558void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
559 std::lock_guard<std::mutex> lock(mCallbackLock);
560 if (mChangeRefreshRateCallback) {
561 mChangeRefreshRateCallback(refreshRateType, configEvent);
562 }
563}
564
Ana Krulec98b5b242018-08-10 15:03:23 -0700565} // namespace android