• 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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
18 
19 #include <cutils/properties.h>
20 #include <poll.h>
21 
22 #include "BrightnessController.h"
23 #include "ExynosHWCModule.h"
24 
Init(const struct brightness_capability * cap)25 void BrightnessController::LinearBrightnessTable::Init(const struct brightness_capability* cap) {
26     if (!cap) {
27         return;
28     }
29     setBrightnessRangeFromAttribute(cap->normal, mBrightnessRanges[BrightnessMode::BM_NOMINAL]);
30     setBrightnessRangeFromAttribute(cap->hbm, mBrightnessRanges[BrightnessMode::BM_HBM]);
31     if (mBrightnessRanges[BrightnessMode::BM_NOMINAL].brightness_max ==
32         mBrightnessRanges[BrightnessMode::BM_HBM].brightness_min) {
33         mBrightnessRanges[BrightnessMode::BM_HBM].brightness_min_exclusive = true;
34     }
35     if (!mBrightnessRanges.at(BrightnessMode::BM_NOMINAL).IsValid()) {
36         ALOGE("%s: brightness range for BM_NOMINAL is invalid!", __func__);
37         return;
38     }
39     //  BM_HBM range is optional for some devices
40     if (mBrightnessRanges.count(BrightnessMode::BM_HBM) > 0) {
41         if (!mBrightnessRanges.at(BrightnessMode::BM_HBM).IsValid()) {
42             ALOGE("%s: brightness range for BM_HBM is invalid!", __func__);
43             return;
44         }
45     }
46     mIsValid = true;
47 }
48 
NitsToBrightness(float nits) const49 std::optional<float> BrightnessController::LinearBrightnessTable::NitsToBrightness(
50         float nits) const {
51     BrightnessMode mode = GetBrightnessModeForNits(nits);
52     if (mode == BrightnessMode::BM_INVALID) {
53         return std::nullopt;
54     }
55 
56     const DisplayBrightnessRange& range = mBrightnessRanges.at(mode);
57     const float brightness = LinearInterpolation(nits,
58         range.nits_min, range.nits_max,
59         range.brightness_min, range.brightness_max);
60     if (isnan(brightness)) {
61         return std::nullopt;
62     }
63 
64     return brightness;
65 }
66 
DbvToBrightness(uint32_t dbv) const67 std::optional<float> BrightnessController::LinearBrightnessTable::DbvToBrightness(
68         uint32_t dbv) const {
69     BrightnessMode bm = getBrightnessModeForDbv(dbv);
70     if (bm == BrightnessMode::BM_INVALID) {
71         return std::nullopt;
72     }
73 
74     std::optional<float> nits = DbvToNits(bm, dbv);
75     if (nits == std::nullopt) {
76         return std::nullopt;
77     }
78 
79     return NitsToBrightness(nits.value());
80 }
81 
BrightnessToNits(float brightness,BrightnessMode & bm) const82 std::optional<float> BrightnessController::LinearBrightnessTable::BrightnessToNits(
83         float brightness, BrightnessMode& bm) const {
84     bm = GetBrightnessMode(brightness);
85     if (bm == BrightnessMode::BM_MAX) {
86         return std::nullopt;
87     }
88     const DisplayBrightnessRange& range = mBrightnessRanges.at(bm);
89     float nits = LinearInterpolation(brightness, range.brightness_min, range.brightness_max,
90                                      range.nits_min, range.nits_max);
91     if (isnan(nits)) {
92         return std::nullopt;
93     }
94 
95     return nits;
96 }
97 
NitsToDbv(BrightnessMode bm,float nits) const98 std::optional<uint32_t> BrightnessController::LinearBrightnessTable::NitsToDbv(BrightnessMode bm,
99                                                                                float nits) const {
100     if (mBrightnessRanges.count(bm) == 0) {
101         return std::nullopt;
102     }
103     const auto& range = mBrightnessRanges.at(bm);
104     float dbv = 0.0;
105 
106     dbv = LinearInterpolation(nits, range.nits_min, range.nits_max, range.dbv_min, range.dbv_max);
107     if (isnan(dbv) || dbv < 0) {
108         return std::nullopt;
109     }
110     return lround(dbv);
111 }
112 
DbvToNits(BrightnessMode bm,uint32_t dbv) const113 std::optional<float> BrightnessController::LinearBrightnessTable::DbvToNits(BrightnessMode bm,
114                                                                             uint32_t dbv) const {
115     if (mBrightnessRanges.count(bm) == 0) {
116         return std::nullopt;
117     }
118     const auto& range = mBrightnessRanges.at(bm);
119     float nits = 0.0;
120 
121     nits = LinearInterpolation(dbv, range.dbv_min, range.dbv_max, range.nits_min, range.nits_max);
122     if (isnan(nits)) {
123         return std::nullopt;
124     }
125     return nits;
126 }
127 
BrightnessController(int32_t panelIndex,std::function<void (void)> refresh,std::function<void (void)> updateDcLhbm)128 BrightnessController::BrightnessController(int32_t panelIndex, std::function<void(void)> refresh,
129                                            std::function<void(void)> updateDcLhbm)
130       : mPanelIndex(panelIndex),
131         mEnhanceHbmReq(false),
132         mLhbmReq(false),
133         mBrightnessFloatReq(-1),
134         mBrightnessLevel(0),
135         mGhbm(HbmMode::OFF),
136         mDimming(false),
137         mLhbm(false),
138         mSdrDim(false),
139         mPrevSdrDim(false),
140         mDimBrightnessReq(false),
141         mOperationRate(0),
142         mFrameRefresh(refresh),
143         mHdrLayerState(HdrLayerState::kHdrNone),
144         mUpdateDcLhbm(updateDcLhbm) {
145     initBrightnessSysfs();
146     initCabcSysfs();
147 }
148 
~BrightnessController()149 BrightnessController::~BrightnessController() {
150     if (mDimmingLooper) {
151         mDimmingLooper->removeMessages(mDimmingHandler);
152     }
153     if (mDimmingThreadRunning) {
154         mDimmingLooper->sendMessage(mDimmingHandler, DimmingMsgHandler::MSG_QUIT);
155         mDimmingThread.join();
156     }
157 }
158 
updateBrightnessTable(std::unique_ptr<const IBrightnessTable> & table)159 void BrightnessController::updateBrightnessTable(std::unique_ptr<const IBrightnessTable>& table) {
160     if (table && table->GetBrightnessRange(BrightnessMode::BM_NOMINAL)) {
161         ALOGI("%s: apply brightness table from libdisplaycolor", __func__);
162         mBrightnessTable = std::move(table);
163     } else {
164         ALOGW("%s: table is not valid!", __func__);
165     }
166     if (!mBrightnessTable) {
167         ALOGE("%s: brightness table is not available!", __func__);
168         return;
169     }
170     auto normal_range = mBrightnessTable->GetBrightnessRange(BrightnessMode::BM_NOMINAL);
171     if (!normal_range) {
172         ALOGE("%s: normal brightness range not available!", __func__);
173         return;
174     }
175 
176     // init to min before SF sets the brightness
177     mDisplayWhitePointNits = normal_range.value().get().nits_min;
178     mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
179     mBrightnessIntfSupported = true;
180 
181     String8 nodeName;
182     nodeName.appendFormat(kDimBrightnessFileNode, mPanelIndex);
183 
184     std::ifstream ifsDimBrightness(nodeName.c_str());
185     if (ifsDimBrightness.fail()) {
186         ALOGW("%s fail to open %s", __func__, nodeName.c_str());
187     } else {
188         ifsDimBrightness >> mDimBrightness;
189         ifsDimBrightness.close();
190         if (mDimBrightness >= normal_range.value().get().dbv_min) mDimBrightness = 0;
191     }
192     mDbmSupported = !!mDimBrightness;
193     ALOGI("%s mDimBrightness=%d, mDbmSupported=%d", __func__, mDimBrightness, mDbmSupported);
194 }
195 
initDrm(const DrmDevice & drmDevice,const DrmConnector & connector)196 int BrightnessController::initDrm(const DrmDevice& drmDevice, const DrmConnector& connector) {
197     initBrightnessTable(drmDevice, connector);
198 
199     initDimmingUsage();
200 
201     mLhbmSupported = connector.lhbm_on().id() != 0;
202     mGhbmSupported = connector.hbm_mode().id() != 0;
203 
204     /* allow the first brightness to apply */
205     mBrightnessFloatReq.set_dirty();
206     return NO_ERROR;
207 }
208 
initDimmingUsage()209 void BrightnessController::initDimmingUsage() {
210     String8 propName;
211     propName.appendFormat(kDimmingUsagePropName, mPanelIndex);
212 
213     mBrightnessDimmingUsage =
214             static_cast<BrightnessDimmingUsage>(property_get_int32(propName.c_str(), 0));
215 
216     propName.clear();
217     propName.appendFormat(kDimmingHbmTimePropName, mPanelIndex);
218     mHbmDimmingTimeUs = property_get_int32(propName.c_str(), kHbmDimmingTimeUs);
219 
220     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) {
221         mDimming.store(true);
222     }
223 
224     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::HBM) {
225         mDimmingHandler = new DimmingMsgHandler(this);
226         mDimmingThread = std::thread(&BrightnessController::dimmingThread, this);
227     }
228 }
229 
initBrightnessSysfs()230 void BrightnessController::initBrightnessSysfs() {
231     String8 nodeName;
232     nodeName.appendFormat(BRIGHTNESS_SYSFS_NODE, mPanelIndex);
233     mBrightnessOfs.open(nodeName.c_str(), std::ofstream::out);
234     if (mBrightnessOfs.fail()) {
235         ALOGE("%s %s fail to open", __func__, nodeName.c_str());
236         return;
237     }
238 
239     nodeName.clear();
240     nodeName.appendFormat(MAX_BRIGHTNESS_SYSFS_NODE, mPanelIndex);
241 
242     std::ifstream ifsMaxBrightness(nodeName.c_str());
243     if (ifsMaxBrightness.fail()) {
244         ALOGE("%s fail to open %s", __func__, nodeName.c_str());
245         return;
246     }
247 
248     ifsMaxBrightness >> mMaxBrightness;
249     ifsMaxBrightness.close();
250 
251     nodeName.clear();
252     nodeName.appendFormat(kGlobalAclModeFileNode, mPanelIndex);
253     mAclModeOfs.open(nodeName.c_str(), std::ofstream::out);
254     if (mAclModeOfs.fail()) {
255         ALOGI("%s %s not supported", __func__, nodeName.c_str());
256     } else {
257         String8 propName;
258         propName.appendFormat(kAclModeDefaultPropName, mPanelIndex);
259 
260         mAclModeDefault = static_cast<AclMode>(property_get_int32(propName, 0));
261         mAclMode.set_dirty();
262     }
263 }
264 
initCabcSysfs()265 void BrightnessController::initCabcSysfs() {
266     mCabcSupport = property_get_bool("vendor.display.cabc.supported", false);
267     if (!mCabcSupport) return;
268 
269     String8 nodeName;
270     nodeName.appendFormat(kLocalCabcModeFileNode, mPanelIndex);
271 
272     mCabcModeOfs.open(nodeName.c_str(), std::ofstream::out);
273     if (mCabcModeOfs.fail()) {
274         ALOGE("%s %s fail to open", __func__, nodeName.c_str());
275         return;
276     }
277 }
278 
initBrightnessTable(const DrmDevice & drmDevice,const DrmConnector & connector)279 void BrightnessController::initBrightnessTable(const DrmDevice& drmDevice,
280                                                const DrmConnector& connector) {
281     if (connector.brightness_cap().id() == 0) {
282         ALOGD("the brightness_cap is not supported");
283         return;
284     }
285 
286     const auto [ret, blobId] = connector.brightness_cap().value();
287     if (ret) {
288         ALOGE("Fail to get brightness_cap (ret = %d)", ret);
289         return;
290     }
291 
292     if (blobId == 0) {
293         ALOGE("the brightness_cap is supported but blob is not valid");
294         return;
295     }
296 
297     drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(drmDevice.fd(), blobId);
298     if (blob == nullptr) {
299         ALOGE("Fail to get brightness_cap blob");
300         return;
301     }
302 
303     const struct brightness_capability *cap =
304             reinterpret_cast<struct brightness_capability *>(blob->data);
305     mKernelBrightnessTable.Init(cap);
306     if (mKernelBrightnessTable.IsValid()) {
307         mBrightnessTable = std::make_unique<LinearBrightnessTable>(mKernelBrightnessTable);
308     }
309 
310     parseHbmModeEnums(connector.hbm_mode());
311 
312     drmModeFreePropertyBlob(blob);
313 }
314 
processEnhancedHbm(bool on)315 int BrightnessController::processEnhancedHbm(bool on) {
316     if (!mGhbmSupported) {
317         return HWC2_ERROR_UNSUPPORTED;
318     }
319 
320     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
321     mEnhanceHbmReq.store(on);
322     if (mEnhanceHbmReq.is_dirty()) {
323         updateStates();
324     }
325     return NO_ERROR;
326 }
327 
processDimmingOff()328 void BrightnessController::processDimmingOff() {
329     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
330     if (mHbmDimming) {
331         mHbmDimming = false;
332         updateStates();
333         mFrameRefresh();
334     }
335 }
336 
updateAclMode()337 int BrightnessController::updateAclMode() {
338     if (!mAclModeOfs.is_open()) return HWC2_ERROR_UNSUPPORTED;
339 
340     if (mColorRenderIntent.get() == ColorRenderIntent::COLORIMETRIC) {
341         mAclMode.store(AclMode::ACL_ENHANCED);
342     } else {
343         mAclMode.store(mAclModeDefault);
344     }
345 
346     if (applyAclViaSysfs() == HWC2_ERROR_NO_RESOURCES)
347         ALOGW("%s try to apply acl_mode when brightness changed", __func__);
348 
349     return NO_ERROR;
350 }
351 
applyAclViaSysfs()352 int BrightnessController::applyAclViaSysfs() {
353     if (!mAclModeOfs.is_open()) return NO_ERROR;
354     if (!mAclMode.is_dirty()) return NO_ERROR;
355 
356     mAclModeOfs.seekp(std::ios_base::beg);
357     mAclModeOfs << std::to_string(static_cast<uint8_t>(mAclMode.get()));
358     mAclModeOfs.flush();
359     if (mAclModeOfs.fail()) {
360         ALOGW("%s write acl_mode to %d error = %s", __func__, mAclMode.get(), strerror(errno));
361         mAclModeOfs.clear();
362         return HWC2_ERROR_NO_RESOURCES;
363     }
364 
365     mAclMode.clear_dirty();
366     ALOGI("%s acl_mode = %d", __func__, mAclMode.get());
367 
368     return NO_ERROR;
369 }
370 
processDisplayBrightness(float brightness,const nsecs_t vsyncNs,bool waitPresent)371 int BrightnessController::processDisplayBrightness(float brightness, const nsecs_t vsyncNs,
372                                                    bool waitPresent) {
373     uint32_t level;
374     bool ghbm;
375 
376     if (mIgnoreBrightnessUpdateRequests) {
377         ALOGI("%s: Brightness update is ignored. requested: %f, current: %f",
378             __func__, brightness, mBrightnessFloatReq.get());
379         return NO_ERROR;
380     }
381 
382     if (brightness < -1.0f || brightness > 1.0f) {
383         return HWC2_ERROR_BAD_PARAMETER;
384     }
385 
386     ATRACE_CALL();
387 
388     /* update ACL */
389     if (applyAclViaSysfs() == HWC2_ERROR_NO_RESOURCES)
390         ALOGE("%s failed to apply acl_mode", __func__);
391 
392     if (!mBrightnessIntfSupported) {
393         level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f);
394         return applyBrightnessViaSysfs(level);
395     }
396 
397     {
398         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
399         /* apply the first brightness */
400         if (mBrightnessFloatReq.is_dirty()) mBrightnessLevel.set_dirty();
401 
402         mBrightnessFloatReq.store(brightness);
403         if (!mBrightnessFloatReq.is_dirty()) {
404             return NO_ERROR;
405         }
406 
407         // check if it will go drm path for below cases.
408         // case 1: hbm state will change
409         // case 2: for hwc3, brightness command could apply at next present if possible
410         if (queryBrightness(brightness, &ghbm, &level) == NO_ERROR) {
411             // ghbm on/off always go drm path
412             // check if this will cause a hbm transition
413             if (mGhbmSupported && (mGhbm.get() != HbmMode::OFF) != ghbm) {
414                 // this brightness change will go drm path
415                 updateStates();
416                 mFrameRefresh(); // force next frame to update brightness
417                 return NO_ERROR;
418             }
419             // there will be a Present to apply this brightness change
420             if (waitPresent) {
421                 // this brightness change will go drm path
422                 updateStates();
423                 return NO_ERROR;
424             }
425         } else {
426             level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f);
427         }
428         // clear dirty before go sysfs path
429         mBrightnessFloatReq.clear_dirty();
430     }
431 
432     // Sysfs path is faster than drm path. If there is an unchecked drm path change, the sysfs
433     // path should check the sysfs content.
434     if (mUncheckedGbhmRequest) {
435         ATRACE_NAME("check_ghbm_mode");
436         checkSysfsStatus(GetPanelSysfileByIndex(kGlobalHbmModeFileNode),
437                          {std::to_string(toUnderlying(mPendingGhbmStatus.load()))}, vsyncNs * 5);
438         mUncheckedGbhmRequest = false;
439     }
440 
441     if (mUncheckedLhbmRequest) {
442         ATRACE_NAME("check_lhbm_mode");
443         checkSysfsStatus(GetPanelSysfileByIndex(kLocalHbmModeFileNode),
444                          {std::to_string(mPendingLhbmStatus)}, vsyncNs * 5);
445         mUncheckedLhbmRequest = false;
446     }
447 
448     return applyBrightnessViaSysfs(level);
449 }
450 
ignoreBrightnessUpdateRequests(bool ignore)451 int BrightnessController::ignoreBrightnessUpdateRequests(bool ignore) {
452     mIgnoreBrightnessUpdateRequests = ignore;
453 
454     return NO_ERROR;
455 }
456 
setBrightnessNits(float nits,const nsecs_t vsyncNs)457 int BrightnessController::setBrightnessNits(float nits, const nsecs_t vsyncNs) {
458     ALOGI("%s set brightness to %f nits", __func__,  nits);
459 
460     std::optional<float> brightness = mBrightnessTable ?
461         mBrightnessTable->NitsToBrightness(nits) : std::nullopt;
462 
463     if (brightness == std::nullopt) {
464         ALOGI("%s could not find brightness for %f nits", __func__, nits);
465         return -EINVAL;
466     }
467 
468     return processDisplayBrightness(brightness.value(), vsyncNs);
469 }
470 
setBrightnessDbv(uint32_t dbv,const nsecs_t vsyncNs)471 int BrightnessController::setBrightnessDbv(uint32_t dbv, const nsecs_t vsyncNs) {
472     ALOGI("%s set brightness to %u dbv", __func__, dbv);
473 
474     std::optional<float> brightness =
475             mBrightnessTable ? mBrightnessTable->DbvToBrightness(dbv) : std::nullopt;
476 
477     if (brightness == std::nullopt) {
478         ALOGI("%s could not find brightness for %d dbv", __func__, dbv);
479         return -EINVAL;
480     }
481 
482     return processDisplayBrightness(brightness.value(), vsyncNs);
483 }
484 
485 // In HWC3, brightness change could be applied via drm commit or sysfs path.
486 // If a brightness change command does not come with a frame update, this
487 // function wil be called to apply the brghtness change via sysfs path.
applyPendingChangeViaSysfs(const nsecs_t vsyncNs)488 int BrightnessController::applyPendingChangeViaSysfs(const nsecs_t vsyncNs) {
489     ATRACE_CALL();
490     uint32_t level;
491     {
492         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
493 
494         if (!mBrightnessLevel.is_dirty()) {
495             return NO_ERROR;
496         }
497 
498         // there will be a drm commit to apply this brightness change if a GHBM change is pending.
499         if (mGhbm.is_dirty()) {
500             ALOGI("%s standalone brightness change will be handled by next frame update for GHBM",
501                   __func__);
502             return NO_ERROR;
503         }
504 
505         // there will be a drm commit to apply this brightness change if a LHBM change is pending.
506         if (mLhbm.is_dirty()) {
507             ALOGI("%s standalone brightness change will be handled by next frame update for LHBM",
508                   __func__);
509             return NO_ERROR;
510         }
511 
512         // there will be a drm commit to apply this brightness change if a operation rate change is
513         // pending.
514         if (mOperationRate.is_dirty()) {
515             ALOGI("%s standalone brightness change will be handled by next frame update for "
516                   "operation rate",
517                   __func__);
518             return NO_ERROR;
519         }
520 
521         level = mBrightnessLevel.get();
522     }
523 
524     if (mUncheckedBlRequest) {
525         ATRACE_NAME("check_bl_value");
526         checkSysfsStatus(GetPanelSysfileByIndex(BRIGHTNESS_SYSFS_NODE),
527                          {std::to_string(mPendingBl)}, vsyncNs * 5);
528         mUncheckedBlRequest = false;
529     }
530 
531     return applyBrightnessViaSysfs(level);
532 }
533 
processLocalHbm(bool on)534 int BrightnessController::processLocalHbm(bool on) {
535     if (!mLhbmSupported) {
536         return HWC2_ERROR_UNSUPPORTED;
537     }
538 
539     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
540     mLhbmReq.store(on);
541     // As kernel timeout timer might disable LHBM without letting HWC know, enforce mLhbmReq and
542     // mLhbm dirty to ensure the enabling request can be passed through kernel unconditionally.
543     // TODO-b/260915350: move LHBM timeout mechanism from kernel to HWC for easier control and sync.
544     if (on) {
545         mLhbmReq.set_dirty();
546         mLhbm.set_dirty();
547     }
548     if (mLhbmReq.is_dirty()) {
549         updateStates();
550     }
551 
552     return NO_ERROR;
553 }
554 
updateFrameStates(HdrLayerState hdrState,bool sdrDim)555 void BrightnessController::updateFrameStates(HdrLayerState hdrState, bool sdrDim) {
556     mHdrLayerState.store(hdrState);
557     if (!mGhbmSupported) {
558         return;
559     }
560 
561     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
562     mPrevSdrDim.store(mSdrDim.get());
563     mSdrDim.store(sdrDim);
564     if (mSdrDim.is_dirty() || mPrevSdrDim.is_dirty()) {
565         updateStates();
566     }
567 }
568 
updateColorRenderIntent(int32_t intent)569 void BrightnessController::updateColorRenderIntent(int32_t intent) {
570     mColorRenderIntent.store(static_cast<ColorRenderIntent>(intent));
571     if (mColorRenderIntent.is_dirty()) {
572         updateAclMode();
573         ALOGI("%s Color Render Intent = %d", __func__, mColorRenderIntent.get());
574         mColorRenderIntent.clear_dirty();
575     }
576 }
577 
processInstantHbm(bool on)578 int BrightnessController::processInstantHbm(bool on) {
579     if (!mGhbmSupported) {
580         return HWC2_ERROR_UNSUPPORTED;
581     }
582 
583     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
584     mInstantHbmReq.store(on);
585     if (mInstantHbmReq.is_dirty()) {
586         updateStates();
587     }
588     return NO_ERROR;
589 }
590 
processDimBrightness(bool on)591 int BrightnessController::processDimBrightness(bool on) {
592     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
593     mDimBrightnessReq.store(on);
594     if (mDimBrightnessReq.is_dirty()) {
595         updateStates();
596         ALOGI("%s request = %d", __func__, mDimBrightnessReq.get());
597     }
598     return NO_ERROR;
599 }
600 
getSdrDimRatioForInstantHbm()601 float BrightnessController::getSdrDimRatioForInstantHbm() {
602     if (!mBrightnessIntfSupported || !mGhbmSupported) {
603         return 1.0f;
604     }
605 
606     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
607     if (!mInstantHbmReq.get()) {
608         return 1.0f;
609     }
610 
611     float sdr = 0;
612     if (queryBrightness(mBrightnessFloatReq.get(), nullptr, nullptr, &sdr) != NO_ERROR) {
613         return 1.0f;
614     }
615 
616     auto hbm_range = mBrightnessTable->GetBrightnessRange(BrightnessMode::BM_HBM);
617     if (!hbm_range) {
618         ALOGE("%s error HBM brightness range not available!", __func__);
619         return 1.0f;
620     }
621     float peak = hbm_range.value().get().nits_max;
622     if (sdr == 0 || peak == 0) {
623         ALOGW("%s error luminance value sdr %f peak %f", __func__, sdr, peak);
624         return 1.0f;
625     }
626 
627     float ratio = sdr / peak;
628     if (ratio < kGhbmMinDimRatio) {
629         ALOGW("%s sdr dim ratio %f too small", __func__, ratio);
630         ratio = kGhbmMinDimRatio;
631     }
632 
633     return ratio;
634 }
635 
processOperationRate(int32_t hz)636 int BrightnessController::processOperationRate(int32_t hz) {
637     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
638     if (mOperationRate.get() != hz) {
639         ATRACE_CALL();
640         ALOGI("%s: store operation rate %d", __func__, hz);
641         mOperationRate.set_dirty();
642         mOperationRate.store(hz);
643         updateStates();
644     }
645 
646     return NO_ERROR;
647 }
648 
onClearDisplay(bool needModeClear)649 void BrightnessController::onClearDisplay(bool needModeClear) {
650     resetLhbmState();
651     mInstantHbmReq.reset(false);
652 
653     if (mBrightnessLevel.is_dirty()) applyBrightnessViaSysfs(mBrightnessLevel.get());
654 
655     if (!needModeClear) return;
656 
657     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
658     mEnhanceHbmReq.reset(false);
659     mBrightnessFloatReq.reset(-1);
660 
661     mBrightnessLevel.reset(0);
662     mDisplayWhitePointNits = 0;
663     mPrevDisplayWhitePointNits = 0;
664     mGhbm.reset(HbmMode::OFF);
665     mDimming.reset(false);
666     mHbmDimming = false;
667     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) {
668         mDimming.store(true);
669     }
670     mOperationRate.reset(0);
671 
672     std::lock_guard<std::recursive_mutex> lock1(mCabcModeMutex);
673     mCabcMode.reset(CabcMode::OFF);
674 }
675 
prepareFrameCommit(ExynosDisplay & display,const DrmConnector & connector,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const bool mixedComposition,bool & ghbmSync,bool & lhbmSync,bool & blSync,bool & opRateSync)676 int BrightnessController::prepareFrameCommit(ExynosDisplay& display, const DrmConnector& connector,
677                                              ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq,
678                                              const bool mixedComposition, bool& ghbmSync,
679                                              bool& lhbmSync, bool& blSync, bool& opRateSync) {
680     int ret;
681 
682     ghbmSync = false;
683     lhbmSync = false;
684     blSync = false;
685     opRateSync = false;
686 
687     ATRACE_CALL();
688     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
689 
690     bool sync = false;
691     if (mixedComposition && mPrevDisplayWhitePointNits > 0 && mDisplayWhitePointNits > 0) {
692         float diff = std::abs(mPrevDisplayWhitePointNits - mDisplayWhitePointNits);
693         float min = std::min(mPrevDisplayWhitePointNits, mDisplayWhitePointNits);
694         if (diff / min > kBrightnessSyncThreshold) {
695             sync = true;
696             ALOGD("%s: enable brightness sync for change from %f to %f", __func__,
697                   mPrevDisplayWhitePointNits, mDisplayWhitePointNits);
698         }
699     }
700 
701     if (mDimming.is_dirty()) {
702         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.dimming_on(),
703                                             mDimming.get())) < 0) {
704             ALOGE("%s: Fail to set dimming_on property", __func__);
705         }
706         mDimming.clear_dirty();
707     }
708 
709     if (mLhbm.is_dirty() && mLhbmSupported) {
710         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.lhbm_on(),
711                                             mLhbm.get())) < 0) {
712             ALOGE("%s: Fail to set lhbm_on property", __func__);
713         } else {
714             lhbmSync = true;
715         }
716 
717         auto dbv = mBrightnessLevel.get();
718         auto old_dbv = dbv;
719         if (mLhbm.get()) {
720             mUpdateDcLhbm();
721             uint32_t dbv_adj = 0;
722             if (display.getColorAdjustedDbv(dbv_adj)) {
723                 ALOGW("failed to get adjusted dbv");
724             } else if (dbv_adj != dbv && dbv_adj != 0) {
725                 if (mBrightnessTable) {
726                     auto normal_range =
727                             mBrightnessTable->GetBrightnessRange(BrightnessMode::BM_NOMINAL);
728                     if (normal_range) {
729                         dbv_adj = std::clamp(dbv_adj, normal_range.value().get().dbv_min,
730                                              normal_range.value().get().dbv_max);
731                     }
732                 }
733                 ALOGI("lhbm: adjust dbv from %d to %d", dbv, dbv_adj);
734                 dbv = dbv_adj;
735                 mLhbmBrightnessAdj = (dbv != old_dbv);
736             }
737         }
738 
739         if (mLhbmBrightnessAdj) {
740             // case 1: lhbm on and dbv is changed, use the new dbv
741             // case 2: lhbm off and dbv was changed at lhbm on, use current dbv
742             if ((ret = drmReq.atomicAddProperty(connector.id(),
743                                                connector.brightness_level(), dbv)) < 0) {
744                 ALOGE("%s: Fail to set brightness_level property", __func__);
745             } else {
746                 blSync = true;
747                 mUncheckedBlRequest = true;
748                 mPendingBl = dbv;
749             }
750         }
751 
752         // mLhbmBrightnessAdj will last from LHBM on to off
753         if (!mLhbm.get() && mLhbmBrightnessAdj) {
754             mLhbmBrightnessAdj = false;
755         }
756 
757         mLhbm.clear_dirty();
758     }
759 
760     if (mBrightnessLevel.is_dirty()) {
761         // skip if lhbm has updated bl
762         if (!blSync) {
763             if ((ret = drmReq.atomicAddProperty(connector.id(),
764                                                 connector.brightness_level(),
765                                                 mBrightnessLevel.get())) < 0) {
766                 ALOGE("%s: Fail to set brightness_level property", __func__);
767             } else {
768                 mUncheckedBlRequest = true;
769                 mPendingBl = mBrightnessLevel.get();
770                 blSync = sync;
771             }
772         }
773         mBrightnessLevel.clear_dirty();
774         mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
775     }
776 
777     if (mGhbm.is_dirty() && mGhbmSupported) {
778         HbmMode hbmMode = mGhbm.get();
779         auto [hbmEnum, ret] = DrmEnumParser::halToDrmEnum(static_cast<int32_t>(hbmMode),
780                                                           mHbmModeEnums);
781         if (ret < 0) {
782             ALOGE("Fail to convert hbm mode(%d)", hbmMode);
783             return ret;
784         }
785 
786         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.hbm_mode(),
787                                             hbmEnum)) < 0) {
788             ALOGE("%s: Fail to set hbm_mode property", __func__);
789         } else {
790             ghbmSync = sync;
791         }
792         mGhbm.clear_dirty();
793     }
794 
795     mHdrLayerState.clear_dirty();
796 
797     if (mOperationRate.is_dirty()) {
798         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.operation_rate(),
799                                             mOperationRate.get())) < 0) {
800             ALOGE("%s: Fail to set operation_rate property", __func__);
801         } else {
802             opRateSync = sync;
803         }
804         mOperationRate.clear_dirty();
805     }
806 
807     return NO_ERROR;
808 }
809 
handleMessage(const::android::Message & message)810 void BrightnessController::DimmingMsgHandler::handleMessage(const ::android::Message& message) {
811     ALOGI("%s %d", __func__, message.what);
812 
813     switch (message.what) {
814         case MSG_DIMMING_OFF:
815             mBrightnessController->processDimmingOff();
816             break;
817 
818         case MSG_QUIT:
819             mBrightnessController->mDimmingThreadRunning = false;
820             break;
821     }
822 }
823 
dimmingThread()824 void BrightnessController::dimmingThread() {
825     mDimmingLooper = new Looper(false);
826     Looper::setForThread(mDimmingLooper);
827     mDimmingThreadRunning = true;
828     while (mDimmingThreadRunning.load(std::memory_order_relaxed)) {
829         mDimmingLooper->pollOnce(-1);
830     }
831 }
832 
833 // Process all requests to update states for next commit
updateStates()834 int BrightnessController::updateStates() {
835     bool ghbm;
836     uint32_t level;
837     float brightness = mInstantHbmReq.get() ? 1.0f : mBrightnessFloatReq.get();
838     if (queryBrightness(brightness, &ghbm, &level, &mDisplayWhitePointNits)) {
839         ALOGW("%s failed to convert brightness %f", __func__, mBrightnessFloatReq.get());
840         return HWC2_ERROR_UNSUPPORTED;
841     }
842 
843     mBrightnessLevel.store(level);
844     mLhbm.store(mLhbmReq.get());
845 
846     // turn off irc for sun light visibility
847     bool irc = !mEnhanceHbmReq.get();
848     if (ghbm) {
849         mGhbm.store(irc ? HbmMode::ON_IRC_ON : HbmMode::ON_IRC_OFF);
850     } else {
851         mGhbm.store(HbmMode::OFF);
852     }
853 
854     if (mLhbm.is_dirty()) {
855         // Next sysfs path should verify this change has been applied.
856         mUncheckedLhbmRequest = true;
857         mPendingLhbmStatus = mLhbm.get();
858     }
859     if (mGhbm.is_dirty()) {
860         // Next sysfs path should verify this change has been applied.
861         mUncheckedGbhmRequest = true;
862         mPendingGhbmStatus = mGhbm.get();
863     }
864 
865     // no dimming for instant hbm
866     // no dimming if current or previous frame is mixed composition
867     //  - frame N-1: no HDR, HBM off, no sdr dim
868     //  - frame N: HDR visible HBM on, sdr dim is enabled
869     //  - frame N+1, HDR gone, HBM off, no sdr dim.
870     //  We don't need panel dimming for HBM on at frame N and HBM off at frame N+1
871     bool dimming = !mInstantHbmReq.get() && !mSdrDim.get() && !mPrevSdrDim.get();
872     switch (mBrightnessDimmingUsage) {
873         case BrightnessDimmingUsage::HBM:
874             // turn on dimming at HBM on/off
875             // turn off dimming after mHbmDimmingTimeUs or there is an instant hbm on/off
876             if (mGhbm.is_dirty() && dimming) {
877                 mHbmDimming = true;
878                 if (mDimmingLooper) {
879                     mDimmingLooper->removeMessages(mDimmingHandler,
880                                                    DimmingMsgHandler::MSG_DIMMING_OFF);
881                     mDimmingLooper->sendMessageDelayed(us2ns(mHbmDimmingTimeUs), mDimmingHandler,
882                                                        DimmingMsgHandler::MSG_DIMMING_OFF);
883                 }
884             }
885 
886             dimming = dimming && (mHbmDimming);
887             break;
888 
889         case BrightnessDimmingUsage::NONE:
890             dimming = false;
891             break;
892 
893         default:
894             break;
895     }
896     mDimming.store(dimming);
897 
898     mEnhanceHbmReq.clear_dirty();
899     mLhbmReq.clear_dirty();
900     mBrightnessFloatReq.clear_dirty();
901     mInstantHbmReq.clear_dirty();
902     mSdrDim.clear_dirty();
903     mPrevSdrDim.clear_dirty();
904     mDimBrightnessReq.clear_dirty();
905 
906     if (mBrightnessLevel.is_dirty() || mDimming.is_dirty() || mGhbm.is_dirty() ||
907         mLhbm.is_dirty()) {
908         printBrightnessStates("drm");
909     }
910     return NO_ERROR;
911 }
912 
queryBrightness(float brightness,bool * ghbm,uint32_t * level,float * nits)913 int BrightnessController::queryBrightness(float brightness, bool *ghbm, uint32_t *level,
914                                                float *nits) {
915     if (!mBrightnessIntfSupported) {
916         return HWC2_ERROR_UNSUPPORTED;
917     }
918 
919     if (mBrightnessTable == nullptr) {
920         ALOGE("%s: brightness table is empty!", __func__);
921         return HWC2_ERROR_UNSUPPORTED;
922     }
923 
924     auto normal_range = mBrightnessTable->GetBrightnessRange(BrightnessMode::BM_NOMINAL);
925     if (!normal_range) {
926         ALOGE("%s: normal brightness range not available!", __func__);
927         return HWC2_ERROR_UNSUPPORTED;
928     }
929 
930     if (brightness < 0) {
931         // screen off
932         if (ghbm) {
933             *ghbm = false;
934         }
935         if (level) {
936             *level = 0;
937         }
938         if (nits) {
939             *nits = 0;
940         }
941         return NO_ERROR;
942     }
943 
944     BrightnessMode bm = BrightnessMode::BM_MAX;
945     std::optional<float> nits_value = mBrightnessTable->BrightnessToNits(brightness, bm);
946     if (!nits_value) {
947         return -EINVAL;
948     }
949     if (ghbm) {
950         *ghbm = (bm == BrightnessMode::BM_HBM);
951     }
952     std::optional<uint32_t> dbv_value = mBrightnessTable->NitsToDbv(bm, nits_value.value());
953     if (!dbv_value) {
954         return -EINVAL;
955     }
956 
957     if (level) {
958         if ((bm == BrightnessMode::BM_NOMINAL) && mDbmSupported &&
959             (mDimBrightnessReq.get() == true) &&
960             (dbv_value == normal_range.value().get().dbv_min)) {
961             *level = mDimBrightness;
962         } else {
963             *level = dbv_value.value();
964         }
965     }
966     if (nits) {
967         *nits = nits_value.value();
968     }
969 
970     return NO_ERROR;
971 }
972 
973 // Return immediately if it's already in the status. Otherwise poll the status
checkSysfsStatus(const std::string & file,const std::vector<std::string> & expectedValue,const nsecs_t timeoutNs)974 int BrightnessController::checkSysfsStatus(const std::string& file,
975                                            const std::vector<std::string>& expectedValue,
976                                            const nsecs_t timeoutNs) {
977     ATRACE_CALL();
978 
979     if (expectedValue.size() == 0) {
980       return -EINVAL;
981     }
982 
983     char buf[16];
984     UniqueFd fd = open(file.c_str(), O_RDONLY);
985     if (fd.get() < 0) {
986         ALOGE("%s failed to open sysfs %s: %s", __func__, file.c_str(), strerror(errno));
987         return -ENOENT;
988     }
989 
990     int size = read(fd.get(), buf, sizeof(buf));
991     if (size <= 0) {
992         ALOGE("%s failed to read from %s: %s", __func__, file.c_str(), strerror(errno));
993         return -EIO;
994     }
995 
996     // '- 1' to remove trailing '\n'
997     std::string val = std::string(buf, size - 1);
998     if (std::find(expectedValue.begin(), expectedValue.end(), val) != expectedValue.end()) {
999         return OK;
1000     } else if (timeoutNs == 0) {
1001         // not get the expected value and no intention to wait
1002         return -EINVAL;
1003     }
1004 
1005     struct pollfd pfd;
1006     int ret = -EINVAL;
1007 
1008     auto startTime = systemTime(SYSTEM_TIME_MONOTONIC);
1009     pfd.fd = fd.get();
1010     pfd.events = POLLPRI;
1011     while (true) {
1012         auto currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1013         // int64_t for nsecs_t
1014         auto remainTimeNs = timeoutNs - (currentTime - startTime);
1015         if (remainTimeNs <= 0) {
1016             remainTimeNs = ms2ns(1);
1017         }
1018         int pollRet = poll(&pfd, 1, ns2ms(remainTimeNs));
1019         if (pollRet == 0) {
1020             ALOGW("%s poll %s timeout", __func__, file.c_str());
1021             // time out
1022             ret = -ETIMEDOUT;
1023             break;
1024         } else if (pollRet > 0) {
1025             if (!(pfd.revents & POLLPRI)) {
1026                 continue;
1027             }
1028 
1029             lseek(fd.get(), 0, SEEK_SET);
1030             size = read(fd.get(), buf, sizeof(buf));
1031             if (size > 0) {
1032                 val = std::string(buf, size - 1);
1033                 if (std::find(expectedValue.begin(), expectedValue.end(), val) !=
1034                     expectedValue.end()) {
1035                     ret = OK;
1036                     break;
1037                 } else {
1038                     std::string values;
1039                     for (auto& s : expectedValue) {
1040                         values += s + std::string(" ");
1041                     }
1042                     if (values.size() > 0) {
1043                         values.resize(values.size() - 1);
1044                     }
1045                     ALOGW("%s read %s expected %s after notified on file %s", __func__, val.c_str(),
1046                           values.c_str(), file.c_str());
1047                 }
1048             } else {
1049                 ret = -EIO;
1050                 ALOGE("%s failed to read after notified %d on file %s", __func__, errno,
1051                       file.c_str());
1052                 break;
1053             }
1054         } else {
1055             if (errno == EAGAIN || errno == EINTR) {
1056                 continue;
1057             }
1058 
1059             ALOGE("%s poll failed %d on file %s", __func__, errno, file.c_str());
1060             ret = -errno;
1061             break;
1062         }
1063     };
1064 
1065     return ret;
1066 }
1067 
resetLhbmState()1068 void BrightnessController::resetLhbmState() {
1069     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
1070     mLhbmReq.reset(false);
1071     mLhbm.reset(false);
1072     mLhbmBrightnessAdj = false;
1073 }
1074 
setOutdoorVisibility(LbeState state)1075 void BrightnessController::setOutdoorVisibility(LbeState state) {
1076     std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex);
1077     mOutdoorVisibility = (state != LbeState::OFF);
1078 }
1079 
updateCabcMode()1080 int BrightnessController::updateCabcMode() {
1081     if (!mCabcSupport || mCabcModeOfs.fail()) return HWC2_ERROR_UNSUPPORTED;
1082 
1083     std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex);
1084     CabcMode mode;
1085     if (mOutdoorVisibility)
1086         mode = CabcMode::OFF;
1087     else
1088         mode = isHdrLayerOn() ? CabcMode::CABC_MOVIE_MODE : CabcMode::CABC_UI_MODE;
1089     mCabcMode.store(mode);
1090 
1091     if (mCabcMode.is_dirty()) {
1092         applyCabcModeViaSysfs(static_cast<uint8_t>(mode));
1093         ALOGD("%s, isHdrLayerOn: %d, mOutdoorVisibility: %d.", __func__, isHdrLayerOn(),
1094               mOutdoorVisibility);
1095         mCabcMode.clear_dirty();
1096     }
1097     return NO_ERROR;
1098 }
1099 
applyBrightnessViaSysfs(uint32_t level)1100 int BrightnessController::applyBrightnessViaSysfs(uint32_t level) {
1101     if (mBrightnessOfs.is_open()) {
1102         ATRACE_NAME("write_bl_sysfs");
1103         mBrightnessOfs.seekp(std::ios_base::beg);
1104         mBrightnessOfs << std::to_string(level);
1105         mBrightnessOfs.flush();
1106         if (mBrightnessOfs.fail()) {
1107             ALOGE("%s fail to write brightness %d", __func__, level);
1108             mBrightnessOfs.clear();
1109             return HWC2_ERROR_NO_RESOURCES;
1110         }
1111 
1112         {
1113             std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
1114             mBrightnessLevel.reset(level);
1115             mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
1116             printBrightnessStates("sysfs");
1117         }
1118 
1119         return NO_ERROR;
1120     }
1121 
1122     return HWC2_ERROR_UNSUPPORTED;
1123 }
1124 
applyCabcModeViaSysfs(uint8_t mode)1125 int BrightnessController::applyCabcModeViaSysfs(uint8_t mode) {
1126     if (!mCabcModeOfs.is_open()) return HWC2_ERROR_UNSUPPORTED;
1127 
1128     ATRACE_NAME("write_cabc_mode_sysfs");
1129     mCabcModeOfs.seekp(std::ios_base::beg);
1130     mCabcModeOfs << std::to_string(mode);
1131     mCabcModeOfs.flush();
1132     if (mCabcModeOfs.fail()) {
1133         ALOGE("%s fail to write CabcMode %d", __func__, mode);
1134         mCabcModeOfs.clear();
1135         return HWC2_ERROR_NO_RESOURCES;
1136     }
1137     ALOGI("%s Cabc_Mode=%d", __func__, mode);
1138     return NO_ERROR;
1139 }
1140 
1141 // brightness is normalized to current display brightness
validateLayerBrightness(float brightness)1142 bool BrightnessController::validateLayerBrightness(float brightness) {
1143     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
1144     if (!std::isfinite(brightness)) {
1145         ALOGW("%s layer brightness %f is not a valid floating value", __func__, brightness);
1146         return false;
1147     }
1148 
1149     if (brightness > 1.f || brightness < 0.f) {
1150         ALOGW("%s Brightness is out of [0, 1] range: %f", __func__, brightness);
1151         return false;
1152     }
1153 
1154     return true;
1155 }
1156 
parseHbmModeEnums(const DrmProperty & property)1157 void BrightnessController::parseHbmModeEnums(const DrmProperty& property) {
1158     const std::vector<std::pair<uint32_t, const char *>> modeEnums = {
1159             {static_cast<uint32_t>(HbmMode::OFF), "Off"},
1160             {static_cast<uint32_t>(HbmMode::ON_IRC_ON), "On IRC On"},
1161             {static_cast<uint32_t>(HbmMode::ON_IRC_OFF), "On IRC Off"},
1162     };
1163 
1164     DrmEnumParser::parseEnums(property, modeEnums, mHbmModeEnums);
1165     for (auto &e : mHbmModeEnums) {
1166         ALOGD("hbm mode [hal: %d, drm: %" PRId64 ", %s]", e.first, e.second,
1167               modeEnums[e.first].second);
1168     }
1169 }
1170 
1171 /*
1172  * WARNING: This print is parsed by Battery Historian. Consult with the Battery
1173  *   Historian team before modifying (b/239640926).
1174  */
printBrightnessStates(const char * path)1175 void BrightnessController::printBrightnessStates(const char* path) {
1176     ALOGI("path=%s, id=%d, level=%d, nits=%f, brightness=%f, DimmingOn=%d, Hbm=%d, LhbmOn=%d, "
1177           "OpRate=%d",
1178           path ?: "unknown", mPanelIndex, mBrightnessLevel.get(), mDisplayWhitePointNits,
1179           mBrightnessFloatReq.get(), mDimming.get(), mGhbm.get(), mLhbm.get(),
1180           mOperationRate.get());
1181 }
1182 
dump(String8 & result)1183 void BrightnessController::dump(String8& result) {
1184     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
1185 
1186     result.appendFormat("BrightnessController:\n");
1187     result.appendFormat("\tsysfs support %d, max %d, valid brightness table %d, "
1188                         "lhbm supported %d, ghbm supported %d\n", mBrightnessOfs.is_open(),
1189                         mMaxBrightness, mBrightnessIntfSupported, mLhbmSupported, mGhbmSupported);
1190     result.appendFormat("\trequests: enhance hbm %d, lhbm %d, "
1191                         "brightness %f, instant hbm %d, DimBrightness %d\n",
1192                         mEnhanceHbmReq.get(), mLhbmReq.get(), mBrightnessFloatReq.get(),
1193                         mInstantHbmReq.get(), mDimBrightnessReq.get());
1194     result.appendFormat("\tstates: brighntess level %d, ghbm %d, dimming %d, lhbm %d",
1195                         mBrightnessLevel.get(), mGhbm.get(), mDimming.get(), mLhbm.get());
1196     result.appendFormat("\thdr layer state %d, unchecked lhbm request %d(%d), "
1197                         "unchecked ghbm request %d(%d)\n",
1198                         mHdrLayerState.get(), mUncheckedLhbmRequest.load(),
1199                         mPendingLhbmStatus.load(), mUncheckedGbhmRequest.load(),
1200                         mPendingGhbmStatus.load());
1201     result.appendFormat("\tdimming usage %d, hbm dimming %d, time us %d\n", mBrightnessDimmingUsage,
1202                         mHbmDimming, mHbmDimmingTimeUs);
1203     result.appendFormat("\twhite point nits current %f, previous %f\n", mDisplayWhitePointNits,
1204                         mPrevDisplayWhitePointNits);
1205     result.appendFormat("\tcabc supported %d, cabcMode %d\n", mCabcModeOfs.is_open(),
1206                         mCabcMode.get());
1207     result.appendFormat("\tignore brightness update request %d\n", mIgnoreBrightnessUpdateRequests);
1208     result.appendFormat("\tacl mode supported %d, acl mode %d\n", mAclModeOfs.is_open(),
1209                         mAclMode.get());
1210     result.appendFormat("\toperation rate %d\n", mOperationRate.get());
1211 
1212     result.appendFormat("\n");
1213 }
1214