184 lines
6.1 KiB
C++
184 lines
6.1 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
// TODO(b/129481165): remove the #pragma below and fix conversion issues
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wconversion"
|
|
|
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
|
|
|
#include "VSyncModulator.h"
|
|
|
|
#include <cutils/properties.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <chrono>
|
|
#include <cinttypes>
|
|
#include <mutex>
|
|
|
|
namespace android::scheduler {
|
|
|
|
VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl,
|
|
Scheduler::ConnectionHandle appConnectionHandle,
|
|
Scheduler::ConnectionHandle sfConnectionHandle,
|
|
const OffsetsConfig& config)
|
|
: mPhaseOffsetControl(phaseOffsetControl),
|
|
mAppConnectionHandle(appConnectionHandle),
|
|
mSfConnectionHandle(sfConnectionHandle),
|
|
mOffsetsConfig(config) {
|
|
char value[PROPERTY_VALUE_MAX];
|
|
property_get("debug.sf.vsync_trace_detailed_info", value, "0");
|
|
mTraceDetailedInfo = atoi(value);
|
|
}
|
|
|
|
void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
mOffsetsConfig = config;
|
|
updateOffsetsLocked();
|
|
}
|
|
|
|
void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
|
|
switch (transactionStart) {
|
|
case Scheduler::TransactionStart::EarlyStart:
|
|
ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart");
|
|
mExplicitEarlyWakeup = true;
|
|
break;
|
|
case Scheduler::TransactionStart::EarlyEnd:
|
|
ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart");
|
|
mExplicitEarlyWakeup = false;
|
|
break;
|
|
case Scheduler::TransactionStart::Normal:
|
|
case Scheduler::TransactionStart::Early:
|
|
// Non explicit don't change the explicit early wakeup state
|
|
break;
|
|
}
|
|
|
|
if (mTraceDetailedInfo) {
|
|
ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
|
|
}
|
|
|
|
if (!mExplicitEarlyWakeup &&
|
|
(transactionStart == Scheduler::TransactionStart::Early ||
|
|
transactionStart == Scheduler::TransactionStart::EarlyEnd)) {
|
|
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
|
|
mEarlyTxnStartTime = std::chrono::steady_clock::now();
|
|
}
|
|
|
|
// An early transaction stays an early transaction.
|
|
if (transactionStart == mTransactionStart ||
|
|
mTransactionStart == Scheduler::TransactionStart::EarlyEnd) {
|
|
return;
|
|
}
|
|
mTransactionStart = transactionStart;
|
|
updateOffsets();
|
|
}
|
|
|
|
void VSyncModulator::onTransactionHandled() {
|
|
mTxnAppliedTime = std::chrono::steady_clock::now();
|
|
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;
|
|
|
|
// Apply a margin to account for potential data races
|
|
// This might make us stay in early offsets for one
|
|
// additional frame but it's better to be conservative here.
|
|
if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) {
|
|
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() const {
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
return mOffsets;
|
|
}
|
|
|
|
const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
|
|
// Early offsets are used if we're in the middle of a refresh rate
|
|
// change, or if we recently begin a transaction.
|
|
if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd ||
|
|
mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
|
|
return mOffsetsConfig.early;
|
|
} else if (mRemainingRenderEngineUsageCount > 0) {
|
|
return mOffsetsConfig.earlyGl;
|
|
} else {
|
|
return mOffsetsConfig.late;
|
|
}
|
|
}
|
|
|
|
void VSyncModulator::updateOffsets() {
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
updateOffsetsLocked();
|
|
}
|
|
|
|
void VSyncModulator::updateOffsetsLocked() {
|
|
const Offsets& offsets = getNextOffsets();
|
|
|
|
mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
|
|
mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);
|
|
|
|
mOffsets = offsets;
|
|
|
|
if (!mTraceDetailedInfo) {
|
|
return;
|
|
}
|
|
|
|
const bool isEarly = &offsets == &mOffsetsConfig.early;
|
|
const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
|
|
const bool isLate = &offsets == &mOffsetsConfig.late;
|
|
|
|
ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly);
|
|
ATRACE_INT("Vsync-EarlyGLOffsetsOn", isEarlyGl);
|
|
ATRACE_INT("Vsync-LateOffsetsOn", isLate);
|
|
}
|
|
|
|
} // namespace android::scheduler
|
|
|
|
// TODO(b/129481165): remove the #pragma below and fix conversion issues
|
|
#pragma clang diagnostic pop // ignored "-Wconversion"
|