• 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 
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