diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-14 07:06:04 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-14 07:06:04 +0000 |
commit | bfe32204bab9bb9155a8d664841da7955b834315 (patch) | |
tree | dc74442534bbbee9f73a499b5e580fd4ec575842 | |
parent | 34e98cc0d62920fbbe969c315a21acf1f34aad11 (diff) | |
parent | 07ea90a5c3cf941e4e0db6a2086fe48d7e362b6f (diff) | |
download | common-main-cg-testing-release.tar.gz |
Snap for 8294919 from 07ea90a5c3cf941e4e0db6a2086fe48d7e362b6f to main-cg-testing-releasemain-cg-testing-release
Change-Id: I8b08f23686921b70c77cfa28602e1124d580f877
29 files changed, 840 insertions, 145 deletions
@@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ifneq ($(filter gs101,$(TARGET_BOARD_PLATFORM)),) +ifeq (google,$(TARGET_SOC_NAME)) build_dirs := \ libhwjpeg \ libscaler \ diff --git a/include/displaycolor/displaycolor.h b/include/displaycolor/displaycolor.h index ef1ba4e..b82ff43 100644 --- a/include/displaycolor/displaycolor.h +++ b/include/displaycolor/displaycolor.h @@ -30,6 +30,36 @@ using android::hardware::graphics::common::V1_2::ColorMode; using android::hardware::graphics::common::V1_2::Dataspace; } // namespace hwc +/** + * hwc/displaycolor interface history + * + * 3.0.0.2021-11-18 calibration info intf + * 2.0.0.2021-08-27 pass brightness table for hdr10+ + * 1.0.0.2021-08-25 Initial release + */ + +constexpr struct DisplayColorIntfVer { + uint16_t major; // increase it for new functionalities + uint16_t minor; // for bug fix and cause binary incompatible + uint16_t patch; // for bug fix and binary compatible + + bool operator==(const DisplayColorIntfVer &rhs) const { + return major == rhs.major && + minor == rhs.minor && + patch == rhs.patch; + } + + bool Compatible(const DisplayColorIntfVer &rhs) const { + return major == rhs.major && + minor == rhs.minor; + } + +} kInterfaceVersion { + 3, + 0, + 0, +}; + /// A map associating supported RenderIntents for each supported ColorMode using ColorModesMap = std::map<hwc::ColorMode, std::vector<hwc::RenderIntent>>; @@ -52,6 +82,25 @@ enum BrightnessMode { BM_MAX = 2, }; +struct DisplayBrightnessTable { + float nbm_nits_min; + float nbm_nits_max; + float hbm_nits_min; + float hbm_nits_max; + + uint32_t nbm_dbv_min; + uint32_t nbm_dbv_max; + uint32_t hbm_dbv_min; + uint32_t hbm_dbv_max; +}; + +struct DisplayInfo { + std::string panel_name; + std::string panel_serial; + + DisplayBrightnessTable brightness_table; +}; + struct LayerColorData { bool operator==(const LayerColorData &rhs) const { return dataspace == rhs.dataspace && matrix == rhs.matrix && @@ -219,6 +268,13 @@ struct DisplayScene { bool hdr_full_screen; }; +struct CalibrationInfo { + bool factory_cal_loaded; + bool golden_cal_loaded; + bool common_cal_loaded; + bool dev_cal_loaded; +}; + /// An interface specifying functions that are HW-agnostic. class IDisplayColorGeneric { public: @@ -282,6 +338,13 @@ class IDisplayColorGeneric { virtual bool IsRrCompensationEnabled(DisplayType display) = 0; /** + * @brief Get calibration information for each profiles. + * @param display The display to get the calibration information. + */ + virtual const CalibrationInfo &GetCalibrationInfo( + DisplayType display) const = 0; + + /** * @brief Get a map of supported ColorModes, and supported RenderIntents for * each ColorMode. * @param display The display to get the color modes and render intents. @@ -290,6 +353,10 @@ class IDisplayColorGeneric { DisplayType display) const = 0; }; +extern "C" { + const DisplayColorIntfVer *GetInterfaceVersion(); +} + } // namespace displaycolor #endif // DISPLAYCOLOR_H_ diff --git a/libhwc2.1/Android.mk b/libhwc2.1/Android.mk index 3b87ecf..a6d4078 100644 --- a/libhwc2.1/Android.mk +++ b/libhwc2.1/Android.mk @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# TODO(b/186905324): Switch soc_ver with TARGET_BOARD_PLATFORM +soc_ver := $(TARGET_BOARD_PLATFORM) + LOCAL_PATH:= $(call my-dir) # HAL module implemenation, not prelinked and stored in # hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.product.board>.so @@ -40,6 +43,7 @@ LOCAL_SRC_FILES := \ LOCAL_CFLAGS := -DHLOG_CODE=0 LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libdrm LOCAL_MODULE := libdrmresource @@ -63,7 +67,7 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware \ libvendorgraphicbuffer libbinder_ndk \ android.hardware.power-V1-ndk pixel-power-ext-V1-ndk -LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V3-ndk \ +LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V4-ndk \ libbinder_ndk \ libbase \ libpng \ @@ -85,14 +89,14 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libvirtualdisplay \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwchelper \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1 \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libmaindisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libexternaldisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libvirtualdisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libdevice \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libdisplayinterface \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1 \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdisplayinterface \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdisplayinterface \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdrmresource/include @@ -118,11 +122,12 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS += libacryl libdrm libui libvendorgraphicbuf LOCAL_VINTF_FRAGMENTS += pixel-display-default.xml -include $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/Android.mk +include $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/Android.mk LOCAL_CFLAGS += -DHLOG_CODE=0 LOCAL_CFLAGS += -DLOG_TAG=\"display\" LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) LOCAL_MODULE := libexynosdisplay LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 @@ -146,7 +151,7 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libbinder libexynosdisplay l android.hardware.graphics.allocator@2.0 \ android.hardware.graphics.mapper@2.0 -LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V3-ndk \ +LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V4-ndk \ libbinder_ndk \ libbase @@ -161,13 +166,13 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libvirtualdisplay \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwchelper \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1 \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libmaindisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libexternaldisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libvirtualdisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libdevice \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1 \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdisplayinterface \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdrmresource/include @@ -177,6 +182,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) LOCAL_CFLAGS := -DHLOG_CODE=0 LOCAL_CFLAGS += -DLOG_TAG=\"hwcservice\" +LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) LOCAL_SRC_FILES := \ libhwcService/IExynosHWC.cpp \ @@ -205,7 +211,7 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libexynosdisplay libacryl \ android.hardware.graphics.mapper@2.0 \ libui -LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V3-ndk \ +LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V4-ndk \ libbinder_ndk \ libbase @@ -215,6 +221,7 @@ LOCAL_HEADER_LIBRARIES += libgralloc_headers LOCAL_CFLAGS := -DHLOG_CODE=0 LOCAL_CFLAGS += -DLOG_TAG=\"hwcomposer\" +LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) ifeq ($(BOARD_USES_HWC_SERVICES),true) LOCAL_CFLAGS += -DUSES_HWC_SERVICES @@ -230,13 +237,14 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libvirtualdisplay \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwchelper \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1 \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libmaindisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libexternaldisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libvirtualdisplay \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libdevice \ - $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1 \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/include \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdisplayinterface diff --git a/libhwc2.1/ExynosHWC.cpp b/libhwc2.1/ExynosHWC.cpp index 0a8b412..8b3d9a4 100644 --- a/libhwc2.1/ExynosHWC.cpp +++ b/libhwc2.1/ExynosHWC.cpp @@ -32,6 +32,7 @@ class ExynosHWCService; using namespace android; +using namespace SOC_VERSION; uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { uint32_t hwcVersion = hwc->common.version; diff --git a/libhwc2.1/libdevice/ExynosDevice.cpp b/libhwc2.1/libdevice/ExynosDevice.cpp index b32e250..a2308f6 100644 --- a/libhwc2.1/libdevice/ExynosDevice.cpp +++ b/libhwc2.1/libdevice/ExynosDevice.cpp @@ -30,6 +30,7 @@ #include "VendorGraphicBuffer.h" using namespace vendor::graphics; +using namespace SOC_VERSION; /** * ExynosDevice implementation @@ -440,6 +441,11 @@ int32_t ExynosDevice::registerCallback ( callbackFunc(callbackData, getDisplayId(it->mType, it->mIndex), HWC2_CONNECTION_CONNECTED); } + } else { + // unregistering callback can be used as a sign of ComposerClient's death + for (auto it : mDisplays) { + it->cleanupAfterClientDeath(); + } } } @@ -1006,6 +1012,11 @@ bool ExynosDevice::isLbeSupported() { return mLbeSupported; } +bool ExynosDevice::isColorCalibratedByDevice() { + ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + return display->isColorCalibratedByDevice(); +} + void ExynosDevice::setLbeState(LbeState state) { if (mLbeSupported) { ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); @@ -1048,3 +1059,27 @@ bool ExynosDevice::getLhbmState() { } return false; } + +int ExynosDevice::setMinIdleRefreshRate(const int fps) { + ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + if (display) { + return display->setMinIdleRefreshRate(fps); + } + return BAD_VALUE; +} + +int ExynosDevice::setRefreshRateThrottle(const int delayMs) { + if (delayMs < 0) { + ALOGE("%s fail: delayMs(%d) is less than 0", __func__, delayMs); + return BAD_VALUE; + } + + ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + if (display) { + return display->setRefreshRateThrottleNanos( + std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(delayMs)) + .count()); + } + return BAD_VALUE; +} diff --git a/libhwc2.1/libdevice/ExynosDevice.h b/libhwc2.1/libdevice/ExynosDevice.h index 51b7e30..5c4fd6a 100644 --- a/libhwc2.1/libdevice/ExynosDevice.h +++ b/libhwc2.1/libdevice/ExynosDevice.h @@ -332,6 +332,10 @@ class ExynosDevice { bool isLhbmSupported(); int32_t setLhbmState(bool enabled); bool getLhbmState(); + int setMinIdleRefreshRate(const int fps); + int setRefreshRateThrottle(const int delayMs); + + bool isColorCalibratedByDevice(); public: void enterToTUI() { mIsInTUI = true; }; diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp index 2eaa5d0..7aa6a47 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.cpp +++ b/libhwc2.1/libdevice/ExynosDisplay.cpp @@ -61,13 +61,27 @@ ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker() mPrevRefreshRate(0), mPendingPrevRefreshRate(0), mIdleHintIsEnabled(false), + mForceUpdateIdleHint(false), mIdleHintDeadlineTime(0), mIdleHintSupportIsChecked(false), mIdleHintIsSupported(false), mPowerModeState(HWC2_POWER_MODE_OFF), mVsyncPeriod(16666666), - mPowerHalExtAidl(nullptr) { - InitWorker(); + mPowerHalExtAidl(nullptr), + mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {} + +ExynosDisplay::PowerHalHintWorker::~PowerHalHintWorker() { + Exit(); +} + +int ExynosDisplay::PowerHalHintWorker::Init() { + return InitWorker(); +} + +void ExynosDisplay::PowerHalHintWorker::BinderDiedCallback(void *cookie) { + ALOGE("PowerHal is died"); + auto powerHint = reinterpret_cast<PowerHalHintWorker *>(cookie); + powerHint->forceUpdateHints(); } int32_t ExynosDisplay::PowerHalHintWorker::connectPowerHalExt() { @@ -78,6 +92,7 @@ int32_t ExynosDisplay::PowerHalHintWorker::connectPowerHalExt() { const std::string kInstance = std::string(IPower::descriptor) + "/default"; ndk::SpAIBinder pwBinder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str())); ndk::SpAIBinder pwExtBinder; + AIBinder_getExtension(pwBinder.get(), pwExtBinder.getR()); mPowerHalExtAidl = IPowerExt::fromBinder(pwExtBinder); if (!mPowerHalExtAidl) { @@ -85,6 +100,9 @@ int32_t ExynosDisplay::PowerHalHintWorker::connectPowerHalExt() { return -EINVAL; } + AIBinder_linkToDeath(pwExtBinder.get(), mDeathRecipient.get(), reinterpret_cast<void *>(this)); + + forceUpdateHints(); ALOGI("connect power HAL extension successfully"); return NO_ERROR; } @@ -140,6 +158,7 @@ int32_t ExynosDisplay::PowerHalHintWorker::sendPowerHalExtHint(const std::string } return -EINVAL; } + return NO_ERROR; } @@ -266,16 +285,17 @@ int32_t ExynosDisplay::PowerHalHintWorker::checkIdleHintSupport(void) { return ret; } -int32_t ExynosDisplay::PowerHalHintWorker::updateIdleHint(uint64_t deadlineTime) { +int32_t ExynosDisplay::PowerHalHintWorker::updateIdleHint(int64_t deadlineTime, bool forceUpdate) { int32_t ret = checkIdleHintSupport(); if (ret != NO_ERROR) { return ret; } - bool enableIdleHint = (deadlineTime < systemTime(SYSTEM_TIME_MONOTONIC)); + bool enableIdleHint = + (deadlineTime < systemTime(SYSTEM_TIME_MONOTONIC) && CC_LIKELY(deadlineTime > 0)); ATRACE_INT("HWCIdleHintTimer:", enableIdleHint); - if (mIdleHintIsEnabled != enableIdleHint) { + if (mIdleHintIsEnabled != enableIdleHint || forceUpdate) { ret = sendPowerHalExtHint("DISPLAY_IDLE", enableIdleHint); if (ret == NO_ERROR) { mIdleHintIsEnabled = enableIdleHint; @@ -284,6 +304,19 @@ int32_t ExynosDisplay::PowerHalHintWorker::updateIdleHint(uint64_t deadlineTime) return ret; } +void ExynosDisplay::PowerHalHintWorker::forceUpdateHints(void) { + Lock(); + mPrevRefreshRate = 0; + mNeedUpdateRefreshRateHint = true; + if (mIdleHintSupportIsChecked && mIdleHintIsSupported) { + mForceUpdateIdleHint = true; + } + + Unlock(); + + Signal(); +} + void ExynosDisplay::PowerHalHintWorker::signalRefreshRate(hwc2_power_mode_t powerMode, uint32_t vsyncPeriod) { Lock(); @@ -310,19 +343,28 @@ void ExynosDisplay::PowerHalHintWorker::signalIdle() { Signal(); } +bool ExynosDisplay::PowerHalHintWorker::needUpdateIdleHintLocked(int64_t &timeout) { + if (!mIdleHintIsSupported) { + return false; + } + + int64_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); + bool shouldEnableIdleHint = + (mIdleHintDeadlineTime < currentTime) && CC_LIKELY(mIdleHintDeadlineTime > 0); + if (mIdleHintIsEnabled != shouldEnableIdleHint || mForceUpdateIdleHint) { + return true; + } + + timeout = mIdleHintDeadlineTime - currentTime; + return false; +} + void ExynosDisplay::PowerHalHintWorker::Routine() { Lock(); int ret = 0; - if (!mNeedUpdateRefreshRateHint) { - if (!mIdleHintIsSupported || mIdleHintIsEnabled) { - ret = WaitForSignalOrExitLocked(); - } else { - uint64_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); - if (mIdleHintDeadlineTime > currentTime) { - uint64_t timeout = mIdleHintDeadlineTime - currentTime; - ret = WaitForSignalOrExitLocked(timeout); - } - } + int64_t timeout = -1; + if (!mNeedUpdateRefreshRateHint && !needUpdateIdleHintLocked(timeout)) { + ret = WaitForSignalOrExitLocked(timeout); } if (ret == -EINTR) { @@ -331,7 +373,7 @@ void ExynosDisplay::PowerHalHintWorker::Routine() { } bool needUpdateRefreshRateHint = mNeedUpdateRefreshRateHint; - uint64_t deadlineTime = mIdleHintDeadlineTime; + int64_t deadlineTime = mIdleHintDeadlineTime; hwc2_power_mode_t powerMode = mPowerModeState; uint32_t vsyncPeriod = mVsyncPeriod; @@ -343,9 +385,12 @@ void ExynosDisplay::PowerHalHintWorker::Routine() { * errors. */ mNeedUpdateRefreshRateHint = false; + + bool forceUpdateIdleHint = mForceUpdateIdleHint; + mForceUpdateIdleHint = false; Unlock(); - updateIdleHint(deadlineTime); + updateIdleHint(deadlineTime, forceUpdateIdleHint); if (needUpdateRefreshRateHint) { int32_t rc = updateRefreshRateHintInternal(powerMode, vsyncPeriod); @@ -655,6 +700,8 @@ ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device) mLowFpsLayerInfo.initializeInfos(); + mPowerHalHint.Init(); + mUseDpu = true; mBrightnessState.reset(); @@ -2923,6 +2970,11 @@ int32_t ExynosDisplay::canSkipValidate() { return SKIP_ERR_SKIP_STATIC_CHANGED; } + if (mClientCompositionInfo.mHasCompositionLayer && + mClientCompositionInfo.mTargetBuffer == NULL) { + return SKIP_ERR_INVALID_CLIENT_TARGET_BUFFER; + } + /* * If there is hwc2_layer_request_t * validateDisplay() can't be skipped @@ -3535,9 +3587,17 @@ int32_t ExynosDisplay::getConfigAppliedTime(const uint64_t desiredTime, { uint32_t transientDuration = mDisplayInterface->getConfigChangeDuration(); appliedTime = actualChangeTime; - while (desiredTime > appliedTime) { - DISPLAY_LOGD(eDebugDisplayConfig, "desired time(%" PRId64 ") > applied time(%" PRId64 ")", desiredTime, appliedTime);; - appliedTime += mVsyncPeriod; + + if (desiredTime > appliedTime) { + const int64_t originalAppliedTime = appliedTime; + const int64_t diff = desiredTime - appliedTime; + appliedTime += (diff + mVsyncPeriod - 1) / mVsyncPeriod * mVsyncPeriod; + DISPLAY_LOGD(eDebugDisplayConfig, + "desired time(%" PRId64 "), applied time(%" PRId64 "->%" PRId64 ")", + desiredTime, originalAppliedTime, appliedTime); + } else { + DISPLAY_LOGD(eDebugDisplayConfig, "desired time(%" PRId64 "), applied time(%" PRId64 ")", + desiredTime, appliedTime); } refreshTime = appliedTime - (transientDuration * mVsyncPeriod); @@ -3545,6 +3605,26 @@ int32_t ExynosDisplay::getConfigAppliedTime(const uint64_t desiredTime, return NO_ERROR; } +void ExynosDisplay::calculateTimeline( + hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline) { + int64_t actualChangeTime = 0; + /* actualChangeTime includes transient duration */ + mDisplayInterface->getVsyncAppliedTime(config, &actualChangeTime); + + outTimeline->refreshRequired = true; + getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime, + outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos); + + DISPLAY_LOGD(eDebugDisplayConfig, + "requested config : %d(%d)->%d(%d), " + "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "", + mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, + mDisplayConfigs[config].vsyncPeriod, + mVsyncPeriodChangeConstraints.desiredTimeNanos, + outTimeline->newVsyncAppliedTimeNanos); +} + int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints, hwc_vsync_period_change_timeline_t* outTimeline) @@ -3552,11 +3632,11 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, ATRACE_CALL(); Mutex::Autolock lock(mDisplayMutex); - DISPLAY_LOGD(eDebugDisplayConfig, "%s:: config(%d), seamless(%d), " - "desiredTime(%" PRId64, ")", - config, - vsyncPeriodChangeConstraints->seamlessRequired, - vsyncPeriodChangeConstraints->desiredTimeNanos); + DISPLAY_LOGD(eDebugDisplayConfig, + "config(%d), seamless(%d), " + "desiredTime(%" PRId64 ")", + config, vsyncPeriodChangeConstraints->seamlessRequired, + vsyncPeriodChangeConstraints->desiredTimeNanos); if (isBadConfig(config)) return HWC2_ERROR_BAD_CONFIG; @@ -3588,22 +3668,7 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, mVsyncPeriodChangeConstraints = *vsyncPeriodChangeConstraints; mDesiredConfig = config; - int64_t actualChangeTime = 0; - /* actualChangeTime includes transient duration */ - mDisplayInterface->getVsyncAppliedTime(config, &actualChangeTime); - - outTimeline->refreshRequired = true; - getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, - actualChangeTime, - outTimeline->newVsyncAppliedTimeNanos, - outTimeline->refreshTimeNanos); - - DISPLAY_LOGD(eDebugDisplayConfig, "requested config : %d(%d)->%d(%d), " - "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "", - mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, - config, mDisplayConfigs[config].vsyncPeriod, - mVsyncPeriodChangeConstraints.desiredTimeNanos, - outTimeline->newVsyncAppliedTimeNanos); + calculateTimeline(config, vsyncPeriodChangeConstraints, outTimeline); /* mActiveConfig should be changed immediately for internal status */ mActiveConfig = config; @@ -3696,9 +3761,23 @@ int32_t ExynosDisplay::updateInternalDisplayConfigVariables( return NO_ERROR; } -void ExynosDisplay::updateBtsVsyncPeriod(uint32_t vsync_period, bool forceUpdate) { - if (forceUpdate || vsync_period < mBtsVsyncPeriod) { - mBtsVsyncPeriod = vsync_period; +void ExynosDisplay::updateBtsVsyncPeriod(uint32_t vsyncPeriod, bool forceUpdate) { + if (vsyncPeriod < mBtsVsyncPeriod) { + mBtsVsyncPeriod = vsyncPeriod; + + if (mType == HWC_DISPLAY_PRIMARY) { + uint32_t btsRefreshRate = getBtsRefreshRate(); + + for (size_t i = 0; i < mLayers.size(); i++) { + if (!mLayers[i]->checkDownscaleCap(btsRefreshRate)) { + setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); + break; + } + } + } + } else if (forceUpdate) { + /* TODO: add check for resource can re-assign to Device */ + mBtsVsyncPeriod = vsyncPeriod; } } @@ -3716,8 +3795,8 @@ void ExynosDisplay::updateRefreshRateHint() { int32_t ExynosDisplay::resetConfigRequestStateLocked() { mVsyncPeriod = getDisplayVsyncPeriodFromConfig(mActiveConfig); updateBtsVsyncPeriod(mVsyncPeriod, true); - DISPLAY_LOGD(eDebugDisplayConfig,"Update mVsyncPeriod %d", - mVsyncPeriod); + DISPLAY_LOGD(eDebugDisplayConfig, "Update mVsyncPeriod %d by mActiveConfig(%d)", mVsyncPeriod, + mActiveConfig); updateRefreshRateHint(); @@ -3728,6 +3807,7 @@ int32_t ExynosDisplay::resetConfigRequestStateLocked() { DISPLAY_LOGD(eDebugDisplayInterfaceConfig, "%s: Change mConfigRequestState (%d) to NONE", __func__, mConfigRequestState); mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_NONE; + updateAppliedActiveConfig(mActiveConfig, systemTime(SYSTEM_TIME_MONOTONIC)); } return NO_ERROR; } @@ -3821,8 +3901,10 @@ int32_t ExynosDisplay::doDisplayConfigPostProcess(ExynosDevice *dev) if (actualChangeTime >= mVsyncPeriodChangeConstraints.desiredTimeNanos) { DISPLAY_LOGD(eDebugDisplayConfig, "Request setActiveConfig"); needSetActiveConfig = true; + ATRACE_INT("Pending ActiveConfig", 0); } else { DISPLAY_LOGD(eDebugDisplayConfig, "setActiveConfig still pending"); + ATRACE_INT("Pending ActiveConfig", mDesiredConfig); } if (needSetActiveConfig) { @@ -5338,3 +5420,12 @@ void ExynosDisplay::updateBrightnessState() { ALOGW("Failed to update brighntess"); } } + +void ExynosDisplay::cleanupAfterClientDeath() { + // Invalidate the client target buffer because it will be freed when the client dies + mClientCompositionInfo.mTargetBuffer = NULL; + // Invalidate the skip static flag so that we have to get a new target buffer first + // before we can skip the static layers + mClientCompositionInfo.mSkipStaticInitFlag = false; + mClientCompositionInfo.mSkipFlag = false; +} diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h index c892aab..90bbb76 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.h +++ b/libhwc2.1/libdevice/ExynosDisplay.h @@ -520,7 +520,7 @@ class ExynosDisplay { ExynosLowFpsLayerInfo mLowFpsLayerInfo; // HDR capabilities - std::vector<android_hdr_t> mHdrTypes; + std::vector<int32_t> mHdrTypes; float mMaxLuminance; float mMaxAverageLuminance; float mMinLuminance; @@ -726,7 +726,8 @@ class ExynosDisplay { SKIP_ERR_HAS_REQUEST, SKIP_ERR_DISP_NOT_CONNECTED, SKIP_ERR_DISP_NOT_POWER_ON, - SKIP_ERR_FORCE_VALIDATE + SKIP_ERR_FORCE_VALIDATE, + SKIP_ERR_INVALID_CLIENT_TARGET_BUFFER }; virtual int32_t canSkipValidate(); @@ -874,7 +875,7 @@ class ExynosDisplay { * HWC2_ERROR_BAD_PARAMETER when the brightness is invalid, or * HWC2_ERROR_NO_RESOURCES when the brightness cannot be applied. */ - int32_t setDisplayBrightness(float brightness); + virtual int32_t setDisplayBrightness(float brightness); /* getDisplayConnectionType(..., outType) * Descriptor: HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE @@ -1056,7 +1057,7 @@ class ExynosDisplay { int32_t getConfigAppliedTime(const uint64_t desiredTime, const uint64_t actualChangeTime, int64_t &appliedTime, int64_t &refreshTime); - void updateBtsVsyncPeriod(uint32_t vsync_period, bool forceUpdate = false); + void updateBtsVsyncPeriod(uint32_t vsyncPeriod, bool forceUpdate = false); uint32_t getBtsRefreshRate() const; /* TODO : TBD */ @@ -1070,7 +1071,7 @@ class ExynosDisplay { /* This function is called by ExynosDisplayInterface class to set acquire fence*/ int32_t setReadbackBufferAcqFence(int32_t acqFence); - void dump(String8& result); + virtual void dump(String8& result); virtual int32_t startPostProcessing(); @@ -1112,6 +1113,7 @@ class ExynosDisplay { virtual int32_t updateColorConversionInfo() { return NO_ERROR; }; virtual int32_t updatePresentColorConversionInfo() { return NO_ERROR; }; virtual bool checkRrCompensationEnabled() { return false; }; + virtual bool isColorCalibratedByDevice() { return false; }; virtual int32_t getColorAdjustedDbv(uint32_t &) { return NO_ERROR; } virtual int32_t SetCurrentPanelGammaSource(const displaycolor::DisplayType /* type */, const PanelGammaSource& /* source */) { @@ -1141,6 +1143,8 @@ class ExynosDisplay { } void requestEnhancedHbm(bool on) { mBrightnessState.enhanced_hbm = on; }; + void cleanupAfterClientDeath(); + protected: virtual bool getHDRException(ExynosLayer *layer); virtual int32_t getActiveConfigInternal(hwc2_config_t* outConfig); @@ -1169,18 +1173,19 @@ class ExynosDisplay { mDevice->invalidate(); } + virtual int setMinIdleRefreshRate(const int __unused fps) { return NO_ERROR; } + virtual int setRefreshRateThrottleNanos(const int64_t __unused delayNanos) { + return NO_ERROR; + } + + virtual void updateAppliedActiveConfig(const hwc2_config_t /*newConfig*/, + const int64_t /*ts*/) {} + private: bool skipStaticLayerChanged(ExynosCompositionInfo& compositionInfo); bool skipSignalIdleForVideoLayer(); - inline uint32_t getDisplayVsyncPeriodFromConfig(hwc2_config_t config) { - int32_t vsync_period; - getDisplayAttribute(config, HWC2_ATTRIBUTE_VSYNC_PERIOD, &vsync_period); - assert(vsync_period > 0); - return static_cast<uint32_t>(vsync_period); - } - /// minimum possible dim rate in the case hbm peak is 1000 nits and norml // display brightness is 2 nits static constexpr float kGhbmMinDimRatio = 0.002; @@ -1200,6 +1205,8 @@ class ExynosDisplay { class PowerHalHintWorker : public Worker { public: PowerHalHintWorker(); + virtual ~PowerHalHintWorker(); + int Init(); void signalRefreshRate(hwc2_power_mode_t powerMode, uint32_t vsyncPeriod); void signalIdle(); @@ -1208,6 +1215,7 @@ class ExynosDisplay { void Routine() override; private: + static void BinderDiedCallback(void*); int32_t connectPowerHalExt(); int32_t checkPowerHalExtHintSupport(const std::string& mode); int32_t sendPowerHalExtHint(const std::string& mode, bool enabled); @@ -1216,9 +1224,11 @@ class ExynosDisplay { int32_t updateRefreshRateHintInternal(hwc2_power_mode_t powerMode, uint32_t vsyncPeriod); int32_t sendRefreshRateHint(int refreshRate, bool enabled); + void forceUpdateHints(); int32_t checkIdleHintSupport(); - int32_t updateIdleHint(uint64_t deadlineTime); + int32_t updateIdleHint(int64_t deadlineTime, bool forceUpdate); + bool needUpdateIdleHintLocked(int64_t& timeout) REQUIRES(mutex_); bool mNeedUpdateRefreshRateHint; @@ -1232,7 +1242,8 @@ class ExynosDisplay { std::map<int, bool> mRefreshRateHintSupportMap; bool mIdleHintIsEnabled; - uint64_t mIdleHintDeadlineTime; + bool mForceUpdateIdleHint; + int64_t mIdleHintDeadlineTime; // whether idle hint support is checked bool mIdleHintSupportIsChecked; @@ -1246,9 +1257,23 @@ class ExynosDisplay { // for power HAL extension hints std::shared_ptr<aidl::google::hardware::power::extension::pixel::IPowerExt> mPowerHalExtAidl; + ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; }; PowerHalHintWorker mPowerHalHint; + + protected: + inline uint32_t getDisplayVsyncPeriodFromConfig(hwc2_config_t config) { + int32_t vsync_period; + getDisplayAttribute(config, HWC2_ATTRIBUTE_VSYNC_PERIOD, &vsync_period); + assert(vsync_period > 0); + return static_cast<uint32_t>(vsync_period); + } + + virtual void calculateTimeline( + hwc2_config_t config, + hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t* outTimeline); }; #endif //_EXYNOSDISPLAY_H diff --git a/libhwc2.1/libdevice/ExynosLayer.cpp b/libhwc2.1/libdevice/ExynosLayer.cpp index 826074b..8a86ef0 100644 --- a/libhwc2.1/libdevice/ExynosLayer.cpp +++ b/libhwc2.1/libdevice/ExynosLayer.cpp @@ -891,6 +891,28 @@ int32_t ExynosLayer::resetAssignedResource() return ret; } +bool ExynosLayer::checkDownscaleCap(uint32_t bts_refresh_rate) +{ + if (mOtfMPP == nullptr) return true; + + exynos_image src_img; + exynos_image dst_img; + + setSrcExynosImage(&src_img); + setDstExynosImage(&dst_img); + + const bool isPerpendicular = !!(src_img.transform & HAL_TRANSFORM_ROT_90); + const uint32_t srcWidth = isPerpendicular ? src_img.h : src_img.w; + const uint32_t srcHeight = isPerpendicular ? src_img.w : src_img.h; + const bool scaleDown = (srcWidth > dst_img.w || srcHeight > dst_img.h); + + if (!scaleDown) return true; + + const float resolution = float(src_img.w) * float(src_img.h) * bts_refresh_rate / 1000; + + return mOtfMPP->checkDownscaleCap(resolution, float(dst_img.h) / float(mDisplay->mYres)); +} + void ExynosLayer::setSrcAcquireFence() { if (mAcquireFence == -1 && mPrevAcquireFence != -1) { mAcquireFence = hwcCheckFenceDebug(mDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER, diff --git a/libhwc2.1/libdevice/ExynosLayer.h b/libhwc2.1/libdevice/ExynosLayer.h index 994d045..8ea71e1 100644 --- a/libhwc2.1/libdevice/ExynosLayer.h +++ b/libhwc2.1/libdevice/ExynosLayer.h @@ -421,6 +421,7 @@ class ExynosLayer : public ExynosMPPSource { int32_t setSrcExynosImage(exynos_image *src_img); int32_t setDstExynosImage(exynos_image *dst_img); int32_t resetAssignedResource(); + bool checkDownscaleCap(uint32_t btsRefreshRate); void setSrcAcquireFence(); diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp index 21b7f92..c844b72 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp @@ -63,6 +63,8 @@ static void set_dpp_ch_restriction(struct hwc_dpp_ch_restriction &hwc_dpp_restri hwc_dpp_restriction.restriction.scale_up = 1; } +using namespace SOC_VERSION; + ExynosDeviceDrmInterface::ExynosDeviceDrmInterface(ExynosDevice *exynosDevice) { mType = INTERFACE_TYPE_DRM; diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp index 997b3e1..a38fb2c 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp @@ -405,6 +405,11 @@ ExynosDisplayDrmInterface::~ExynosDisplayDrmInterface() mDrmDevice->DestroyPropertyBlob(mDesiredModeState.old_blob_id); if (mPartialRegionState.blob_id) mDrmDevice->DestroyPropertyBlob(mPartialRegionState.blob_id); + if (mHbmSvDimmingThreadRunning) { + mHbmSvDimmingThreadRunning = false; + mHbmSvDimmingCond.signal(); + mDimmingThread.join(); + } } void ExynosDisplayDrmInterface::init(ExynosDisplay *exynosDisplay) @@ -642,24 +647,21 @@ void ExynosDisplayDrmInterface::Callback( } ExynosDevice *exynosDevice = mExynosDisplay->mDevice; - exynosDevice->compareVsyncPeriod(); - if (exynosDevice->mVsyncDisplayId == mExynosDisplay->mDisplayId) { - auto vsync_2_4CallbackInfo = - exynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4]; - if (vsync_2_4CallbackInfo.funcPointer && vsync_2_4CallbackInfo.callbackData) { - ((HWC2_PFN_VSYNC_2_4)vsync_2_4CallbackInfo.funcPointer)( - vsync_2_4CallbackInfo.callbackData, - mExynosDisplay->mDisplayId, - timestamp, mExynosDisplay->mVsyncPeriod); - ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod)); - return; - } - - auto vsyncCallbackInfo = exynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC]; - if (vsyncCallbackInfo.funcPointer && vsyncCallbackInfo.callbackData) - ((HWC2_PFN_VSYNC)vsyncCallbackInfo.funcPointer)(vsyncCallbackInfo.callbackData, - mExynosDisplay->mDisplayId, timestamp); + auto vsync_2_4CallbackInfo = + exynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4]; + if (vsync_2_4CallbackInfo.funcPointer && vsync_2_4CallbackInfo.callbackData) { + ((HWC2_PFN_VSYNC_2_4)vsync_2_4CallbackInfo.funcPointer)( + vsync_2_4CallbackInfo.callbackData, + mExynosDisplay->mDisplayId, + timestamp, mExynosDisplay->mVsyncPeriod); + ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod)); + return; } + + auto vsyncCallbackInfo = exynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC]; + if (vsyncCallbackInfo.funcPointer && vsyncCallbackInfo.callbackData) + ((HWC2_PFN_VSYNC)vsyncCallbackInfo.funcPointer)(vsyncCallbackInfo.callbackData, + mExynosDisplay->mDisplayId, timestamp); } bool ExynosDisplayDrmInterface::ExynosVsyncCallback::Callback( @@ -993,7 +995,8 @@ int32_t ExynosDisplayDrmInterface::setColorMode(int32_t mode) int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints( hwc2_config_t config, bool test) { - ALOGD("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config); + ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.string(), config, + test); auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(), [config](DrmMode const &m) { return m.id() == config;}); if (mode == mDrmConnector->modes().end()) { @@ -1092,6 +1095,7 @@ int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config) { return HWC2_ERROR_BAD_CONFIG; } + mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC)); if (!setActiveDrmMode(*mode)) { ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config); } else { @@ -1214,6 +1218,9 @@ int32_t ExynosDisplayDrmInterface::updateHdrCapabilities() std::tie(typeBit, ret) = prop_hdr_formats.GetEnumValueWithName("HDR10"); if ((ret == 0) && (hdr_formats & (1 << typeBit))) { mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HDR10); + if (mExynosDisplay->mDevice->mResourceManager->hasHDR10PlusMPP()) { + mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HDR10_PLUS); + } HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d", mExynosDisplay->mDisplayName.string(), HAL_HDR_HDR10); } @@ -1654,6 +1661,7 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() if (mBrightnessCtrl.LhbmOn.is_dirty()) { auto dbv = mBrightnessLevel.get(); + auto old_dbv = dbv; if (mBrightnessCtrl.LhbmOn.get()) { uint32_t dbv_adj = 0; if (mExynosDisplay->getColorAdjustedDbv(dbv_adj)) { @@ -1668,7 +1676,7 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() } } - if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(), + if ((dbv != old_dbv) && (ret = drmReq.atomicAddProperty(mDrmConnector->id(), mDrmConnector->brightness_level(), dbv)) < 0) { HWC_LOGE(mExynosDisplay, "%s: Fail to set brightness_level property", __func__); } @@ -1754,6 +1762,10 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() return ret; } drmReq.restorePset(); + if (out_fences[mDrmCrtc->pipe()] >= 0) { + fence_close((int)out_fences[mDrmCrtc->pipe()], mExynosDisplay, FENCE_TYPE_RETIRE, + FENCE_IP_DPP); + } if ((ret = updateColorSettings(drmReq, dqeEnable)) != 0) { HWC_LOGE(mExynosDisplay, "failed to update color settings, ret=%d", ret); return ret; @@ -2319,6 +2331,43 @@ int32_t ExynosDisplayDrmInterface::getDisplayIdentificationData( return HWC2_ERROR_NONE; } +void ExynosDisplayDrmInterface::checkHbmSvDimming() { + status_t ret = 0; + uint32_t wait = 0; + + while (mHbmSvDimmingThreadRunning) { + if (wait == 0) { + Mutex::Autolock lock(mHbmSvDimmingMutex); + ret = mHbmSvDimmingCond.wait(mHbmSvDimmingMutex); + } else { + Mutex::Autolock lock(mHbmSvDimmingMutex); + ret = mHbmSvDimmingCond.waitRelative(mHbmSvDimmingMutex, us2ns(wait)); + } + // When the time out, it turns dimming off(hbm sv dimming done). + // Then, it waits the next hbm sv dimming event. + if (ret == TIMED_OUT) { + ret = 0; + wait = 0; + ALOGI("checking the dimming status"); + endHbmSvDimming(); + } else { + wait = mHbmDimmingTimeUs; + } + } +} + +void ExynosDisplayDrmInterface::endHbmSvDimming() { + Mutex::Autolock lock(mBrightnessUpdateMutex); + if (!mHbmSvDimming) return; + mHbmSvDimming = false; + mBrightnessCtrl.DimmingOn.store(false); + + if (mDimmingOnFd && mBrightnessCtrl.DimmingOn.is_dirty()) { + writeFileNode(mDimmingOnFd, mBrightnessCtrl.DimmingOn.get()); + mBrightnessCtrl.DimmingOn.clear_dirty(); + } +} + void ExynosDisplayDrmInterface::getBrightnessInterfaceSupport() { if (mDrmConnector->brightness_cap().id() == 0) { ALOGD("the brightness_cap is not supported"); @@ -2365,17 +2414,25 @@ void ExynosDisplayDrmInterface::getBrightnessInterfaceSupport() { mBrightnessState.reset(); mBrightnessCtrl.reset(); - mHbmModeFd = fopen(kHbmModeFileNode, "w+"); - if (mHbmModeFd == NULL) ALOGE("%s open failed! %s", kHbmModeFileNode, strerror(errno)); + String8 node_name; + node_name.appendFormat(kHbmModeFileNode, mExynosDisplay->mIndex); + mHbmModeFd = fopen(node_name.string(), "w+"); + if (mHbmModeFd == NULL) ALOGE("%s open failed! %s", node_name.string(), strerror(errno)); - mDimmingOnFd = fopen(kDimmingOnFileNode, "w+"); - if (mDimmingOnFd == NULL) ALOGE("%s open failed! %s", kDimmingOnFileNode, strerror(errno)); + node_name.clear(); + node_name.appendFormat(kDimmingOnFileNode, mExynosDisplay->mIndex); + mDimmingOnFd = fopen(node_name.string(), "w+"); + if (mDimmingOnFd == NULL) ALOGE("%s open failed! %s", node_name.string(), strerror(errno)); if (mDimmingOnFd) { mBrightnessDimmingUsage = static_cast<BrightnessDimmingUsage>( property_get_int32("vendor.display.brightness.dimming.usage", 0)); mHbmDimmingTimeUs = property_get_int32("vendor.display.brightness.dimming.hbm_time", kHbmDimmingTimeUs); + if (mBrightnessDimmingUsage == BrightnessDimmingUsage::HBM) { + mHbmSvDimmingThreadRunning = true; + mDimmingThread = std::thread(&ExynosDisplayDrmInterface::checkHbmSvDimming, this); + } } return; @@ -2489,21 +2546,14 @@ void ExynosDisplayDrmInterface::setupBrightnessConfig() { case BrightnessDimmingUsage::HBM: if ((static_cast<uint32_t>(hbm_mode) > static_cast<uint32_t>(HbmMode::OFF)) != mBrightnessCtrl.HbmMode.get() > static_cast<uint32_t>(HbmMode::OFF)) { - gettimeofday(&mHbmDimmingStart, NULL); if (brightness_state.hdr_full_screen != mBrightnessState.hdr_full_screen) { mBrightnessState.hdr_full_screen = brightness_state.hdr_full_screen; } else { mHbmSvDimming = true; + mHbmSvDimmingCond.signal(); } } - - if (mHbmSvDimming) { - struct timeval curr_time; - gettimeofday(&curr_time, NULL); - curr_time.tv_usec += (curr_time.tv_sec - mHbmDimmingStart.tv_sec) * 1000000; - long duration = curr_time.tv_usec - mHbmDimmingStart.tv_usec; - if (duration > mHbmDimmingTimeUs) mHbmSvDimming = false; - } + if (mBrightnessLevel.get() == 0) mHbmSvDimming = false; dimming_on = dimming_on && (mHbmSvDimming); break; case BrightnessDimmingUsage::NONE: diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h index 62ab701..5345329 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h @@ -429,6 +429,8 @@ class ExynosDisplayDrmInterface : void getBrightnessInterfaceSupport(); void setupBrightnessConfig(); void parseHbmModeEnums(const DrmProperty &property); + void checkHbmSvDimming(); + void endHbmSvDimming(); FILE *mHbmModeFd; FILE *mDimmingOnFd; bool mBrightntessIntfSupported = false; @@ -491,9 +493,9 @@ class ExynosDisplayDrmInterface : // TODO: hbm in dual display is not supported. It should support it in // the furture. static constexpr const char *kHbmModeFileNode = - "/sys/class/backlight/panel0-backlight/hbm_mode"; + "/sys/class/backlight/panel%d-backlight/hbm_mode"; static constexpr const char *kDimmingOnFileNode = - "/sys/class/backlight/panel0-backlight/dimming_on"; + "/sys/class/backlight/panel%d-backlight/dimming_on"; static constexpr int32_t kHbmDimmingTimeUs = 5000000; @@ -514,7 +516,10 @@ class ExynosDisplayDrmInterface : BrightnessDimmingUsage mBrightnessDimmingUsage; bool mHbmSvDimming; int32_t mHbmDimmingTimeUs; - struct timeval mHbmDimmingStart; + std::thread mDimmingThread; + bool mHbmSvDimmingThreadRunning; + Condition mHbmSvDimmingCond; + Mutex mHbmSvDimmingMutex; private: int32_t getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize, uint8_t *outData); diff --git a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp index 20193ab..d847c2b 100644 --- a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp +++ b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp @@ -36,6 +36,10 @@ DrmEventListener::DrmEventListener(DrmDevice *drm) : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) { } +DrmEventListener::~DrmEventListener() { + Exit(); +} + int DrmEventListener::Init() { struct epoll_event ev; char buffer[1024]; diff --git a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp index 97dc0dd..d2b4a02 100644 --- a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp +++ b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp @@ -49,6 +49,7 @@ VSyncWorker::VSyncWorker() } VSyncWorker::~VSyncWorker() { + Exit(); } int VSyncWorker::Init(DrmDevice *drm, int display) { diff --git a/libhwc2.1/libdrmresource/include/drmeventlistener.h b/libhwc2.1/libdrmresource/include/drmeventlistener.h index 541d074..dbecadb 100644 --- a/libhwc2.1/libdrmresource/include/drmeventlistener.h +++ b/libhwc2.1/libdrmresource/include/drmeventlistener.h @@ -51,8 +51,7 @@ class DrmEventListener : public Worker { static const uint32_t maxFds = 3; public: DrmEventListener(DrmDevice *drm); - virtual ~DrmEventListener() { - } + virtual ~DrmEventListener(); int Init(); diff --git a/libhwc2.1/libdrmresource/utils/worker.cpp b/libhwc2.1/libdrmresource/utils/worker.cpp index 3b24312..4dbd0d9 100644 --- a/libhwc2.1/libdrmresource/utils/worker.cpp +++ b/libhwc2.1/libdrmresource/utils/worker.cpp @@ -26,7 +26,6 @@ Worker::Worker(const char *name, int priority, bool is_rt) } Worker::~Worker() { - Exit(); } int Worker::InitWorker() { diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp index be61d68..8ba3020 100644 --- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp +++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp @@ -28,6 +28,8 @@ #define SKIP_FRAME_COUNT 3 extern struct exynos_hwc_control exynosHWCControl; +using namespace SOC_VERSION; + ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice *device) : ExynosDisplay(index, device) { diff --git a/libhwc2.1/libhwcService/ExynosHWCService.cpp b/libhwc2.1/libhwcService/ExynosHWCService.cpp index da936a8..33d42ea 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.cpp +++ b/libhwc2.1/libhwcService/ExynosHWCService.cpp @@ -13,10 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "ExynosHWCService.h" -#include "ExynosVirtualDisplayModule.h" -#include "ExynosVirtualDisplay.h" + +#include <chrono> + #include "ExynosExternalDisplay.h" +#include "ExynosVirtualDisplay.h" +#include "ExynosVirtualDisplayModule.h" #define HWC_SERVICE_DEBUG 0 namespace android { @@ -261,6 +265,18 @@ void ExynosHWCService::setScaleDownRatio(uint32_t physicalType, mHWCCtx->device->invalidate(); } +void ExynosHWCService::setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) { + ALOGD("%s:: display_id(%d), state(%d), lux(%d)", __func__, display_id, state, lux); + if (mHWCCtx) { + auto display = mHWCCtx->device->getDisplay(display_id); + + if (display != nullptr) { + display->setLbeState(static_cast<LbeState>(state)); + display->setLbeAmbientLight(lux); + } + } +} + void ExynosHWCService::setHWCDebug(int debug) { ALOGD_IF(HWC_SERVICE_DEBUG, "%s, debug %d", __func__, debug); @@ -428,4 +444,31 @@ int32_t ExynosHWCService::setDisplayLhbm(int32_t display_id, uint32_t on) { return -EINVAL; } +int32_t ExynosHWCService::setMinIdleRefreshRate(uint32_t display_id, int32_t fps) { + ALOGD("ExynosHWCService::%s() display_id(%u) fps(%d)", __func__, display_id, fps); + + auto display = mHWCCtx->device->getDisplay(display_id); + + if (display != nullptr) { + return display->setMinIdleRefreshRate(fps); + } + + return -EINVAL; +} + +int32_t ExynosHWCService::setRefreshRateThrottle(uint32_t display_id, int32_t delayMs) { + ALOGD("ExynosHWCService::%s() display_id(%u) delayMs(%d)", __func__, display_id, delayMs); + + auto display = mHWCCtx->device->getDisplay(display_id); + + if (display != nullptr) { + return display->setRefreshRateThrottleNanos( + std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(delayMs)) + .count()); + } + + return -EINVAL; +} + } //namespace android diff --git a/libhwc2.1/libhwcService/ExynosHWCService.h b/libhwc2.1/libhwcService/ExynosHWCService.h index 25f4516..cb47655 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.h +++ b/libhwc2.1/libhwcService/ExynosHWCService.h @@ -66,6 +66,7 @@ public: virtual int setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val); virtual int setDDIScaler(uint32_t width, uint32_t height); + virtual void setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) override; #if 0 void setPSRExitCallback(void (*callback)(exynos_hwc_composer_device_1_t *)); virtual void notifyPSRExit(); @@ -75,6 +76,9 @@ public: virtual int32_t setDisplayBrightness(int32_t display_id, float brightness); virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on); + virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t fps); + virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t delayMs); + private: friend class Singleton<ExynosHWCService>; ExynosHWCService(); diff --git a/libhwc2.1/libhwcService/IExynosHWC.cpp b/libhwc2.1/libhwcService/IExynosHWC.cpp index 62f52fe..51a2fba 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.cpp +++ b/libhwc2.1/libhwcService/IExynosHWC.cpp @@ -61,6 +61,9 @@ enum { SET_PANEL_GAMMA_TABLE_SOURCE = 1001, SET_DISPLAY_BRIGHTNESS = 1002, SET_DISPLAY_LHBM = 1003, + SET_LBE_CTRL = 1004, + SET_MIN_IDLE_REFRESH_RATE = 1005, + SET_REFRESH_RATE_THROTTLE = 1006, }; class BpExynosHWCService : public BpInterface<IExynosHWCService> { @@ -295,6 +298,16 @@ public: ALOGE("SET_SCALE_DOWN_RATIO transact error(%d)", result); } + virtual void setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeInt32(display_id); + data.writeInt32(state); + data.writeInt32(lux); + int result = remote()->transact(SET_LBE_CTRL, data, &reply); + if (result != NO_ERROR) ALOGE("SET_LBE_CTRL transact error(%d)", result); + } + virtual void setHWCDebug(int debug) { Parcel data, reply; @@ -402,6 +415,26 @@ public: if (result) ALOGE("SET_DISPLAY_LHBM transact error(%d)", result); return result; } + + virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t fps) { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeUint32(display_id); + data.writeInt32(fps); + int result = remote()->transact(SET_MIN_IDLE_REFRESH_RATE, data, &reply); + if (result) ALOGE("SET_MIN_IDLE_REFRESH_RATE transact error(%d)", result); + return result; + } + + virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t delay_ms) { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeUint32(display_id); + data.writeInt32(delay_ms); + int result = remote()->transact(SET_REFRESH_RATE_THROTTLE, data, &reply); + if (result) ALOGE("SET_REFRESH_RATE_THROTTLE transact error(%d)", result); + return result; + } }; IMPLEMENT_META_INTERFACE(ExynosHWCService, "android.hal.ExynosHWCService"); @@ -647,6 +680,29 @@ status_t BnExynosHWCService::onTransact( return NO_ERROR; } break; + case SET_LBE_CTRL: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + uint32_t display_id = data.readInt32(); + uint32_t state = data.readInt32(); + uint32_t lux = data.readInt32(); + setLbeCtrl(display_id, state, lux); + return NO_ERROR; + } break; + + case SET_MIN_IDLE_REFRESH_RATE: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + uint32_t display_id = data.readUint32(); + int32_t fps = data.readInt32(); + return setMinIdleRefreshRate(display_id, fps); + } break; + + case SET_REFRESH_RATE_THROTTLE: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + uint32_t display_id = data.readUint32(); + int32_t delay_ms = data.readInt32(); + return setRefreshRateThrottle(display_id, delay_ms); + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libhwc2.1/libhwcService/IExynosHWC.h b/libhwc2.1/libhwcService/IExynosHWC.h index 30af1c3..a410008 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.h +++ b/libhwc2.1/libhwcService/IExynosHWC.h @@ -66,11 +66,14 @@ public: virtual int32_t setDisplayDeviceMode(int32_t display_id, int32_t mode) = 0; virtual int32_t setPanelGammaTableSource(int32_t display_id, int32_t type, int32_t source) = 0; + virtual void setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) = 0; /* virtual void notifyPSRExit() = 0; */ virtual int32_t setDisplayBrightness(int32_t display_id, float brightness) = 0; virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on) = 0; + virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t refresh_rate) = 0; + virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t throttle) = 0; }; /* Native Interface */ diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp index c69388c..26727f2 100644 --- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp +++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp @@ -19,6 +19,10 @@ #include "ExynosPrimaryDisplay.h" +#include <linux/fb.h> +#include <poll.h> + +#include <chrono> #include <fstream> #include "ExynosDevice.h" @@ -28,10 +32,10 @@ #include "ExynosHWCDebug.h" #include "ExynosHWCHelper.h" -#include <linux/fb.h> - extern struct exynos_hwc_control exynosHWCControl; +using namespace SOC_VERSION; + static const std::map<const DisplayType, const std::string> panelSysfsPath = {{DisplayType::DISPLAY_PRIMARY, "/sys/devices/platform/exynos-drm/primary-panel/"}, {DisplayType::DISPLAY_SECONDARY, "/sys/devices/platform/exynos-drm/secondary-panel/"}}; @@ -65,8 +69,11 @@ static std::string loadPanelGammaCalibration(const std::string &file) { } ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) - : ExynosDisplay(index, device) -{ + : ExynosDisplay(index, device), + mMinIdleRefreshRate(0), + mRefreshRateDelayNanos(0), + mLastRefreshRateAppliedNanos(0), + mAppliedActiveConfig(0) { // TODO : Hard coded here mNumMaxPriorityAllowed = 5; @@ -94,9 +101,28 @@ ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) mResolutionInfo.nDSCXSliceSize[2] = 720; mResolutionInfo.nPanelType[2] = PANEL_LEGACY; -#if defined(MAX_BRIGHTNESS_NODE_BASE) && defined(BRIGHTNESS_NODE_BASE) - FILE *maxBrightnessFd = fopen(MAX_BRIGHTNESS_NODE_BASE, "r"); - ALOGI("Trying %s open for get max brightness", MAX_BRIGHTNESS_NODE_BASE); + static_assert(sizeof(BRIGHTNESS_NODE_0_BASE) != 0 && sizeof(MAX_BRIGHTNESS_NODE_0_BASE) != 0, + "Invalid brightness 0 node"); + static_assert(sizeof(BRIGHTNESS_NODE_1_BASE) != 0 && sizeof(MAX_BRIGHTNESS_NODE_1_BASE) != 0, + "Invalid brightness 1 node"); + std::string brightness_node; + std::string max_brightness_node; + switch (mIndex) { + case 0: + max_brightness_node = MAX_BRIGHTNESS_NODE_0_BASE; + brightness_node = BRIGHTNESS_NODE_0_BASE; + break; + case 1: + max_brightness_node = MAX_BRIGHTNESS_NODE_1_BASE; + brightness_node = BRIGHTNESS_NODE_1_BASE; + break; + default: + ALOGE("assgin brightness node failed (mIndex: %d)", mIndex); + break; + } + + FILE *maxBrightnessFd = fopen(max_brightness_node.c_str(), "r"); + ALOGI("Trying %s open for get max brightness", max_brightness_node.c_str()); if (maxBrightnessFd != NULL) { char val[MAX_BRIGHTNESS_LEN] = {0}; @@ -105,11 +131,11 @@ ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) mMaxBrightness = atoi(val); ALOGI("Max brightness : %d", mMaxBrightness); - mBrightnessFd = fopen(BRIGHTNESS_NODE_BASE, "w+"); - ALOGI("Trying %s open for brightness control", BRIGHTNESS_NODE_BASE); + mBrightnessFd = fopen(brightness_node.c_str(), "w+"); + ALOGI("Trying %s open for brightness control", brightness_node.c_str()); if (mBrightnessFd == NULL) - ALOGE("%s open failed! %s", BRIGHTNESS_NODE_BASE, strerror(errno)); + ALOGE("%s open failed! %s", brightness_node.c_str(), strerror(errno)); } else { ALOGE("Max brightness read failed (size: %zu)", size); @@ -122,7 +148,6 @@ ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) } else { ALOGE("Brightness node is not opened"); } -#endif #if defined EARLY_WAKUP_NODE_BASE mEarlyWakeupFd = fopen(EARLY_WAKUP_NODE_BASE, "w"); @@ -228,7 +253,7 @@ int32_t ExynosPrimaryDisplay::applyPendingConfig() { int32_t ExynosPrimaryDisplay::setPowerOn() { ATRACE_CALL(); - + updateAppliedActiveConfig(0, 0); int ret = applyPendingConfig(); if (mPowerModeState == HWC2_POWER_MODE_OFF) { @@ -441,12 +466,36 @@ int32_t ExynosPrimaryDisplay::SetCurrentPanelGammaSource(const DisplayType type, return HWC2_ERROR_NONE; } +// Both setDisplayBrightness and setLhbmState will change display brightness and +// each goes different path (sysfs and drm/kms) +// +// case 1: setDisplayBrightness happens before setLhbmState +// Don't care. brightness change by setLhbmState will happen after brightness +// change by setDisplayBrightness. +// +// case 2: setLhbmState happends before setDisplayBrightness +// block current call until brightness change by setLhbmState completes. +int32_t ExynosPrimaryDisplay::setDisplayBrightness(float brightness) { + if (mLhbmStatusPending) { + // This could be done in setLhbmState and block this call on + // mLhbmStatusPending. But it may increase the time for UDFPS path + checkLhbmMode(mLastRequestedLhbm, ms2ns(200)); + mLhbmStatusPending = false; + } + return ExynosDisplay::setDisplayBrightness(brightness); +} + int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) { + ATRACE_CALL(); requestLhbm(enabled); ALOGI("setLhbmState =%d", enabled); std::unique_lock<std::mutex> lk(lhbm_mutex_); mLhbmChanged = false; + + mLhbmStatusPending = true; + mLastRequestedLhbm = enabled; + if (!lhbm_cond_.wait_for(lk, std::chrono::milliseconds(1000), [this] { return mLhbmChanged; })) { ALOGI("setLhbmState =%d timeout !", enabled); @@ -458,6 +507,75 @@ int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) { } } +// return immediately if it's already in the status. Otherwise poll the status +bool ExynosPrimaryDisplay::checkLhbmMode(bool status, nsecs_t timeoutNs) { + ATRACE_CALL(); + char buf[1]; + auto startTime = systemTime(SYSTEM_TIME_MONOTONIC); + + UniqueFd fd = open(kLocalHbmModeFileNode, O_RDONLY); + + int size = read(fd.get(), buf, 1); + if (size != 1) { + ALOGE("%s failed to read from %s", __func__, kLocalHbmModeFileNode); + return false; + } + + if (buf[0] == (status ? '1' : '0')) { + return true; + } + + struct pollfd pfds[1]; + int ret = EINVAL; + + pfds[0].fd = fd.get(); + pfds[0].events = POLLPRI; + while (true) { + auto currentTime = systemTime(SYSTEM_TIME_MONOTONIC); + // int64_t for nsecs_t + auto remainTimeNs = timeoutNs - (currentTime - startTime); + if (remainTimeNs <= 0) { + remainTimeNs = ms2ns(1); + } + int pollRet = poll(&pfds[0], 1, ns2ms(remainTimeNs)); + if (pollRet == 0) { + ALOGW("%s poll timeout", __func__); + // time out + ret = ETIMEDOUT; + break; + } else if (pollRet > 0) { + if (!(pfds[0].revents & POLLPRI)) { + continue; + } + + lseek(fd.get(), 0, SEEK_SET); + size = read(fd.get(), buf, 1); + if (size == 1) { + if (buf[0] == (status ? '1' : '0')) { + ret = 0; + } else { + ALOGE("%s status %d expected %d after notified", __func__, buf[0], status); + ret = EINVAL; + } + } else { + ret = EIO; + ALOGE("%s failed to read after notified %d", __func__, errno); + } + break; + } else { + if (errno == EAGAIN || errno == EINTR) { + continue; + } + + ALOGE("%s poll failed %d", __func__, errno); + ret = errno; + break; + } + }; + + return ret == NO_ERROR; +} + bool ExynosPrimaryDisplay::getLhbmState() { return mLhbmOn; } @@ -474,3 +592,115 @@ void ExynosPrimaryDisplay::setWakeupDisplay() { writeFileNode(mWakeupDispFd, 1); } } + +int ExynosPrimaryDisplay::setMinIdleRefreshRate(const int fps) { + mMinIdleRefreshRate = fps; + + const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "min_vrefresh"; + std::ofstream ofs(path); + if (!ofs.is_open()) { + ALOGW("Unable to open node '%s', error = %s", path.c_str(), strerror(errno)); + return errno; + } else { + ofs << mMinIdleRefreshRate; + ofs.close(); + ALOGI("ExynosPrimaryDisplay::%s() writes min_vrefresh(%d) to the sysfs node", __func__, + fps); + } + return NO_ERROR; +} + +int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos) { + mRefreshRateDelayNanos = delayNanos; + + const int32_t refreshRateDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::nanoseconds(mRefreshRateDelayNanos)) + .count(); + const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "idle_delay_ms"; + std::ofstream ofs(path); + if (!ofs.is_open()) { + ALOGW("Unable to open node '%s', error = %s", path.c_str(), strerror(errno)); + return errno; + } else { + ofs << refreshRateDelayMs; + ofs.close(); + ALOGI("ExynosPrimaryDisplay::%s() writes idle_delay_ms(%d) to the sysfs node", __func__, + refreshRateDelayMs); + } + + return NO_ERROR; +} + +void ExynosPrimaryDisplay::dump(String8 &result) { + ExynosDisplay::dump(result); + result.appendFormat("Min idle refresh rate: %d\n", mMinIdleRefreshRate); + result.appendFormat("Refresh rate delay: %" PRId64 "ns\n\n", mRefreshRateDelayNanos); +} + +void ExynosPrimaryDisplay::calculateTimeline( + hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline) { + int64_t desiredUpdateTime = vsyncPeriodChangeConstraints->desiredTimeNanos; + const int64_t origDesiredUpdateTime = desiredUpdateTime; + const int64_t threshold = mRefreshRateDelayNanos; + int64_t lastUpdateDelta = 0; + int64_t actualChangeTime = 0; + bool isDelayed = false; + + /* actualChangeTime includes transient duration */ + mDisplayInterface->getVsyncAppliedTime(config, &actualChangeTime); + + outTimeline->refreshRequired = true; + + /* when refresh rate is from high to low */ + if (threshold != 0 && mLastRefreshRateAppliedNanos != 0 && + mDisplayConfigs[mActiveConfig].vsyncPeriod < mDisplayConfigs[config].vsyncPeriod) { + lastUpdateDelta = desiredUpdateTime - mLastRefreshRateAppliedNanos; + if (lastUpdateDelta < threshold) { + /* in this case, the active config change needs to be delayed */ + isDelayed = true; + desiredUpdateTime += threshold - lastUpdateDelta; + } + } + mVsyncPeriodChangeConstraints.desiredTimeNanos = desiredUpdateTime; + + getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime, + outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos); + + if (isDelayed) { + DISPLAY_LOGD(eDebugDisplayConfig, + "requested config : %d(%d)->%d(%d) is delayed! " + "delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", " + "desired %" PRId64 "->%" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 + ", refreshTimeNanos:%" PRId64, + mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, + mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, + threshold - lastUpdateDelta, threshold, origDesiredUpdateTime, + mVsyncPeriodChangeConstraints.desiredTimeNanos, + outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos); + } else { + DISPLAY_LOGD(eDebugDisplayConfig, + "requested config : %d(%d)->%d(%d), " + "lastUpdateDelta %" PRId64 ", threshold %" PRId64 ", " + "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "", + mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, + mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, threshold, + mVsyncPeriodChangeConstraints.desiredTimeNanos, + outTimeline->newVsyncAppliedTimeNanos); + } +} + +void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConfig, + const int64_t ts) { + if (mAppliedActiveConfig == 0 || + getDisplayVsyncPeriodFromConfig(mAppliedActiveConfig) != + getDisplayVsyncPeriodFromConfig(newConfig)) { + DISPLAY_LOGD(eDebugDisplayConfig, + "%s mAppliedActiveConfig(%d->%d), mLastRefreshRateAppliedNanos(%" PRIu64 + " -> %" PRIu64 ")", + __func__, mAppliedActiveConfig, newConfig, mLastRefreshRateAppliedNanos, ts); + mLastRefreshRateAppliedNanos = ts; + } + + mAppliedActiveConfig = newConfig; +} diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h index c49ae5e..e8b76ec 100644 --- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h +++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h @@ -20,8 +20,6 @@ #include "../libdevice/ExynosDisplay.h" -class ExynosMPPModule; - class ExynosPrimaryDisplay : public ExynosDisplay { public: /* Methods */ @@ -37,6 +35,8 @@ class ExynosPrimaryDisplay : public ExynosDisplay { virtual bool isLhbmSupported() { return mLhbmFd ? true : false; } virtual int32_t setLhbmState(bool enabled); + virtual int32_t setDisplayBrightness(float brightness) override; + virtual bool getLhbmState(); virtual void notifyLhbmState(bool enabled); virtual void setWakeupDisplay(); @@ -44,6 +44,12 @@ class ExynosPrimaryDisplay : public ExynosDisplay { virtual void initDisplayInterface(uint32_t interfaceType); virtual int32_t doDisplayConfigInternal(hwc2_config_t config) override; + virtual int setMinIdleRefreshRate(const int fps) override; + virtual int setRefreshRateThrottleNanos(const int64_t delayNs) override; + virtual void dump(String8& result) override; + virtual void updateAppliedActiveConfig(const hwc2_config_t newConfig, + const int64_t ts) override; + protected: /* setPowerMode(int32_t mode) * Descriptor: HWC2_FUNCTION_SET_POWER_MODE @@ -66,6 +72,8 @@ class ExynosPrimaryDisplay : public ExynosDisplay { static constexpr const char* kPanelGammaCalFilePrefix = "gamma_calib_data"; enum PanelGammaSource currentPanelGammaSource = PanelGammaSource::GAMMA_DEFAULT; + bool checkLhbmMode(bool status, nsecs_t timoutNs); + hwc2_config_t mPendActiveConfig = UINT_MAX; bool mFirstPowerOn = true; @@ -81,6 +89,10 @@ class ExynosPrimaryDisplay : public ExynosDisplay { FILE* mLhbmFd; bool mLhbmOn; bool mLhbmChanged; + + std::atomic<bool> mLastRequestedLhbm; + std::atomic<bool> mLhbmStatusPending; + static constexpr const char *kLocalHbmModeFileNode = "/sys/class/backlight/panel0-backlight/local_hbm_mode"; std::mutex lhbm_mutex_; @@ -89,6 +101,14 @@ class ExynosPrimaryDisplay : public ExynosDisplay { FILE* mWakeupDispFd; static constexpr const char* kWakeupDispFilePath = "/sys/devices/platform/1c300000.drmdecon/early_wakeup"; + + void calculateTimeline(hwc2_config_t config, + hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t* outTimeline) override; + int mMinIdleRefreshRate; + int64_t mRefreshRateDelayNanos; + int64_t mLastRefreshRateAppliedNanos; + hwc2_config_t mAppliedActiveConfig; }; #endif diff --git a/libhwc2.1/libresource/ExynosResourceManager.cpp b/libhwc2.1/libresource/ExynosResourceManager.cpp index fed8a3c..502baac 100644 --- a/libhwc2.1/libresource/ExynosResourceManager.cpp +++ b/libhwc2.1/libresource/ExynosResourceManager.cpp @@ -85,6 +85,7 @@ feature_support_t feature_table[] = using namespace android; using namespace vendor::graphics; +using namespace SOC_VERSION; ExynosMPPVector ExynosResourceManager::mOtfMPPs; ExynosMPPVector ExynosResourceManager::mM2mMPPs; diff --git a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h index af0c918..9e5daa8 100644 --- a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h +++ b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h @@ -21,8 +21,6 @@ #define VIRTUAL_DISLAY_SKIP_LAYER 0x00000100 -class ExynosMPPModule; - enum WFDState { DISABLE_WFD, GOOGLEWFD, diff --git a/libhwc2.1/pixel-display-default.xml b/libhwc2.1/pixel-display-default.xml index 1a08386..31c569e 100644 --- a/libhwc2.1/pixel-display-default.xml +++ b/libhwc2.1/pixel-display-default.xml @@ -1,7 +1,7 @@ <manifest version="1.0" type="device"> <hal format="aidl"> <name>com.google.hardware.pixel.display</name> - <version>3</version> + <version>4</version> <fqname>IDisplay/default</fqname> </hal> </manifest> diff --git a/libhwc2.1/pixel-display.cpp b/libhwc2.1/pixel-display.cpp index b6d0eb3..409cfe0 100644 --- a/libhwc2.1/pixel-display.cpp +++ b/libhwc2.1/pixel-display.cpp @@ -23,6 +23,8 @@ #include <sys/types.h> #include <utils/Errors.h> +#include "ExynosDisplay.h" + extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer); using ::aidl::com::google::hardware::pixel::display::Display; @@ -137,9 +139,29 @@ ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) { ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle, const std::string &imageName, int *_aidl_return) { - *_aidl_return = readCompensationImage(native_handle, imageName); + if (mDevice && mDevice->isColorCalibratedByDevice()) { + *_aidl_return = readCompensationImage(native_handle, imageName); + } else { + *_aidl_return = -1; + } return ndk::ScopedAStatus::ok(); } + +ndk::ScopedAStatus Display::setMinIdleRefreshRate(int fps, int *_aidl_return) { + if (mDevice) { + *_aidl_return = mDevice->setMinIdleRefreshRate(fps); + return ndk::ScopedAStatus::ok(); + } + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus Display::setRefreshRateThrottle(int delayMs, int *_aidl_return) { + if (mDevice) { + *_aidl_return = mDevice->setRefreshRateThrottle(delayMs); + return ndk::ScopedAStatus::ok(); + } + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} } // namespace display } // namespace pixel } // namespace hardware diff --git a/libhwc2.1/pixel-display.h b/libhwc2.1/pixel-display.h index 7e0d33b..f0fd627 100644 --- a/libhwc2.1/pixel-display.h +++ b/libhwc2.1/pixel-display.h @@ -47,6 +47,8 @@ public: ndk::ScopedAStatus setCompensationImageHandle(const NativeHandle &native_handle, const std::string &imageName, int *_aidl_return) override; + ndk::ScopedAStatus setMinIdleRefreshRate(int fps, int *_aidl_return) override; + ndk::ScopedAStatus setRefreshRateThrottle(int delayMs, int *_aidl_return) override; private: ExynosDevice *mDevice = nullptr; |