unplugged-system/frameworks/native/services/surfaceflinger/mediatek/ScheduleHelper.h

190 lines
7.5 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.
*/
#pragma once
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <log/log.h>
#include <thread>
#include <utils/Trace.h>
#include <utils/Mutex.h>
#include <android-base/properties.h>
#define MAX_DELAY_COUNT 5
namespace android {
// ---------------------------------------------------------------------------
class ScheduleHelper
{
public:
bool mDebug;
int64_t mDelayTransactionThreshold;
size_t mPendingTransactionsCount;
size_t mLocklessTransactionsCount;
int64_t mSfWorkDuration;
int64_t mVsyncPeriod;
int64_t mLastScheduledPresentTime;
std::vector<int64_t> mDelayedTimesForPending;
std::vector<int64_t> mDelayedTimesForLockless;
Mutex mPendings;
Mutex mLockless;
Mutex mGeneral;
static ScheduleHelper& getInstance() {
static ScheduleHelper gInstance;
return gInstance;
}
~ScheduleHelper() {};
int64_t getDelayTimeForTransaction(bool isauto, int64_t desiredTime) {
int64_t delayed_time = 0;
if (!isauto) {
Mutex::Autolock lock(mGeneral);
const auto now = systemTime();
// we add 2ms to cover slight shift of presentTime
const auto nextPredictedPresentTime = mLastScheduledPresentTime + mVsyncPeriod + ms2ns(2);
const auto delayedWakeUpTime = desiredTime - mSfWorkDuration;
delayed_time = delayedWakeUpTime - now;
if (desiredTime <= nextPredictedPresentTime || // don't delay if it is in next vsync.
delayed_time > mDelayTransactionThreshold) { // don't delay too much
delayed_time = 0;
}
}
ATRACE_INT64("delayedTransaction", delayed_time);
return delayed_time;
}
int64_t checkDelayTimeForPendingTransaction(bool isauto, int64_t desiredTime) {
int64_t delayTime = getDelayTimeForTransaction(isauto, desiredTime);
Mutex::Autolock lock(mPendings);
if (delayTime > 0 && mDelayedTimesForPending.size() < MAX_DELAY_COUNT) {
if (mDelayedTimesForPending.size() < MAX_DELAY_COUNT) {
mDelayedTimesForPending.push_back(delayTime);
} else {
ALOGW("can't delay more pending transaction");
}
}
return delayTime;
}
int64_t checkDelayForLocklessTransaction(bool isauto, int64_t desiredTime) {
return getDelayTimeForTransaction(isauto, desiredTime);
}
void queueDelayTimeForLocklessTransaction(int64_t delayTime) {
Mutex::Autolock lock(mLockless);
mLocklessTransactionsCount+=1;
if (delayTime > 0 && mDelayedTimesForLockless.size() < MAX_DELAY_COUNT) {
if (mDelayedTimesForLockless.size() < MAX_DELAY_COUNT) {
mDelayedTimesForLockless.push_back(delayTime);
} else {
ALOGW("can't delay more lockless transaction");
}
}
}
int64_t getNextDelayedTimeOfPendingTransactions() {
Mutex::Autolock lock(mPendings);
if (mDelayedTimesForPending.empty()) return 0;
int64_t delayTime = mDelayedTimesForPending.back();
mDelayedTimesForPending.pop_back();
return delayTime;
}
void updateDurationVsync(int64_t sfduration, int64_t vsync) {
Mutex::Autolock lock(mGeneral);
mSfWorkDuration = sfduration;
mVsyncPeriod = vsync;
}
void updateLastSchedulePresentTime(int64_t time) {
Mutex::Autolock lock(mGeneral);
mLastScheduledPresentTime = time;
}
void resetLocklessCount() {
Mutex::Autolock lock(mLockless);
mDelayedTimesForLockless.clear();
mLocklessTransactionsCount = 0;
}
void increasePendingTransactionsCount() {
Mutex::Autolock lock(mPendings);
mPendingTransactionsCount += 1;
}
void resetPendingTransactionsCount() {
Mutex::Autolock lock(mPendings);
mPendingTransactionsCount = 0;
}
bool hasPendingTransactions() {
Mutex::Autolock lock1(mPendings);
Mutex::Autolock lock2(mLockless);
// If all pending transactions are delayed and all lockless transactions
// are delayed, there is no pending transactions.
if (mDebug) {
ATRACE_INT("PendingTransactionsCount", static_cast<int>(mPendingTransactionsCount));
ATRACE_INT("DelayedTimesForPending", static_cast<int>(mDelayedTimesForPending.size()));
ATRACE_INT("LocklessTransactionsCount", static_cast<int>(mLocklessTransactionsCount));
ATRACE_INT("DelayedTimesForLockless", static_cast<int>(mDelayedTimesForLockless.size()));
}
if ((mPendingTransactionsCount - mDelayedTimesForPending.size() == 0) &&
(mLocklessTransactionsCount - mDelayedTimesForLockless.size() ==0)) {
return false;
}
return true;
}
private:
ScheduleHelper() {
mDebug = base::GetBoolProperty("debug.sf.schedule_helper", false);
mDelayTransactionThreshold = base::GetIntProperty("debug.sf.mDelayTransactionThreshold", 500000000);
mDelayedTimesForPending.reserve(MAX_DELAY_COUNT);
mDelayedTimesForLockless.reserve(MAX_DELAY_COUNT);
mPendingTransactionsCount = 0;
mLocklessTransactionsCount = 0;
mSfWorkDuration = 0;
mVsyncPeriod = 0;
mLastScheduledPresentTime = 0;
}
};
// ---------------------------------------------------------------------------
}; // namespace android