diff options
author | Shiyong Li <shiyongli@google.com> | 2023-02-13 22:04:19 +0000 |
---|---|---|
committer | Shiyong Li <shiyongli@google.com> | 2023-03-01 00:52:40 +0000 |
commit | 95751650af91965ed09da35e4e3d040356399879 (patch) | |
tree | eb9695389a035cbb4d57d28445fffa24285075a9 | |
parent | d67728ca3e22c8a7270c5f13bbfe84d9f142890a (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.h | 4 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDisplay.h | 4 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp | 10 | ||||
-rw-r--r-- | libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp | 197 | ||||
-rw-r--r-- | libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h | 14 |
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 = |