blob: 7a3bf8edafd648f760b2dbdd4eb60cadca11bc87 [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
#include "VSyncModulator.h"
#include <cutils/properties.h>
#include <utils/Trace.h>
#include <cinttypes>
#include <mutex>
namespace android {
using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
VSyncModulator::VSyncModulator() {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.vsync_trace_detailed_info", value, "0");
mTraceDetailedInfo = atoi(value);
// Populate the offset map with some default offsets.
const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
}
void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
nsecs_t thresholdForNextVsync) {
std::lock_guard<std::mutex> lock(mMutex);
mOffsetMap.insert_or_assign(OffsetType::Early, early);
mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
mOffsetMap.insert_or_assign(OffsetType::Late, late);
mThresholdForNextVsync = thresholdForNextVsync;
updateOffsetsLocked();
}
void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
if (transactionStart == Scheduler::TransactionStart::EARLY) {
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
}
// An early transaction stays an early transaction.
if (transactionStart == mTransactionStart ||
mTransactionStart == Scheduler::TransactionStart::EARLY) {
return;
}
mTransactionStart = transactionStart;
updateOffsets();
}
void VSyncModulator::onTransactionHandled() {
if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
mTransactionStart = Scheduler::TransactionStart::NORMAL;
updateOffsets();
}
void VSyncModulator::onRefreshRateChangeInitiated() {
if (mRefreshRateChangePending) {
return;
}
mRefreshRateChangePending = true;
updateOffsets();
}
void VSyncModulator::onRefreshRateChangeCompleted() {
if (!mRefreshRateChangePending) {
return;
}
mRefreshRateChangePending = false;
updateOffsets();
}
void VSyncModulator::onRefreshed(bool usedRenderEngine) {
bool updateOffsetsNeeded = false;
if (mRemainingEarlyFrameCount > 0) {
mRemainingEarlyFrameCount--;
updateOffsetsNeeded = true;
}
if (usedRenderEngine) {
mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
updateOffsetsNeeded = true;
} else if (mRemainingRenderEngineUsageCount > 0) {
mRemainingRenderEngineUsageCount--;
updateOffsetsNeeded = true;
}
if (updateOffsetsNeeded) {
updateOffsets();
}
}
VSyncModulator::Offsets VSyncModulator::getOffsets() {
std::lock_guard<std::mutex> lock(mMutex);
return mOffsets;
}
VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
return mOffsetMap.at(getNextOffsetType());
}
VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
mRefreshRateChangePending) {
return OffsetType::Early;
} else if (mRemainingRenderEngineUsageCount > 0) {
return OffsetType::EarlyGl;
} else {
return OffsetType::Late;
}
}
void VSyncModulator::updateOffsets() {
std::lock_guard<std::mutex> lock(mMutex);
updateOffsetsLocked();
}
void VSyncModulator::updateOffsetsLocked() {
const Offsets desired = getNextOffsets();
if (mSfConnectionHandle != nullptr) {
mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
}
if (mAppConnectionHandle != nullptr) {
mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
}
flushOffsets();
}
void VSyncModulator::flushOffsets() {
OffsetType type = getNextOffsetType();
mOffsets = mOffsetMap.at(type);
if (!mTraceDetailedInfo) {
return;
}
ATRACE_INT("Vsync-EarlyOffsetsOn",
mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
ATRACE_INT("Vsync-EarlyGLOffsetsOn",
mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
ATRACE_INT("Vsync-LateOffsetsOn",
mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
}
} // namespace android