1 /* 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 17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS 18 19 #include "Scheduler.h" 20 21 #include <algorithm> 22 #include <cinttypes> 23 #include <cstdint> 24 #include <memory> 25 #include <numeric> 26 27 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> 28 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> 29 #include <configstore/Utils.h> 30 #include <cutils/properties.h> 31 #include <input/InputWindow.h> 32 #include <system/window.h> 33 #include <ui/DisplayStatInfo.h> 34 #include <utils/Timers.h> 35 #include <utils/Trace.h> 36 37 #include "DispSync.h" 38 #include "DispSyncSource.h" 39 #include "EventControlThread.h" 40 #include "EventThread.h" 41 #include "IdleTimer.h" 42 #include "InjectVSyncSource.h" 43 #include "LayerInfo.h" 44 #include "SchedulerUtils.h" 45 #include "SurfaceFlingerProperties.h" 46 47 namespace android { 48 49 using namespace android::hardware::configstore; 50 using namespace android::hardware::configstore::V1_0; 51 using namespace android::sysprop; 52 53 #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 58 std::atomic<int64_t> Scheduler::sNextId = 0; 59 60 Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, 61 const scheduler::RefreshRateConfigs& refreshRateConfig) 62 : mHasSyncFramework(running_without_sync_framework(true)), 63 mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)), 64 mPrimaryHWVsyncEnabled(false), 65 mHWVsyncAvailable(false), 66 mRefreshRateConfigs(refreshRateConfig) { 67 // 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); 74 75 mSetIdleTimerMs = set_idle_timer_ms(0); 76 mSupportKernelTimer = support_kernel_idle_timer(false); 77 78 mSetTouchTimerMs = set_touch_timer_ms(0); 79 80 char value[PROPERTY_VALUE_MAX]; 81 property_get("debug.sf.set_idle_timer_ms", value, "0"); 82 int int_value = atoi(value); 83 if (int_value) { 84 mSetIdleTimerMs = atoi(value); 85 } 86 87 if (mSetIdleTimerMs > 0) { 88 if (mSupportKernelTimer) { 89 mIdleTimer = 90 std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( 91 mSetIdleTimerMs), 92 [this] { resetKernelTimerCallback(); }, 93 [this] { 94 expiredKernelTimerCallback(); 95 }); 96 } else { 97 mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( 98 mSetIdleTimerMs), 99 [this] { resetTimerCallback(); }, 100 [this] { expiredTimerCallback(); }); 101 } 102 mIdleTimer->start(); 103 } 104 105 if (mSetTouchTimerMs > 0) { 106 // Touch events are coming to SF every 100ms, so the timer needs to be higher than that 107 mTouchTimer = 108 std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs), 109 [this] { resetTouchTimerCallback(); }, 110 [this] { expiredTouchTimerCallback(); }); 111 mTouchTimer->start(); 112 } 113 } 114 115 Scheduler::~Scheduler() { 116 // Ensure the IdleTimer thread is joined before we start destroying state. 117 mTouchTimer.reset(); 118 mIdleTimer.reset(); 119 } 120 121 sp<Scheduler::ConnectionHandle> Scheduler::createConnection( 122 const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback, 123 impl::EventThread::InterceptVSyncsCallback interceptCallback) { 124 const int64_t id = sNextId++; 125 ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); 126 127 std::unique_ptr<EventThread> eventThread = 128 makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, 129 std::move(interceptCallback)); 130 131 auto eventThreadConnection = 132 createConnectionInternal(eventThread.get(), std::move(resyncCallback)); 133 mConnections.emplace(id, 134 std::make_unique<Connection>(new ConnectionHandle(id), 135 eventThreadConnection, 136 std::move(eventThread))); 137 return mConnections[id]->handle; 138 } 139 140 std::unique_ptr<EventThread> Scheduler::makeEventThread( 141 const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, 142 impl::EventThread::InterceptVSyncsCallback interceptCallback) { 143 std::unique_ptr<VSyncSource> eventThreadSource = 144 std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName); 145 return std::make_unique<impl::EventThread>(std::move(eventThreadSource), 146 std::move(interceptCallback), connectionName); 147 } 148 149 sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread, 150 ResyncCallback&& resyncCallback) { 151 return eventThread->createEventConnection(std::move(resyncCallback)); 152 } 153 154 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( 155 const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) { 156 RETURN_VALUE_IF_INVALID(nullptr); 157 return createConnectionInternal(mConnections[handle->id]->thread.get(), 158 std::move(resyncCallback)); 159 } 160 161 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) { 162 RETURN_VALUE_IF_INVALID(nullptr); 163 return mConnections[handle->id]->thread.get(); 164 } 165 166 sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) { 167 RETURN_VALUE_IF_INVALID(nullptr); 168 return mConnections[handle->id]->eventConnection; 169 } 170 171 void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle, 172 PhysicalDisplayId displayId, bool connected) { 173 RETURN_IF_INVALID(); 174 mConnections[handle->id]->thread->onHotplugReceived(displayId, connected); 175 } 176 177 void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) { 178 RETURN_IF_INVALID(); 179 mConnections[handle->id]->thread->onScreenAcquired(); 180 } 181 182 void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) { 183 RETURN_IF_INVALID(); 184 mConnections[handle->id]->thread->onScreenReleased(); 185 } 186 187 void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, 188 int32_t configId) { 189 RETURN_IF_INVALID(); 190 mConnections[handle->id]->thread->onConfigChanged(displayId, configId); 191 } 192 193 void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const { 194 RETURN_IF_INVALID(); 195 mConnections.at(handle->id)->thread->dump(result); 196 } 197 198 void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) { 199 RETURN_IF_INVALID(); 200 mConnections[handle->id]->thread->setPhaseOffset(phaseOffset); 201 } 202 203 void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) { 204 stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0); 205 stats->vsyncPeriod = mPrimaryDispSync->getPeriod(); 206 } 207 208 void Scheduler::enableHardwareVsync() { 209 std::lock_guard<std::mutex> lock(mHWVsyncLock); 210 if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { 211 mPrimaryDispSync->beginResync(); 212 mEventControlThread->setVsyncEnabled(true); 213 mPrimaryHWVsyncEnabled = true; 214 } 215 } 216 217 void Scheduler::disableHardwareVsync(bool makeUnavailable) { 218 std::lock_guard<std::mutex> lock(mHWVsyncLock); 219 if (mPrimaryHWVsyncEnabled) { 220 mEventControlThread->setVsyncEnabled(false); 221 mPrimaryDispSync->endResync(); 222 mPrimaryHWVsyncEnabled = false; 223 } 224 if (makeUnavailable) { 225 mHWVsyncAvailable = false; 226 } 227 } 228 229 void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { 230 { 231 std::lock_guard<std::mutex> lock(mHWVsyncLock); 232 if (makeAvailable) { 233 mHWVsyncAvailable = makeAvailable; 234 } else if (!mHWVsyncAvailable) { 235 // Hardware vsync is not currently available, so abort the resync 236 // attempt for now 237 return; 238 } 239 } 240 241 if (period <= 0) { 242 return; 243 } 244 245 setVsyncPeriod(period); 246 } 247 248 ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) { 249 std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState; 250 return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() { 251 if (const auto vsync = ptr.lock()) { 252 vsync->resync(getVsyncPeriod); 253 } 254 }; 255 } 256 257 void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) { 258 static constexpr nsecs_t kIgnoreDelay = ms2ns(500); 259 260 const nsecs_t now = systemTime(); 261 const nsecs_t last = lastResyncTime.exchange(now); 262 263 if (now - last > kIgnoreDelay) { 264 scheduler.resyncToHardwareVsync(false, getVsyncPeriod()); 265 } 266 } 267 268 void Scheduler::setRefreshSkipCount(int count) { 269 mPrimaryDispSync->setRefreshSkipCount(count); 270 } 271 272 void Scheduler::setVsyncPeriod(const nsecs_t period) { 273 std::lock_guard<std::mutex> lock(mHWVsyncLock); 274 mPrimaryDispSync->setPeriod(period); 275 276 if (!mPrimaryHWVsyncEnabled) { 277 mPrimaryDispSync->beginResync(); 278 mEventControlThread->setVsyncEnabled(true); 279 mPrimaryHWVsyncEnabled = true; 280 } 281 } 282 283 void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) { 284 bool needsHwVsync = false; 285 *periodChanged = false; 286 { // Scope for the lock 287 std::lock_guard<std::mutex> lock(mHWVsyncLock); 288 if (mPrimaryHWVsyncEnabled) { 289 needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged); 290 } 291 } 292 293 if (needsHwVsync) { 294 enableHardwareVsync(); 295 } else { 296 disableHardwareVsync(false); 297 } 298 } 299 300 void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) { 301 if (mPrimaryDispSync->addPresentFence(fenceTime)) { 302 enableHardwareVsync(); 303 } else { 304 disableHardwareVsync(false); 305 } 306 } 307 308 void Scheduler::setIgnorePresentFences(bool ignore) { 309 mPrimaryDispSync->setIgnorePresentFences(ignore); 310 } 311 312 nsecs_t Scheduler::expectedPresentTime() { 313 return mPrimaryDispSync->expectedPresentTime(); 314 } 315 316 void Scheduler::dumpPrimaryDispSync(std::string& result) const { 317 mPrimaryDispSync->dump(result); 318 } 319 320 std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( 321 std::string const& name, int windowType) { 322 RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) 323 ? RefreshRateType::DEFAULT 324 : RefreshRateType::PERFORMANCE; 325 326 const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); 327 const uint32_t fps = (refreshRate) ? refreshRate->fps : 0; 328 return mLayerHistory.createLayer(name, fps); 329 } 330 331 void Scheduler::addLayerPresentTimeAndHDR( 332 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, 333 nsecs_t presentTime, bool isHDR) { 334 mLayerHistory.insert(layerHandle, presentTime, isHDR); 335 } 336 337 void Scheduler::setLayerVisibility( 338 const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) { 339 mLayerHistory.setVisibility(layerHandle, visible); 340 } 341 342 void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) { 343 fn(*mPrimaryDispSync); 344 } 345 346 void Scheduler::updateFpsBasedOnContent() { 347 auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR(); 348 const uint32_t refreshRateRound = std::round(refreshRate); 349 RefreshRateType newRefreshRateType; 350 { 351 std::lock_guard<std::mutex> lock(mFeatureStateLock); 352 if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) { 353 return; 354 } 355 mContentRefreshRate = refreshRateRound; 356 ATRACE_INT("ContentFPS", mContentRefreshRate); 357 358 mIsHDRContent = isHDR; 359 ATRACE_INT("ContentHDR", mIsHDRContent); 360 361 mCurrentContentFeatureState = refreshRateRound > 0 362 ? ContentFeatureState::CONTENT_DETECTION_ON 363 : ContentFeatureState::CONTENT_DETECTION_OFF; 364 newRefreshRateType = calculateRefreshRateType(); 365 if (mRefreshRateType == newRefreshRateType) { 366 return; 367 } 368 mRefreshRateType = newRefreshRateType; 369 } 370 changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); 371 } 372 373 void Scheduler::setChangeRefreshRateCallback( 374 const ChangeRefreshRateCallback& changeRefreshRateCallback) { 375 std::lock_guard<std::mutex> lock(mCallbackLock); 376 mChangeRefreshRateCallback = changeRefreshRateCallback; 377 } 378 379 void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { 380 std::lock_guard<std::mutex> lock(mCallbackLock); 381 mGetVsyncPeriod = getVsyncPeriod; 382 } 383 384 void Scheduler::updateFrameSkipping(const int64_t skipCount) { 385 ATRACE_INT("FrameSkipCount", skipCount); 386 if (mSkipCount != skipCount) { 387 // Only update DispSync if it hasn't been updated yet. 388 mPrimaryDispSync->setRefreshSkipCount(skipCount); 389 mSkipCount = skipCount; 390 } 391 } 392 393 void Scheduler::resetIdleTimer() { 394 if (mIdleTimer) { 395 mIdleTimer->reset(); 396 } 397 } 398 399 void Scheduler::notifyTouchEvent() { 400 if (mTouchTimer) { 401 mTouchTimer->reset(); 402 } 403 404 if (mSupportKernelTimer) { 405 resetIdleTimer(); 406 } 407 } 408 409 void Scheduler::resetTimerCallback() { 410 timerChangeRefreshRate(IdleTimerState::RESET); 411 ATRACE_INT("ExpiredIdleTimer", 0); 412 } 413 414 void Scheduler::resetKernelTimerCallback() { 415 ATRACE_INT("ExpiredKernelIdleTimer", 0); 416 std::lock_guard<std::mutex> lock(mCallbackLock); 417 if (mGetVsyncPeriod) { 418 resyncToHardwareVsync(false, mGetVsyncPeriod()); 419 } 420 } 421 422 void Scheduler::expiredTimerCallback() { 423 timerChangeRefreshRate(IdleTimerState::EXPIRED); 424 ATRACE_INT("ExpiredIdleTimer", 1); 425 } 426 427 void Scheduler::resetTouchTimerCallback() { 428 // We do not notify the applications about config changes when idle timer is reset. 429 touchChangeRefreshRate(TouchState::ACTIVE); 430 ATRACE_INT("TouchState", 1); 431 } 432 433 void Scheduler::expiredTouchTimerCallback() { 434 // We do not notify the applications about config changes when idle timer expires. 435 touchChangeRefreshRate(TouchState::INACTIVE); 436 ATRACE_INT("TouchState", 0); 437 } 438 439 void Scheduler::expiredKernelTimerCallback() { 440 ATRACE_INT("ExpiredKernelIdleTimer", 1); 441 // Disable HW Vsync if the timer expired, as we don't need it 442 // enabled if we're not pushing frames. 443 disableHardwareVsync(false); 444 } 445 446 std::string Scheduler::doDump() { 447 std::ostringstream stream; 448 stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl; 449 stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl; 450 return stream.str(); 451 } 452 453 void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { 454 RefreshRateType newRefreshRateType; 455 { 456 std::lock_guard<std::mutex> lock(mFeatureStateLock); 457 if (mCurrentIdleTimerState == idleTimerState) { 458 return; 459 } 460 mCurrentIdleTimerState = idleTimerState; 461 newRefreshRateType = calculateRefreshRateType(); 462 if (mRefreshRateType == newRefreshRateType) { 463 return; 464 } 465 mRefreshRateType = newRefreshRateType; 466 } 467 changeRefreshRate(newRefreshRateType, ConfigEvent::None); 468 } 469 470 void Scheduler::touchChangeRefreshRate(TouchState touchState) { 471 ConfigEvent event = ConfigEvent::None; 472 RefreshRateType newRefreshRateType; 473 { 474 std::lock_guard<std::mutex> lock(mFeatureStateLock); 475 if (mCurrentTouchState == touchState) { 476 return; 477 } 478 mCurrentTouchState = touchState; 479 newRefreshRateType = calculateRefreshRateType(); 480 if (mRefreshRateType == newRefreshRateType) { 481 return; 482 } 483 mRefreshRateType = newRefreshRateType; 484 // Send an event in case that content detection is on as touch has a higher priority 485 if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { 486 event = ConfigEvent::Changed; 487 } 488 } 489 changeRefreshRate(newRefreshRateType, event); 490 } 491 492 Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { 493 // HDR content is not supported on PERFORMANCE mode 494 if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) { 495 return RefreshRateType::DEFAULT; 496 } 497 498 // As long as touch is active we want to be in performance mode 499 if (mCurrentTouchState == TouchState::ACTIVE) { 500 return RefreshRateType::PERFORMANCE; 501 } 502 503 // If timer has expired as it means there is no new content on the screen 504 if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) { 505 return RefreshRateType::DEFAULT; 506 } 507 508 // If content detection is off we choose performance as we don't know the content fps 509 if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) { 510 return RefreshRateType::PERFORMANCE; 511 } 512 513 // Content detection is on, find the appropriate refresh rate 514 // Start with the smallest refresh rate which is within a margin of the content 515 RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE; 516 constexpr float MARGIN = 0.05f; 517 auto iter = mRefreshRateConfigs.getRefreshRates().cbegin(); 518 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { 519 if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) { 520 currRefreshRateType = iter->first; 521 break; 522 } 523 ++iter; 524 } 525 526 // Some content aligns better on higher refresh rate. For example for 45fps we should choose 527 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't 528 // align well with both 529 float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / 530 float(mContentRefreshRate); 531 if (std::abs(std::round(ratio) - ratio) > MARGIN) { 532 while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { 533 ratio = iter->second->fps / float(mContentRefreshRate); 534 535 if (std::abs(std::round(ratio) - ratio) <= MARGIN) { 536 currRefreshRateType = iter->first; 537 break; 538 } 539 ++iter; 540 } 541 } 542 543 return currRefreshRateType; 544 } 545 546 void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { 547 std::lock_guard<std::mutex> lock(mCallbackLock); 548 if (mChangeRefreshRateCallback) { 549 mChangeRefreshRateCallback(refreshRateType, configEvent); 550 } 551 } 552 553 } // namespace android 554