• 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     bool validateLayerBrightness(float brightness);
81 
82     /**
83      * processInstantHbm for GHBM UDFPS
84      *  - on true: turn on HBM at next frame with peak brightness
85      *       false: turn off HBM at next frame and use system display brightness
86      *              from processDisplayBrightness
87      */
88     int processInstantHbm(bool on);
89 
90     /**
91      * updateFrameStates
92      *  - hdrState: hdr layer size in this frame
93      *  - sdrDim: whether any dimmed sdr layer in this frame
94      */
95     void updateFrameStates(HdrLayerState hdrState, bool sdrDim);
96 
97     /**
98      * updateColorRenderIntent
99      *  - intent: color render intent
100      */
101     void updateColorRenderIntent(int32_t intent);
102 
103     /**
104      * Dim ratio to keep the sdr brightness unchange after an instant hbm on with peak brightness.
105      */
106     float getSdrDimRatioForInstantHbm();
107 
108     void onClearDisplay(bool needModeClear);
109 
110     /**
111      * apply brightness change on drm path.
112      * Note: only this path can hold the lock for a long time
113      */
114     int prepareFrameCommit(ExynosDisplay& display, const DrmConnector& connector,
115                            ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq,
116                            const bool mixedComposition, bool& ghbmSync, bool& lhbmSync,
117                            bool& blSync, bool& opRateSync);
118 
isGhbmSupported()119     bool isGhbmSupported() { return mGhbmSupported; }
isLhbmSupported()120     bool isLhbmSupported() { return mLhbmSupported; }
121 
isGhbmOn()122     bool isGhbmOn() {
123         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
124         return mGhbm.get() != HbmMode::OFF;
125     }
126 
isLhbmOn()127     bool isLhbmOn() {
128         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
129         return mLhbm.get();
130     }
131     int checkSysfsStatus(const std::string& file, const std::vector<std::string>& expectedValue,
132                          const nsecs_t timeoutNs);
fileExists(const std::string & file)133     bool fileExists(const std::string& file) {
134         struct stat sb;
135         return stat(file.c_str(), &sb) == 0;
136     }
137     void resetLhbmState();
138 
getBrightnessLevel()139     uint32_t getBrightnessLevel() {
140         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
141         return mBrightnessLevel.get();
142     }
143 
isDimSdr()144     bool isDimSdr() {
145         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
146         return mInstantHbmReq.get();
147     }
148 
getHdrLayerState()149     HdrLayerState getHdrLayerState() {
150         return mHdrLayerState.get();
151     }
152 
getOperationRate()153     uint32_t getOperationRate() {
154         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
155         return mOperationRate.get();
156     }
157 
isSupported()158     bool isSupported() {
159         // valid mMaxBrightness means both brightness and max_brightness sysfs exist
160         return mMaxBrightness > 0;
161     }
162 
163     void dump(String8 &result);
164 
165     void setOutdoorVisibility(LbeState state);
166 
167     int updateCabcMode();
168 
GetPanelSysfileByIndex(const char * file_pattern)169     const std::string GetPanelSysfileByIndex(const char *file_pattern) {
170         String8 nodeName;
171         nodeName.appendFormat(file_pattern, mPanelIndex);
172         return nodeName.c_str();
173     }
174 
GetPanelRefreshRateSysfile()175     const std::string GetPanelRefreshRateSysfile() {
176         String8 nodeName;
177         nodeName.appendFormat(kRefreshrateFileNode,
178                               mPanelIndex == 0           ? "primary"
179                                       : mPanelIndex == 1 ? "secondary"
180                                                          : "unknown");
181         return nodeName.c_str();
182     }
183 
184     void updateBrightnessTable(const IBrightnessTable* table);
getBrightnessRanges()185     const BrightnessRangeMap& getBrightnessRanges() const {
186         return mKernelBrightnessTable.GetBrightnessRangeMap();
187     }
188 
189     /*
190      * WARNING: This enum is parsed by Battery Historian. Add new values, but
191      *  do not modify/remove existing ones. Alternatively, consult with the
192      *  Battery Historian team (b/239640926).
193      */
194     enum class BrightnessRange : uint32_t {
195         NORMAL = 0,
196         HBM = 1,
197         MAX,
198     };
199 
200     /*
201      * WARNING: This enum is parsed by Battery Historian. Add new values, but
202      *  do not modify/remove existing ones. Alternatively, consult with the
203      *  Battery Historian team (b/239640926).
204      */
205     enum class HbmMode {
206         OFF = 0,
207         ON_IRC_ON = 1,
208         ON_IRC_OFF = 2,
209     };
210 
211     /*
212      * LHBM command need take a couple of frames to become effective
213      * DISABLED - finish sending disabling command to panel
214      * ENABLED - panel finishes boosting brightness to the peak value
215      * ENABLING - finish sending enabling command to panel (panel begins boosting brightness)
216      * Note: the definition should be consistent with kernel driver
217      */
218     enum class LhbmMode {
219         DISABLED = 0,
220         ENABLED = 1,
221         ENABLING = 2,
222     };
223 
224     /*
225      * BrightnessDimmingUsage:
226      * NORMAL- enable dimming
227      * HBM-    enable dimming only for hbm transition
228      * NONE-   disable dimming
229      *
230      * WARNING: This enum is parsed by Battery Historian. Add new values, but
231      *  do not modify/remove existing ones. Alternatively, consult with the
232      *  Battery Historian team (b/239640926).
233      */
234     enum class BrightnessDimmingUsage {
235         NORMAL = 0,
236         HBM = 1,
237         NONE,
238     };
239 
240     static constexpr const char *kLocalHbmModeFileNode =
241                 "/sys/class/backlight/panel%d-backlight/local_hbm_mode";
242     static constexpr const char* kDimBrightnessFileNode =
243             "/sys/class/backlight/panel%d-backlight/dim_brightness";
244     static constexpr const char* kRefreshrateFileNode =
245             "/sys/devices/platform/exynos-drm/%s-panel/refresh_rate";
246 
247 private:
248     // This is a backup implementation of brightness table. It would be applied only when the system
249     // failed to initiate libdisplaycolor. The complete implementation is class
250     // DisplayData::BrightnessTable
251     class LinearBrightnessTable : public IBrightnessTable {
252     public:
LinearBrightnessTable()253         LinearBrightnessTable() : mIsValid(false) {}
254         void Init(const struct brightness_capability* cap);
IsValid()255         bool IsValid() const { return mIsValid; }
GetBrightnessRangeMap()256         const BrightnessRangeMap& GetBrightnessRangeMap() const { return mBrightnessRanges; }
257 
258         /* IBrightnessTable functions */
GetBrightnessRange(BrightnessMode bm)259         std::optional<std::reference_wrapper<const DisplayBrightnessRange>> GetBrightnessRange(
260                 BrightnessMode bm) const override {
261             if (mBrightnessRanges.count(bm) == 0) {
262                 return std::nullopt;
263             }
264             return mBrightnessRanges.at(bm);
265         }
266         std::optional<float> BrightnessToNits(float brightness, BrightnessMode& bm) const override;
267         std::optional<float> NitsToBrightness(float nits) const override;
268         std::optional<float> DbvToBrightness(uint32_t dbv) const override;
269         std::optional<uint32_t> NitsToDbv(BrightnessMode bm, float nits) const override;
270         std::optional<float> DbvToNits(BrightnessMode bm, uint32_t dbv) const override;
271 
GetBrightnessMode(float brightness)272         BrightnessMode GetBrightnessMode(float brightness) const {
273             for (const auto& [mode, range] : mBrightnessRanges) {
274                 if (((!range.brightness_min_exclusive && brightness == range.brightness_min) ||
275                      brightness > range.brightness_min) &&
276                     brightness <= range.brightness_max) {
277                     return mode;
278                 }
279             }
280             // return BM_MAX if there is no matching range
281             return BrightnessMode::BM_MAX;
282         }
283 
GetBrightnessModeForNits(float nits)284         BrightnessMode GetBrightnessModeForNits(float nits) const {
285             for (const auto& [mode, range] : mBrightnessRanges) {
286                 if (nits >= range.nits_min && nits <= range.nits_max) {
287                     return mode;
288                 }
289             }
290             // return BM_INVALID if there is no matching range
291             return BrightnessMode::BM_INVALID;
292         }
293 
getBrightnessModeForDbv(uint32_t dbv)294         BrightnessMode getBrightnessModeForDbv(uint32_t dbv) const {
295             for (const auto& [mode, range] : mBrightnessRanges) {
296                 if (dbv >= range.dbv_min && dbv <= range.dbv_max) {
297                     return mode;
298                 }
299             }
300             // return BM_INVALID if there is no matching range
301             return BrightnessMode::BM_INVALID;
302         }
303 
304     private:
setBrightnessRangeFromAttribute(const struct brightness_attribute & attr,displaycolor::DisplayBrightnessRange & range)305         static void setBrightnessRangeFromAttribute(const struct brightness_attribute& attr,
306                                                     displaycolor::DisplayBrightnessRange& range) {
307             range.nits_min = attr.nits.min;
308             range.nits_max = attr.nits.max;
309             range.dbv_min = attr.level.min;
310             range.dbv_max = attr.level.max;
311             range.brightness_min_exclusive = false;
312             range.brightness_min = static_cast<float>(attr.percentage.min) / 100.0f;
313             range.brightness_max = static_cast<float>(attr.percentage.max) / 100.0f;
314         }
315         /**
316          * Implement linear interpolation/extrapolation formula:
317          *  y = y1+(y2-y1)*(x-x1)/(x2-x1)
318          * Return NAN for following cases:
319          *  - Attempt to do extrapolation when x1==x2
320          *  - Undefined output when (x2 == x1) and (y2 != y1)
321          */
LinearInterpolation(float x,float x1,float x2,float y1,float y2)322         static inline float LinearInterpolation(float x, float x1, float x2, float y1, float y2) {
323             if (x2 == x1) {
324                 if (x != x1) {
325                     ALOGE("%s: attempt to do extrapolation when x1==x2", __func__);
326                     return NAN;
327                 }
328                 if (y2 == y1) {
329                     // This is considered a normal case. (interpolation between a single point)
330                     return y1;
331                 } else {
332                     // The output is undefined when (y1!=y2)
333                     ALOGE("%s: undefined output when (x2 == x1) and (y2 != y1)", __func__);
334                     return NAN;
335                 }
336             }
337             float t = (x - x1) / (x2 - x1);
338             return y1 + (y2 - y1) * t;
339         }
SupportHBM()340         inline bool SupportHBM() const {
341             return mBrightnessRanges.count(BrightnessMode::BM_HBM) > 0;
342         }
343         bool mIsValid;
344         BrightnessRangeMap mBrightnessRanges;
345     };
346     // sync brightness change for mixed composition when there is more than 50% luminance change.
347     // The percentage is calculated as:
348     //        (big_lumi - small_lumi) / small_lumi
349     // For mixed composition, if remove brightness animations, the minimum brightness jump is
350     // between nbm peak and hbm peak. 50% will cover known panels
351     static constexpr float kBrightnessSyncThreshold = 0.5f;
352     // Worst case for panel with brightness range 2 nits to 1000 nits.
353     static constexpr float kGhbmMinDimRatio = 0.002;
354     static constexpr int32_t kHbmDimmingTimeUs = 5000000;
355     static constexpr const char *kGlobalHbmModeFileNode =
356                 "/sys/class/backlight/panel%d-backlight/hbm_mode";
357     static constexpr const char* kDimmingUsagePropName =
358             "vendor.display.%d.brightness.dimming.usage";
359     static constexpr const char* kDimmingHbmTimePropName =
360             "vendor.display.%d.brightness.dimming.hbm_time";
361     static constexpr const char* kGlobalAclModeFileNode =
362             "/sys/class/backlight/panel%d-backlight/acl_mode";
363     static constexpr const char* kAclModeDefaultPropName =
364             "vendor.display.%d.brightness.acl.default";
365 
366     int queryBrightness(float brightness, bool* ghbm = nullptr, uint32_t* level = nullptr,
367                         float *nits = nullptr);
368     void initBrightnessTable(const DrmDevice& device, const DrmConnector& connector);
369     void initBrightnessSysfs();
370     void initCabcSysfs();
371     void initDimmingUsage();
372     int applyBrightnessViaSysfs(uint32_t level);
373     int applyCabcModeViaSysfs(uint8_t mode);
374     int updateStates(); // REQUIRES(mBrightnessMutex)
375     void dimmingThread();
376     void processDimmingOff();
377     int updateAclMode();
378 
379     void parseHbmModeEnums(const DrmProperty& property);
380 
381     void printBrightnessStates(const char* path); // REQUIRES(mBrightnessMutex)
382 
383     bool mLhbmSupported = false;
384     bool mGhbmSupported = false;
385     bool mDbmSupported = false;
386     bool mBrightnessIntfSupported = false;
387     LinearBrightnessTable mKernelBrightnessTable;
388     // External object from libdisplaycolor
389     const IBrightnessTable* mBrightnessTable = nullptr;
390 
391     int32_t mPanelIndex;
392     DrmEnumParser::MapHal2DrmEnum mHbmModeEnums;
393 
394     // brightness state
395     std::recursive_mutex mBrightnessMutex;
396     // requests
397     CtrlValue<bool> mEnhanceHbmReq;       // GUARDED_BY(mBrightnessMutex)
398     CtrlValue<bool> mLhbmReq;             // GUARDED_BY(mBrightnessMutex)
399     CtrlValue<float> mBrightnessFloatReq; // GUARDED_BY(mBrightnessMutex)
400     CtrlValue<bool> mInstantHbmReq;       // GUARDED_BY(mBrightnessMutex)
401     // states to drm after updateStates call
402     CtrlValue<uint32_t> mBrightnessLevel; // GUARDED_BY(mBrightnessMutex)
403     CtrlValue<HbmMode> mGhbm;             // GUARDED_BY(mBrightnessMutex)
404     CtrlValue<bool> mDimming;             // GUARDED_BY(mBrightnessMutex)
405     CtrlValue<bool> mLhbm;                // GUARDED_BY(mBrightnessMutex)
406     CtrlValue<bool> mSdrDim;              // GUARDED_BY(mBrightnessMutex)
407     CtrlValue<bool> mPrevSdrDim;          // GUARDED_BY(mBrightnessMutex)
408     CtrlValue<bool> mDimBrightnessReq;    // GUARDED_BY(mBrightnessMutex)
409     CtrlValue<uint32_t> mOperationRate;   // GUARDED_BY(mBrightnessMutex)
410 
411     // Indicating if the last LHBM on has changed the brightness level
412     bool mLhbmBrightnessAdj = false;
413 
414     // Indicating if brightness updates are ignored
415     bool mIgnoreBrightnessUpdateRequests = false;
416 
417     std::function<void(void)> mFrameRefresh;
418     CtrlValue<HdrLayerState> mHdrLayerState;
419     CtrlValue<ColorRenderIntent> mColorRenderIntent;
420 
421     // these are used by sysfs path to wait drm path bl change task
422     // indicationg an unchecked LHBM change in drm path
423     std::atomic<bool> mUncheckedLhbmRequest = false;
424     std::atomic<bool> mPendingLhbmStatus = false;
425     // indicationg an unchecked GHBM change in drm path
426     std::atomic<bool> mUncheckedGbhmRequest = false;
427     std::atomic<HbmMode> mPendingGhbmStatus = HbmMode::OFF;
428     // indicating an unchecked brightness change in drm path
429     std::atomic<bool> mUncheckedBlRequest = false;
430     std::atomic<uint32_t> mPendingBl = 0;
431 
432     // these are dimming related
433     BrightnessDimmingUsage mBrightnessDimmingUsage = BrightnessDimmingUsage::NORMAL;
434     bool mHbmDimming = false; // GUARDED_BY(mBrightnessMutex)
435     int32_t mHbmDimmingTimeUs = 0;
436     std::thread mDimmingThread;
437     std::atomic<bool> mDimmingThreadRunning;
438     ::android::sp<::android::Looper> mDimmingLooper;
439     ::android::sp<DimmingMsgHandler> mDimmingHandler;
440 
441     // sysfs path
442     std::ofstream mBrightnessOfs;
443     uint32_t mMaxBrightness = 0; // read from sysfs
444     std::ofstream mCabcModeOfs;
445     bool mCabcSupport = false;
446     uint32_t mDimBrightness = 0;
447 
448     // Note IRC or dimming is not in consideration for now.
449     float mDisplayWhitePointNits = 0;
450     float mPrevDisplayWhitePointNits = 0;
451 
452     std::function<void(void)> mUpdateDcLhbm;
453 
454     // state for control ACL state
455     enum class AclMode {
456         ACL_OFF = 0,
457         ACL_NORMAL,
458         ACL_ENHANCED,
459     };
460 
461     std::ofstream mAclModeOfs;
462     CtrlValue<AclMode> mAclMode;
463     AclMode mAclModeDefault = AclMode::ACL_OFF;
464 
465     // state for control CABC state
466     enum class CabcMode {
467         OFF = 0,
468         CABC_UI_MODE,
469         CABC_STILL_MODE,
470         CABC_MOVIE_MODE,
471     };
472 
473     static constexpr const char* kLocalCabcModeFileNode =
474             "/sys/class/backlight/panel%d-backlight/cabc_mode";
475     std::recursive_mutex mCabcModeMutex;
476     bool mOutdoorVisibility = false; // GUARDED_BY(mCabcModeMutex)
isHdrLayerOn()477     bool isHdrLayerOn() { return mHdrLayerState.get() == HdrLayerState::kHdrLarge; }
478     CtrlValue<CabcMode> mCabcMode; // GUARDED_BY(mCabcModeMutex)
479 };
480 
481 #endif // _BRIGHTNESS_CONTROLLER_H_
482