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