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