/* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include "VsyncSchedule.h" #include "Utils/Dumper.h" #include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" #include "../TracedOrdinal.h" namespace android::scheduler { class VsyncSchedule::PredictedVsyncTracer { // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. constexpr auto makeVsyncCallback() { return [this](nsecs_t, nsecs_t, nsecs_t) { mParity = !mParity; schedule(); }; } public: explicit PredictedVsyncTracer(std::shared_ptr dispatch) : mRegistration(std::move(dispatch), makeVsyncCallback(), __func__) { schedule(); } private: void schedule() { mRegistration.schedule({0, 0, 0}); } TracedOrdinal mParity = {"VSYNC-predicted", 0}; VSyncCallbackRegistration mRegistration; }; VsyncSchedule::VsyncSchedule(ftl::NonNull modePtr, FeatureFlags features, RequestHardwareVsync requestHardwareVsync) : mId(modePtr->getPhysicalDisplayId()), mRequestHardwareVsync(std::move(requestHardwareVsync)), mTracker(createTracker(modePtr)), mDispatch(createDispatch(mTracker)), mController(createController(modePtr->getPhysicalDisplayId(), *mTracker, features)), mTracer(features.test(Feature::kTracePredictedVsync) ? std::make_unique(mDispatch) : nullptr) {} VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller, RequestHardwareVsync requestHardwareVsync) : mId(id), mRequestHardwareVsync(std::move(requestHardwareVsync)), mTracker(std::move(tracker)), mDispatch(std::move(dispatch)), mController(std::move(controller)) {} VsyncSchedule::~VsyncSchedule() = default; Period VsyncSchedule::period() const { return Period::fromNs(mTracker->currentPeriod()); } Period VsyncSchedule::minFramePeriod() const { if (FlagManager::getInstance().vrr_config()) { return mTracker->minFramePeriod(); } return period(); } TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint, ftl::Optional lastVsyncOpt) const { return TimePoint::fromNs( mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns(), lastVsyncOpt.transform( [](TimePoint t) { return t.ns(); }))); } void VsyncSchedule::dump(std::string& out) const { utils::Dumper dumper(out); { std::lock_guard lock(mHwVsyncLock); dumper.dump("hwVsyncState", ftl::enum_string(mHwVsyncState)); ftl::FakeGuard guard(kMainThreadContext); dumper.dump("pendingHwVsyncState", ftl::enum_string(mPendingHwVsyncState)); dumper.eol(); } out.append("VsyncController:\n"); mController->dump(out); out.append("VsyncDispatch:\n"); mDispatch->dump(out); } VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull modePtr) { // TODO(b/144707443): Tune constants. constexpr size_t kHistorySize = 20; constexpr size_t kMinSamplesForPrediction = 6; constexpr uint32_t kDiscardOutlierPercent = 20; return std::make_unique(std::make_unique(), modePtr, kHistorySize, kMinSamplesForPrediction, kDiscardOutlierPercent); } VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(TrackerPtr tracker) { using namespace std::chrono_literals; // TODO(b/144707443): Tune constants. constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; return std::make_unique(std::make_unique(), std::move(tracker), kGroupDispatchWithin.count(), kSnapToSameVsyncWithin.count()); } VsyncSchedule::ControllerPtr VsyncSchedule::createController(PhysicalDisplayId id, VsyncTracker& tracker, FeatureFlags features) { // TODO(b/144707443): Tune constants. constexpr size_t kMaxPendingFences = 20; const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); auto reactor = std::make_unique(id, std::make_unique(), tracker, kMaxPendingFences, hasKernelIdleTimer); reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); return reactor; } void VsyncSchedule::onDisplayModeChanged(ftl::NonNull modePtr, bool force) { std::lock_guard lock(mHwVsyncLock); mController->onDisplayModeChanged(modePtr, force); enableHardwareVsyncLocked(); } bool VsyncSchedule::addResyncSample(TimePoint timestamp, ftl::Optional hwcVsyncPeriod) { bool needsHwVsync = false; bool periodFlushed = false; { std::lock_guard lock(mHwVsyncLock); if (mHwVsyncState == HwVsyncState::Enabled) { needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(), hwcVsyncPeriod.transform(&Period::ns), &periodFlushed); } } if (needsHwVsync) { enableHardwareVsync(); } else { constexpr bool kDisallow = false; disableHardwareVsync(kDisallow); } return periodFlushed; } void VsyncSchedule::enableHardwareVsync() { std::lock_guard lock(mHwVsyncLock); enableHardwareVsyncLocked(); } void VsyncSchedule::enableHardwareVsyncLocked() { ATRACE_CALL(); if (mHwVsyncState == HwVsyncState::Disabled) { getTracker().resetModel(); mRequestHardwareVsync(mId, true); mHwVsyncState = HwVsyncState::Enabled; } } void VsyncSchedule::disableHardwareVsync(bool disallow) { ATRACE_CALL(); std::lock_guard lock(mHwVsyncLock); switch (mHwVsyncState) { case HwVsyncState::Enabled: mRequestHardwareVsync(mId, false); [[fallthrough]]; case HwVsyncState::Disabled: mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled; break; case HwVsyncState::Disallowed: break; } } bool VsyncSchedule::isHardwareVsyncAllowed(bool makeAllowed) { std::lock_guard lock(mHwVsyncLock); if (makeAllowed && mHwVsyncState == HwVsyncState::Disallowed) { mHwVsyncState = HwVsyncState::Disabled; } return mHwVsyncState != HwVsyncState::Disallowed; } void VsyncSchedule::setPendingHardwareVsyncState(bool enabled) { mPendingHwVsyncState = enabled ? HwVsyncState::Enabled : HwVsyncState::Disabled; } bool VsyncSchedule::getPendingHardwareVsyncState() const { return mPendingHwVsyncState == HwVsyncState::Enabled; } } // namespace android::scheduler