diff options
Diffstat (limited to 'services/surfaceflinger/Scheduler/VsyncModulator.cpp')
-rw-r--r-- | services/surfaceflinger/Scheduler/VsyncModulator.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp new file mode 100644 index 0000000000..194d808836 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2019 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 + +#undef LOG_TAG +#define LOG_TAG "VsyncModulator" + +#include "VsyncModulator.h" + +#include <android-base/properties.h> +#include <log/log.h> +#include <utils/Trace.h> + +#include <chrono> +#include <cinttypes> +#include <mutex> + +using namespace std::chrono_literals; + +namespace android::scheduler { + +const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms; + +VsyncModulator::VsyncModulator(const VsyncConfigSet& config, Now now) + : mVsyncConfigSet(config), + mNow(now), + mTraceDetailedInfo(base::GetBoolProperty("debug.sf.vsync_trace_detailed_info", false)) {} + +VsyncModulator::VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigSet& config) { + std::lock_guard<std::mutex> lock(mMutex); + mVsyncConfigSet = config; + return updateVsyncConfigLocked(); +} + +VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule( + TransactionSchedule schedule) { + switch (schedule) { + case Schedule::EarlyStart: + ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__); + mEarlyWakeup = true; + break; + case Schedule::EarlyEnd: + ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__); + mEarlyWakeup = false; + break; + case Schedule::Late: + // No change to mEarlyWakeup for non-explicit states. + break; + } + + if (mTraceDetailedInfo) { + ATRACE_INT("mEarlyWakeup", mEarlyWakeup); + } + + if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) { + mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES; + mEarlyTransactionStartTime = mNow(); + } + + // An early transaction stays an early transaction. + if (schedule == mTransactionSchedule || mTransactionSchedule == Schedule::EarlyEnd) { + return std::nullopt; + } + mTransactionSchedule = schedule; + return updateVsyncConfig(); +} + +VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() { + mLastTransactionCommitTime = mNow(); + if (mTransactionSchedule == Schedule::Late) return std::nullopt; + mTransactionSchedule = Schedule::Late; + return updateVsyncConfig(); +} + +VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeInitiated() { + if (mRefreshRateChangePending) return std::nullopt; + mRefreshRateChangePending = true; + return updateVsyncConfig(); +} + +VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeCompleted() { + if (!mRefreshRateChangePending) return std::nullopt; + mRefreshRateChangePending = false; + return updateVsyncConfig(); +} + +VsyncModulator::VsyncConfigOpt VsyncModulator::onDisplayRefresh(bool usedGpuComposition) { + bool updateOffsetsNeeded = false; + + if (mEarlyTransactionStartTime.load() + MIN_EARLY_TRANSACTION_TIME <= + mLastTransactionCommitTime.load()) { + if (mEarlyTransactionFrames > 0) { + mEarlyTransactionFrames--; + updateOffsetsNeeded = true; + } + } + if (usedGpuComposition) { + mEarlyGpuFrames = MIN_EARLY_GPU_FRAMES; + updateOffsetsNeeded = true; + } else if (mEarlyGpuFrames > 0) { + mEarlyGpuFrames--; + updateOffsetsNeeded = true; + } + + if (!updateOffsetsNeeded) return std::nullopt; + return updateVsyncConfig(); +} + +VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const { + std::lock_guard<std::mutex> lock(mMutex); + return mVsyncConfig; +} + +const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const { + // Early offsets are used if we're in the middle of a refresh rate + // change, or if we recently begin a transaction. + if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || + mRefreshRateChangePending) { + return mVsyncConfigSet.early; + } else if (mEarlyGpuFrames > 0) { + return mVsyncConfigSet.earlyGpu; + } else { + return mVsyncConfigSet.late; + } +} + +VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfig() { + std::lock_guard<std::mutex> lock(mMutex); + return updateVsyncConfigLocked(); +} + +VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfigLocked() { + const VsyncConfig& offsets = getNextVsyncConfig(); + mVsyncConfig = offsets; + + if (mTraceDetailedInfo) { + const bool isEarly = &offsets == &mVsyncConfigSet.early; + const bool isEarlyGpu = &offsets == &mVsyncConfigSet.earlyGpu; + const bool isLate = &offsets == &mVsyncConfigSet.late; + + ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly); + ATRACE_INT("Vsync-EarlyGpuOffsetsOn", isEarlyGpu); + ATRACE_INT("Vsync-LateOffsetsOn", isLate); + } + + return offsets; +} + +} // namespace android::scheduler |