blob: 194d80883615b6f74cecb2c5691b3d9b1c813d03 [file] [log] [blame]
/*
* 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