481 lines
18 KiB
C++
481 lines
18 KiB
C++
/* Copyright Statement:
|
|
*
|
|
* This software/firmware and related documentation ("MediaTek Software") are
|
|
* protected under relevant copyright laws. The information contained herein is
|
|
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
|
|
* the prior written permission of MediaTek inc. and/or its licensors, any
|
|
* reproduction, modification, use or disclosure of MediaTek Software, and
|
|
* information contained herein, in whole or in part, shall be strictly
|
|
* prohibited.
|
|
*
|
|
* MediaTek Inc. (C) 2022. All rights reserved.
|
|
*
|
|
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
|
|
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
|
|
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
|
|
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
|
|
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
|
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
|
|
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
|
|
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
|
|
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
|
|
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
|
|
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
|
|
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
|
|
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
|
|
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
|
|
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
|
|
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
|
|
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
|
|
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
|
|
*
|
|
* The following software/firmware and/or related documentation ("MediaTek
|
|
* Software") have been modified by MediaTek Inc. All revisions are subject to
|
|
* any receiver's applicable license agreements with MediaTek Inc.
|
|
*/
|
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
|
|
|
#include <cinttypes>
|
|
#include <gui/TraceUtils.h>
|
|
#include <log/log.h>
|
|
#include <android-base/properties.h>
|
|
|
|
#include "MtkDuration.h"
|
|
|
|
namespace android {
|
|
// ---------------------------------------------------------------------------
|
|
bool isDynamicDurationEnable() {
|
|
static bool read = false, sw = false;
|
|
// check switch first
|
|
if (!read) {
|
|
sw = base::GetBoolProperty("vendor.debug.sf.dynamic_duration.switch", false);
|
|
read = true;
|
|
}
|
|
return sw;
|
|
}
|
|
nsecs_t loadMtkDuration(const char* name) {
|
|
// if switch is off, not allow to get MKT Duration
|
|
if (!isDynamicDurationEnable() || name == nullptr) return -1;
|
|
return base::GetIntProperty(name, -1);
|
|
}
|
|
|
|
int vsync2hz(nsecs_t vsync) {
|
|
return vsync > 0 ?
|
|
static_cast<int>(std::round(static_cast<float>(ms2ns(1000))/static_cast<float>(vsync))) : -1;
|
|
}
|
|
|
|
// below code from VsyncConfiguration.cpp
|
|
nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
|
|
return vsyncDuration - sfDuration.count() % vsyncDuration;
|
|
}
|
|
|
|
nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
|
|
std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
|
|
return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
|
|
}
|
|
// above code from VsyncConfiguration.cpp
|
|
|
|
MtkDuration::MtkDuration() {
|
|
mType = DurationType_Unset;
|
|
mVsyncPeriod = 0;
|
|
nsecs_t sf_decouple = loadMtkDuration(MTK_DURATION_SF_DECOUPLE);
|
|
nsecs_t app_decouple = loadMtkDuration(MTK_DURATION_APP_DECOUPLE);
|
|
mDecoupleDuration = {
|
|
.sfOffset = 0,
|
|
.appOffset = 0,
|
|
.sfWorkDuration = std::chrono::nanoseconds(sf_decouple),
|
|
.appWorkDuration = std::chrono::nanoseconds(app_decouple),
|
|
};
|
|
mDecoupleModeSwitch = base::GetBoolProperty("vendor.debug.sf.dynamic_duration.switch.decouple", isDynamicDurationEnable());
|
|
mDrawingDecoupleMode = false;
|
|
mActiveDisplayId = 0;
|
|
mActiveDisplayIndex = 0;
|
|
|
|
mOverrideModeChange = false;
|
|
mOverrideDuration = {
|
|
.sfOffset = 0,
|
|
.appOffset = 0,
|
|
.sfWorkDuration = std::chrono::nanoseconds(0),
|
|
.appWorkDuration = std::chrono::nanoseconds(0),
|
|
};
|
|
mOverrideModeSwitch = base::GetBoolProperty("vendor.debug.sf.dynamic_duration.switch.override", false);
|
|
|
|
mIsExtraVsyncSupported = false;
|
|
mIsClientComposition = false;
|
|
}
|
|
|
|
bool MtkDuration::isEnable() {
|
|
return isDynamicDurationEnable();
|
|
}
|
|
|
|
nsecs_t MtkDuration::initMtkDuration(const char* type, nsecs_t vsync, nsecs_t origin) const {
|
|
if (type == nullptr || vsync == 0) return origin;
|
|
const std::string prop
|
|
= type + std::to_string(vsync2hz(vsync));
|
|
nsecs_t duration = loadMtkDuration(prop.c_str());
|
|
if (duration <= 0) {
|
|
// if duration is not set, we try to get default max/min
|
|
if (vsync > DEFAULT_MIN_VSYNC) {
|
|
const std::string default_prop
|
|
= type + std::to_string(vsync2hz(DEFAULT_MIN_VSYNC));
|
|
duration = loadMtkDuration(default_prop.c_str());
|
|
} else if (vsync < DEFAULT_MAX_VSYNC) {
|
|
const std::string default_prop
|
|
= type + std::to_string(vsync2hz(DEFAULT_MAX_VSYNC));
|
|
duration = loadMtkDuration(default_prop.c_str());
|
|
}
|
|
}
|
|
return duration > 0 ? duration : origin;
|
|
}
|
|
|
|
bool MtkDuration::usingMtkDuration() {
|
|
std::lock_guard<std::mutex> lock(mTypeMutex);
|
|
if (((mType & DurationType_Override) == DurationType_Override) ||
|
|
((mType & DurationType_Decouple) == DurationType_Decouple)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
scheduler::VsyncConfig MtkDuration::getMtkDuration(scheduler::VsyncConfig &original) {
|
|
std::lock_guard<std::mutex> lock(mTypeMutex);
|
|
if ((mType & DurationType_Override) == DurationType_Override) {
|
|
ATRACE_NAME("DurationType_Override");
|
|
scheduler::VsyncConfig config = mOverrideDuration;
|
|
bool change = false;
|
|
if (config.sfWorkDuration.count() <= 0) {
|
|
config.sfWorkDuration = original.sfWorkDuration;
|
|
change = true;
|
|
}
|
|
if (config.appWorkDuration.count() <= 0) {
|
|
config.appWorkDuration = original.appWorkDuration;
|
|
change = true;
|
|
}
|
|
if (change) updateDurationOffset(config);
|
|
return config;
|
|
} else if ((mType & DurationType_Decouple) == DurationType_Decouple) {
|
|
ATRACE_NAME("DurationType_Decouple");
|
|
return mDecoupleDuration;
|
|
} else {
|
|
ALOGE("MtkDuration not using mtk duration but someone is trying to get");
|
|
return {};
|
|
}
|
|
}
|
|
|
|
void MtkDuration::updateDurations() {
|
|
if (isDecoupleModeAvailable()) {
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
updateDurationOffset(mDecoupleDuration);
|
|
}
|
|
if (mOverrideModeSwitch) {
|
|
std::lock_guard<std::mutex> lock(mOverrideModeMutex);
|
|
updateDurationOffset(mOverrideDuration);
|
|
}
|
|
}
|
|
|
|
void MtkDuration::setVsyncPeriod(nsecs_t vsync) {
|
|
if (mVsyncPeriod == vsync) return;
|
|
mVsyncPeriod = vsync;
|
|
updateDurations();
|
|
}
|
|
|
|
void MtkDuration::updateDurationOffset(scheduler::VsyncConfig& config) {
|
|
config.sfOffset = config.sfWorkDuration.count() < mVsyncPeriod
|
|
? sfDurationToOffset(config.sfWorkDuration, mVsyncPeriod)
|
|
: sfDurationToOffset(config.sfWorkDuration, mVsyncPeriod) - mVsyncPeriod;
|
|
config.appOffset = config.appWorkDuration.count() < mVsyncPeriod
|
|
? appDurationToOffset(config.appWorkDuration, config.sfWorkDuration, mVsyncPeriod)
|
|
: appDurationToOffset(config.appWorkDuration, config.sfWorkDuration, mVsyncPeriod) - mVsyncPeriod;
|
|
}
|
|
|
|
bool MtkDuration::onDisplayRefresh() {
|
|
ATRACE_NAME("MtkDuration::onDisplayRefresh");
|
|
bool updateNeeded = false;
|
|
// Override mode
|
|
updateNeeded |= isOverrideModeChange();
|
|
// Decouple mode
|
|
updateNeeded |= isDecoupleModeChange();
|
|
// Default unset
|
|
return updateNeeded;
|
|
}
|
|
|
|
std::chrono::nanoseconds MtkDuration::getCurrentMtkPresentLatency(
|
|
std::chrono::nanoseconds app, std::chrono::nanoseconds sf) {
|
|
if ((mType & DurationType_Override) == DurationType_Override) {
|
|
return mOverrideDuration.appWorkDuration + mOverrideDuration.sfWorkDuration;
|
|
} else if ((mType & DurationType_Decouple) == DurationType_Decouple) {
|
|
return mDecoupleDuration.appWorkDuration + mDecoupleDuration.sfWorkDuration;
|
|
} else {
|
|
return app + sf;
|
|
}
|
|
}
|
|
std::chrono::nanoseconds MtkDuration::getDecoupleMtkPresentLatency(
|
|
std::chrono::nanoseconds app, std::chrono::nanoseconds sf) {
|
|
if (isDecoupleModeAvailable()) {
|
|
return mDecoupleDuration.appWorkDuration + mDecoupleDuration.sfWorkDuration;
|
|
}
|
|
return app + sf;
|
|
}
|
|
|
|
void MtkDuration::setIsExtraVsyncSupported(bool support) {
|
|
mIsExtraVsyncSupported = support;
|
|
}
|
|
|
|
uint32_t MtkDuration::setExtraVsyncCount(uint64_t disp_id, uint32_t count) {
|
|
std::lock_guard<std::mutex> lock(mExtraVsyncMutex);
|
|
for (size_t i = 0; i < mRequestedExtraVsyncCounts.size(); i++) {
|
|
if (mRequestedExtraVsyncCounts[i].disp_id == disp_id) {
|
|
ALOGD("update extraVsyncCount %" PRIu64 ", %" PRIu32 , disp_id, count);
|
|
mRequestedExtraVsyncCounts[i].count = count;
|
|
return count;
|
|
}
|
|
}
|
|
ALOGV("new extraVsyncCount %" PRIu64 ", %" PRIu32 , disp_id, count);
|
|
mRequestedExtraVsyncCounts.emplace_back(disp_id, count);
|
|
return count;
|
|
}
|
|
|
|
size_t MtkDuration::getExtraVsyncCount() {
|
|
size_t result = 0;
|
|
if (mIsExtraVsyncSupported) {
|
|
std::lock_guard<std::mutex> lock(mExtraVsyncMutex);
|
|
for (size_t i = 0; i < mRequestedExtraVsyncCounts.size(); i++) {
|
|
if (mActiveDisplayId == mRequestedExtraVsyncCounts[i].disp_id) {
|
|
result += static_cast<size_t>(mRequestedExtraVsyncCounts[i].count);
|
|
break;
|
|
}
|
|
}
|
|
if (result == 0 && mIsClientComposition) {
|
|
result = 1;
|
|
}
|
|
ALOGV("getExtraVsyncCount=%zu, mIsClientComposition=%s", result, (mIsClientComposition?"yes":"no"));
|
|
ATRACE_FORMAT("EV=%zu C=%s", result, (mIsClientComposition?"1":"0"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void MtkDuration::setIsClientComposition(bool is) {
|
|
std::lock_guard<std::mutex> lock(mExtraVsyncMutex);
|
|
mIsClientComposition = is;
|
|
ALOGV("setIsClientComposition %s", mIsClientComposition ? "yes" : "no");
|
|
}
|
|
|
|
bool MtkDuration::controlGpuBackpressure(bool origin) {
|
|
return mIsExtraVsyncSupported || origin;
|
|
}
|
|
|
|
int MtkDuration::getExtraBuffers() {
|
|
if (!mIsExtraVsyncSupported) return 0;
|
|
static int count = base::GetIntProperty("vendor.debug.sf.dynamic_duration.extra_buffers", 1);
|
|
return count;
|
|
}
|
|
|
|
// Decouple mode - START
|
|
bool MtkDuration::isDecoupleModeAvailable() {
|
|
// If hwc support extra vsync to present, we disable deboule mode.
|
|
return mDecoupleModeSwitch && !mIsExtraVsyncSupported;
|
|
}
|
|
|
|
bool MtkDuration::duringTransaction(size_t i) {
|
|
return 0 < mDispMML[i].transactionFrames;
|
|
}
|
|
|
|
void MtkDuration::decreTransactionFrames() {
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
if (mDispMML[i].transactionFrames > 0) {
|
|
mDispMML[i].transactionFrames--;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MtkDuration::getDecoupleModeLocked(size_t i) {
|
|
if (duringTransaction(i)) {
|
|
// duration transaction
|
|
return mDispMML[i].transactionMode && isDecoupleModeAvailable();
|
|
}
|
|
return mDispMML[i].decoupleMode && isDecoupleModeAvailable();
|
|
}
|
|
|
|
size_t MtkDuration::getActiveDisplayIndex() {
|
|
if (mActiveDisplayIndex == INVALID_ACTIVE_DISPLAY_INDEX ||
|
|
mDispMML[mActiveDisplayIndex].displayId != mActiveDisplayId) {
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
if (mDispMML[i].displayId == mActiveDisplayId) {
|
|
mActiveDisplayIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (mActiveDisplayIndex == INVALID_ACTIVE_DISPLAY_INDEX) {
|
|
ALOGW("mActiveDisplayIndex !valid, return 0 instead");
|
|
mActiveDisplayIndex = 0;
|
|
}
|
|
return mActiveDisplayIndex;
|
|
}
|
|
|
|
bool MtkDuration::getDecoupleModeUpdate() {
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
decreTransactionFrames();
|
|
return getDecoupleModeLocked(getActiveDisplayIndex());
|
|
}
|
|
|
|
void MtkDuration::onNewInternalDisplay(uint64_t id) {
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
if (mDispMML[i].displayId == id) {
|
|
ALOGW("onNewInternalDisplay, already exist %" PRIu64, id);
|
|
return;
|
|
}
|
|
}
|
|
mDispMML.emplace_back(id, false, 0, false);
|
|
ALOGD("onNewInternalDisplay, %" PRIu64, id);
|
|
}
|
|
|
|
void MtkDuration::updateActiveDisplayId(uint64_t id) {
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
mActiveDisplayId = id;
|
|
|
|
bool find = false;
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
if (mDispMML[i].displayId == mActiveDisplayId) {
|
|
find = true;
|
|
mActiveDisplayIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (!find) {
|
|
ALOGW("updateActiveDisplayId !find %" PRIu64, id);
|
|
} else {
|
|
ALOGD("updateActiveDisplayId %" PRIu64, id);
|
|
}
|
|
}
|
|
|
|
void MtkDuration::setDecoupleMode(uint64_t id, bool mode) {
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
bool find = false;
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
if (mDispMML[i].displayId == id) {
|
|
find = true;
|
|
if (mDispMML[i].decoupleMode != mode && !duringTransaction(i)) {
|
|
mDispMML[i].transactionFrames = MIN_TRANSACTION_FRAMES;
|
|
mDispMML[i].transactionMode = mode;
|
|
}
|
|
mDispMML[i].decoupleMode = mode;
|
|
break;
|
|
}
|
|
}
|
|
if (find) {
|
|
std::string name = "DecoupleMode_" + std::to_string(id);
|
|
ATRACE_INT(name.c_str(), (mode?1:0));
|
|
}
|
|
}
|
|
|
|
bool MtkDuration::isDecoupleModeChange() {
|
|
if (isDecoupleModeAvailable()) {
|
|
bool nextMode = getDecoupleModeUpdate();
|
|
if (mDrawingDecoupleMode != nextMode) {
|
|
mDrawingDecoupleMode = nextMode;
|
|
std::lock_guard<std::mutex> lock(mTypeMutex);
|
|
if (mDrawingDecoupleMode) {
|
|
mType |= DurationType_Decouple;
|
|
} else {
|
|
mType &= ~(DurationType_Decouple);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
// Decouple mode - END
|
|
|
|
// Override mode - START
|
|
bool MtkDuration::isOverrideModeChange() {
|
|
std::lock_guard<std::mutex> lock(mOverrideModeMutex);
|
|
if (mOverrideModeSwitch && mOverrideModeChange) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MtkDuration::setOverrideDuration(nsecs_t app, nsecs_t sf) {
|
|
if (!mOverrideModeSwitch) {
|
|
ALOGE("MtkDuration override mode is disabled");
|
|
return;
|
|
}
|
|
bool set = false;
|
|
{
|
|
std::lock_guard<std::mutex> lock(mOverrideModeMutex);
|
|
mOverrideModeChange = true;
|
|
if (app <= 0 && sf <= 0) {
|
|
mOverrideDuration = {
|
|
.sfOffset = 0,
|
|
.appOffset = 0,
|
|
.sfWorkDuration = std::chrono::nanoseconds(0),
|
|
.appWorkDuration = std::chrono::nanoseconds(0),
|
|
};
|
|
set = false;
|
|
} else {
|
|
mOverrideDuration = {
|
|
.sfOffset = 0,
|
|
.appOffset = 0,
|
|
.sfWorkDuration = std::chrono::nanoseconds(sf),
|
|
.appWorkDuration = std::chrono::nanoseconds(app),
|
|
};
|
|
updateDurationOffset(mOverrideDuration);
|
|
set = true;
|
|
}
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(mTypeMutex);
|
|
if (set) {
|
|
mType |= DurationType_Override;
|
|
} else {
|
|
mType &= ~(DurationType_Override);
|
|
}
|
|
}
|
|
}
|
|
// Override mode - END
|
|
|
|
void MtkDuration::dump(std::string& result) {
|
|
using base::StringAppendF;
|
|
StringAppendF(&result,
|
|
"\n MTKDuration: current type: %d\n"
|
|
" Decouple mode switch: %s Using decouple mode: %s\n"
|
|
" Decouple app phase: %9" PRId64 " ns\tDecouple SF phase: %9" PRId64
|
|
" ns\n"
|
|
" Decouple app duration: %9lld ns\tDecouple SF duration: %9lld ns\n"
|
|
" Override mode switch: %s Using Override mode: %s\n"
|
|
" Override app phase: %9" PRId64 " ns\tOverride SF phase: %9" PRId64
|
|
" ns\n"
|
|
" Override app duration: %9lld ns\tOverride SF duration: %9lld ns\n"
|
|
" ExtraVsyncSupported=%s\n\n",
|
|
mType,
|
|
mDecoupleModeSwitch ? "true" : "false",
|
|
mDrawingDecoupleMode ? "true" : "false",
|
|
mDecoupleDuration.appOffset, mDecoupleDuration.sfOffset,
|
|
mDecoupleDuration.appWorkDuration.count(), mDecoupleDuration.sfWorkDuration.count(),
|
|
mOverrideModeSwitch ? "true" : "false",
|
|
(mType & DurationType_Override) == DurationType_Override ? "true" : "false",
|
|
mOverrideDuration.appOffset, mOverrideDuration.sfOffset,
|
|
mOverrideDuration.appWorkDuration.count(), mOverrideDuration.sfWorkDuration.count(),
|
|
mIsExtraVsyncSupported ? "yes" : "no");
|
|
{
|
|
std::lock_guard<std::mutex> lock(mDecoupleModeMutex);
|
|
for (size_t i = 0; i < mDispMML.size(); i++) {
|
|
StringAppendF(&result, " DispMML[%zu]: dispId=%" PRIu64 ", mode=%s\n",
|
|
i, mDispMML[i].displayId, mDispMML[i].decoupleMode?"true":"false");
|
|
}
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(mExtraVsyncMutex);
|
|
for (size_t i = 0; i < mRequestedExtraVsyncCounts.size(); i++) {
|
|
StringAppendF(&result, " ExtraVsync[%zu]: dispId=%" PRIu64 ", count=%" PRIu32 "\n",
|
|
i, mRequestedExtraVsyncCounts[i].disp_id, mRequestedExtraVsyncCounts[i].count);
|
|
}
|
|
}
|
|
result.append("\n");
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
}; // namespace android
|