blob: ffcd94820e998edc34d3831c3299bfa500e35ecc [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,
Ana Krulec98b5b242018-08-10 15:03:23 -0700121 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700122 auto eventThread = makeEventThread(connectionName, phaseOffsetNs, offsetThresholdForNextVsync,
123 std::move(interceptCallback));
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700124 return createConnection(std::move(eventThread));
Dominik Laskowski98041832019-08-01 18:35:59 -0700125}
Ana Krulec98b5b242018-08-10 15:03:23 -0700126
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700127Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700128 const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
129 ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
Dominik Laskowskif654d572018-12-20 11:03:06 -0800130
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700131 auto connection =
132 createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
Dominik Laskowski98041832019-08-01 18:35:59 -0700133
134 mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
135 return handle;
Ana Krulec98b5b242018-08-10 15:03:23 -0700136}
137
Ana Krulec0c8cd522018-08-31 12:27:28 -0700138std::unique_ptr<EventThread> Scheduler::makeEventThread(
Dominik Laskowski98041832019-08-01 18:35:59 -0700139 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
140 impl::EventThread::InterceptVSyncsCallback&& interceptCallback) {
141 auto source = std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs,
142 offsetThresholdForNextVsync,
143 true /* traceVsync */, connectionName);
144 return std::make_unique<impl::EventThread>(std::move(source), std::move(interceptCallback),
145 connectionName);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800146}
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 -0700159EventThread* Scheduler::getEventThread(ConnectionHandle handle) {
160 RETURN_IF_INVALID_HANDLE(handle, nullptr);
161 return mConnections[handle].thread.get();
Ana Krulec98b5b242018-08-10 15:03:23 -0700162}
163
Dominik Laskowski98041832019-08-01 18:35:59 -0700164sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
165 RETURN_IF_INVALID_HANDLE(handle, nullptr);
166 return mConnections[handle].connection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700167}
168
Dominik Laskowski98041832019-08-01 18:35:59 -0700169void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
170 bool connected) {
171 RETURN_IF_INVALID_HANDLE(handle);
172 mConnections[handle].thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700173}
174
Dominik Laskowski98041832019-08-01 18:35:59 -0700175void Scheduler::onScreenAcquired(ConnectionHandle handle) {
176 RETURN_IF_INVALID_HANDLE(handle);
177 mConnections[handle].thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700178}
179
Dominik Laskowski98041832019-08-01 18:35:59 -0700180void Scheduler::onScreenReleased(ConnectionHandle handle) {
181 RETURN_IF_INVALID_HANDLE(handle);
182 mConnections[handle].thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700183}
184
Dominik Laskowski98041832019-08-01 18:35:59 -0700185void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
Ady Abraham447052e2019-02-13 16:07:27 -0800186 int32_t configId) {
Dominik Laskowski98041832019-08-01 18:35:59 -0700187 RETURN_IF_INVALID_HANDLE(handle);
188 mConnections[handle].thread->onConfigChanged(displayId, configId);
Ady Abraham447052e2019-02-13 16:07:27 -0800189}
190
Dominik Laskowski98041832019-08-01 18:35:59 -0700191void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
192 RETURN_IF_INVALID_HANDLE(handle);
193 mConnections.at(handle).thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700194}
195
Dominik Laskowski98041832019-08-01 18:35:59 -0700196void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
197 RETURN_IF_INVALID_HANDLE(handle);
198 mConnections[handle].thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700199}
Ana Krulece588e312018-09-18 12:32:24 -0700200
201void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
202 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
203 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
204}
205
206void Scheduler::enableHardwareVsync() {
207 std::lock_guard<std::mutex> lock(mHWVsyncLock);
208 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
209 mPrimaryDispSync->beginResync();
210 mEventControlThread->setVsyncEnabled(true);
211 mPrimaryHWVsyncEnabled = true;
212 }
213}
214
215void Scheduler::disableHardwareVsync(bool makeUnavailable) {
216 std::lock_guard<std::mutex> lock(mHWVsyncLock);
217 if (mPrimaryHWVsyncEnabled) {
218 mEventControlThread->setVsyncEnabled(false);
219 mPrimaryDispSync->endResync();
220 mPrimaryHWVsyncEnabled = false;
221 }
222 if (makeUnavailable) {
223 mHWVsyncAvailable = false;
224 }
225}
226
Ana Krulecc2870422019-01-29 19:00:58 -0800227void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
228 {
229 std::lock_guard<std::mutex> lock(mHWVsyncLock);
230 if (makeAvailable) {
231 mHWVsyncAvailable = makeAvailable;
232 } else if (!mHWVsyncAvailable) {
233 // Hardware vsync is not currently available, so abort the resync
234 // attempt for now
235 return;
236 }
237 }
238
239 if (period <= 0) {
240 return;
241 }
242
243 setVsyncPeriod(period);
244}
245
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700246void Scheduler::resync() {
Ana Krulecc2870422019-01-29 19:00:58 -0800247 static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
248
249 const nsecs_t now = systemTime();
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700250 const nsecs_t last = mLastResyncTime.exchange(now);
Ana Krulecc2870422019-01-29 19:00:58 -0800251
252 if (now - last > kIgnoreDelay) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700253 resyncToHardwareVsync(false,
254 mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
Ana Krulecc2870422019-01-29 19:00:58 -0800255 }
256}
257
Dominik Laskowski98041832019-08-01 18:35:59 -0700258void Scheduler::setVsyncPeriod(nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800259 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700260 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800261
262 if (!mPrimaryHWVsyncEnabled) {
263 mPrimaryDispSync->beginResync();
264 mEventControlThread->setVsyncEnabled(true);
265 mPrimaryHWVsyncEnabled = true;
266 }
Ana Krulece588e312018-09-18 12:32:24 -0700267}
268
Dominik Laskowski98041832019-08-01 18:35:59 -0700269void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700270 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700271 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700272 { // Scope for the lock
273 std::lock_guard<std::mutex> lock(mHWVsyncLock);
274 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700275 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700276 }
277 }
278
279 if (needsHwVsync) {
280 enableHardwareVsync();
281 } else {
282 disableHardwareVsync(false);
283 }
284}
285
286void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
287 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
288 enableHardwareVsync();
289 } else {
290 disableHardwareVsync(false);
291 }
292}
293
294void Scheduler::setIgnorePresentFences(bool ignore) {
295 mPrimaryDispSync->setIgnorePresentFences(ignore);
296}
297
Ady Abraham8fe11022019-06-12 17:11:12 -0700298nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800299 return mPrimaryDispSync->expectedPresentTime();
300}
301
Ady Abraham09bd3922019-04-08 10:44:56 -0700302std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700303 std::string const& name, int windowType) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700304 uint32_t defaultFps, performanceFps;
305 if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
306 defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
307 performanceFps =
308 mRefreshRateConfigs
309 .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
310 ? RefreshRateType::DEFAULT
311 : RefreshRateType::PERFORMANCE)
312 .fps;
313 } else {
314 defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
315 performanceFps = defaultFps;
316 }
Ana Krulecad083c42019-06-26 16:28:08 -0700317 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700318}
319
Ady Abrahama315ce72019-04-24 14:35:20 -0700320void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700321 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700322 nsecs_t presentTime, bool isHDR) {
323 mLayerHistory.insert(layerHandle, presentTime, isHDR);
324}
325
326void Scheduler::setLayerVisibility(
327 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
328 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100329}
330
Ady Abraham09bd3922019-04-08 10:44:56 -0700331void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700332 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
333 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700334 RefreshRateType newRefreshRateType;
335 {
336 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700337 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700338 return;
339 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700340 mFeatures.contentRefreshRate = refreshRateRound;
341 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700342
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700343 mFeatures.isHDRContent = isHDR;
344 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700345
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700346 mFeatures.contentDetection =
347 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700348 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700349 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700350 return;
351 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700352 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800353 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700354 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100355}
356
Dominik Laskowski98041832019-08-01 18:35:59 -0700357void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800358 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski98041832019-08-01 18:35:59 -0700359 mChangeRefreshRateCallback = std::move(callback);
Ady Abrahama1a49af2019-02-07 14:36:55 -0800360}
361
Ana Krulecfb772822018-11-30 10:44:07 +0100362void Scheduler::resetIdleTimer() {
363 if (mIdleTimer) {
364 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800365 }
366}
367
Ady Abraham8532d012019-05-08 14:50:56 -0700368void Scheduler::notifyTouchEvent() {
369 if (mTouchTimer) {
370 mTouchTimer->reset();
371 }
372
Dominik Laskowski98041832019-08-01 18:35:59 -0700373 if (mSupportKernelTimer && mIdleTimer) {
374 mIdleTimer->reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700375 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700376
377 // Touch event will boost the refresh rate to performance.
378 // Clear Layer History to get fresh FPS detection
379 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700380}
381
Ady Abraham6fe2c172019-07-12 12:37:57 -0700382void Scheduler::setDisplayPowerState(bool normal) {
383 {
384 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700385 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700386 }
387
388 if (mDisplayPowerTimer) {
389 mDisplayPowerTimer->reset();
390 }
391
392 // Display Power event will boost the refresh rate to performance.
393 // Clear Layer History to get fresh FPS detection
394 mLayerHistory.clearHistory();
395}
396
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700397void Scheduler::kernelIdleTimerCallback(TimerState state) {
398 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100399
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700400 const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
401 if (state == TimerState::Reset && refreshRate.first == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700402 // If we're not in performance mode then the kernel timer shouldn't do
403 // anything, as the refresh rate during DPU power collapse will be the
404 // same.
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700405 resyncToHardwareVsync(true /* makeAvailable */, refreshRate.second.vsyncPeriod);
406 } else if (state == TimerState::Expired && refreshRate.first != RefreshRateType::PERFORMANCE) {
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700407 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
408 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
409 // need to update the DispSync model anyway.
410 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700411 }
412}
413
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700414void Scheduler::idleTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700415 handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700416 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100417}
418
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700419void Scheduler::touchTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700420 const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
421 handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700422 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700423}
424
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700425void Scheduler::displayPowerTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700426 handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
427 true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700428 ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
Alec Mouridc28b372019-04-18 21:17:13 -0700429}
430
Dominik Laskowski98041832019-08-01 18:35:59 -0700431void Scheduler::dump(std::string& result) const {
Ana Krulecb43429d2019-01-09 14:28:51 -0800432 std::ostringstream stream;
Dominik Laskowski98041832019-08-01 18:35:59 -0700433 if (mIdleTimer) {
434 stream << "+ Idle timer interval: " << mIdleTimer->interval().count() << " ms\n";
435 }
436 if (mTouchTimer) {
437 stream << "+ Touch timer interval: " << mTouchTimer->interval().count() << " ms\n";
438 }
439
440 result.append(stream.str());
Ana Krulecb43429d2019-01-09 14:28:51 -0800441}
442
Ady Abraham6fe2c172019-07-12 12:37:57 -0700443template <class T>
444void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
Ady Abraham8532d012019-05-08 14:50:56 -0700445 ConfigEvent event = ConfigEvent::None;
446 RefreshRateType newRefreshRateType;
447 {
448 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6fe2c172019-07-12 12:37:57 -0700449 if (*currentState == newState) {
Ady Abraham8532d012019-05-08 14:50:56 -0700450 return;
451 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700452 *currentState = newState;
Ady Abraham8532d012019-05-08 14:50:56 -0700453 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700454 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham8532d012019-05-08 14:50:56 -0700455 return;
456 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700457 mFeatures.refreshRateType = newRefreshRateType;
458 if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
Ady Abraham8532d012019-05-08 14:50:56 -0700459 event = ConfigEvent::Changed;
460 }
461 }
462 changeRefreshRate(newRefreshRateType, event);
463}
464
Ady Abraham09bd3922019-04-08 10:44:56 -0700465Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700466 if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
467 return RefreshRateType::DEFAULT;
468 }
469
Ady Abraham8532d012019-05-08 14:50:56 -0700470 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700471 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700472 return RefreshRateType::DEFAULT;
473 }
474
Ady Abraham6fe2c172019-07-12 12:37:57 -0700475 // If Display Power is not in normal operation we want to be in performance mode.
476 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700477 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700478 return RefreshRateType::PERFORMANCE;
479 }
480
Ady Abraham8532d012019-05-08 14:50:56 -0700481 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700482 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700483 return RefreshRateType::PERFORMANCE;
484 }
485
486 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700487 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700488 return RefreshRateType::DEFAULT;
489 }
490
Ady Abraham09bd3922019-04-08 10:44:56 -0700491 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700492 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700493 return RefreshRateType::PERFORMANCE;
494 }
495
Wei Wang09be73f2019-07-02 14:29:18 -0700496 // Content detection is on, find the appropriate refresh rate with minimal error
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700497 // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700498 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700499 auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(),
500 mRefreshRateConfigs.getRefreshRateMap().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700501 [rate](const auto& lhs, const auto& rhs) -> bool {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700502 return std::abs(lhs.second.fps - rate) <
503 std::abs(rhs.second.fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700504 });
505 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700506
Ady Abraham85b3f012019-04-08 11:04:14 -0700507 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
508 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
509 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700510 constexpr float MARGIN = 0.05f;
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700511 float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700512 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700513 while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
514 ratio = iter->second.fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700515
Ady Abraham85b3f012019-04-08 11:04:14 -0700516 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
517 currRefreshRateType = iter->first;
518 break;
519 }
520 ++iter;
521 }
522 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700523
524 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800525}
526
Daniel Solomon0f0ddc12019-08-19 19:31:09 -0700527Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
528 std::lock_guard<std::mutex> lock(mFeatureStateLock);
529 return mFeatures.refreshRateType;
530}
531
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800532void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
533 std::lock_guard<std::mutex> lock(mCallbackLock);
534 if (mChangeRefreshRateCallback) {
535 mChangeRefreshRateCallback(refreshRateType, configEvent);
536 }
537}
538
Ana Krulec98b5b242018-08-10 15:03:23 -0700539} // namespace android