1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _BRIGHTNESS_CONTROLLER_H_ 18 #define _BRIGHTNESS_CONTROLLER_H_ 19 20 #include <drm/samsung_drm.h> 21 #include <utils/Looper.h> 22 #include <utils/Mutex.h> 23 24 #include <fstream> 25 #include <thread> 26 27 #include "ExynosDisplayDrmInterface.h" 28 29 /** 30 * Brightness change requests come from binder calls or HWC itself. 31 * The request could be applied via next drm commit or immeditely via sysfs. 32 * 33 * To make it simple, setDisplayBrightness from SF, if not triggering a HBM on/off, 34 * will be applied immediately via sysfs path. All other requests will be applied via next 35 * drm commit. 36 * 37 * Sysfs path is faster than drm path. So if there is a pending drm commit that may 38 * change brightness level, sfsfs path task should wait until it has completed. 39 */ 40 class BrightnessController { 41 public: 42 using HdrLayerState = displaycolor::HdrLayerState; 43 using DisplayBrightnessRange = displaycolor::DisplayBrightnessRange; 44 using BrightnessRangeMap = displaycolor::BrightnessRangeMap; 45 using IBrightnessTable = displaycolor::IBrightnessTable; 46 using BrightnessMode = displaycolor::BrightnessMode; 47 using ColorRenderIntent = displaycolor::hwc::RenderIntent; 48 49 class DimmingMsgHandler : public virtual ::android::MessageHandler { 50 public: 51 enum { 52 MSG_QUIT, 53 MSG_DIMMING_OFF, 54 }; DimmingMsgHandler(BrightnessController * bc)55 DimmingMsgHandler(BrightnessController* bc) : mBrightnessController(bc) {} 56 void handleMessage(const Message& message) override; 57 58 private: 59 BrightnessController* mBrightnessController; 60 }; 61 62 BrightnessController(int32_t panelIndex, std::function<void(void)> refresh, 63 std::function<void(void)> updateDcLhbm); 64 ~BrightnessController(); 65 66 BrightnessController(int32_t panelIndex); 67 int initDrm(const DrmDevice& drmDevice, 68 const DrmConnector& connector); 69 70 int processEnhancedHbm(bool on); 71 int processDisplayBrightness(float bl, const nsecs_t vsyncNs, bool waitPresent = false); 72 int ignoreBrightnessUpdateRequests(bool ignore); 73 int setBrightnessNits(float nits, const nsecs_t vsyncNs); 74 int setBrightnessDbv(uint32_t dbv, const nsecs_t vsyncNs); 75 int processLocalHbm(bool on); 76 int processDimBrightness(bool on); 77 int processOperationRate(int32_t hz); isDbmSupported()78 bool isDbmSupported() { return mDbmSupported; } 79 int applyPendingChangeViaSysfs(const nsecs_t vsyncNs); 80 int applyAclViaSysfs(); 81 bool validateLayerBrightness(float brightness); 82 83 /** 84 * processInstantHbm for GHBM UDFPS 85 * - on true: turn on HBM at next frame with peak brightness 86 * false: turn off HBM at next frame and use system display brightness 87 * from processDisplayBrightness 88 */ 89 int processInstantHbm(bool on); 90 91 /** 92 * updateFrameStates 93 * - hdrState: hdr layer size in this frame 94 * - sdrDim: whether any dimmed sdr layer in this frame 95 */ 96 void updateFrameStates(HdrLayerState hdrState, bool sdrDim); 97 98 /** 99 * updateColorRenderIntent 100 * - intent: color render intent 101 */ 102 void updateColorRenderIntent(int32_t intent); 103 104 /** 105 * Dim ratio to keep the sdr brightness unchange after an instant hbm on with peak brightness. 106 */ 107 float getSdrDimRatioForInstantHbm(); 108 109 void onClearDisplay(bool needModeClear); 110 111 /** 112 * apply brightness change on drm path. 113 * Note: only this path can hold the lock for a long time 114 */ 115 int prepareFrameCommit(ExynosDisplay& display, const DrmConnector& connector, 116 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, 117 const bool mixedComposition, bool& ghbmSync, bool& lhbmSync, 118 bool& blSync, bool& opRateSync); 119 isGhbmSupported()120 bool isGhbmSupported() { return mGhbmSupported; } isLhbmSupported()121 bool isLhbmSupported() { return mLhbmSupported; } 122 isGhbmOn()123 bool isGhbmOn() { 124 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 125 return mGhbm.get() != HbmMode::OFF; 126 } 127 isLhbmOn()128 bool isLhbmOn() { 129 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 130 return mLhbm.get(); 131 } 132 int checkSysfsStatus(const std::string& file, const std::vector<std::string>& expectedValue, 133 const nsecs_t timeoutNs); fileExists(const std::string & file)134 bool fileExists(const std::string& file) { 135 struct stat sb; 136 return stat(file.c_str(), &sb) == 0; 137 } 138 void resetLhbmState(); 139 getBrightnessLevel()140 uint32_t getBrightnessLevel() { 141 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 142 return mBrightnessLevel.get(); 143 } 144 getBrightnessNitsAndMode()145 std::optional<std::tuple<float, BrightnessMode>> getBrightnessNitsAndMode() { 146 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 147 BrightnessMode brightnessMode; 148 if (mBrightnessTable == nullptr) { 149 return std::nullopt; 150 } 151 152 auto brightness = mBrightnessTable->DbvToBrightness(mBrightnessLevel.get()); 153 if (brightness == std::nullopt) { 154 return std::nullopt; 155 } 156 auto nits = mBrightnessTable->BrightnessToNits(brightness.value(), brightnessMode); 157 if (nits == std::nullopt) { 158 return std::nullopt; 159 } 160 return std::make_tuple(nits.value(), brightnessMode); 161 } 162 isDimSdr()163 bool isDimSdr() { 164 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 165 return mInstantHbmReq.get(); 166 } 167 getHdrLayerState()168 HdrLayerState getHdrLayerState() { 169 return mHdrLayerState.get(); 170 } 171 getOperationRate()172 uint32_t getOperationRate() { 173 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 174 return mOperationRate.get(); 175 } 176 isOperationRatePending()177 bool isOperationRatePending() { 178 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 179 return mOperationRate.is_dirty(); 180 } 181 isSupported()182 bool isSupported() { 183 // valid mMaxBrightness means both brightness and max_brightness sysfs exist 184 return mMaxBrightness > 0; 185 } 186 187 void dump(String8 &result); 188 189 void setOutdoorVisibility(LbeState state); 190 191 int updateCabcMode(); 192 GetPanelSysfileByIndex(const char * file_pattern)193 const std::string GetPanelSysfileByIndex(const char *file_pattern) { 194 String8 nodeName; 195 nodeName.appendFormat(file_pattern, mPanelIndex); 196 return nodeName.c_str(); 197 } 198 GetPanelRefreshRateSysfile()199 const std::string GetPanelRefreshRateSysfile() { 200 String8 nodeName; 201 nodeName.appendFormat(kRefreshrateFileNode, 202 mPanelIndex == 0 ? "primary" 203 : mPanelIndex == 1 ? "secondary" 204 : "unknown"); 205 return nodeName.c_str(); 206 } 207 208 void updateBrightnessTable(std::unique_ptr<const IBrightnessTable>& table); getBrightnessRanges()209 const BrightnessRangeMap& getBrightnessRanges() const { 210 return mKernelBrightnessTable.GetBrightnessRangeMap(); 211 } 212 213 /* 214 * WARNING: This enum is parsed by Battery Historian. Add new values, but 215 * do not modify/remove existing ones. Alternatively, consult with the 216 * Battery Historian team (b/239640926). 217 */ 218 enum class BrightnessRange : uint32_t { 219 NORMAL = 0, 220 HBM = 1, 221 MAX, 222 }; 223 224 /* 225 * WARNING: This enum is parsed by Battery Historian. Add new values, but 226 * do not modify/remove existing ones. Alternatively, consult with the 227 * Battery Historian team (b/239640926). 228 */ 229 enum class HbmMode { 230 OFF = 0, 231 ON_IRC_ON = 1, 232 ON_IRC_OFF = 2, 233 }; 234 235 /* 236 * LHBM command need take a couple of frames to become effective 237 * DISABLED - finish sending disabling command to panel 238 * ENABLED - panel finishes boosting brightness to the peak value 239 * ENABLING - finish sending enabling command to panel (panel begins boosting brightness) 240 * Note: the definition should be consistent with kernel driver 241 */ 242 enum class LhbmMode { 243 DISABLED = 0, 244 ENABLED = 1, 245 ENABLING = 2, 246 }; 247 248 /* 249 * BrightnessDimmingUsage: 250 * NORMAL- enable dimming 251 * HBM- enable dimming only for hbm transition 252 * NONE- disable dimming 253 * 254 * WARNING: This enum is parsed by Battery Historian. Add new values, but 255 * do not modify/remove existing ones. Alternatively, consult with the 256 * Battery Historian team (b/239640926). 257 */ 258 enum class BrightnessDimmingUsage { 259 NORMAL = 0, 260 HBM = 1, 261 NONE, 262 }; 263 264 static constexpr const char *kLocalHbmModeFileNode = 265 "/sys/class/backlight/panel%d-backlight/local_hbm_mode"; 266 static constexpr const char* kDimBrightnessFileNode = 267 "/sys/class/backlight/panel%d-backlight/dim_brightness"; 268 static constexpr const char* kRefreshrateFileNode = 269 "/sys/devices/platform/exynos-drm/%s-panel/refresh_rate"; 270 271 private: 272 // This is a backup implementation of brightness table. It would be applied only when the system 273 // failed to initiate libdisplaycolor. The complete implementation is class 274 // DisplayData::BrightnessTable 275 class LinearBrightnessTable : public IBrightnessTable { 276 public: LinearBrightnessTable()277 LinearBrightnessTable() : mIsValid(false) {} 278 void Init(const struct brightness_capability* cap); IsValid()279 bool IsValid() const { return mIsValid; } GetBrightnessRangeMap()280 const BrightnessRangeMap& GetBrightnessRangeMap() const { return mBrightnessRanges; } 281 282 /* IBrightnessTable functions */ GetBrightnessRange(BrightnessMode bm)283 std::optional<std::reference_wrapper<const DisplayBrightnessRange>> GetBrightnessRange( 284 BrightnessMode bm) const override { 285 if (mBrightnessRanges.count(bm) == 0) { 286 return std::nullopt; 287 } 288 return mBrightnessRanges.at(bm); 289 } 290 std::optional<float> BrightnessToNits(float brightness, BrightnessMode& bm) const override; 291 std::optional<float> NitsToBrightness(float nits) const override; 292 std::optional<float> DbvToBrightness(uint32_t dbv) const override; 293 std::optional<uint32_t> NitsToDbv(BrightnessMode bm, float nits) const override; 294 std::optional<float> DbvToNits(BrightnessMode bm, uint32_t dbv) const override; 295 GetBrightnessMode(float brightness)296 BrightnessMode GetBrightnessMode(float brightness) const { 297 for (const auto& [mode, range] : mBrightnessRanges) { 298 if (((!range.brightness_min_exclusive && brightness == range.brightness_min) || 299 brightness > range.brightness_min) && 300 brightness <= range.brightness_max) { 301 return mode; 302 } 303 } 304 // return BM_MAX if there is no matching range 305 return BrightnessMode::BM_MAX; 306 } 307 GetBrightnessModeForNits(float nits)308 BrightnessMode GetBrightnessModeForNits(float nits) const { 309 for (const auto& [mode, range] : mBrightnessRanges) { 310 if (nits >= range.nits_min && nits <= range.nits_max) { 311 return mode; 312 } 313 } 314 // return BM_INVALID if there is no matching range 315 return BrightnessMode::BM_INVALID; 316 } 317 getBrightnessModeForDbv(uint32_t dbv)318 BrightnessMode getBrightnessModeForDbv(uint32_t dbv) const { 319 for (const auto& [mode, range] : mBrightnessRanges) { 320 if (dbv >= range.dbv_min && dbv <= range.dbv_max) { 321 return mode; 322 } 323 } 324 // return BM_INVALID if there is no matching range 325 return BrightnessMode::BM_INVALID; 326 } 327 328 private: setBrightnessRangeFromAttribute(const struct brightness_attribute & attr,displaycolor::DisplayBrightnessRange & range)329 static void setBrightnessRangeFromAttribute(const struct brightness_attribute& attr, 330 displaycolor::DisplayBrightnessRange& range) { 331 range.nits_min = attr.nits.min; 332 range.nits_max = attr.nits.max; 333 range.dbv_min = attr.level.min; 334 range.dbv_max = attr.level.max; 335 range.brightness_min_exclusive = false; 336 range.brightness_min = static_cast<float>(attr.percentage.min) / 100.0f; 337 range.brightness_max = static_cast<float>(attr.percentage.max) / 100.0f; 338 } 339 /** 340 * Implement linear interpolation/extrapolation formula: 341 * y = y1+(y2-y1)*(x-x1)/(x2-x1) 342 * Return NAN for following cases: 343 * - Attempt to do extrapolation when x1==x2 344 * - Undefined output when (x2 == x1) and (y2 != y1) 345 */ LinearInterpolation(float x,float x1,float x2,float y1,float y2)346 static inline float LinearInterpolation(float x, float x1, float x2, float y1, float y2) { 347 if (x2 == x1) { 348 if (x != x1) { 349 ALOGE("%s: attempt to do extrapolation when x1==x2", __func__); 350 return NAN; 351 } 352 if (y2 == y1) { 353 // This is considered a normal case. (interpolation between a single point) 354 return y1; 355 } else { 356 // The output is undefined when (y1!=y2) 357 ALOGE("%s: undefined output when (x2 == x1) and (y2 != y1)", __func__); 358 return NAN; 359 } 360 } 361 float t = (x - x1) / (x2 - x1); 362 return y1 + (y2 - y1) * t; 363 } SupportHBM()364 inline bool SupportHBM() const { 365 return mBrightnessRanges.count(BrightnessMode::BM_HBM) > 0; 366 } 367 bool mIsValid; 368 BrightnessRangeMap mBrightnessRanges; 369 }; 370 // sync brightness change for mixed composition when there is more than 50% luminance change. 371 // The percentage is calculated as: 372 // (big_lumi - small_lumi) / small_lumi 373 // For mixed composition, if remove brightness animations, the minimum brightness jump is 374 // between nbm peak and hbm peak. 50% will cover known panels 375 static constexpr float kBrightnessSyncThreshold = 0.5f; 376 // Worst case for panel with brightness range 2 nits to 1000 nits. 377 static constexpr float kGhbmMinDimRatio = 0.002; 378 static constexpr int32_t kHbmDimmingTimeUs = 5000000; 379 static constexpr const char *kGlobalHbmModeFileNode = 380 "/sys/class/backlight/panel%d-backlight/hbm_mode"; 381 static constexpr const char* kDimmingUsagePropName = 382 "vendor.display.%d.brightness.dimming.usage"; 383 static constexpr const char* kDimmingHbmTimePropName = 384 "vendor.display.%d.brightness.dimming.hbm_time"; 385 static constexpr const char* kGlobalAclModeFileNode = 386 "/sys/class/backlight/panel%d-backlight/acl_mode"; 387 static constexpr const char* kAclModeDefaultPropName = 388 "vendor.display.%d.brightness.acl.default"; 389 390 int queryBrightness(float brightness, bool* ghbm = nullptr, uint32_t* level = nullptr, 391 float *nits = nullptr); 392 void initBrightnessTable(const DrmDevice& device, const DrmConnector& connector); 393 void initBrightnessSysfs(); 394 void initCabcSysfs(); 395 void initDimmingUsage(); 396 int applyBrightnessViaSysfs(uint32_t level); 397 int applyCabcModeViaSysfs(uint8_t mode); 398 int updateStates(); // REQUIRES(mBrightnessMutex) 399 void dimmingThread(); 400 void processDimmingOff(); 401 int updateAclMode(); 402 403 void parseHbmModeEnums(const DrmProperty& property); 404 405 void printBrightnessStates(const char* path); // REQUIRES(mBrightnessMutex) 406 407 bool mLhbmSupported = false; 408 bool mGhbmSupported = false; 409 bool mDbmSupported = false; 410 bool mBrightnessIntfSupported = false; 411 LinearBrightnessTable mKernelBrightnessTable; 412 // External object from libdisplaycolor 413 std::unique_ptr<const IBrightnessTable> mBrightnessTable; 414 415 int32_t mPanelIndex; 416 DrmEnumParser::MapHal2DrmEnum mHbmModeEnums; 417 418 // brightness state 419 std::recursive_mutex mBrightnessMutex; 420 // requests 421 CtrlValue<bool> mEnhanceHbmReq; // GUARDED_BY(mBrightnessMutex) 422 CtrlValue<bool> mLhbmReq; // GUARDED_BY(mBrightnessMutex) 423 CtrlValue<float> mBrightnessFloatReq; // GUARDED_BY(mBrightnessMutex) 424 CtrlValue<bool> mInstantHbmReq; // GUARDED_BY(mBrightnessMutex) 425 // states to drm after updateStates call 426 CtrlValue<uint32_t> mBrightnessLevel; // GUARDED_BY(mBrightnessMutex) 427 CtrlValue<HbmMode> mGhbm; // GUARDED_BY(mBrightnessMutex) 428 CtrlValue<bool> mDimming; // GUARDED_BY(mBrightnessMutex) 429 CtrlValue<bool> mLhbm; // GUARDED_BY(mBrightnessMutex) 430 CtrlValue<bool> mSdrDim; // GUARDED_BY(mBrightnessMutex) 431 CtrlValue<bool> mPrevSdrDim; // GUARDED_BY(mBrightnessMutex) 432 CtrlValue<bool> mDimBrightnessReq; // GUARDED_BY(mBrightnessMutex) 433 CtrlValue<uint32_t> mOperationRate; // GUARDED_BY(mBrightnessMutex) 434 435 // Indicating if the last LHBM on has changed the brightness level 436 bool mLhbmBrightnessAdj = false; 437 438 // Indicating if brightness updates are ignored 439 bool mIgnoreBrightnessUpdateRequests = false; 440 441 std::function<void(void)> mFrameRefresh; 442 CtrlValue<HdrLayerState> mHdrLayerState; 443 CtrlValue<ColorRenderIntent> mColorRenderIntent; 444 445 // these are used by sysfs path to wait drm path bl change task 446 // indicationg an unchecked LHBM change in drm path 447 std::atomic<bool> mUncheckedLhbmRequest = false; 448 std::atomic<bool> mPendingLhbmStatus = false; 449 // indicationg an unchecked GHBM change in drm path 450 std::atomic<bool> mUncheckedGbhmRequest = false; 451 std::atomic<HbmMode> mPendingGhbmStatus = HbmMode::OFF; 452 // indicating an unchecked brightness change in drm path 453 std::atomic<bool> mUncheckedBlRequest = false; 454 std::atomic<uint32_t> mPendingBl = 0; 455 456 // these are dimming related 457 BrightnessDimmingUsage mBrightnessDimmingUsage = BrightnessDimmingUsage::NORMAL; 458 bool mHbmDimming = false; // GUARDED_BY(mBrightnessMutex) 459 int32_t mHbmDimmingTimeUs = 0; 460 std::thread mDimmingThread; 461 std::atomic<bool> mDimmingThreadRunning; 462 ::android::sp<::android::Looper> mDimmingLooper; 463 ::android::sp<DimmingMsgHandler> mDimmingHandler; 464 465 // sysfs path 466 std::ofstream mBrightnessOfs; 467 uint32_t mMaxBrightness = 0; // read from sysfs 468 std::ofstream mCabcModeOfs; 469 bool mCabcSupport = false; 470 uint32_t mDimBrightness = 0; 471 472 // Note IRC or dimming is not in consideration for now. 473 float mDisplayWhitePointNits = 0; 474 float mPrevDisplayWhitePointNits = 0; 475 476 std::function<void(void)> mUpdateDcLhbm; 477 478 // state for control ACL state 479 enum class AclMode { 480 ACL_OFF = 0, 481 ACL_NORMAL, 482 ACL_ENHANCED, 483 }; 484 485 std::ofstream mAclModeOfs; 486 CtrlValue<AclMode> mAclMode; 487 AclMode mAclModeDefault = AclMode::ACL_OFF; 488 489 // state for control CABC state 490 enum class CabcMode { 491 OFF = 0, 492 CABC_UI_MODE, 493 CABC_STILL_MODE, 494 CABC_MOVIE_MODE, 495 }; 496 497 static constexpr const char* kLocalCabcModeFileNode = 498 "/sys/class/backlight/panel%d-backlight/cabc_mode"; 499 std::recursive_mutex mCabcModeMutex; 500 bool mOutdoorVisibility = false; // GUARDED_BY(mCabcModeMutex) isHdrLayerOn()501 bool isHdrLayerOn() { return mHdrLayerState.get() == HdrLayerState::kHdrLarge; } 502 CtrlValue<CabcMode> mCabcMode; // GUARDED_BY(mCabcModeMutex) 503 }; 504 505 #endif // _BRIGHTNESS_CONTROLLER_H_ 506