summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShiyong Li <shiyongli@google.com>2023-02-13 22:04:19 +0000
committerShiyong Li <shiyongli@google.com>2023-03-01 00:52:40 +0000
commit95751650af91965ed09da35e4e3d040356399879 (patch)
treeeb9695389a035cbb4d57d28445fffa24285075a9
parentd67728ca3e22c8a7270c5f13bbfe84d9f142890a (diff)
libhwc2.1: keep refresh rate unchangeable if LHBM is enabled
- block refresh rate switching before enabling LHBM and unblock after disabling. - set 1 second timeout to unblock in case disabling action is not called on time somehow. Bug: 268991972 Test: lock/unlock screen by fingerprint Change-Id: I5703d89ca8482a3ff7b70795705ac01fd3c2b8d2 Signed-off-by: Shiyong Li <shiyongli@google.com>
-rw-r--r--libhwc2.1/libdevice/BrightnessController.h4
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.h4
-rw-r--r--libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp10
-rw-r--r--libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp197
-rw-r--r--libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h14
5 files changed, 154 insertions, 75 deletions
diff --git a/libhwc2.1/libdevice/BrightnessController.h b/libhwc2.1/libdevice/BrightnessController.h
index 30cd899..66f4b23 100644
--- a/libhwc2.1/libdevice/BrightnessController.h
+++ b/libhwc2.1/libdevice/BrightnessController.h
@@ -116,6 +116,10 @@ public:
}
int checkSysfsStatus(const std::string& file, const std::vector<std::string>& expectedValue,
const nsecs_t timeoutNs);
+ bool fileExists(const std::string& file) {
+ struct stat sb;
+ return stat(file.c_str(), &sb) == 0;
+ }
void resetLhbmState();
uint32_t getBrightnessLevel() {
diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h
index 4318947..2b876c0 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.h
+++ b/libhwc2.1/libdevice/ExynosDisplay.h
@@ -1277,9 +1277,9 @@ class ExynosDisplay {
bool usePowerHintSession();
void setPeakRefreshRate(float rr) { mPeakRefreshRate = rr; }
- float getPeakRefreshRate() {
+ uint32_t getPeakRefreshRate() {
float opRate = mOperationRateManager ? mOperationRateManager->getOperationRate() : 0;
- return opRate ?: mPeakRefreshRate;
+ return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate));
}
// check if there are any dimmed layers
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
index ea9a07e..3746a46 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
@@ -1112,9 +1112,6 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints(
ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.string(), config,
test);
- if (mExynosDisplay->mOperationRateManager) {
- mExynosDisplay->mOperationRateManager->onConfig(config);
- }
auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(),
[config](DrmMode const &m) { return m.id() == config;});
if (mode == mDrmConnector->modes().end()) {
@@ -1151,6 +1148,9 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints(
if (!test) {
if (modeBlob) { /* only replace desired mode if it has changed */
mDesiredModeState.setMode(*mode, modeBlob, drmReq);
+ if (mExynosDisplay->mOperationRateManager) {
+ mExynosDisplay->mOperationRateManager->onConfig(config);
+ }
} else {
ALOGD("%s:: same desired mode %d", __func__, config);
}
@@ -1236,6 +1236,10 @@ int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config) {
return HWC2_ERROR_BAD_CONFIG;
}
+ if (mExynosDisplay->mOperationRateManager) {
+ mExynosDisplay->mOperationRateManager->onConfig(config);
+ }
+
mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC));
if (!setActiveDrmMode(*mode)) {
ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config);
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
index 7078b83..a6b5582 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
@@ -170,7 +170,8 @@ int ExynosPrimaryDisplay::getDDIScalerMode(int width, int height) {
}
int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
- if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
+ if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
+ !isConfigSettingEnabled()) {
mPendActiveConfig = config;
mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config);
@@ -195,7 +196,8 @@ int32_t ExynosPrimaryDisplay::setActiveConfigInternal(hwc2_config_t config, bool
ALOGI("%s:: Same display config is set", __func__);
return HWC2_ERROR_NONE;
}
- if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
+ if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
+ !isConfigSettingEnabled()) {
mPendActiveConfig = config;
return HWC2_ERROR_NONE;
}
@@ -525,45 +527,53 @@ bool ExynosPrimaryDisplay::isLhbmSupported() {
return mBrightnessController->isLhbmSupported();
}
+bool ExynosPrimaryDisplay::isConfigSettingEnabled() {
+ int64_t msSinceDisabled =
+ (systemTime(SYSTEM_TIME_MONOTONIC) - mConfigSettingDisabledTimestamp) / 1000000;
+ return !mConfigSettingDisabled || msSinceDisabled > kLhbmMaxEnablingDurationMs;
+}
+
+void ExynosPrimaryDisplay::enableConfigSetting(bool en) {
+ if (!en) {
+ mConfigSettingDisabled = true;
+ mConfigSettingDisabledTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ return;
+ }
+
+ 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);
+ } else {
+ DISPLAY_LOGI("%s: succeed to set mPendActiveConfig=%d", __func__, config);
+ }
+ }
+}
+
// This function should be called by other threads (e.g. sensor HAL).
// HWCService can call this function but it should be for test purpose only.
int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
- int ret;
+ int ret = OK;
// NOTE: mLhbmOn could be set to false at any time by setPowerOff in another
// thread. Make sure no side effect if that happens. Or add lock if we have
// to when new code is added.
DISPLAY_ATRACE_CALL();
+ DISPLAY_LOGI("%s: enabled=%d", __func__, enabled);
{
- ATRACE_NAME("wait for power mode on");
+ ATRACE_NAME("wait_for_power_on");
std::unique_lock<std::mutex> lock(mPowerModeMutex);
if (mPowerModeState != HWC2_POWER_MODE_ON) {
mNotifyPowerOn = true;
if (!mPowerOnCondition.wait_for(lock, std::chrono::milliseconds(2000), [this]() {
return (mPowerModeState == HWC2_POWER_MODE_ON);
})) {
- ALOGW("%s(%d) wait for power mode on timeout !", __func__, enabled);
+ DISPLAY_LOGW("%s: wait for power mode on timeout !", __func__);
return TIMED_OUT;
}
}
}
- float peak_rr = getPeakRefreshRate();
- if (enabled && peak_rr > 0) {
- ATRACE_NAME("wait for peak rr sent");
- auto rrSysfs = mBrightnessController->GetPanelRefreshRateSysfile();
- ret = mBrightnessController->checkSysfsStatus(rrSysfs,
- {std::to_string(std::lround(peak_rr))},
- ms2ns(kLhbmWaitForPeakRefreshRateMs));
- if (ret != OK) {
- ALOGE("%s: check refresh rate sysfs node failed", __func__);
- return -EINVAL;
- }
- }
-
- if (enabled) {
- setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
- }
-
auto lhbmSysfs = mBrightnessController->GetPanelSysfileByIndex(
BrightnessController::kLocalHbmModeFileNode);
ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
@@ -572,84 +582,135 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
0);
bool wasDisabled = ret == OK;
if (!enabled && wasDisabled) {
- ALOGW("lhbm is at DISABLED state, skip disabling");
+ DISPLAY_LOGW("%s: lhbm is at DISABLED state, skip disabling", __func__);
return NO_ERROR;
} else if (enabled && !wasDisabled) {
requestLhbm(true);
- ALOGI("lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer");
+ DISPLAY_LOGI("%s: lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer",
+ __func__);
return NO_ERROR;
}
- int64_t lhbmEnablingNanos;
- std::vector<std::string> checkingValue = {
- std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
- if (enabled) {
- checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
- std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
- lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+ std::vector<std::string> checkingValue;
+ if (!enabled) {
+ ATRACE_NAME("disable_lhbm");
+ checkingValue = {
+ std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
+ 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__);
+ }
+ setLHBMRefreshRateThrottle(0);
+ Mutex::Autolock lock(mDisplayMutex);
+ enableConfigSetting(true);
+ mLhbmOn = false;
+ return NO_ERROR;
}
+
+ ATRACE_NAME("enable_lhbm");
+ int64_t lhbmWaitForRrNanos, lhbmEnablingNanos, lhbmEnablingDoneNanos;
+ bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
+ 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 (mBrightnessController->fileExists(rrSysfs)) {
+ ATRACE_NAME("wait_for_peak_rate_sent");
+ if (peakRate) {
+ 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);
+ }
+ } else {
+ ATRACE_NAME("wait_for_peak_rate_blindly");
+ DISPLAY_LOGW("%s: missing refresh rate path: %s", __func__, rrSysfs.c_str());
+ // blindly wait for (3 full frames + 1 frame uncertainty) to ensure DM finishes
+ // switching refresh rate
+ for (int32_t i = 0; i < 4; i++) {
+ if (mDisplayInterface->waitVBlank()) {
+ DISPLAY_LOGE("%s: failed to blindly wait for peak refresh rate=%d, i=%d", __func__,
+ peakRate, i);
+ ret = -ENODEV;
+ goto enable_err;
+ }
+ }
+ }
+ {
+ 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);
- constexpr uint32_t kSysfsCheckTimeoutMs = 500;
- ALOGI("setLhbmState =%d", enabled);
ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
ms2ns(kSysfsCheckTimeoutMs));
if (ret != OK) {
- ALOGE("failed to update lhbm mode");
- if (enabled) {
- setLHBMRefreshRateThrottle(0);
- }
- return -ENODEV;
+ DISPLAY_LOGE("%s: failed to enable lhbm", __func__);
+ setLHBMRefreshRateThrottle(0);
+ goto enable_err;
}
- if (enabled) {
- int64_t lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
- bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
+ lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+ {
+ ATRACE_NAME("wait_for_peak_brightness");
if (enablingStateSupported) {
- ATRACE_NAME("lhbm_wait_peak_brightness");
ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
{std::to_string(static_cast<int>(
BrightnessController::LhbmMode::ENABLED))},
ms2ns(kSysfsCheckTimeoutMs));
if (ret != OK) {
- ALOGE("failed to wait for lhbm becoming effective");
- return -EIO;
+ DISPLAY_LOGE("%s: failed to wait for lhbm becoming effective", __func__);
+ goto enable_err;
}
} else {
// lhbm takes effect at next vblank
- ATRACE_NAME("lhbm_wait_apply");
- if (mDisplayInterface->waitVBlank()) {
- ALOGE("%s failed to wait vblank for taking effect", __func__);
- return -ENODEV;
- }
- ATRACE_NAME("lhbm_wait_peak_brightness");
- for (int32_t i = mFramesToReachLhbmPeakBrightness; i > 0; i--) {
- if (mDisplayInterface->waitVBlank()) {
- ALOGE("%s failed to wait vblank for peak brightness, %d", __func__, i);
- return -ENODEV;
+ for (int32_t i = mFramesToReachLhbmPeakBrightness + 1; i > 0; i--) {
+ ret = mDisplayInterface->waitVBlank();
+ if (ret) {
+ DISPLAY_LOGE("%s: failed to wait vblank for peak brightness, %d", __func__, i);
+ goto enable_err;
}
}
}
- ALOGI("lhbm delay mode: %s, latency(ms): total: %d cmd: %d\n",
- enablingStateSupported ? "poll" : "fixed",
- static_cast<int>((systemTime(SYSTEM_TIME_MONOTONIC) - lhbmEnablingNanos) / 1000000),
- static_cast<int>((lhbmEnablingDoneNanos - lhbmEnablingNanos) / 1000000));
- } else {
- setLHBMRefreshRateThrottle(0);
- // lhbm takes effect at next vblank
- ATRACE_NAME("lhbm_wait_apply");
- if (mDisplayInterface->waitVBlank()) {
- ALOGE("%s failed to wait vblank for taking effect", __func__);
- return -ENODEV;
- }
}
+ DISPLAY_LOGI("%s: latency: %04d = %03d|rr@%03d + %03d|en + %03d|boost@%s", __func__,
+ getTimestampDeltaMs(0, lhbmWaitForRrNanos),
+ getTimestampDeltaMs(lhbmEnablingNanos, lhbmWaitForRrNanos), peakRate,
+ getTimestampDeltaMs(lhbmEnablingDoneNanos, lhbmEnablingNanos),
+ getTimestampDeltaMs(0, lhbmEnablingDoneNanos),
+ enablingStateSupported ? "polling" : "fixed");
- mLhbmOn = enabled;
+ mLhbmOn = true;
if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn)) {
mLhbmOn = false;
- ALOGE("%s power off during request lhbm on", __func__);
+ DISPLAY_LOGE("%s: power off during request lhbm on", __func__);
return -EINVAL;
}
return NO_ERROR;
+enable_err:
+ Mutex::Autolock lock(mDisplayMutex);
+ enableConfigSetting(true);
+ return ret;
}
bool ExynosPrimaryDisplay::getLhbmState() {
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
index 7603690..e111907 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
@@ -87,6 +87,7 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
// Prepare multi resolution
ResolutionInfo mResolutionInfo;
std::string getPanelSysfsPath(const displaycolor::DisplayType& type);
+ bool isConfigSettingEnabled();
uint32_t mRcdId = -1;
@@ -120,9 +121,18 @@ class ExynosPrimaryDisplay : public ExynosDisplay {
FILE* mLhbmFd;
std::atomic<bool> mLhbmOn;
int32_t mFramesToReachLhbmPeakBrightness;
+ bool mConfigSettingDisabled = false;
+ int64_t mConfigSettingDisabledTimestamp = 0;
// timeout value of waiting for peak refresh rate
- static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 200;
- static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000;
+ static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 100U;
+ static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000U;
+ static constexpr uint32_t kLhbmMaxEnablingDurationMs = 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;
+ }
FILE* mEarlyWakeupDispFd;
static constexpr const char* kWakeupDispFilePath =