• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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