blob: e393f1b2a6da9fca752cfe9227d074c46851d32e [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);
79
Ana Krulecfb772822018-11-30 10:44:07 +010080 char value[PROPERTY_VALUE_MAX];
Ana Kruleca5bdd9d2019-01-29 19:00:58 -080081 property_get("debug.sf.set_idle_timer_ms", value, "0");
Ady Abrahambe59c0d2019-03-05 13:01:13 -080082 int int_value = atoi(value);
83 if (int_value) {
84 mSetIdleTimerMs = atoi(value);
85 }
Ana Krulecfb772822018-11-30 10:44:07 +010086
87 if (mSetIdleTimerMs > 0) {
Alec Mouridc28b372019-04-18 21:17:13 -070088 if (mSupportKernelTimer) {
Ana Krulecf2c006d2019-06-21 15:37:07 -070089 mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
90 std::chrono::milliseconds(mSetIdleTimerMs),
91 [this] { resetKernelTimerCallback(); },
92 [this] { expiredKernelTimerCallback(); });
Alec Mouridc28b372019-04-18 21:17:13 -070093 } else {
Ana Krulecf2c006d2019-06-21 15:37:07 -070094 mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
95 std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); },
96 [this] { expiredTimerCallback(); });
Alec Mouridc28b372019-04-18 21:17:13 -070097 }
Ana Krulecfb772822018-11-30 10:44:07 +010098 mIdleTimer->start();
99 }
Ady Abraham8532d012019-05-08 14:50:56 -0700100
101 if (mSetTouchTimerMs > 0) {
102 // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
Ana Krulecf2c006d2019-06-21 15:37:07 -0700103 mTouchTimer = std::make_unique<scheduler::OneShotTimer>(
104 std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); },
105 [this] { expiredTouchTimerCallback(); });
Ady Abraham8532d012019-05-08 14:50:56 -0700106 mTouchTimer->start();
107 }
Ana Krulece588e312018-09-18 12:32:24 -0700108}
109
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800110Scheduler::~Scheduler() {
Ana Krulecf2c006d2019-06-21 15:37:07 -0700111 // Ensure the OneShotTimer threads are joined before we start destroying state.
Ady Abraham8532d012019-05-08 14:50:56 -0700112 mTouchTimer.reset();
Lloyd Pique1f9f1a42019-01-31 13:04:00 -0800113 mIdleTimer.reset();
114}
Ana Krulec0c8cd522018-08-31 12:27:28 -0700115
Ana Krulec98b5b242018-08-10 15:03:23 -0700116sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
Ady Abraham45e4e362019-06-07 18:20:51 -0700117 const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
118 ResyncCallback resyncCallback,
Ana Krulec98b5b242018-08-10 15:03:23 -0700119 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
120 const int64_t id = sNextId++;
121 ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
122
Ana Krulec98b5b242018-08-10 15:03:23 -0700123 std::unique_ptr<EventThread> eventThread =
Dominik Laskowskif654d572018-12-20 11:03:06 -0800124 makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
Ady Abraham45e4e362019-06-07 18:20:51 -0700125 offsetThresholdForNextVsync, std::move(interceptCallback));
Dominik Laskowskif654d572018-12-20 11:03:06 -0800126
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800127 auto eventThreadConnection =
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700128 createConnectionInternal(eventThread.get(), std::move(resyncCallback),
129 ISurfaceComposer::eConfigChangedSuppress);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800130 mConnections.emplace(id,
131 std::make_unique<Connection>(new ConnectionHandle(id),
132 eventThreadConnection,
133 std::move(eventThread)));
Ana Krulec98b5b242018-08-10 15:03:23 -0700134 return mConnections[id]->handle;
135}
136
Ana Krulec0c8cd522018-08-31 12:27:28 -0700137std::unique_ptr<EventThread> Scheduler::makeEventThread(
Ady Abraham45e4e362019-06-07 18:20:51 -0700138 const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
139 nsecs_t offsetThresholdForNextVsync,
Ana Krulec0c8cd522018-08-31 12:27:28 -0700140 impl::EventThread::InterceptVSyncsCallback interceptCallback) {
141 std::unique_ptr<VSyncSource> eventThreadSource =
Ady Abraham45e4e362019-06-07 18:20:51 -0700142 std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
143 true, connectionName);
Dominik Laskowskibd52c842019-01-28 18:11:23 -0800144 return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800145 std::move(interceptCallback), connectionName);
146}
147
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700148sp<EventThreadConnection> Scheduler::createConnectionInternal(
149 EventThread* eventThread, ResyncCallback&& resyncCallback,
150 ISurfaceComposer::ConfigChanged configChanged) {
151 return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
Ana Krulec0c8cd522018-08-31 12:27:28 -0700152}
153
Ana Krulec98b5b242018-08-10 15:03:23 -0700154sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700155 const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
156 ISurfaceComposer::ConfigChanged configChanged) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700157 RETURN_VALUE_IF_INVALID(nullptr);
Dominik Laskowskiccf37d72019-02-01 16:47:58 -0800158 return createConnectionInternal(mConnections[handle->id]->thread.get(),
Ady Abraham0f4a1b12019-06-04 16:04:04 -0700159 std::move(resyncCallback), configChanged);
Ana Krulec98b5b242018-08-10 15:03:23 -0700160}
161
162EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700163 RETURN_VALUE_IF_INVALID(nullptr);
164 return mConnections[handle->id]->thread.get();
Ana Krulec98b5b242018-08-10 15:03:23 -0700165}
166
Ana Krulec85c39af2018-12-26 17:29:57 -0800167sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700168 RETURN_VALUE_IF_INVALID(nullptr);
169 return mConnections[handle->id]->eventConnection;
Ana Krulec98b5b242018-08-10 15:03:23 -0700170}
171
172void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800173 PhysicalDisplayId displayId, bool connected) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700174 RETURN_IF_INVALID();
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800175 mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
Ana Krulec98b5b242018-08-10 15:03:23 -0700176}
177
178void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700179 RETURN_IF_INVALID();
180 mConnections[handle->id]->thread->onScreenAcquired();
Ana Krulec98b5b242018-08-10 15:03:23 -0700181}
182
183void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700184 RETURN_IF_INVALID();
185 mConnections[handle->id]->thread->onScreenReleased();
Ana Krulec98b5b242018-08-10 15:03:23 -0700186}
187
Ady Abraham447052e2019-02-13 16:07:27 -0800188void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
189 int32_t configId) {
190 RETURN_IF_INVALID();
191 mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
192}
193
Yiwei Zhang5434a782018-12-05 18:06:32 -0800194void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700195 RETURN_IF_INVALID();
196 mConnections.at(handle->id)->thread->dump(result);
Ana Krulec98b5b242018-08-10 15:03:23 -0700197}
198
199void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
Ana Krulec0c8cd522018-08-31 12:27:28 -0700200 RETURN_IF_INVALID();
201 mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
Ana Krulec98b5b242018-08-10 15:03:23 -0700202}
Ana Krulece588e312018-09-18 12:32:24 -0700203
204void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
205 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
206 stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
207}
208
209void Scheduler::enableHardwareVsync() {
210 std::lock_guard<std::mutex> lock(mHWVsyncLock);
211 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
212 mPrimaryDispSync->beginResync();
213 mEventControlThread->setVsyncEnabled(true);
214 mPrimaryHWVsyncEnabled = true;
215 }
216}
217
218void Scheduler::disableHardwareVsync(bool makeUnavailable) {
219 std::lock_guard<std::mutex> lock(mHWVsyncLock);
220 if (mPrimaryHWVsyncEnabled) {
221 mEventControlThread->setVsyncEnabled(false);
222 mPrimaryDispSync->endResync();
223 mPrimaryHWVsyncEnabled = false;
224 }
225 if (makeUnavailable) {
226 mHWVsyncAvailable = false;
227 }
228}
229
Ana Krulecc2870422019-01-29 19:00:58 -0800230void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
231 {
232 std::lock_guard<std::mutex> lock(mHWVsyncLock);
233 if (makeAvailable) {
234 mHWVsyncAvailable = makeAvailable;
235 } else if (!mHWVsyncAvailable) {
236 // Hardware vsync is not currently available, so abort the resync
237 // attempt for now
238 return;
239 }
240 }
241
242 if (period <= 0) {
243 return;
244 }
245
246 setVsyncPeriod(period);
247}
248
249ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
250 std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
251 return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
252 if (const auto vsync = ptr.lock()) {
253 vsync->resync(getVsyncPeriod);
254 }
255 };
256}
257
258void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
259 static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
260
261 const nsecs_t now = systemTime();
262 const nsecs_t last = lastResyncTime.exchange(now);
263
264 if (now - last > kIgnoreDelay) {
265 scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
266 }
267}
268
269void Scheduler::setRefreshSkipCount(int count) {
270 mPrimaryDispSync->setRefreshSkipCount(count);
271}
272
Ana Krulece588e312018-09-18 12:32:24 -0700273void Scheduler::setVsyncPeriod(const nsecs_t period) {
Ady Abraham3aff9172019-02-07 19:10:26 -0800274 std::lock_guard<std::mutex> lock(mHWVsyncLock);
Ana Krulece588e312018-09-18 12:32:24 -0700275 mPrimaryDispSync->setPeriod(period);
Ady Abraham3aff9172019-02-07 19:10:26 -0800276
277 if (!mPrimaryHWVsyncEnabled) {
278 mPrimaryDispSync->beginResync();
279 mEventControlThread->setVsyncEnabled(true);
280 mPrimaryHWVsyncEnabled = true;
281 }
Ana Krulece588e312018-09-18 12:32:24 -0700282}
283
Alec Mourif8e689c2019-05-20 18:32:22 -0700284void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
Ana Krulece588e312018-09-18 12:32:24 -0700285 bool needsHwVsync = false;
Alec Mourif8e689c2019-05-20 18:32:22 -0700286 *periodFlushed = false;
Ana Krulece588e312018-09-18 12:32:24 -0700287 { // Scope for the lock
288 std::lock_guard<std::mutex> lock(mHWVsyncLock);
289 if (mPrimaryHWVsyncEnabled) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700290 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
Ana Krulece588e312018-09-18 12:32:24 -0700291 }
292 }
293
294 if (needsHwVsync) {
295 enableHardwareVsync();
296 } else {
297 disableHardwareVsync(false);
298 }
299}
300
301void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
302 if (mPrimaryDispSync->addPresentFence(fenceTime)) {
303 enableHardwareVsync();
304 } else {
305 disableHardwareVsync(false);
306 }
307}
308
309void Scheduler::setIgnorePresentFences(bool ignore) {
310 mPrimaryDispSync->setIgnorePresentFences(ignore);
311}
312
Ady Abraham8fe11022019-06-12 17:11:12 -0700313nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
Ady Abrahamc3e21312019-02-07 14:30:23 -0800314 return mPrimaryDispSync->expectedPresentTime();
315}
316
Ady Abraham3aff9172019-02-07 19:10:26 -0800317void Scheduler::dumpPrimaryDispSync(std::string& result) const {
318 mPrimaryDispSync->dump(result);
319}
320
Ady Abraham09bd3922019-04-08 10:44:56 -0700321std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
Ady Abraham8f1ee7f2019-04-05 10:32:50 -0700322 std::string const& name, int windowType) {
323 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
324 ? RefreshRateType::DEFAULT
325 : RefreshRateType::PERFORMANCE;
Ady Abraham09bd3922019-04-08 10:44:56 -0700326
327 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
328 const uint32_t fps = (refreshRate) ? refreshRate->fps : 0;
329 return mLayerHistory.createLayer(name, fps);
330}
331
Ady Abrahama315ce72019-04-24 14:35:20 -0700332void Scheduler::addLayerPresentTimeAndHDR(
Ady Abraham09bd3922019-04-08 10:44:56 -0700333 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
Ady Abrahama315ce72019-04-24 14:35:20 -0700334 nsecs_t presentTime, bool isHDR) {
335 mLayerHistory.insert(layerHandle, presentTime, isHDR);
336}
337
338void Scheduler::setLayerVisibility(
339 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
340 mLayerHistory.setVisibility(layerHandle, visible);
Ana Krulec3084c052018-11-21 20:27:17 +0100341}
342
Kevin DuBois413287f2019-02-25 08:46:47 -0800343void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
344 fn(*mPrimaryDispSync);
345}
346
Ady Abraham09bd3922019-04-08 10:44:56 -0700347void Scheduler::updateFpsBasedOnContent() {
Ady Abrahama315ce72019-04-24 14:35:20 -0700348 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
349 const uint32_t refreshRateRound = std::round(refreshRate);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700350 RefreshRateType newRefreshRateType;
351 {
352 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abrahama315ce72019-04-24 14:35:20 -0700353 if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
Ady Abraham6398a0a2019-04-18 19:30:44 -0700354 return;
355 }
Ady Abrahama315ce72019-04-24 14:35:20 -0700356 mContentRefreshRate = refreshRateRound;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700357 ATRACE_INT("ContentFPS", mContentRefreshRate);
358
Ady Abrahama315ce72019-04-24 14:35:20 -0700359 mIsHDRContent = isHDR;
360 ATRACE_INT("ContentHDR", mIsHDRContent);
361
362 mCurrentContentFeatureState = refreshRateRound > 0
363 ? ContentFeatureState::CONTENT_DETECTION_ON
364 : ContentFeatureState::CONTENT_DETECTION_OFF;
Ady Abraham6398a0a2019-04-18 19:30:44 -0700365 newRefreshRateType = calculateRefreshRateType();
366 if (mRefreshRateType == newRefreshRateType) {
367 return;
368 }
369 mRefreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800370 }
Ady Abraham6398a0a2019-04-18 19:30:44 -0700371 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
Ana Krulec3084c052018-11-21 20:27:17 +0100372}
373
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800374void Scheduler::setChangeRefreshRateCallback(
375 const ChangeRefreshRateCallback& changeRefreshRateCallback) {
Ana Krulec7d1d6832018-12-27 11:10:09 -0800376 std::lock_guard<std::mutex> lock(mCallbackLock);
Ana Krulec8d3e4f32019-03-05 10:40:33 -0800377 mChangeRefreshRateCallback = changeRefreshRateCallback;
Ady Abrahama1a49af2019-02-07 14:36:55 -0800378}
379
Alec Mouridc28b372019-04-18 21:17:13 -0700380void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
381 std::lock_guard<std::mutex> lock(mCallbackLock);
382 mGetVsyncPeriod = getVsyncPeriod;
383}
384
Ana Krulec3084c052018-11-21 20:27:17 +0100385void Scheduler::updateFrameSkipping(const int64_t skipCount) {
386 ATRACE_INT("FrameSkipCount", skipCount);
387 if (mSkipCount != skipCount) {
388 // Only update DispSync if it hasn't been updated yet.
389 mPrimaryDispSync->setRefreshSkipCount(skipCount);
390 mSkipCount = skipCount;
391 }
392}
393
Ana Krulecfb772822018-11-30 10:44:07 +0100394void Scheduler::resetIdleTimer() {
395 if (mIdleTimer) {
396 mIdleTimer->reset();
Ady Abrahama1a49af2019-02-07 14:36:55 -0800397 }
398}
399
Ady Abraham8532d012019-05-08 14:50:56 -0700400void Scheduler::notifyTouchEvent() {
401 if (mTouchTimer) {
402 mTouchTimer->reset();
403 }
404
405 if (mSupportKernelTimer) {
406 resetIdleTimer();
407 }
Ady Abrahama9bf4ca2019-06-11 19:08:58 -0700408
409 // Touch event will boost the refresh rate to performance.
410 // Clear Layer History to get fresh FPS detection
411 mLayerHistory.clearHistory();
Ady Abraham8532d012019-05-08 14:50:56 -0700412}
413
Ady Abrahama1a49af2019-02-07 14:36:55 -0800414void Scheduler::resetTimerCallback() {
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800415 timerChangeRefreshRate(IdleTimerState::RESET);
416 ATRACE_INT("ExpiredIdleTimer", 0);
Ana Krulecfb772822018-11-30 10:44:07 +0100417}
418
Alec Mouridc28b372019-04-18 21:17:13 -0700419void Scheduler::resetKernelTimerCallback() {
420 ATRACE_INT("ExpiredKernelIdleTimer", 0);
421 std::lock_guard<std::mutex> lock(mCallbackLock);
422 if (mGetVsyncPeriod) {
Alec Mourif8e689c2019-05-20 18:32:22 -0700423 resyncToHardwareVsync(true, mGetVsyncPeriod());
Alec Mouridc28b372019-04-18 21:17:13 -0700424 }
425}
426
Ana Krulecfb772822018-11-30 10:44:07 +0100427void Scheduler::expiredTimerCallback() {
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800428 timerChangeRefreshRate(IdleTimerState::EXPIRED);
429 ATRACE_INT("ExpiredIdleTimer", 1);
Ana Krulecfb772822018-11-30 10:44:07 +0100430}
431
Ady Abraham8532d012019-05-08 14:50:56 -0700432void Scheduler::resetTouchTimerCallback() {
433 // We do not notify the applications about config changes when idle timer is reset.
434 touchChangeRefreshRate(TouchState::ACTIVE);
435 ATRACE_INT("TouchState", 1);
436}
437
438void Scheduler::expiredTouchTimerCallback() {
439 // We do not notify the applications about config changes when idle timer expires.
440 touchChangeRefreshRate(TouchState::INACTIVE);
441 ATRACE_INT("TouchState", 0);
442}
443
Alec Mouridc28b372019-04-18 21:17:13 -0700444void Scheduler::expiredKernelTimerCallback() {
445 ATRACE_INT("ExpiredKernelIdleTimer", 1);
446 // Disable HW Vsync if the timer expired, as we don't need it
447 // enabled if we're not pushing frames.
448 disableHardwareVsync(false);
449}
450
Ana Krulecb43429d2019-01-09 14:28:51 -0800451std::string Scheduler::doDump() {
452 std::ostringstream stream;
453 stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
Ady Abraham8532d012019-05-08 14:50:56 -0700454 stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
Ana Krulecb43429d2019-01-09 14:28:51 -0800455 return stream.str();
456}
457
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800458void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700459 RefreshRateType newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800460 {
461 std::lock_guard<std::mutex> lock(mFeatureStateLock);
Ady Abraham6398a0a2019-04-18 19:30:44 -0700462 if (mCurrentIdleTimerState == idleTimerState) {
463 return;
464 }
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800465 mCurrentIdleTimerState = idleTimerState;
Ady Abraham09bd3922019-04-08 10:44:56 -0700466 newRefreshRateType = calculateRefreshRateType();
Ady Abraham6398a0a2019-04-18 19:30:44 -0700467 if (mRefreshRateType == newRefreshRateType) {
468 return;
469 }
470 mRefreshRateType = newRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800471 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700472 changeRefreshRate(newRefreshRateType, ConfigEvent::None);
473}
474
Ady Abraham8532d012019-05-08 14:50:56 -0700475void Scheduler::touchChangeRefreshRate(TouchState touchState) {
476 ConfigEvent event = ConfigEvent::None;
477 RefreshRateType newRefreshRateType;
478 {
479 std::lock_guard<std::mutex> lock(mFeatureStateLock);
480 if (mCurrentTouchState == touchState) {
481 return;
482 }
483 mCurrentTouchState = touchState;
484 newRefreshRateType = calculateRefreshRateType();
485 if (mRefreshRateType == newRefreshRateType) {
486 return;
487 }
488 mRefreshRateType = newRefreshRateType;
489 // Send an event in case that content detection is on as touch has a higher priority
490 if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
491 event = ConfigEvent::Changed;
492 }
493 }
494 changeRefreshRate(newRefreshRateType, event);
495}
496
Ady Abraham09bd3922019-04-08 10:44:56 -0700497Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Ady Abraham8532d012019-05-08 14:50:56 -0700498 // HDR content is not supported on PERFORMANCE mode
499 if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700500 return RefreshRateType::DEFAULT;
501 }
502
Ady Abraham8532d012019-05-08 14:50:56 -0700503 // As long as touch is active we want to be in performance mode
504 if (mCurrentTouchState == TouchState::ACTIVE) {
505 return RefreshRateType::PERFORMANCE;
506 }
507
508 // If timer has expired as it means there is no new content on the screen
509 if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
Ady Abrahama315ce72019-04-24 14:35:20 -0700510 return RefreshRateType::DEFAULT;
511 }
512
Ady Abraham09bd3922019-04-08 10:44:56 -0700513 // If content detection is off we choose performance as we don't know the content fps
514 if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
515 return RefreshRateType::PERFORMANCE;
516 }
517
518 // Content detection is on, find the appropriate refresh rate
Ady Abraham85b3f012019-04-08 11:04:14 -0700519 // Start with the smallest refresh rate which is within a margin of the content
520 RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE;
521 constexpr float MARGIN = 0.05f;
Ady Abraham09bd3922019-04-08 10:44:56 -0700522 auto iter = mRefreshRateConfigs.getRefreshRates().cbegin();
Ady Abraham09bd3922019-04-08 10:44:56 -0700523 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
Ady Abraham85b3f012019-04-08 11:04:14 -0700524 if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) {
Ady Abraham09bd3922019-04-08 10:44:56 -0700525 currRefreshRateType = iter->first;
526 break;
527 }
528 ++iter;
529 }
530
Ady Abraham85b3f012019-04-08 11:04:14 -0700531 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
532 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
533 // align well with both
534 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
535 float(mContentRefreshRate);
536 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
537 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
538 ratio = iter->second->fps / float(mContentRefreshRate);
Ady Abraham09bd3922019-04-08 10:44:56 -0700539
Ady Abraham85b3f012019-04-08 11:04:14 -0700540 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
541 currRefreshRateType = iter->first;
542 break;
543 }
544 ++iter;
545 }
546 }
Ady Abraham09bd3922019-04-08 10:44:56 -0700547
548 return currRefreshRateType;
Ana Krulecfefd6ae2019-02-13 17:53:08 -0800549}
550
551void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
552 std::lock_guard<std::mutex> lock(mCallbackLock);
553 if (mChangeRefreshRateCallback) {
554 mChangeRefreshRateCallback(refreshRateType, configEvent);
555 }
556}
557
Ana Krulec98b5b242018-08-10 15:03:23 -0700558} // namespace android