summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShiyong Li <shiyongli@google.com>2023-04-07 21:14:16 +0000
committerShiyong Li <shiyongli@google.com>2023-04-25 18:19:30 +0000
commit88780476976e4194bbaa581a5713b69d8d963a1e (patch)
treed498590e90af5f42ae961147c4366400fd2cdb2a
parent8582373b324ca932f4e583aa5caf742123e629f0 (diff)
downloadcommon-88780476976e4194bbaa581a5713b69d8d963a1e.tar.gz
libhwc2.1: actively set lhbm desired refresh rate during lhbm period
- set lhbm desired refresh rate at enabling lhbm and restore SF desired one at disabling if needed. - always notify SF with it's desired Vsync if SF's refresh rate != lhbm's Bug: 250979028 Test: udfps auth with SmoothDisplay=on/off, check perfetto trace Signed-off-by: Shiyong Li <shiyongli@google.com> Change-Id: If011dbf12c1f979a50988cc375e74c7f53617d68
-rw-r--r--libhwc2.1/ExynosHWCDebug.h7
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.cpp24
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.h11
-rw-r--r--libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp29
-rw-r--r--libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp126
-rw-r--r--libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h10
6 files changed, 151 insertions, 56 deletions
diff --git a/libhwc2.1/ExynosHWCDebug.h b/libhwc2.1/ExynosHWCDebug.h
index 25178d1..37d96fd 100644
--- a/libhwc2.1/ExynosHWCDebug.h
+++ b/libhwc2.1/ExynosHWCDebug.h
@@ -114,6 +114,13 @@ int32_t saveFenceTrace(ExynosDisplay *display);
saveErrorLog(saveString, this); \
}
+#define DISPLAY_DRM_LOGI(msg, ...) \
+ ALOGI("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__)
+#define DISPLAY_DRM_LOGW(msg, ...) \
+ ALOGW("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__)
+#define DISPLAY_DRM_LOGE(msg, ...) \
+ ALOGE("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__)
+
#define MPP_LOGV(msg, ...) ALOGV("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
#define MPP_LOGI(msg, ...) ALOGI("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
#define MPP_LOGW(msg, ...) ALOGW("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp
index 7d23696..a29927d 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.cpp
+++ b/libhwc2.1/libdevice/ExynosDisplay.cpp
@@ -4086,6 +4086,12 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config,
if (isBadConfig(config)) return HWC2_ERROR_BAD_CONFIG;
+ if (!isConfigSettingEnabled()) {
+ mPendingConfig = config;
+ DISPLAY_LOGI("%s: config setting disabled, set pending config=%d", __func__, config);
+ return HWC2_ERROR_NONE;
+ }
+
if (mDisplayConfigs[mActiveConfig].groupId != mDisplayConfigs[config].groupId) {
if (vsyncPeriodChangeConstraints->seamlessRequired) {
DISPLAY_LOGD(eDebugDisplayConfig, "Case : Seamless is not allowed");
@@ -6285,6 +6291,11 @@ void ExynosDisplay::updateRefreshRateIndicator() {
mRefreshRateIndicatorHandler->handleSysfsEvent();
}
+uint32_t ExynosDisplay::getPeakRefreshRate() {
+ float opRate = mOperationRateManager ? mOperationRateManager->getOperationRate() : 0;
+ return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate));
+}
+
VsyncPeriodNanos ExynosDisplay::getVsyncPeriod(const int32_t config) {
const auto &it = mDisplayConfigs.find(config);
if (it == mDisplayConfigs.end()) return 0;
@@ -6297,3 +6308,16 @@ uint32_t ExynosDisplay::getRefreshRate(const int32_t config) {
constexpr float nsecsPerSec = std::chrono::nanoseconds(1s).count();
return round(nsecsPerSec / period * 0.1f) * 10;
}
+
+uint32_t ExynosDisplay::getConfigId(const int32_t refreshRate, const int32_t width,
+ const int32_t height) {
+ for (auto entry : mDisplayConfigs) {
+ auto config = entry.first;
+ auto displayCfg = entry.second;
+ if (getRefreshRate(config) == refreshRate && displayCfg.width == width &&
+ displayCfg.height == height) {
+ return config;
+ }
+ }
+ return UINT_MAX;
+}
diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h
index 41c6a93..8a12393 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.h
+++ b/libhwc2.1/libdevice/ExynosDisplay.h
@@ -562,6 +562,8 @@ class ExynosDisplay {
hwc2_config_t mDesiredConfig;
hwc2_config_t mActiveConfig = UINT_MAX;
+ hwc2_config_t mPendingConfig = UINT_MAX;
+ int64_t mLastVsyncTimestamp = 0;
void initDisplay();
@@ -1282,16 +1284,17 @@ class ExynosDisplay {
virtual void updateAppliedActiveConfig(const hwc2_config_t /*newConfig*/,
const int64_t /*ts*/) {}
+ virtual bool isConfigSettingEnabled() { return true; }
+ virtual void enableConfigSetting(bool /*en*/) {}
+
// is the hint session both enabled and supported
bool usePowerHintSession();
void setPeakRefreshRate(float rr) { mPeakRefreshRate = rr; }
- uint32_t getPeakRefreshRate() {
- float opRate = mOperationRateManager ? mOperationRateManager->getOperationRate() : 0;
- return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate));
- }
+ uint32_t getPeakRefreshRate();
VsyncPeriodNanos getVsyncPeriod(const int32_t config);
uint32_t getRefreshRate(const int32_t config);
+ uint32_t getConfigId(const int32_t refreshRate, const int32_t width, const int32_t height);
// check if there are any dimmed layers
bool isMixedComposition();
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
index 6a2be7d..375153b 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
@@ -747,6 +747,30 @@ void ExynosDisplayDrmInterface::Callback(
if (!mExynosDisplay->mPlugState || !mVsyncCallback.getVSyncEnabled()) {
return;
}
+
+ // Refresh rate during enabling LHBM might be different from the one SF expects.
+ // HWC just reports the SF expected Vsync to make UI smoothness consistent even if
+ // HWC runs at different refresh rate temporarily.
+ if (!mExynosDisplay->isConfigSettingEnabled()) {
+ int64_t pendingPeriodNs =
+ mExynosDisplay->getVsyncPeriod(mExynosDisplay->mPendingConfig);
+ int64_t activePeriodNs = mExynosDisplay->getVsyncPeriod(mExynosDisplay->mActiveConfig);
+ if (pendingPeriodNs && mExynosDisplay->mLastVsyncTimestamp) {
+ if (activePeriodNs > pendingPeriodNs) {
+ DISPLAY_DRM_LOGW("wrong vsync period: %" PRId64 "us (active), %" PRId64
+ "us (pending)",
+ activePeriodNs / 1000, pendingPeriodNs / 1000);
+ } else if (activePeriodNs != pendingPeriodNs) {
+ int64_t deltaNs = timestamp - mExynosDisplay->mLastVsyncTimestamp;
+ if (deltaNs < (pendingPeriodNs - ms2ns(2))) {
+ DISPLAY_DRM_LOGI("skip mismatching Vsync callback, delta=%" PRId64 "us",
+ deltaNs / 1000);
+ return;
+ }
+ }
+ }
+ }
+ mExynosDisplay->mLastVsyncTimestamp = timestamp;
}
ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
@@ -1152,6 +1176,7 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints(
if (mExynosDisplay->mOperationRateManager) {
mExynosDisplay->mOperationRateManager->onConfig(config);
}
+ DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
} else {
ALOGD("%s:: same desired mode %d", __func__, config);
}
@@ -1243,9 +1268,9 @@ int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config) {
mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC));
if (!setActiveDrmMode(*mode)) {
- ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config);
+ DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
} else {
- ALOGE("%s:: %s config(%d) failed", __func__, mExynosDisplay->mDisplayName.string(), config);
+ DISPLAY_DRM_LOGE("%s: config(%d) failed", __func__, config);
}
return 0;
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
index a6b5582..379fbdd 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
@@ -172,7 +172,7 @@ int ExynosPrimaryDisplay::getDDIScalerMode(int width, int height) {
int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
!isConfigSettingEnabled()) {
- mPendActiveConfig = config;
+ mPendingConfig = config;
mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config);
return NO_ERROR;
@@ -181,8 +181,8 @@ int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
}
int32_t ExynosPrimaryDisplay::getActiveConfigInternal(hwc2_config_t *outConfig) {
- if (outConfig && mPendActiveConfig != UINT_MAX) {
- *outConfig = mPendActiveConfig;
+ if (outConfig && mPendingConfig != UINT_MAX) {
+ *outConfig = mPendingConfig;
return HWC2_ERROR_NONE;
}
return ExynosDisplay::getActiveConfigInternal(outConfig);
@@ -198,18 +198,19 @@ int32_t ExynosPrimaryDisplay::setActiveConfigInternal(hwc2_config_t config, bool
}
if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
!isConfigSettingEnabled()) {
- mPendActiveConfig = config;
+ mPendingConfig = config;
return HWC2_ERROR_NONE;
}
return ExynosDisplay::setActiveConfigInternal(config, force);
}
int32_t ExynosPrimaryDisplay::applyPendingConfig() {
- hwc2_config_t config;
+ if (!isConfigSettingEnabled()) return HWC2_ERROR_NONE;
- if (mPendActiveConfig != UINT_MAX) {
- config = mPendActiveConfig;
- mPendActiveConfig = UINT_MAX;
+ hwc2_config_t config;
+ if (mPendingConfig != UINT_MAX) {
+ config = mPendingConfig;
+ mPendingConfig = UINT_MAX;
} else {
getActiveConfigInternal(&config);
}
@@ -530,7 +531,7 @@ bool ExynosPrimaryDisplay::isLhbmSupported() {
bool ExynosPrimaryDisplay::isConfigSettingEnabled() {
int64_t msSinceDisabled =
(systemTime(SYSTEM_TIME_MONOTONIC) - mConfigSettingDisabledTimestamp) / 1000000;
- return !mConfigSettingDisabled || msSinceDisabled > kLhbmMaxEnablingDurationMs;
+ return !mConfigSettingDisabled || msSinceDisabled > kConfigDisablingMaxDurationMs;
}
void ExynosPrimaryDisplay::enableConfigSetting(bool en) {
@@ -541,13 +542,41 @@ void ExynosPrimaryDisplay::enableConfigSetting(bool en) {
}
mConfigSettingDisabled = false;
- if (mPendActiveConfig != UINT_MAX) {
- hwc2_config_t config = mPendActiveConfig;
- if (applyPendingConfig() != HWC2_ERROR_NONE) {
- DISPLAY_LOGW("%s: failed to set mPendActiveConfig=%d", __func__, config);
+}
+
+void ExynosPrimaryDisplay::setLhbmDisplayConfig(uint32_t refreshRate) {
+ auto config = getConfigId(refreshRate, mDisplayConfigs[mActiveConfig].width,
+ mDisplayConfigs[mActiveConfig].height);
+
+ if (config == UINT_MAX) {
+ DISPLAY_LOGE("%s: failed to get config for rate=%d", __func__, refreshRate);
+ return;
+ }
+ if (mPendingConfig == UINT_MAX) mPendingConfig = mActiveConfig;
+
+ if (ExynosDisplay::setActiveConfigInternal(config, true) == HWC2_ERROR_NONE) {
+ DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, config, refreshRate);
+ } else {
+ DISPLAY_LOGW("%s: failed to set config=%d rate=%d", __func__, config, refreshRate);
+ }
+}
+
+void ExynosPrimaryDisplay::restoreLhbmDisplayConfig() {
+ if (mPendingConfig == UINT_MAX) return;
+
+ hwc2_config_t pendingCfg = mPendingConfig;
+ if (mPendingConfig != mActiveConfig) {
+ if (applyPendingConfig() == HWC2_ERROR_NONE) {
+ DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, pendingCfg,
+ getRefreshRate(pendingCfg));
} else {
- DISPLAY_LOGI("%s: succeed to set mPendActiveConfig=%d", __func__, config);
+ DISPLAY_LOGE("%s: failed to set config=%d rate=%d", __func__, pendingCfg,
+ getRefreshRate(pendingCfg));
}
+ } else {
+ mPendingConfig = UINT_MAX;
+ DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, pendingCfg,
+ getRefreshRate(pendingCfg));
}
}
@@ -594,19 +623,24 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
std::vector<std::string> checkingValue;
if (!enabled) {
ATRACE_NAME("disable_lhbm");
- checkingValue = {
- std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
+ {
+ ATRACE_NAME("apply_pending_rate");
+ Mutex::Autolock lock(mDisplayMutex);
+ enableConfigSetting(true);
+ restoreLhbmDisplayConfig();
+ }
requestLhbm(false);
- ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
- ms2ns(kSysfsCheckTimeoutMs));
- if (ret != OK) {
- DISPLAY_LOGW("%s: failed to send lhbm-off cmd", __func__);
- } else if (mDisplayInterface->waitVBlank()) {
- DISPLAY_LOGE("%s: failed to wait vblank of making lhbm-off cmd effective", __func__);
+ {
+ ATRACE_NAME("wait_for_lhbm_off_cmd");
+ checkingValue = {
+ std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
+ ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
+ ms2ns(kSysfsCheckTimeoutMs));
+ if (ret != OK) {
+ DISPLAY_LOGW("%s: failed to send lhbm-off cmd", __func__);
+ }
}
setLHBMRefreshRateThrottle(0);
- Mutex::Autolock lock(mDisplayMutex);
- enableConfigSetting(true);
mLhbmOn = false;
return NO_ERROR;
}
@@ -617,21 +651,23 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
uint32_t peakRate;
auto rrSysfs = mBrightnessController->GetPanelRefreshRateSysfile();
lhbmWaitForRrNanos = systemTime(SYSTEM_TIME_MONOTONIC);
- hwc2_config_t curConfig;
{
Mutex::Autolock lock(mDisplayMutex);
peakRate = getPeakRefreshRate();
- getActiveConfigInternal(&curConfig);
- if (curConfig == peakRate) {
- enableConfigSetting(false);
+ if (peakRate < 60) {
+ DISPLAY_LOGE("%s: invalid peak rate=%d", __func__, peakRate);
+ return -EINVAL;
}
+ if (getRefreshRate(mActiveConfig) != peakRate) {
+ ATRACE_NAME("request_peak_rate");
+ setLhbmDisplayConfig(peakRate);
+ }
+ enableConfigSetting(false);
}
if (mBrightnessController->fileExists(rrSysfs)) {
- ATRACE_NAME("wait_for_peak_rate_sent");
- if (peakRate) {
- ret = mBrightnessController->checkSysfsStatus(rrSysfs, {std::to_string(peakRate)},
- ms2ns(kLhbmWaitForPeakRefreshRateMs));
- }
+ ATRACE_NAME("wait_for_peak_rate_cmd");
+ ret = mBrightnessController->checkSysfsStatus(rrSysfs, {std::to_string(peakRate)},
+ ms2ns(kLhbmWaitForPeakRefreshRateMs));
if (ret != OK) {
DISPLAY_LOGW("%s: failed to poll peak refresh rate=%d, ret=%d", __func__, peakRate,
ret);
@@ -650,24 +686,21 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
}
}
}
- {
- Mutex::Autolock lock(mDisplayMutex);
- if (isConfigSettingEnabled()) {
- enableConfigSetting(false);
- }
- }
setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
- requestLhbm(enabled);
- ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
- ms2ns(kSysfsCheckTimeoutMs));
- if (ret != OK) {
- DISPLAY_LOGE("%s: failed to enable lhbm", __func__);
- setLHBMRefreshRateThrottle(0);
- goto enable_err;
+ requestLhbm(true);
+ {
+ ATRACE_NAME("wait_for_lhbm_on_cmd");
+ ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
+ ms2ns(kSysfsCheckTimeoutMs));
+ if (ret != OK) {
+ DISPLAY_LOGE("%s: failed to enable lhbm", __func__);
+ setLHBMRefreshRateThrottle(0);
+ goto enable_err;
+ }
}
lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -710,6 +743,7 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
enable_err:
Mutex::Autolock lock(mDisplayMutex);
enableConfigSetting(true);
+ restoreLhbmDisplayConfig();
return ret;
}
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
index e111907..796f6ef 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
@@ -64,6 +64,8 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
virtual int32_t setBootDisplayConfig(int32_t config) override;
virtual int32_t clearBootDisplayConfig() override;
virtual int32_t getPreferredDisplayConfigInternal(int32_t* outConfig) override;
+ virtual bool isConfigSettingEnabled() override;
+ virtual void enableConfigSetting(bool en) override;
protected:
/* setPowerMode(int32_t mode)
@@ -87,7 +89,6 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
// Prepare multi resolution
ResolutionInfo mResolutionInfo;
std::string getPanelSysfsPath(const displaycolor::DisplayType& type);
- bool isConfigSettingEnabled();
uint32_t mRcdId = -1;
@@ -99,7 +100,6 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
bool checkLhbmMode(bool status, nsecs_t timoutNs);
void setLHBMRefreshRateThrottle(const uint32_t delayMs);
- hwc2_config_t mPendActiveConfig = UINT_MAX;
bool mFirstPowerOn = true;
bool mNotifyPowerOn = false;
std::mutex mPowerModeMutex;
@@ -116,6 +116,8 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
int32_t setDisplayIdleDelayNanos(int32_t delayNanos,
const DispIdleTimerRequester requester);
void initDisplayHandleIdleExit();
+ void setLhbmDisplayConfig(uint32_t refreshRate);
+ void restoreLhbmDisplayConfig();
// LHBM
FILE* mLhbmFd;
@@ -126,9 +128,9 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
// timeout value of waiting for peak refresh rate
static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 100U;
static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000U;
- static constexpr uint32_t kLhbmMaxEnablingDurationMs = 1000U;
+ static constexpr uint32_t kConfigDisablingMaxDurationMs = 1000U;
static constexpr uint32_t kSysfsCheckTimeoutMs = 500U;
- void enableConfigSetting(bool en);
+
int32_t getTimestampDeltaMs(int64_t endNs, int64_t beginNs) {
if (endNs == 0) endNs = systemTime(SYSTEM_TIME_MONOTONIC);
return (endNs - beginNs) / 1000000;