/* 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) 2021. 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 "SfCpuPolicyAdapter.h" #include #include #include #include #include #ifdef MTK_COMPOSER_EXT #include #endif namespace android { #ifndef MTK_CUTTLESTONE const SfCpuPolicy::Config SfCpuPolicyAdapter::HighPerfCong = {125000000, 30, 125000000, 10}; const SfCpuPolicy::Config SfCpuPolicyAdapter::NormalPerfCong = {125000000, 10, 125000000, 5}; #endif static int CONFIG_HW_COMP_RATE_MIN_ENABLE_CPU_POLICY = 60; //eg HW comp, min rate to start the cpu policy, eg 60 hz static int CONFIG_GPU_COMP_RATE_MIN_ENABLE_CPU_POLICY = 60; //eg GPU comp, min rate to start the cpu policy, eg 60hz & gpu is using static int CONFIG_HW_COMP_SUSPEND_CPU_POLICY = 0 ; // [0 ~ 1], suspend the comunication of XGF, ie auto control by scheduler per min resource requirement static int CONFIG_HW_COMP_HFR_SUSPEND_CPU_POLICY = 0 ; // [0 ~ 1], suspend the comunication of XGF, ie auto control by scheduler per min resource requirement static int CONFIG_VP_LP_SUSPEND_CPU_POLICY = 0 ; // [0 ~ 1], suspend if VPLP hint got static int CONFIG_FORCE_SUSPEND_CPU_POLICY = 0 ; // testing only, force suspend mode static int CONFIG_POWER_UP_MARGIN_120 = 500000; // 500000 nsec, 0.5 ms static int CONFIG_POWER_DOWN_MARGIN_120 = 2000000; // 2000000 nsec static int CONFIG_POWER_UP_MARGIN_90 = 500000; // 500000 nsec, 0.5 ms static int CONFIG_POWER_DOWN_MARGIN_90 = 2000000; // 2000000 nsec static int CONFIG_POWER_UP_MARGIN = 500000; // 500000 nsec, 0.5 ms static int CONFIG_POWER_DOWN_MARGIN = 2000000; // 2000000 nsec static bool logEnabled() { static bool checked = false; static bool enabled = false; if (!checked){ char value[PROPERTY_VALUE_MAX] = {}; property_get("vendor.debug.sf.cpupolicy.log", value, "1"); enabled = (atoi(value)>=2); checked = true; } return enabled; } SfCpuPolicyAdapter& SfCpuPolicyAdapter::getInstance(frametimeline::FrameTimeline & frameTimeline) { static SfCpuPolicyAdapter gInstance(frameTimeline); return gInstance; } bool SfCpuPolicyAdapter::isEnabled() { static bool checked = false; static bool enabled = false; if (!checked){ char value[PROPERTY_VALUE_MAX] = {}; property_get("vendor.debug.sf.cpupolicy", value, "1"); enabled = (atoi(value) != 0); struct utsname u; if (uname (&u) < 0){ enabled = false; checked = true; return enabled; } std::string str = u.release; // eg: str = "5.10.41-android12-5-gdce53f229c13"; if (enabled) { std::string const delims{ ".-"}; std::string str_big_version; std::string str_middle_version; int big_version; int middle_version; size_t beg = 0; size_t pos = 0; beg = str.find_first_not_of(delims, pos); if ( beg != std::string::npos) { pos = str.find_first_of(delims, beg + 1); str_big_version = str.substr(beg, pos - beg); } beg = str.find_first_not_of(delims, pos); if ( beg != std::string::npos) { pos = str.find_first_of(delims, beg + 1); str_middle_version = str.substr(beg, pos - beg); } big_version = std::stoi(str_big_version); // eg 5 middle_version = std::stoi(str_middle_version); //eg 10 if ((big_version > 5) || (big_version == 5 && middle_version >=10)) { enabled = true; }else { enabled = false; } } ALOGI("release %s enabled %d", u.release, enabled); checked = true; } return enabled; } void SfCpuPolicyAdapter::notifyPowerSuspend(bool enable) { mPowerSuspend = enable; } void SfCpuPolicyAdapter::notifyHwcHwbinderTid(int tid) { ALOGV("notifyHwcHwbinderTid"); if (mCpuPolicy == nullptr) return; if (mFnNotifyHwcHwbinderTid) { mFnNotifyHwcHwbinderTid(mCpuPolicy, tid); } else { ALOGE("!mFnNotifyHwcHwbinderTid"); } } void SfCpuPolicyAdapter::notifyVpLpEnable(bool enable) { std::lock_guard lock(mMutex); mVpLpEnableDbg = enable; ALOGD("%s enable %d", __FUNCTION__, enable); } bool SfCpuPolicyAdapter::getVpLpEnable() { bool enable = false; { std::lock_guard lock(mMutex); int layerCnt = 0; bool vplpFound = false; for (auto it = mVpLpLayers.begin(); it != mVpLpLayers.end(); ++it) { if(it->second == VPLP_LAYER_CHECKED_OK) { vplpFound = true; } layerCnt ++; } mVpLpEnable = (vplpFound && (layerCnt == 1)); // allowed only one surfaceview/vp layer enable = mVpLpEnable || mVpLpEnableDbg; ALOGV("%s: vplp layer cnt %d", __FUNCTION__, layerCnt); } return enable; } void SfCpuPolicyAdapter::notifyLayerConnect(const void * token, const std::string& name) { std::lock_guard lock(mMutex); if (token == nullptr) return; bool layerMatch = false; #define SURFACEVIEW_LAYER_NAME "SurfaceView" std::vector LayerNameArr = {SURFACEVIEW_LAYER_NAME}; for(size_t i = 0; i < LayerNameArr.size(); ++i) { if (name.find(LayerNameArr[i]) != std::string::npos) { layerMatch = true; break; } } if (layerMatch) { // add mVpLpLayers if (logEnabled()) { ALOGD("%s: token=%p , %s", __FUNCTION__, token, name.c_str()); } mVpLpLayers.emplace(token, VPLP_LAYER_UNCHECKED); // pending check } } void SfCpuPolicyAdapter::notifyLayerDisconnect(const void * token){ std::lock_guard lock(mMutex); if (token == nullptr) return; auto it = mVpLpLayers.find(token); if (it != mVpLpLayers.end()) { if (logEnabled()) { ALOGD("%s: token=%p", __FUNCTION__, token); } mVpLpLayers.erase(it); } } void SfCpuPolicyAdapter::notifyLayerSetBuffer(const void * token, const sp& buffer){ #ifndef MTK_CUTTLESTONE std::lock_guard lock(mMutex); if (token != nullptr && buffer != nullptr) { uint32_t w = buffer->getWidth(); uint32_t h = buffer->getHeight(); auto it = mVpLpLayers.find(token); if (it != mVpLpLayers.end()) { if (it->second == VPLP_LAYER_UNCHECKED) { if (w <=2000 && h <=2000 ) { // quick check for 1920x1080p gralloc_extra_ion_sf_info_t extInfo; GRALLOC_EXTRA_RESULT result = gralloc_extra_query(buffer->handle, GRALLOC_EXTRA_GET_IOCTL_ION_SF_INFO, &extInfo); if (result == GRALLOC_EXTRA_OK && ((unsigned int)extInfo.status & GRALLOC_EXTRA_MASK_TYPE) == GRALLOC_EXTRA_BIT_TYPE_VIDEO) { it->second = VPLP_LAYER_CHECKED_OK; // checked and valid vp layer if (logEnabled()) { ALOGD("%s: token=%p", __FUNCTION__, token); } } else { it->second = VPLP_LAYER_CHECKED_NOT_OK; // checked and not valid vp layer } } else { it->second = VPLP_LAYER_CHECKED_NOT_OK; // checked and not valid vp layer } } } } #else if (token != nullptr && buffer != nullptr) { if (logEnabled()) { ALOGV("%s: token=%p", __FUNCTION__, token); } } #endif //MTK_CUTTLESTONE } SfCpuPolicy::EnableReason SfCpuPolicyAdapter::checkIfNeedSuspend(int rate, bool gpu_comp, bool * sus_mid, nsecs_t *targetTime) { bool needSuspend = true; // true to disable the SF CPU policy #ifdef MTK_COMPOSER_EXT bool vpLpState = false; #endif SfCpuPolicy::EnableReason ret = SfCpuPolicy::EnableReason::NONE; // init the min required resource, not set to none at beginig if (rate > 95 ){ ret = SfCpuPolicy::EnableReason::MIN_SPEED_120; } else if (rate > 65 ){ ret = SfCpuPolicy::EnableReason::MIN_SPEED_90; } else { ret = SfCpuPolicy::EnableReason::MIN_SPEED_60; } // simple rule to enable cpu policy if (rate >= CONFIG_HW_COMP_RATE_MIN_ENABLE_CPU_POLICY) { needSuspend = false; ret = SfCpuPolicy::EnableReason::SF_SPEED; } else if (gpu_comp && rate >= CONFIG_GPU_COMP_RATE_MIN_ENABLE_CPU_POLICY) { needSuspend = false; ret = SfCpuPolicy::EnableReason::RE_SPEED; } if (!mPowerSuspend){ /* update lastFps while screen on */ mLastFps = mFrameTimeline.computeFps(0,0); ATRACE_INT("SfCpu_fps", (int)mLastFps); } if (rate) { // estiminate the fps and provide the min resource static SfCpuPolicy::EnableReason suspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_120; static SfCpuPolicy::EnableReason oldSuspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_120; static int count_90 = 0; static int count_60 = 0; static int count_30 = 0; if (!mPowerSuspend){ oldSuspendSpeed = suspendSpeed; if (mLastFps >= 95.0f) { static int credit = 0; suspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_120; if (!gpu_comp) { credit ++; if (credit >= 5) credit = 5; }else { credit = 0; } if (!gpu_comp && (credit >= 5) && CONFIG_HW_COMP_HFR_SUSPEND_CPU_POLICY) { needSuspend = true; ret = SfCpuPolicy::EnableReason::MIN_SPEED_120; } } else if (mLastFps < 95.0f && mLastFps >= 69.0f) { // ie take 70~95 fps as 90 fps, 5 is the margin suspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_90; if (oldSuspendSpeed != suspendSpeed) { count_90 = 0; }else { count_90 ++; } if (count_90 >= 45) { /* The time would be more than 0.5s below 95 fps. Suspend the cpu policy. */ if (!gpu_comp && CONFIG_HW_COMP_HFR_SUSPEND_CPU_POLICY) { needSuspend = true; ret = SfCpuPolicy::EnableReason::MIN_SPEED_90; } nsecs_t predictTarget = calcTargetTime ((int)90); if (targetTime != nullptr) { *targetTime = predictTarget; } count_90 = 45; } } else if (mLastFps < 69.0f) { // ie take 0-69 fps as 60 fps, 9 is the margin suspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_60; if (oldSuspendSpeed > suspendSpeed) { count_60 = 0; }else { count_60 ++; } if (count_60 >= 20) { /* The time would be more than 0.3s below 69 fps. Suspend the cpu policy. */ if (!gpu_comp && CONFIG_HW_COMP_SUSPEND_CPU_POLICY) { needSuspend = true; ret = SfCpuPolicy::EnableReason::MIN_SPEED_60; } nsecs_t predictTarget = calcTargetTime ((int)60); if (targetTime != nullptr) { *targetTime = predictTarget; } count_60 = 20; } if (mLastFps <= 35.0f) { suspendSpeed = SfCpuPolicy::EnableReason::MIN_SPEED_30; if (oldSuspendSpeed > suspendSpeed) { count_30 = 0; }else { count_30 ++; } if (count_30 >= 20) { /* The time would be more than 0.6s below 35 fps. Suspend the cpu policy. */ if (!gpu_comp && CONFIG_VP_LP_SUSPEND_CPU_POLICY) { if(getVpLpEnable()) { needSuspend = true; ret = SfCpuPolicy::EnableReason::MIN_SPEED_30; #ifdef MTK_COMPOSER_EXT vpLpState = true; #endif if (sus_mid){ *sus_mid = true; } } } else if (!gpu_comp && CONFIG_HW_COMP_SUSPEND_CPU_POLICY) { needSuspend = true; ret = SfCpuPolicy::EnableReason::MIN_SPEED_30; } nsecs_t predictTarget = calcTargetTime ((int)60); if (targetTime != nullptr) { *targetTime = predictTarget; } count_30 = 20; } } } if (logEnabled()){ ALOGD("needSuspend %d suspendSpeed %d count_30 %d count_60 %d count_90 %d avg fps %f", needSuspend, suspendSpeed, count_30, count_60, count_90, mLastFps); } } } if (!mPowerSuspend) { static nsecs_t lastFrameEndTime = 0; nsecs_t currentTime = systemTime(); bool longTime = lastFrameEndTime && (currentTime - lastFrameEndTime) >= 1000000000 ; //1s bool reset_workaround = lastFrameEndTime && (currentTime - lastFrameEndTime) >= 100000000 ; //100 ms , 10 fps if (!gpu_comp && reset_workaround) { // avoid calculate if end 2 end too long // Idle mode pattern check, 10 fps notifyResetCalculation(); } static int old_mS2sFps = 0; if (old_mS2sFps != (int)mS2sFps) { // reduce trace. it is 0 for most cases ATRACE_INT("SfCpu_fps_curr", (int)mS2sFps); old_mS2sFps = (int)mS2sFps; } if (!gpu_comp && (mS2sFps > 0) && (mS2sFps <=10.0f) ){ // Idle mode pattern check, 10 fps needSuspend = true; nsecs_t predictTarget = calcTargetTime ((int)10); if (targetTime != nullptr) { *targetTime = predictTarget; } notifyResetCalculation(); } if (!gpu_comp && (mS2sFps > 0) && (mLastFps <= 10.0f)) { // low frame rate // Idle mode pattern check, 10 fps // make the target time longer since perfmance is not needed. needSuspend = true; nsecs_t predictTarget = calcTargetTime ((int)10); if (targetTime != nullptr) { *targetTime = predictTarget; } notifyResetCalculation(); } if ((mS2sFps > 0) && (mS2sFps <= 5.0f)){ // Idle mode pattern check, 0-5 fps needSuspend = true; nsecs_t predictTarget = calcTargetTime ((int)10); if (targetTime != nullptr) { *targetTime = predictTarget; } notifyResetCalculation(); } if (mLastFps < 1.0f && longTime) { // almost idle screen needSuspend = true; ret = SfCpuPolicy::EnableReason::NONE; // make the target time longer since perfmance is not needed. nsecs_t predictTarget = calcTargetTime ((int)10); if (targetTime != nullptr) { *targetTime = predictTarget; } } if (CONFIG_FORCE_SUSPEND_CPU_POLICY) { needSuspend = true; } lastFrameEndTime = currentTime; } mSuspendNeed = needSuspend; bool oldSuspend = mSuspend; mSuspend = (mPowerSuspend || mSuspendNeed); #ifdef MTK_COMPOSER_EXT #ifndef MTK_CUTTLESTONE if (vpLpState != mLastVpLpState) { if (mMtkComposerExtIntf) { ComposerExt::ScenarioHint val = vpLpState ? ComposerExt::ScenarioHint::kVideoPlyback: ComposerExt::ScenarioHint::kGeneral; mMtkComposerExtIntf->setScenarioHint(val, ComposerExt::ScenarioHint::kVideoPlyback); } mLastVpLpState = vpLpState; } #else //MTK_CUTTLESTONE mLastVpLpState = false; #endif //MTK_CUTTLESTONE #endif if (mPowerSuspend) { ret = SfCpuPolicy::EnableReason::NONE; } if (logEnabled()){ ALOGD("mSuspend %d mPowerSuspend %d mSuspendNeed %d gpu %d", mSuspend, mPowerSuspend, mSuspendNeed, gpu_comp); } if (mSuspend && !oldSuspend){ notifyResetCalculation(); } if (targetTime != nullptr) { ATRACE_INT("SfCpu_targetTime", (int)(*targetTime)/10000); } return ret; } SfCpuPolicyAdapter::SfCpuPolicyAdapter(frametimeline::FrameTimeline & frameTimeline): mFrameTimeline(frameTimeline), mSoHandle(nullptr), mFnCreateSfCpuPolicy(nullptr), mFnDestroySfCpuPolicy(nullptr), mFnSetupConfig(nullptr), mFnSetupPerfMeas(nullptr), mFnNotifyFrameStart(nullptr), mFnNotifySpeedUpRE(nullptr), mFnNotifyFrameEnd(nullptr), mFnNotifyClearCorrection(nullptr), mFnNotifyResetCalculation(nullptr), mFnNotifyHwcHwbinderTid(nullptr) { ALOGV("SfCpuPolicyAdapter"); mSoHandle = dlopen("libsf_cpupolicy.so", RTLD_LAZY); typedef SfCpuPolicy* (*CreateSfCpuPolicy)(); typedef void (*DestroySfCpuPolicy)(SfCpuPolicy*); typedef void (*SetupConfig)(SfCpuPolicy*,SfCpuPolicy::Config & conf,bool suspend); typedef void (*SetupPerfMeas)(SfCpuPolicy* cpuPolicy, SfCpuPolicy::PerfMeas * perfMeas); typedef void (*NotifyFrameStart)(SfCpuPolicy* cpuPolicy, nsecs_t startTime, int64_t vsyncId, bool suspend); typedef void (*NotifySpeedUpRE)(SfCpuPolicy* cpuPolicy, int resource, int64_t vsyncId); typedef void (*NotifyFrameEnd)(SfCpuPolicy* cpuPolicy, nsecs_t endTime, int64_t vsyncId, bool suspend); typedef void (*NotifyClearCorrection)(SfCpuPolicy* cpuPolicy, int64_t vsyncId, bool clear, bool heavyLoading); typedef void (*NotifyResetCalculation)(SfCpuPolicy* cpuPolicy, int64_t vsyncId); typedef void (*NotifyHwcHwbinderTid)(SfCpuPolicy* cpuPolicy, int tid); mFnCreateSfCpuPolicy = reinterpret_cast(dlsym(mSoHandle, "createSfCpuPolicy")); mFnDestroySfCpuPolicy = reinterpret_cast(dlsym(mSoHandle, "destroySfCpuPolicy")); mFnSetupConfig = reinterpret_cast(dlsym(mSoHandle, "setupConfig")); mFnSetupPerfMeas = reinterpret_cast(dlsym(mSoHandle, "setupPerfMeas")); mFnNotifyFrameStart = reinterpret_cast(dlsym(mSoHandle, "notifyFrameStart")); mFnNotifySpeedUpRE = reinterpret_cast(dlsym(mSoHandle, "notifySpeedUpRE")); mFnNotifyFrameEnd = reinterpret_cast(dlsym(mSoHandle, "notifyFrameEnd")); mFnNotifyClearCorrection = reinterpret_cast(dlsym(mSoHandle, "notifyClearCorrection")); mFnNotifyResetCalculation = reinterpret_cast(dlsym(mSoHandle, "notifyResetCalculation")); mFnNotifyHwcHwbinderTid = reinterpret_cast(dlsym(mSoHandle, "notifyHwcHwbinderTid")); if (mSoHandle) { if (nullptr == mFnCreateSfCpuPolicy) { ALOGE("finding createSfCpuPolicy() failed"); } else if (nullptr == mFnSetupPerfMeas) { ALOGE("finding setupPerfMeas() failed"); } else { mCpuPolicy = createSfCpuPolicy(); } if (nullptr == mFnDestroySfCpuPolicy) { ALOGE("finding destroySfCpuPolicy() failed"); } if (nullptr == mFnSetupConfig) { ALOGE("finding setupConfig() failed"); } if (nullptr == mFnNotifyFrameStart) { ALOGE("finding notifyFrameStart() failed"); } if (nullptr == mFnNotifySpeedUpRE) { ALOGE("finding notifySpeedUpRE() failed"); } if (nullptr == mFnNotifyFrameEnd) { ALOGE("finding notifyFrameEnd() failed"); } if (nullptr == mFnNotifyClearCorrection) { ALOGE("finding notifyClearCorrection() failed"); } if (nullptr == mFnNotifyResetCalculation) { ALOGE("finding notifyResetCalculation() failed"); } if (nullptr == mFnNotifyHwcHwbinderTid) { ALOGE("finding notifyHwcHwbinderTid() failed"); } } else { ALOGE("open libsf_cpupolicy failed"); } InitProp(); } void SfCpuPolicyAdapter::InitProp(){ char value[PROPERTY_VALUE_MAX] = {}; int iValue = 0; property_get("vendor.debug.sf.cpupolicy.hw_comp_min", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_HW_COMP_RATE_MIN_ENABLE_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.gpu_comp_min", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_GPU_COMP_RATE_MIN_ENABLE_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.hw_comp_suspend", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_HW_COMP_SUSPEND_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.hw_hfr_suspend", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_HW_COMP_HFR_SUSPEND_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.vp_lp_suspend", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_VP_LP_SUSPEND_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.force_suspend", value, "-1"); iValue = (atoi(value)); if (iValue >= 0) { CONFIG_FORCE_SUSPEND_CPU_POLICY = iValue; } property_get("vendor.debug.sf.cpupolicy.power_up_120", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_UP_MARGIN_120 = iValue; } property_get("vendor.debug.sf.cpupolicy.power_up_90", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_UP_MARGIN_90 = iValue; } property_get("vendor.debug.sf.cpupolicy.power_up_margin", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_UP_MARGIN = iValue; } property_get("vendor.debug.sf.cpupolicy.power_down_120", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_DOWN_MARGIN_120 = iValue; } property_get("vendor.debug.sf.cpupolicy.power_down_90", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_DOWN_MARGIN_90 = iValue; } property_get("vendor.debug.sf.cpupolicy.power_down_margin", value, "-1"); iValue = (atoi(value)); if (iValue != -1) { CONFIG_POWER_DOWN_MARGIN = iValue; } } SfCpuPolicy* SfCpuPolicyAdapter::createSfCpuPolicy(){ ALOGV("createSfCpuPolicy"); if (mFnCreateSfCpuPolicy) { SfCpuPolicy *cpuPolicy = mFnCreateSfCpuPolicy(); if (mFnSetupPerfMeas) { mFnSetupPerfMeas (cpuPolicy, this); } return cpuPolicy; } return nullptr; } void SfCpuPolicyAdapter::destroySfCpuPolicy(){ if (mCpuPolicy == nullptr) return; if (mFnDestroySfCpuPolicy) { mFnDestroySfCpuPolicy(mCpuPolicy); } } void SfCpuPolicyAdapter::setupConfig(SfCpuPolicy::Config & conf) { if (mCpuPolicy == nullptr) return; if (mIsLastFrameFinished && mSuspend) { if (mFnSetupConfig) { mFnSetupConfig(mCpuPolicy, conf, true); } return; } if (mFnSetupConfig) { mFnSetupConfig(mCpuPolicy, conf, false); } } void SfCpuPolicyAdapter::notifyFrameStart( nsecs_t startTime, int64_t vsyncId) { ALOGV("notifyFrameStart %" PRId64" ", vsyncId); if (mCpuPolicy == nullptr){ ALOGE("mCpuPolicy == null"); return; } static nsecs_t lastFrameStartTimeChk = 0; static int count = 0; nsecs_t currentTime = systemTime(); bool longTime = lastFrameStartTimeChk && mLastFrameEndTime && (currentTime - mLastFrameEndTime) >= 40000000 ; // 40 ms // calculate the current fps if the last start is long time. if (longTime) { count ++; if (currentTime- lastFrameStartTimeChk >= 300000000) { // 300 ms mS2sFps = count * 1000000000 /(currentTime- lastFrameStartTimeChk); } }else { lastFrameStartTimeChk = mLastFrameEndTime; count = 0; mS2sFps = 0; } // notify frame end if last frame just contains start and no end if (!mIsLastFrameFinished) { if (mFnNotifyFrameEnd) { //notify 0 endTime , ie. the frame should be cancel. mFnNotifyFrameEnd(mCpuPolicy, 0, mLastVsyncId, false); mIsLastFrameFinished = true; } } if (mSuspend) { if (mFnNotifyFrameStart) { mFnNotifyFrameStart(mCpuPolicy, startTime, vsyncId, mSuspend); } return; } if (mFnNotifyFrameStart) { mFnNotifyFrameStart(mCpuPolicy, startTime, vsyncId, mSuspend); mLastVsyncId = vsyncId; } mIsLastFrameFinished = false; } void SfCpuPolicyAdapter::notifySpeedUpRE(int resource) { ALOGV("notifySpeedUpRE %" PRId64" ", mLastVsyncId); if (mCpuPolicy == nullptr){ ALOGE("mCpuPolicy == null"); return; } if (mFnNotifySpeedUpRE) { mFnNotifySpeedUpRE(mCpuPolicy, resource, mLastVsyncId); } else { ALOGE("!mFnNotifySpeedUpRE"); } } void SfCpuPolicyAdapter::notifyFrameEnd( nsecs_t endTime) { ALOGV("notifyFrameEnd %" PRId64" ", mLastVsyncId); mLastFrameEndTime = systemTime(); if (mCpuPolicy == nullptr) return; if (mIsLastFrameFinished && mSuspend) { if (mFnNotifyFrameEnd) { mFnNotifyFrameEnd(mCpuPolicy, endTime, mLastVsyncId, true); } return; } if (mFnNotifyFrameEnd) { mFnNotifyFrameEnd(mCpuPolicy, endTime, mLastVsyncId, false); } else { ALOGE("!mFnNotifyFrameEnd"); } mIsLastFrameFinished = true; } void SfCpuPolicyAdapter::notifyClearCorrection(bool clear, bool heavyLoading) { ALOGV("notifyClearCorrection"); if (mCpuPolicy == nullptr) return; if (mIsLastFrameFinished && mSuspend) { return; } if (mFnNotifyClearCorrection) { mFnNotifyClearCorrection(mCpuPolicy, mLastVsyncId, clear, heavyLoading); } else { ALOGE("!mFnNotifyClearCorrection"); } } void SfCpuPolicyAdapter::notifyResetCalculation() { ALOGV("notifyResetCalculation"); if (mCpuPolicy == nullptr) return; if (mIsLastFrameFinished && mSuspend) { return; } if (mFnNotifyResetCalculation) { mFnNotifyResetCalculation(mCpuPolicy, mLastVsyncId); } else { ALOGE("!mFnNotifyResetCalculation"); } } bool SfCpuPolicyAdapter::needIncreasePerf(nsecs_t startTime, nsecs_t endTime, nsecs_t targetTime) { nsecs_t margin = CONFIG_POWER_UP_MARGIN; if (targetTime <= 8000000) { // 8ms margin = CONFIG_POWER_UP_MARGIN_120; } else if (targetTime <= 11000000){ // 11ms margin = CONFIG_POWER_UP_MARGIN_90; } nsecs_t predictTarget = targetTime - margin ; bool ret = mFrameTimeline.isPresentLate(startTime, endTime, targetTime, predictTarget); return ret; } bool SfCpuPolicyAdapter::needReducePerf(nsecs_t startTime, nsecs_t endTime, nsecs_t targetTime) { nsecs_t margin = CONFIG_POWER_DOWN_MARGIN; if (targetTime <= 8000000) { // 8ms margin = CONFIG_POWER_DOWN_MARGIN_120; } else if (targetTime <= 11000000){ // 11ms margin = CONFIG_POWER_DOWN_MARGIN_90; } nsecs_t predictTarget = targetTime - margin ; bool ret = mFrameTimeline.isPresentEarly(startTime, endTime, targetTime, predictTarget); return ret; } nsecs_t SfCpuPolicyAdapter::calcTargetTime(int fps){ nsecs_t targetTime = 16* 1000000; if(fps > 125) { // 144 fps targetTime = 6* 1000000; // 6ms }else if (fps > 95) { // 120 fps targetTime = 8* 1000000; // 8ms }else if (fps > 68) { // 90 fps targetTime = 11* 1000000; // 11ms } else if (fps > 35){ // 60 fps targetTime = 16* 1000000; // 16ms } else { targetTime = 25* 1000000; // 25ms } ALOGV("refresh rate fps %d", fps); return targetTime; } SfCpuPolicyAdapter::~SfCpuPolicyAdapter(){ if (mSoHandle) { dlclose(mSoHandle); mSoHandle = nullptr; } if (mCpuPolicy != nullptr) { destroySfCpuPolicy(); mCpuPolicy = nullptr; } } #ifdef MTK_COMPOSER_EXT void SfCpuPolicyAdapter::setComposerExtIntf(ComposerExt::ClientInterface* intf) { mMtkComposerExtIntf = intf; } #endif }// namespace android