blob: 952643ce70cbb3a46dd96124104009d8f1dca826 [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
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);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700368 if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700369 return;
370 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700371 mFeatures.contentRefreshRate = refreshRateRound;
372 ATRACE_INT("ContentFPS", refreshRateRound);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700373
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700374 mFeatures.isHDRContent = isHDR;
375 ATRACE_INT("ContentHDR", isHDR);
Ady Abrahama315ce72019-04-24 14:35:20 -0700376
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700377 mFeatures.contentDetection =
378 refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700379 newRefreshRateType = calculateRefreshRateType();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700380 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700381 return;
382 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700383 mFeatures.refreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800384 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700385 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100386}
387
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800388void Scheduler::setChangeRefreshRateCallback(
Alec Mouri7f015182019-07-11 13:56:22 -0700389 const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800390 std::lock_guard<std::mutex> lock(mCallbackLock);
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800391 mChangeRefreshRateCallback = changeRefreshRateCallback;
Ady Abrahama1a49af2019-02-07 14:36:55 -0800392}
393
Alec Mouri7f015182019-07-11 13:56:22 -0700394void Scheduler::setGetCurrentRefreshRateTypeCallback(
395 const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
396 std::lock_guard<std::mutex> lock(mCallbackLock);
397 mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
398}
399
Alec Mouridc28b372019-04-18 21:17:13 -0700400void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
401 std::lock_guard<std::mutex> lock(mCallbackLock);
402 mGetVsyncPeriod = getVsyncPeriod;
403}
404
Ana Krulec3084c052018-11-21 20:27:17 +0100405void Scheduler::updateFrameSkipping(const int64_t skipCount) {
406 ATRACE_INT("FrameSkipCount", skipCount);
407 if (mSkipCount != skipCount) {
408 // Only update DispSync if it hasn't been updated yet.
409 mPrimaryDispSync->setRefreshSkipCount(skipCount);
410 mSkipCount = skipCount;
411 }
412}
413
Ana Krulecfb772822018-11-30 10:44:07 +0100414void Scheduler::resetIdleTimer() {
415 if (mIdleTimer) {
416 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800417 }
418}
419
Ady Abraham8532d012019-05-08 14:50:56 -0700420void Scheduler::notifyTouchEvent() {
421 if (mTouchTimer) {
422 mTouchTimer->reset();
423 }
424
425 if (mSupportKernelTimer) {
426 resetIdleTimer();
427 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700428
429 // Touch event will boost the refresh rate to performance.
430 // Clear Layer History to get fresh FPS detection
431 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700432}
433
Ady Abraham6fe2c172019-07-12 12:37:57 -0700434void Scheduler::setDisplayPowerState(bool normal) {
435 {
436 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700437 mFeatures.isDisplayPowerStateNormal = normal;
Ady Abraham6fe2c172019-07-12 12:37:57 -0700438 }
439
440 if (mDisplayPowerTimer) {
441 mDisplayPowerTimer->reset();
442 }
443
444 // Display Power event will boost the refresh rate to performance.
445 // Clear Layer History to get fresh FPS detection
446 mLayerHistory.clearHistory();
447}
448
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700449void Scheduler::kernelIdleTimerCallback(TimerState state) {
450 ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100451
Alec Mouridc28b372019-04-18 21:17:13 -0700452 std::lock_guard<std::mutex> lock(mCallbackLock);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700453 if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
454
455 const auto type = mGetCurrentRefreshRateTypeCallback();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700456 if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
Alec Mouri7f015182019-07-11 13:56:22 -0700457 // If we're not in performance mode then the kernel timer shouldn't do
458 // anything, as the refresh rate during DPU power collapse will be the
459 // same.
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700460 resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700461 } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700462 // Disable HW VSYNC if the timer expired, as we don't need it enabled if
463 // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
464 // need to update the DispSync model anyway.
465 disableHardwareVsync(false /* makeUnavailable */);
Alec Mouridc28b372019-04-18 21:17:13 -0700466 }
467}
468
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700469void Scheduler::idleTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700470 handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700471 ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
Ana Krulecfb772822018-11-30 10:44:07 +0100472}
473
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700474void Scheduler::touchTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700475 const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
476 handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700477 ATRACE_INT("TouchState", static_cast<int>(touch));
Ady Abraham8532d012019-05-08 14:50:56 -0700478}
479
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700480void Scheduler::displayPowerTimerCallback(TimerState state) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700481 handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
482 true /* eventOnContentDetection */);
Dominik Laskowski3a80a382019-07-25 11:16:07 -0700483 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();
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700504 if (mFeatures.refreshRateType == newRefreshRateType) {
Ady Abraham8532d012019-05-08 14:50:56 -0700505 return;
506 }
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700507 mFeatures.refreshRateType = newRefreshRateType;
508 if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
Ady Abraham8532d012019-05-08 14:50:56 -0700509 event = ConfigEvent::Changed;
510 }
511 }
512 changeRefreshRate(newRefreshRateType, event);
513}
514
Ady Abraham09bd3922019-04-08 10:44:56 -0700515Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700516 // HDR content is not supported on PERFORMANCE mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700517 if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700518 return RefreshRateType::DEFAULT;
519 }
520
Ady Abraham6fe2c172019-07-12 12:37:57 -0700521 // If Display Power is not in normal operation we want to be in performance mode.
522 // When coming back to normal mode, a grace period is given with DisplayPowerTimer
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700523 if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
Ady Abraham6fe2c172019-07-12 12:37:57 -0700524 return RefreshRateType::PERFORMANCE;
525 }
526
Ady Abraham8532d012019-05-08 14:50:56 -0700527 // As long as touch is active we want to be in performance mode
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700528 if (mFeatures.touch == TouchState::Active) {
Ady Abraham8532d012019-05-08 14:50:56 -0700529 return RefreshRateType::PERFORMANCE;
530 }
531
532 // If timer has expired as it means there is no new content on the screen
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700533 if (mFeatures.idleTimer == TimerState::Expired) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700534 return RefreshRateType::DEFAULT;
535 }
536
Ady Abraham09bd3922019-04-08 10:44:56 -0700537 // If content detection is off we choose performance as we don't know the content fps
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700538 if (mFeatures.contentDetection == ContentDetectionState::Off) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700539 return RefreshRateType::PERFORMANCE;
540 }
541
Wei Wang09be73f2019-07-02 14:29:18 -0700542 // Content detection is on, find the appropriate refresh rate with minimal error
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700543 const float rate = static_cast<float>(mFeatures.contentRefreshRate);
Wei Wang09be73f2019-07-02 14:29:18 -0700544 auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
545 mRefreshRateConfigs.getRefreshRates().cend(),
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700546 [rate](const auto& lhs, const auto& rhs) -> bool {
547 return std::abs(lhs.second->fps - rate) <
548 std::abs(rhs.second->fps - rate);
Wei Wang09be73f2019-07-02 14:29:18 -0700549 });
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;
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700556 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
Ady Abraham85b3f012019-04-08 11:04:14 -0700557 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
558 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
Dominik Laskowskidd252cd2019-07-26 09:10:16 -0700559 ratio = iter->second->fps / rate;
Ady Abraham09bd3922019-04-08 10:44:56 -0700560
Ady Abraham85b3f012019-04-08 11:04:14 -0700561 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
562 currRefreshRateType = iter->first;
563 break;
564 }
565 ++iter;
566 }
567 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700568
569 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800570}
571
572void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
573 std::lock_guard<std::mutex> lock(mCallbackLock);
574 if (mChangeRefreshRateCallback) {
575 mChangeRefreshRateCallback(refreshRateType, configEvent);
576 }
577}
578
Ana Krulec98b5b242018-08-10 15:03:23 -0700579} // namespace android