blob: b2b85bcc4b4fe9e1f3e13224b77739a27f8d35bb [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
Ana Krulec7ab56032018-11-02 20:51:06 +010017#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
Ana Krulec98b5b242018-08-10 15:03:23 -070019#include "Scheduler.h"
20
Ana Krulec434c22d2018-11-28 13:48:36 +010021#include <algorithm>
Ana Krulec98b5b242018-08-10 15:03:23 -070022#include <cinttypes>
23#include <cstdint>
24#include <memory>
Ana Krulec7ab56032018-11-02 20:51:06 +010025#include <numeric>
Ana Krulec98b5b242018-08-10 15:03:23 -070026
Ana Krulece588e312018-09-18 12:32:24 -070027#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
28#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
Ana Krulece588e312018-09-18 12:32:24 -070029#include <configstore/Utils.h>
Ana Krulecfb772822018-11-30 10:44:07 +010030#include <cutils/properties.h>
Ady Abraham8f1ee7f2019-04-05 10:32:50 -070031#include <input/InputWindow.h>
Ana Krulecfefd6ae2019-02-13 17:53:08 -080032#include <system/window.h>
Ana Krulece588e312018-09-18 12:32:24 -070033#include <ui/DisplayStatInfo.h>
Ana Krulec3084c052018-11-21 20:27:17 +010034#include <utils/Timers.h>
Ana Krulec7ab56032018-11-02 20:51:06 +010035#include <utils/Trace.h>
Ana Krulec98b5b242018-08-10 15:03:23 -070036
37#include "DispSync.h"
38#include "DispSyncSource.h"
Ana Krulece588e312018-09-18 12:32:24 -070039#include "EventControlThread.h"
Ana Krulec98b5b242018-08-10 15:03:23 -070040#include "EventThread.h"
41#include "InjectVSyncSource.h"
Ady Abraham09bd3922019-04-08 10:44:56 -070042#include "LayerInfo.h"
Ana Krulecf2c006d2019-06-21 15:37:07 -070043#include "OneShotTimer.h"
Ana Krulec434c22d2018-11-28 13:48:36 +010044#include "SchedulerUtils.h"
Sundong Ahnd5e08f62018-12-12 20:27:28 +090045#include "SurfaceFlingerProperties.h"
Ana Krulec98b5b242018-08-10 15:03:23 -070046
47namespace android {
48
Ana Krulece588e312018-09-18 12:32:24 -070049using namespace android::hardware::configstore;
50using namespace android::hardware::configstore::V1_0;
Sundong Ahnd5e08f62018-12-12 20:27:28 +090051using namespace android::sysprop;
Ana Krulece588e312018-09-18 12:32:24 -070052
Ana Krulec0c8cd522018-08-31 12:27:28 -070053#define RETURN_VALUE_IF_INVALID(value) \
54 if (handle == nullptr || mConnections.count(handle->id) == 0) return value
55#define RETURN_IF_INVALID() \
56 if (handle == nullptr || mConnections.count(handle->id) == 0) return
57
Ana Krulec98b5b242018-08-10 15:03:23 -070058std::atomic<int64_t> Scheduler::sNextId = 0;
59
Ady Abraham09bd3922019-04-08 10:44:56 -070060Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
61 const scheduler::RefreshRateConfigs& refreshRateConfig)
Sundong Ahnd5e08f62018-12-12 20:27:28 +090062 : mHasSyncFramework(running_without_sync_framework(true)),
63 mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
Ana Krulece588e312018-09-18 12:32:24 -070064 mPrimaryHWVsyncEnabled(false),
Ady Abraham09bd3922019-04-08 10:44:56 -070065 mHWVsyncAvailable(false),
66 mRefreshRateConfigs(refreshRateConfig) {
Ana Krulece588e312018-09-18 12:32:24 -070067 // Note: We create a local temporary with the real DispSync implementation
68 // type temporarily so we can initialize it with the configured values,
69 // before storing it for more generic use using the interface type.
70 auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
71 primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
72 mPrimaryDispSync = std::move(primaryDispSync);
73 mEventControlThread = std::make_unique<impl::EventControlThread>(function);
Ana Krulecfb772822018-11-30 10:44:07 +010074
Ady Abrahambe59c0d2019-03-05 13:01:13 -080075 mSetIdleTimerMs = set_idle_timer_ms(0);
Alec Mouridc28b372019-04-18 21:17:13 -070076 mSupportKernelTimer = support_kernel_idle_timer(false);
Ady Abrahambe59c0d2019-03-05 13:01:13 -080077
Ady Abraham8532d012019-05-08 14:50:56 -070078 mSetTouchTimerMs = set_touch_timer_ms(0);
Ady Abraham6fe2c172019-07-12 12:37:57 -070079 mSetDisplayPowerTimerMs = set_display_power_timer_ms(0);
Ady Abraham8532d012019-05-08 14:50:56 -070080
Ana Krulecfb772822018-11-30 10:44:07 +010081 char value[PROPERTY_VALUE_MAX];
Ana Kruleca5bdd9d2019-01-29 19:00:58 -080082 property_get("debug.sf.set_idle_timer_ms", value, "0");
Ady Abrahambe59c0d2019-03-05 13:01:13 -080083 int int_value = atoi(value);
84 if (int_value) {
85 mSetIdleTimerMs = atoi(value);
86 }
Ana Krulecfb772822018-11-30 10:44:07 +010087
88 if (mSetIdleTimerMs > 0) {
Alec Mouridc28b372019-04-18 21:17:13 -070089 if (mSupportKernelTimer) {
Ana Krulecf2c006d2019-06-21 15:37:07 -070090 mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
91 std::chrono::milliseconds(mSetIdleTimerMs),
Dominik Laskowski3a80a382019-07-25 11:16:07 -070092 [this] { kernelIdleTimerCallback(TimerState::RESET); },
93 [this] { kernelIdleTimerCallback(TimerState::EXPIRED); });
Alec Mouridc28b372019-04-18 21:17:13 -070094 } else {
Ana Krulecf2c006d2019-06-21 15:37:07 -070095 mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
Dominik Laskowski3a80a382019-07-25 11:16:07 -070096 std::chrono::milliseconds(mSetIdleTimerMs),
97 [this] { idleTimerCallback(TimerState::RESET); },
98 [this] { idleTimerCallback(TimerState::EXPIRED); });
Alec Mouridc28b372019-04-18 21:17:13 -070099 }
Ana Krulecfb772822018-11-30 10:44:07 +0100100 mIdleTimer->start();
101 }
Ady Abraham8532d012019-05-08 14:50:56 -0700102
103 if (mSetTouchTimerMs > 0) {
104 // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
Ana Krulecf2c006d2019-06-21 15:37:07 -0700105 mTouchTimer = std::make_unique<scheduler::OneShotTimer>(
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700106 std::chrono::milliseconds(mSetTouchTimerMs),
107 [this] { touchTimerCallback(TimerState::RESET); },
108 [this] { touchTimerCallback(TimerState::EXPIRED); });
Ady Abraham8532d012019-05-08 14:50:56 -0700109 mTouchTimer->start();
110 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700111
112 if (mSetDisplayPowerTimerMs > 0) {
113 mDisplayPowerTimer = std::make_unique<scheduler::OneShotTimer>(
114 std::chrono::milliseconds(mSetDisplayPowerTimerMs),
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700115 [this] { displayPowerTimerCallback(TimerState::RESET); },
116 [this] { displayPowerTimerCallback(TimerState::EXPIRED); });
Ady Abraham6fe2c172019-07-12 12:37:57 -0700117 mDisplayPowerTimer->start();
118 }
Ana Krulece588e312018-09-18 12:32:24 -0700119}
120
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800121Scheduler::~Scheduler() {
Ana Krulecf2c006d2019-06-21 15:37:07 -0700122 // Ensure the OneShotTimer threads are joined before we start destroying state.
Ady Abraham6fe2c172019-07-12 12:37:57 -0700123 mDisplayPowerTimer.reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700124 mTouchTimer.reset();
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800125 mIdleTimer.reset();
126}
Ana Krulec0c8cd522018-08-31 12:27:28 -0700127
Ana Krulec98b5b242018-08-10 15:03:23 -0700128sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
Ady Abraham45e4e362019-06-07 18:20:51 -0700129 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
130 ResyncCallback resyncCallback,
Ana Krulec98b5b242018-08-10 15:03:23 -0700131 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
132 const int64_t id = sNextId++;
133 ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
134
Ana Krulec98b5b242018-08-10 15:03:23 -0700135 std::unique_ptr<EventThread> eventThread =
Dominik Laskowskif654d572018-12-20 11:03:06 -0800136 makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
Ady Abraham45e4e362019-06-07 18:20:51 -0700137 offsetThresholdForNextVsync, std::move(interceptCallback));
Dominik Laskowskif654d572018-12-20 11:03:06 -0800138
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800139 auto eventThreadConnection =
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700140 createConnectionInternal(eventThread.get(), std::move(resyncCallback),
141 ISurfaceComposer::eConfigChangedSuppress);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800142 mConnections.emplace(id,
143 std::make_unique<Connection>(new ConnectionHandle(id),
144 eventThreadConnection,
145 std::move(eventThread)));
Ana Krulec98b5b242018-08-10 15:03:23 -0700146 return mConnections[id]->handle;
147}
148
Ana Krulec0c8cd522018-08-31 12:27:28 -0700149std::unique_ptr<EventThread> Scheduler::makeEventThread(
Ady Abraham45e4e362019-06-07 18:20:51 -0700150 const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
151 nsecs_t offsetThresholdForNextVsync,
Ana Krulec0c8cd522018-08-31 12:27:28 -0700152 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
153 std::unique_ptr<VSyncSource> eventThreadSource =
Ady Abraham45e4e362019-06-07 18:20:51 -0700154 std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
155 true, connectionName);
Dominik Laskowskibd52c842019-01-28 18:11:23 -0800156 return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800157 std::move(interceptCallback), connectionName);
158}
159
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700160sp<EventThreadConnection> Scheduler::createConnectionInternal(
161 EventThread* eventThread, ResyncCallback&& resyncCallback,
162 ISurfaceComposer::ConfigChanged configChanged) {
163 return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
Ana Krulec0c8cd522018-08-31 12:27:28 -0700164}
165
Ana Krulec98b5b242018-08-10 15:03:23 -0700166sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700167 const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
168 ISurfaceComposer::ConfigChanged configChanged) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700169 RETURN_VALUE_IF_INVALID(nullptr);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800170 return createConnectionInternal(mConnections[handle->id]->thread.get(),
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700171 std::move(resyncCallback), configChanged);
Ana Krulec98b5b242018-08-10 15:03:23 -0700172}
173
174EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700175 RETURN_VALUE_IF_INVALID(nullptr);
176 return mConnections[handle->id]->thread.get();
Ana Krulec98b5b242018-08-10 15:03:23 -0700177}
178
Ana Krulec85c39af2018-12-26 17:29:57 -0800179sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700180 RETURN_VALUE_IF_INVALID(nullptr);
181 return mConnections[handle->id]->eventConnection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700182}
183
184void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800185 PhysicalDisplayId displayId, bool connected) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700186 RETURN_IF_INVALID();
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800187 mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700188}
189
190void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700191 RETURN_IF_INVALID();
192 mConnections[handle->id]->thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700193}
194
195void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700196 RETURN_IF_INVALID();
197 mConnections[handle->id]->thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700198}
199
Ady Abraham447052e2019-02-13 16:07:27 -0800200void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
201 int32_t configId) {
202 RETURN_IF_INVALID();
203 mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
204}
205
Yiwei Zhang5434a782018-12-05 18:06:32 -0800206void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700207 RETURN_IF_INVALID();
208 mConnections.at(handle->id)->thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700209}
210
211void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700212 RETURN_IF_INVALID();
213 mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700214}
Ana Krulece588e312018-09-18 12:32:24 -0700215
216void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
217 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
218 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
219}
220
221void Scheduler::enableHardwareVsync() {
222 std::lock_guard<std::mutex> lock(mHWVsyncLock);
223 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
224 mPrimaryDispSync->beginResync();
225 mEventControlThread->setVsyncEnabled(true);
226 mPrimaryHWVsyncEnabled = true;
227 }
228}
229
230void Scheduler::disableHardwareVsync(bool makeUnavailable) {
231 std::lock_guard<std::mutex> lock(mHWVsyncLock);
232 if (mPrimaryHWVsyncEnabled) {
233 mEventControlThread->setVsyncEnabled(false);
234 mPrimaryDispSync->endResync();
235 mPrimaryHWVsyncEnabled = false;
236 }
237 if (makeUnavailable) {
238 mHWVsyncAvailable = false;
239 }
240}
241
Ana Krulecc2870422019-01-29 19:00:58 -0800242void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
243 {
244 std::lock_guard<std::mutex> lock(mHWVsyncLock);
245 if (makeAvailable) {
246 mHWVsyncAvailable = makeAvailable;
247 } else if (!mHWVsyncAvailable) {
248 // Hardware vsync is not currently available, so abort the resync
249 // attempt for now
250 return;
251 }
252 }
253
254 if (period <= 0) {
255 return;
256 }
257
258 setVsyncPeriod(period);
259}
260
261ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
262 std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
263 return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
264 if (const auto vsync = ptr.lock()) {
265 vsync->resync(getVsyncPeriod);
266 }
267 };
268}
269
270void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
271 static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
272
273 const nsecs_t now = systemTime();
274 const nsecs_t last = lastResyncTime.exchange(now);
275
276 if (now - last > kIgnoreDelay) {
277 scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
278 }
279}
280
281void Scheduler::setRefreshSkipCount(int count) {
282 mPrimaryDispSync->setRefreshSkipCount(count);
283}
284
Ana Krulece588e312018-09-18 12:32:24 -0700285void Scheduler::setVsyncPeriod(const nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800286 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700287 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800288
289 if (!mPrimaryHWVsyncEnabled) {
290 mPrimaryDispSync->beginResync();
291 mEventControlThread->setVsyncEnabled(true);
292 mPrimaryHWVsyncEnabled = true;
293 }
Ana Krulece588e312018-09-18 12:32:24 -0700294}
295
Alec Mourif8e689c2019-05-20 18:32:22 -0700296void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700297 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700298 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700299 { // Scope for the lock
300 std::lock_guard<std::mutex> lock(mHWVsyncLock);
301 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700302 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700303 }
304 }
305
306 if (needsHwVsync) {
307 enableHardwareVsync();
308 } else {
309 disableHardwareVsync(false);
310 }
311}
312
313void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
314 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
315 enableHardwareVsync();
316 } else {
317 disableHardwareVsync(false);
318 }
319}
320
321void Scheduler::setIgnorePresentFences(bool ignore) {
322 mPrimaryDispSync->setIgnorePresentFences(ignore);
323}
324
Ady Abraham8fe11022019-06-12 17:11:12 -0700325nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800326 return mPrimaryDispSync->expectedPresentTime();
327}
328
Ady Abraham3aff9172019-02-07 19:10:26 -0800329void Scheduler::dumpPrimaryDispSync(std::string& result) const {
330 mPrimaryDispSync->dump(result);
331}
332
Ady Abraham09bd3922019-04-08 10:44:56 -0700333std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700334 std::string const& name, int windowType) {
335 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
336 ? RefreshRateType::DEFAULT
337 : RefreshRateType::PERFORMANCE;
Ady Abraham09bd3922019-04-08 10:44:56 -0700338
339 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
Ana Krulecad083c42019-06-26 16:28:08 -0700340 const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
341
342 const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
343 const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
344 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700345}
346
Ady Abrahama315ce72019-04-24 14:35:20 -0700347void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700348 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700349 nsecs_t presentTime, bool isHDR) {
350 mLayerHistory.insert(layerHandle, presentTime, isHDR);
351}
352
353void Scheduler::setLayerVisibility(
354 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
355 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100356}
357
Kevin DuBois413287f2019-02-25 08:46:47 -0800358void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
359 fn(*mPrimaryDispSync);
360}
361
Ady Abraham09bd3922019-04-08 10:44:56 -0700362void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700363 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
364 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700365 RefreshRateType newRefreshRateType;
366 {
367 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abrahama315ce72019-04-24 14:35:20 -0700368 if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700369 return;
370 }
Ady Abrahama315ce72019-04-24 14:35:20 -0700371 mContentRefreshRate = refreshRateRound;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700372 ATRACE_INT("ContentFPS", mContentRefreshRate);
373
Ady Abrahama315ce72019-04-24 14:35:20 -0700374 mIsHDRContent = isHDR;
375 ATRACE_INT("ContentHDR", mIsHDRContent);
376
377 mCurrentContentFeatureState = refreshRateRound > 0
378 ? ContentFeatureState::CONTENT_DETECTION_ON
379 : ContentFeatureState::CONTENT_DETECTION_OFF;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700380 newRefreshRateType = calculateRefreshRateType();
381 if (mRefreshRateType == newRefreshRateType) {
382 return;
383 }
384 mRefreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800385 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700386 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100387}
388
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800389void Scheduler::setChangeRefreshRateCallback(
Alec Mouri7f015182019-07-11 13:56:22 -0700390 const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800391 std::lock_guard<std::mutex> lock(mCallbackLock);
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800392 mChangeRefreshRateCallback = changeRefreshRateCallback;
Ady Abrahama1a49af2019-02-07 14:36:55 -0800393}
394
Alec Mouri7f015182019-07-11 13:56:22 -0700395void Scheduler::setGetCurrentRefreshRateTypeCallback(
396 const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
397 std::lock_guard<std::mutex> lock(mCallbackLock);
398 mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
399}
400
Alec Mouridc28b372019-04-18 21:17:13 -0700401void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
402 std::lock_guard<std::mutex> lock(mCallbackLock);
403 mGetVsyncPeriod = getVsyncPeriod;
404}
405
Ana Krulec3084c052018-11-21 20:27:17 +0100406void Scheduler::updateFrameSkipping(const int64_t skipCount) {
407 ATRACE_INT("FrameSkipCount", skipCount);
408 if (mSkipCount != skipCount) {
409 // Only update DispSync if it hasn't been updated yet.
410 mPrimaryDispSync->setRefreshSkipCount(skipCount);
411 mSkipCount = skipCount;
412 }
413}
414
Ana Krulecfb772822018-11-30 10:44:07 +0100415void Scheduler::resetIdleTimer() {
416 if (mIdleTimer) {
417 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800418 }
419}
420
Ady Abraham8532d012019-05-08 14:50:56 -0700421void Scheduler::notifyTouchEvent() {
422 if (mTouchTimer) {
423 mTouchTimer->reset();
424 }
425
426 if (mSupportKernelTimer) {
427 resetIdleTimer();
428 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700429
430 // Touch event will boost the refresh rate to performance.
431 // Clear Layer History to get fresh FPS detection
432 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700433}
434
Ady Abraham6fe2c172019-07-12 12:37:57 -0700435void Scheduler::setDisplayPowerState(bool normal) {
436 {
437 std::lock_guard<std::mutex> lock(mFeatureStateLock);
438 mIsDisplayPowerStateNormal = normal;
439 }
440
441 if (mDisplayPowerTimer) {
442 mDisplayPowerTimer->reset();
443 }
444
445 // Display Power event will boost the refresh rate to performance.
446 // Clear Layer History to get fresh FPS detection
447 mLayerHistory.clearHistory();
448}
449
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700450void Scheduler::kernelIdleTimerCallback(TimerState state) {
451 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100452
Alec Mouridc28b372019-04-18 21:17:13 -0700453 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700454 if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
455
456 const auto type = mGetCurrentRefreshRateTypeCallback();
457 if (state == TimerState::RESET && type == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700458 // If we're not in performance mode then the kernel timer shouldn't do
459 // anything, as the refresh rate during DPU power collapse will be the
460 // same.
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700461 resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
462 } else if (state == TimerState::EXPIRED && type != RefreshRateType::PERFORMANCE) {
463 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
464 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
465 // need to update the DispSync model anyway.
466 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700467 }
468}
469
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700470void Scheduler::idleTimerCallback(TimerState state) {
471 handleTimerStateChanged(&mCurrentIdleTimerState, state, false /* eventOnContentDetection */);
472 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100473}
474
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700475void Scheduler::touchTimerCallback(TimerState state) {
476 const TouchState touch = state == TimerState::RESET ? TouchState::ACTIVE : TouchState::INACTIVE;
477 handleTimerStateChanged(&mCurrentTouchState, touch, true /* eventOnContentDetection */);
478 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700479}
480
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700481void Scheduler::displayPowerTimerCallback(TimerState state) {
482 handleTimerStateChanged(&mDisplayPowerTimerState, state, true /* eventOnContentDetection */);
483 ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
Alec Mouridc28b372019-04-18 21:17:13 -0700484}
485
Ana Krulecb43429d2019-01-09 14:28:51 -0800486std::string Scheduler::doDump() {
487 std::ostringstream stream;
488 stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
Ady Abraham8532d012019-05-08 14:50:56 -0700489 stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
Ana Krulecb43429d2019-01-09 14:28:51 -0800490 return stream.str();
491}
492
Ady Abraham6fe2c172019-07-12 12:37:57 -0700493template <class T>
494void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
Ady Abraham8532d012019-05-08 14:50:56 -0700495 ConfigEvent event = ConfigEvent::None;
496 RefreshRateType newRefreshRateType;
497 {
498 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6fe2c172019-07-12 12:37:57 -0700499 if (*currentState == newState) {
Ady Abraham8532d012019-05-08 14:50:56 -0700500 return;
501 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700502 *currentState = newState;
Ady Abraham8532d012019-05-08 14:50:56 -0700503 newRefreshRateType = calculateRefreshRateType();
504 if (mRefreshRateType == newRefreshRateType) {
505 return;
506 }
507 mRefreshRateType = newRefreshRateType;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700508 if (eventOnContentDetection &&
509 mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
Ady Abraham8532d012019-05-08 14:50:56 -0700510 event = ConfigEvent::Changed;
511 }
512 }
513 changeRefreshRate(newRefreshRateType, event);
514}
515
Ady Abraham09bd3922019-04-08 10:44:56 -0700516Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700517 // HDR content is not supported on PERFORMANCE mode
518 if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700519 return RefreshRateType::DEFAULT;
520 }
521
Ady Abraham6fe2c172019-07-12 12:37:57 -0700522 // If Display Power is not in normal operation we want to be in performance mode.
523 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700524 if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == TimerState::RESET) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700525 return RefreshRateType::PERFORMANCE;
526 }
527
Ady Abraham8532d012019-05-08 14:50:56 -0700528 // As long as touch is active we want to be in performance mode
529 if (mCurrentTouchState == TouchState::ACTIVE) {
530 return RefreshRateType::PERFORMANCE;
531 }
532
533 // If timer has expired as it means there is no new content on the screen
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700534 if (mCurrentIdleTimerState == TimerState::EXPIRED) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700535 return RefreshRateType::DEFAULT;
536 }
537
Ady Abraham09bd3922019-04-08 10:44:56 -0700538 // If content detection is off we choose performance as we don't know the content fps
539 if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
540 return RefreshRateType::PERFORMANCE;
541 }
542
Wei Wang09be73f2019-07-02 14:29:18 -0700543 // Content detection is on, find the appropriate refresh rate with minimal error
544 auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
545 mRefreshRateConfigs.getRefreshRates().cend(),
546 [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
547 return std::abs(l.second->fps - static_cast<float>(rate)) <
548 std::abs(r.second->fps - static_cast<float>(rate));
549 });
550 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700551
Ady Abraham85b3f012019-04-08 11:04:14 -0700552 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
553 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
554 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700555 constexpr float MARGIN = 0.05f;
Ady Abraham85b3f012019-04-08 11:04:14 -0700556 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
557 float(mContentRefreshRate);
558 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
559 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
560 ratio = iter->second->fps / float(mContentRefreshRate);
Ady Abraham09bd3922019-04-08 10:44:56 -0700561
Ady Abraham85b3f012019-04-08 11:04:14 -0700562 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
563 currRefreshRateType = iter->first;
564 break;
565 }
566 ++iter;
567 }
568 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700569
570 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800571}
572
573void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
574 std::lock_guard<std::mutex> lock(mCallbackLock);
575 if (mChangeRefreshRateCallback) {
576 mChangeRefreshRateCallback(refreshRateType, configEvent);
577 }
578}
579
Ana Krulec98b5b242018-08-10 15:03:23 -0700580} // namespace android