blob: 38834273a46eea70f0f31a74ed135f183a8334c7 [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 Laskowskidd252cd2019-07-26 09:10:16 -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),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -070097 [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),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700107 [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 Laskowskidd252cd2019-07-26 09:10:16 -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
Dominik Laskowski7c9dbf92019-08-01 17:57:31 -0700121Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
122 std::unique_ptr<EventControlThread> eventControlThread,
123 const scheduler::RefreshRateConfigs& configs)
124 : mHasSyncFramework(false),
125 mPrimaryDispSync(std::move(primaryDispSync)),
126 mEventControlThread(std::move(eventControlThread)),
127 mRefreshRateConfigs(configs) {}
128
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800129Scheduler::~Scheduler() {
Ana Krulecf2c006d2019-06-21 15:37:07 -0700130 // Ensure the OneShotTimer threads are joined before we start destroying state.
Ady Abraham6fe2c172019-07-12 12:37:57 -0700131 mDisplayPowerTimer.reset();
Ady Abraham8532d012019-05-08 14:50:56 -0700132 mTouchTimer.reset();
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800133 mIdleTimer.reset();
134}
Ana Krulec0c8cd522018-08-31 12:27:28 -0700135
Ana Krulec98b5b242018-08-10 15:03:23 -0700136sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
Ady Abraham45e4e362019-06-07 18:20:51 -0700137 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
138 ResyncCallback resyncCallback,
Ana Krulec98b5b242018-08-10 15:03:23 -0700139 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
140 const int64_t id = sNextId++;
141 ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
142
Ana Krulec98b5b242018-08-10 15:03:23 -0700143 std::unique_ptr<EventThread> eventThread =
Dominik Laskowskif654d572018-12-20 11:03:06 -0800144 makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
Ady Abraham45e4e362019-06-07 18:20:51 -0700145 offsetThresholdForNextVsync, std::move(interceptCallback));
Dominik Laskowskif654d572018-12-20 11:03:06 -0800146
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800147 auto eventThreadConnection =
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700148 createConnectionInternal(eventThread.get(), std::move(resyncCallback),
149 ISurfaceComposer::eConfigChangedSuppress);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800150 mConnections.emplace(id,
151 std::make_unique<Connection>(new ConnectionHandle(id),
152 eventThreadConnection,
153 std::move(eventThread)));
Ana Krulec98b5b242018-08-10 15:03:23 -0700154 return mConnections[id]->handle;
155}
156
Ana Krulec0c8cd522018-08-31 12:27:28 -0700157std::unique_ptr<EventThread> Scheduler::makeEventThread(
Ady Abraham45e4e362019-06-07 18:20:51 -0700158 const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
159 nsecs_t offsetThresholdForNextVsync,
Ana Krulec0c8cd522018-08-31 12:27:28 -0700160 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
161 std::unique_ptr<VSyncSource> eventThreadSource =
Ady Abraham45e4e362019-06-07 18:20:51 -0700162 std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
163 true, connectionName);
Dominik Laskowskibd52c842019-01-28 18:11:23 -0800164 return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800165 std::move(interceptCallback), connectionName);
166}
167
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700168sp<EventThreadConnection> Scheduler::createConnectionInternal(
169 EventThread* eventThread, ResyncCallback&& resyncCallback,
170 ISurfaceComposer::ConfigChanged configChanged) {
171 return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
Ana Krulec0c8cd522018-08-31 12:27:28 -0700172}
173
Ana Krulec98b5b242018-08-10 15:03:23 -0700174sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700175 const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
176 ISurfaceComposer::ConfigChanged configChanged) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700177 RETURN_VALUE_IF_INVALID(nullptr);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800178 return createConnectionInternal(mConnections[handle->id]->thread.get(),
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700179 std::move(resyncCallback), configChanged);
Ana Krulec98b5b242018-08-10 15:03:23 -0700180}
181
182EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700183 RETURN_VALUE_IF_INVALID(nullptr);
184 return mConnections[handle->id]->thread.get();
Ana Krulec98b5b242018-08-10 15:03:23 -0700185}
186
Ana Krulec85c39af2018-12-26 17:29:57 -0800187sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700188 RETURN_VALUE_IF_INVALID(nullptr);
189 return mConnections[handle->id]->eventConnection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700190}
191
192void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800193 PhysicalDisplayId displayId, bool connected) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700194 RETURN_IF_INVALID();
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800195 mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700196}
197
198void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700199 RETURN_IF_INVALID();
200 mConnections[handle->id]->thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700201}
202
203void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700204 RETURN_IF_INVALID();
205 mConnections[handle->id]->thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700206}
207
Ady Abraham447052e2019-02-13 16:07:27 -0800208void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
209 int32_t configId) {
210 RETURN_IF_INVALID();
211 mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
212}
213
Yiwei Zhang5434a782018-12-05 18:06:32 -0800214void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700215 RETURN_IF_INVALID();
216 mConnections.at(handle->id)->thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700217}
218
219void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700220 RETURN_IF_INVALID();
221 mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700222}
Ana Krulece588e312018-09-18 12:32:24 -0700223
224void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
225 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
226 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
227}
228
229void Scheduler::enableHardwareVsync() {
230 std::lock_guard<std::mutex> lock(mHWVsyncLock);
231 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
232 mPrimaryDispSync->beginResync();
233 mEventControlThread->setVsyncEnabled(true);
234 mPrimaryHWVsyncEnabled = true;
235 }
236}
237
238void Scheduler::disableHardwareVsync(bool makeUnavailable) {
239 std::lock_guard<std::mutex> lock(mHWVsyncLock);
240 if (mPrimaryHWVsyncEnabled) {
241 mEventControlThread->setVsyncEnabled(false);
242 mPrimaryDispSync->endResync();
243 mPrimaryHWVsyncEnabled = false;
244 }
245 if (makeUnavailable) {
246 mHWVsyncAvailable = false;
247 }
248}
249
Ana Krulecc2870422019-01-29 19:00:58 -0800250void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
251 {
252 std::lock_guard<std::mutex> lock(mHWVsyncLock);
253 if (makeAvailable) {
254 mHWVsyncAvailable = makeAvailable;
255 } else if (!mHWVsyncAvailable) {
256 // Hardware vsync is not currently available, so abort the resync
257 // attempt for now
258 return;
259 }
260 }
261
262 if (period <= 0) {
263 return;
264 }
265
266 setVsyncPeriod(period);
267}
268
269ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
270 std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
271 return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
272 if (const auto vsync = ptr.lock()) {
273 vsync->resync(getVsyncPeriod);
274 }
275 };
276}
277
278void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
279 static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
280
281 const nsecs_t now = systemTime();
282 const nsecs_t last = lastResyncTime.exchange(now);
283
284 if (now - last > kIgnoreDelay) {
285 scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
286 }
287}
288
289void Scheduler::setRefreshSkipCount(int count) {
290 mPrimaryDispSync->setRefreshSkipCount(count);
291}
292
Ana Krulece588e312018-09-18 12:32:24 -0700293void Scheduler::setVsyncPeriod(const nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800294 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700295 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800296
297 if (!mPrimaryHWVsyncEnabled) {
298 mPrimaryDispSync->beginResync();
299 mEventControlThread->setVsyncEnabled(true);
300 mPrimaryHWVsyncEnabled = true;
301 }
Ana Krulece588e312018-09-18 12:32:24 -0700302}
303
Alec Mourif8e689c2019-05-20 18:32:22 -0700304void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700305 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700306 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700307 { // Scope for the lock
308 std::lock_guard<std::mutex> lock(mHWVsyncLock);
309 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700310 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700311 }
312 }
313
314 if (needsHwVsync) {
315 enableHardwareVsync();
316 } else {
317 disableHardwareVsync(false);
318 }
319}
320
321void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
322 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
323 enableHardwareVsync();
324 } else {
325 disableHardwareVsync(false);
326 }
327}
328
329void Scheduler::setIgnorePresentFences(bool ignore) {
330 mPrimaryDispSync->setIgnorePresentFences(ignore);
331}
332
Ady Abraham8fe11022019-06-12 17:11:12 -0700333nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800334 return mPrimaryDispSync->expectedPresentTime();
335}
336
Ady Abraham3aff9172019-02-07 19:10:26 -0800337void Scheduler::dumpPrimaryDispSync(std::string& result) const {
338 mPrimaryDispSync->dump(result);
339}
340
Ady Abraham09bd3922019-04-08 10:44:56 -0700341std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700342 std::string const& name, int windowType) {
343 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
344 ? RefreshRateType::DEFAULT
345 : RefreshRateType::PERFORMANCE;
Ady Abraham09bd3922019-04-08 10:44:56 -0700346
347 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
Ana Krulecad083c42019-06-26 16:28:08 -0700348 const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
349
350 const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
351 const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
352 return mLayerHistory.createLayer(name, defaultFps, performanceFps);
Ady Abraham09bd3922019-04-08 10:44:56 -0700353}
354
Ady Abrahama315ce72019-04-24 14:35:20 -0700355void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700356 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700357 nsecs_t presentTime, bool isHDR) {
358 mLayerHistory.insert(layerHandle, presentTime, isHDR);
359}
360
361void Scheduler::setLayerVisibility(
362 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
363 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100364}
365
Kevin DuBois413287f2019-02-25 08:46:47 -0800366void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
367 fn(*mPrimaryDispSync);
368}
369
Ady Abraham09bd3922019-04-08 10:44:56 -0700370void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700371 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
372 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700373 RefreshRateType newRefreshRateType;
374 {
375 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700376 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700377 return;
378 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700379 mFeatures.contentRefreshRate = refreshRateRound;
380 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700381
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700382 mFeatures.isHDRContent = isHDR;
383 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700384
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700385 mFeatures.contentDetection =
386 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700387 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700388 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700389 return;
390 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700391 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800392 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700393 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100394}
395
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800396void Scheduler::setChangeRefreshRateCallback(
Alec Mouri7f015182019-07-11 13:56:22 -0700397 const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800398 std::lock_guard<std::mutex> lock(mCallbackLock);
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800399 mChangeRefreshRateCallback = changeRefreshRateCallback;
Ady Abrahama1a49af2019-02-07 14:36:55 -0800400}
401
Alec Mouri7f015182019-07-11 13:56:22 -0700402void Scheduler::setGetCurrentRefreshRateTypeCallback(
403 const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
404 std::lock_guard<std::mutex> lock(mCallbackLock);
405 mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
406}
407
Alec Mouridc28b372019-04-18 21:17:13 -0700408void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
409 std::lock_guard<std::mutex> lock(mCallbackLock);
410 mGetVsyncPeriod = getVsyncPeriod;
411}
412
Ana Krulec3084c052018-11-21 20:27:17 +0100413void Scheduler::updateFrameSkipping(const int64_t skipCount) {
414 ATRACE_INT("FrameSkipCount", skipCount);
415 if (mSkipCount != skipCount) {
416 // Only update DispSync if it hasn't been updated yet.
417 mPrimaryDispSync->setRefreshSkipCount(skipCount);
418 mSkipCount = skipCount;
419 }
420}
421
Ana Krulecfb772822018-11-30 10:44:07 +0100422void Scheduler::resetIdleTimer() {
423 if (mIdleTimer) {
424 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800425 }
426}
427
Ady Abraham8532d012019-05-08 14:50:56 -0700428void Scheduler::notifyTouchEvent() {
429 if (mTouchTimer) {
430 mTouchTimer->reset();
431 }
432
433 if (mSupportKernelTimer) {
434 resetIdleTimer();
435 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700436
437 // Touch event will boost the refresh rate to performance.
438 // Clear Layer History to get fresh FPS detection
439 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700440}
441
Ady Abraham6fe2c172019-07-12 12:37:57 -0700442void Scheduler::setDisplayPowerState(bool normal) {
443 {
444 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700445 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700446 }
447
448 if (mDisplayPowerTimer) {
449 mDisplayPowerTimer->reset();
450 }
451
452 // Display Power event will boost the refresh rate to performance.
453 // Clear Layer History to get fresh FPS detection
454 mLayerHistory.clearHistory();
455}
456
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700457void Scheduler::kernelIdleTimerCallback(TimerState state) {
458 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100459
Alec Mouridc28b372019-04-18 21:17:13 -0700460 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700461 if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
462
463 const auto type = mGetCurrentRefreshRateTypeCallback();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700464 if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700465 // If we're not in performance mode then the kernel timer shouldn't do
466 // anything, as the refresh rate during DPU power collapse will be the
467 // same.
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700468 resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700469 } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700470 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
471 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
472 // need to update the DispSync model anyway.
473 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700474 }
475}
476
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700477void Scheduler::idleTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700478 handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700479 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100480}
481
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700482void Scheduler::touchTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700483 const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
484 handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700485 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700486}
487
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700488void Scheduler::displayPowerTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700489 handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
490 true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700491 ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
Alec Mouridc28b372019-04-18 21:17:13 -0700492}
493
Ana Krulecb43429d2019-01-09 14:28:51 -0800494std::string Scheduler::doDump() {
495 std::ostringstream stream;
496 stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
Ady Abraham8532d012019-05-08 14:50:56 -0700497 stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
Ana Krulecb43429d2019-01-09 14:28:51 -0800498 return stream.str();
499}
500
Ady Abraham6fe2c172019-07-12 12:37:57 -0700501template <class T>
502void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
Ady Abraham8532d012019-05-08 14:50:56 -0700503 ConfigEvent event = ConfigEvent::None;
504 RefreshRateType newRefreshRateType;
505 {
506 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6fe2c172019-07-12 12:37:57 -0700507 if (*currentState == newState) {
Ady Abraham8532d012019-05-08 14:50:56 -0700508 return;
509 }
Ady Abraham6fe2c172019-07-12 12:37:57 -0700510 *currentState = newState;
Ady Abraham8532d012019-05-08 14:50:56 -0700511 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700512 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham8532d012019-05-08 14:50:56 -0700513 return;
514 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700515 mFeatures.refreshRateType = newRefreshRateType;
516 if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
Ady Abraham8532d012019-05-08 14:50:56 -0700517 event = ConfigEvent::Changed;
518 }
519 }
520 changeRefreshRate(newRefreshRateType, event);
521}
522
Ady Abraham09bd3922019-04-08 10:44:56 -0700523Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700524 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700525 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700526 return RefreshRateType::DEFAULT;
527 }
528
Ady Abraham6fe2c172019-07-12 12:37:57 -0700529 // If Display Power is not in normal operation we want to be in performance mode.
530 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700531 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700532 return RefreshRateType::PERFORMANCE;
533 }
534
Ady Abraham8532d012019-05-08 14:50:56 -0700535 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700536 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700537 return RefreshRateType::PERFORMANCE;
538 }
539
540 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700541 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700542 return RefreshRateType::DEFAULT;
543 }
544
Ady Abraham09bd3922019-04-08 10:44:56 -0700545 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700546 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700547 return RefreshRateType::PERFORMANCE;
548 }
549
Wei Wang09be73f2019-07-02 14:29:18 -0700550 // Content detection is on, find the appropriate refresh rate with minimal error
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700551 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Wei Wang09be73f2019-07-02 14:29:18 -0700552 auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
553 mRefreshRateConfigs.getRefreshRates().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700554 [rate](const auto& lhs, const auto& rhs) -> bool {
555 return std::abs(lhs.second->fps - rate) <
556 std::abs(rhs.second->fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700557 });
558 RefreshRateType currRefreshRateType = iter->first;
Ady Abraham09bd3922019-04-08 10:44:56 -0700559
Ady Abraham85b3f012019-04-08 11:04:14 -0700560 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
561 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
562 // align well with both
Wei Wang09be73f2019-07-02 14:29:18 -0700563 constexpr float MARGIN = 0.05f;
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700564 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700565 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
566 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700567 ratio = iter->second->fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700568
Ady Abraham85b3f012019-04-08 11:04:14 -0700569 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
570 currRefreshRateType = iter->first;
571 break;
572 }
573 ++iter;
574 }
575 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700576
577 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800578}
579
580void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
581 std::lock_guard<std::mutex> lock(mCallbackLock);
582 if (mChangeRefreshRateCallback) {
583 mChangeRefreshRateCallback(refreshRateType, configEvent);
584 }
585}
586
Ana Krulec98b5b242018-08-10 15:03:23 -0700587} // namespace android