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 44 class DimmingMsgHandler : public virtual ::android::MessageHandler { 45 public: 46 enum { 47 MSG_QUIT, 48 MSG_DIMMING_OFF, 49 }; DimmingMsgHandler(BrightnessController * bc)50 DimmingMsgHandler(BrightnessController* bc) : mBrightnessController(bc) {} 51 void handleMessage(const Message& message) override; 52 53 private: 54 BrightnessController* mBrightnessController; 55 }; 56 57 BrightnessController(int32_t panelIndex, std::function<void(void)> refresh, 58 std::function<void(void)> updateDcLhbm); 59 ~BrightnessController(); 60 61 BrightnessController(int32_t panelIndex); 62 int initDrm(const DrmDevice& drmDevice, 63 const DrmConnector& connector); 64 65 int processEnhancedHbm(bool on); 66 int processDisplayBrightness(float bl, const nsecs_t vsyncNs, bool waitPresent = false); 67 int processLocalHbm(bool on); 68 int processDimBrightness(bool on); isDbmSupported()69 bool isDbmSupported() { return mDbmSupported; } 70 int applyPendingChangeViaSysfs(const nsecs_t vsyncNs); 71 bool validateLayerBrightness(float brightness); 72 73 /** 74 * processInstantHbm for GHBM UDFPS 75 * - on true: turn on HBM at next frame with peak brightness 76 * false: turn off HBM at next frame and use system display brightness 77 * from processDisplayBrightness 78 */ 79 int processInstantHbm(bool on); 80 81 /** 82 * updateFrameStates 83 * - hdrState: hdr layer size in this frame 84 * - sdrDim: whether any dimmed sdr layer in this frame 85 */ 86 void updateFrameStates(HdrLayerState hdrState, bool sdrDim); 87 88 /** 89 * Dim ratio to keep the sdr brightness unchange after an instant hbm on with peak brightness. 90 */ 91 float getSdrDimRatioForInstantHbm(); 92 93 void onClearDisplay(bool needModeClear); 94 95 /** 96 * apply brightness change on drm path. 97 * Note: only this path can hold the lock for a long time 98 */ 99 int prepareFrameCommit(ExynosDisplay& display, 100 const DrmConnector& connector, 101 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, 102 const bool mixedComposition, 103 bool& ghbmSync, bool& lhbmSync, bool& blSync); 104 isGhbmSupported()105 bool isGhbmSupported() { return mGhbmSupported; } isLhbmSupported()106 bool isLhbmSupported() { return mLhbmSupported; } 107 isGhbmOn()108 bool isGhbmOn() { 109 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 110 return mGhbm.get() != HbmMode::OFF; 111 } 112 isLhbmOn()113 bool isLhbmOn() { 114 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 115 return mLhbm.get(); 116 } 117 int checkSysfsStatus(const char *file, const std::vector<std::string>& expectedValue, 118 const nsecs_t timeoutNs); 119 void resetLhbmState(); 120 getBrightnessLevel()121 uint32_t getBrightnessLevel() { 122 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 123 return mBrightnessLevel.get(); 124 } 125 isDimSdr()126 bool isDimSdr() { 127 std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); 128 return mInstantHbmReq.get(); 129 } 130 getHdrLayerState()131 HdrLayerState getHdrLayerState() { 132 return mHdrLayerState.get(); 133 } 134 isSupported()135 bool isSupported() { 136 // valid mMaxBrightness means both brightness and max_brightness sysfs exist 137 return mMaxBrightness > 0; 138 } 139 140 void dump(String8 &result); 141 142 void setOutdoorVisibility(LbeState state); 143 144 int updateCabcMode(); 145 146 struct BrightnessTable { 147 float mBriStart; 148 float mBriEnd; 149 uint32_t mBklStart; 150 uint32_t mBklEnd; 151 uint32_t mNitsStart; 152 uint32_t mNitsEnd; BrightnessTableBrightnessTable153 BrightnessTable() {} BrightnessTableBrightnessTable154 BrightnessTable(const brightness_attribute &attr) 155 : mBriStart(static_cast<float>(attr.percentage.min) / 100.0f), 156 mBriEnd(static_cast<float>(attr.percentage.max) / 100.0f), 157 mBklStart(attr.level.min), 158 mBklEnd(attr.level.max), 159 mNitsStart(attr.nits.min), 160 mNitsEnd(attr.nits.max) {} 161 }; 162 getBrightnessTable()163 const BrightnessTable *getBrightnessTable() { return mBrightnessTable; } 164 165 /* 166 * WARNING: This enum is parsed by Battery Historian. Add new values, but 167 * do not modify/remove existing ones. Alternatively, consult with the 168 * Battery Historian team (b/239640926). 169 */ 170 enum class BrightnessRange : uint32_t { 171 NORMAL = 0, 172 HBM = 1, 173 MAX, 174 }; 175 176 /* 177 * WARNING: This enum is parsed by Battery Historian. Add new values, but 178 * do not modify/remove existing ones. Alternatively, consult with the 179 * Battery Historian team (b/239640926). 180 */ 181 enum class HbmMode { 182 OFF = 0, 183 ON_IRC_ON = 1, 184 ON_IRC_OFF = 2, 185 }; 186 187 /* 188 * LHBM command need take a couple of frames to become effective 189 * DISABLED - finish sending disabling command to panel 190 * ENABLED - panel finishes boosting brightness to the peak value 191 * ENABLING - finish sending enabling command to panel (panel begins boosting brightness) 192 * Note: the definition should be consistent with kernel driver 193 */ 194 enum class LhbmMode { 195 DISABLED = 0, 196 ENABLED = 1, 197 ENABLING = 2, 198 }; 199 200 /* 201 * BrightnessDimmingUsage: 202 * NORMAL- enable dimming 203 * HBM- enable dimming only for hbm transition 204 * NONE- disable dimming 205 * 206 * WARNING: This enum is parsed by Battery Historian. Add new values, but 207 * do not modify/remove existing ones. Alternatively, consult with the 208 * Battery Historian team (b/239640926). 209 */ 210 enum class BrightnessDimmingUsage { 211 NORMAL = 0, 212 HBM = 1, 213 NONE, 214 }; 215 216 static constexpr const char *kLocalHbmModeFileNode = 217 "/sys/class/backlight/panel%d-backlight/local_hbm_mode"; 218 static constexpr const char* kDimBrightnessFileNode = 219 "/sys/class/backlight/panel%d-backlight/dim_brightness"; 220 221 private: 222 // sync brightness change for mixed composition when there is more than 50% luminance change. 223 // The percentage is calculated as: 224 // (big_lumi - small_lumi) / small_lumi 225 // For mixed composition, if remove brightness animations, the minimum brightness jump is 226 // between nbm peak and hbm peak. 50% will cover known panels 227 static constexpr float kBrightnessSyncThreshold = 0.5f; 228 // Worst case for panel with brightness range 2 nits to 1000 nits. 229 static constexpr float kGhbmMinDimRatio = 0.002; 230 static constexpr int32_t kHbmDimmingTimeUs = 5000000; 231 static constexpr const char *kGlobalHbmModeFileNode = 232 "/sys/class/backlight/panel%d-backlight/hbm_mode"; 233 static constexpr const char* kDimmingUsagePropName = 234 "vendor.display.%d.brightness.dimming.usage"; 235 static constexpr const char* kDimmingHbmTimePropName = 236 "vendor.display.%d.brightness.dimming.hbm_time"; 237 238 int queryBrightness(float brightness, bool* ghbm = nullptr, uint32_t* level = nullptr, 239 float *nits = nullptr); 240 void initBrightnessTable(const DrmDevice& device, const DrmConnector& connector); 241 void initBrightnessSysfs(); 242 void initCabcSysfs(); 243 void initDimmingUsage(); 244 int applyBrightnessViaSysfs(uint32_t level); 245 int applyCabcModeViaSysfs(uint8_t mode); 246 int updateStates() REQUIRES(mBrightnessMutex); 247 void dimmingThread(); 248 void processDimmingOff(); 249 250 void parseHbmModeEnums(const DrmProperty& property); 251 252 void printBrightnessStates(const char* path) REQUIRES(mBrightnessMutex); 253 254 bool mLhbmSupported = false; 255 bool mGhbmSupported = false; 256 bool mDbmSupported = false; 257 bool mBrightnessIntfSupported = false; 258 BrightnessTable mBrightnessTable[toUnderlying(BrightnessRange::MAX)]; 259 260 int32_t mPanelIndex; 261 DrmEnumParser::MapHal2DrmEnum mHbmModeEnums; 262 263 // brightness state 264 std::recursive_mutex mBrightnessMutex; 265 // requests 266 CtrlValue<bool> mEnhanceHbmReq GUARDED_BY(mBrightnessMutex); 267 CtrlValue<bool> mLhbmReq GUARDED_BY(mBrightnessMutex); 268 CtrlValue<float> mBrightnessFloatReq GUARDED_BY(mBrightnessMutex); 269 CtrlValue<bool> mInstantHbmReq GUARDED_BY(mBrightnessMutex); 270 // states to drm after updateStates call 271 CtrlValue<uint32_t> mBrightnessLevel GUARDED_BY(mBrightnessMutex); 272 CtrlValue<HbmMode> mGhbm GUARDED_BY(mBrightnessMutex); 273 CtrlValue<bool> mDimming GUARDED_BY(mBrightnessMutex); 274 CtrlValue<bool> mLhbm GUARDED_BY(mBrightnessMutex); 275 CtrlValue<bool> mSdrDim GUARDED_BY(mBrightnessMutex); 276 CtrlValue<bool> mPrevSdrDim GUARDED_BY(mBrightnessMutex); 277 CtrlValue<bool> mDimBrightnessReq GUARDED_BY(mBrightnessMutex); 278 279 // Indicating if the last LHBM on has changed the brightness level 280 bool mLhbmBrightnessAdj = false; 281 282 std::function<void(void)> mFrameRefresh; 283 CtrlValue<HdrLayerState> mHdrLayerState; 284 285 // these are used by sysfs path to wait drm path bl change task 286 // indicationg an unchecked LHBM change in drm path 287 std::atomic<bool> mUncheckedLhbmRequest = false; 288 std::atomic<bool> mPendingLhbmStatus = false; 289 // indicationg an unchecked GHBM change in drm path 290 std::atomic<bool> mUncheckedGbhmRequest = false; 291 std::atomic<HbmMode> mPendingGhbmStatus = HbmMode::OFF; 292 // indicating an unchecked brightness change in drm path 293 std::atomic<bool> mUncheckedBlRequest = false; 294 std::atomic<uint32_t> mPendingBl = 0; 295 296 // these are dimming related 297 BrightnessDimmingUsage mBrightnessDimmingUsage = BrightnessDimmingUsage::NORMAL; 298 bool mHbmDimming GUARDED_BY(mBrightnessMutex) = false; 299 int32_t mHbmDimmingTimeUs = 0; 300 std::thread mDimmingThread; 301 std::atomic<bool> mDimmingThreadRunning; 302 ::android::sp<::android::Looper> mDimmingLooper; 303 ::android::sp<DimmingMsgHandler> mDimmingHandler; 304 305 // sysfs path 306 std::ofstream mBrightnessOfs; 307 uint32_t mMaxBrightness = 0; // read from sysfs 308 std::ofstream mCabcModeOfs; 309 bool mCabcSupport = false; 310 uint32_t mDimBrightness = 0; 311 312 // Note IRC or dimming is not in consideration for now. 313 float mDisplayWhitePointNits = 0; 314 float mPrevDisplayWhitePointNits = 0; 315 316 std::function<void(void)> mUpdateDcLhbm; 317 318 // state for control CABC state 319 enum class CabcMode { 320 OFF = 0, 321 CABC_UI_MODE, 322 CABC_STILL_MODE, 323 CABC_MOVIE_MODE, 324 }; 325 326 static constexpr const char* kLocalCabcModeFileNode = 327 "/sys/class/backlight/panel%d-backlight/cabc_mode"; 328 std::recursive_mutex mCabcModeMutex; 329 bool mOutdoorVisibility GUARDED_BY(mCabcModeMutex) = false; isHdrLayerOn()330 bool isHdrLayerOn() { return mHdrLayerState.get() == HdrLayerState::kHdrLarge; } 331 CtrlValue<CabcMode> mCabcMode GUARDED_BY(mCabcModeMutex); 332 }; 333 334 #endif // _BRIGHTNESS_CONTROLLER_H_ 335