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