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