• 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 
BrightnessController(int32_t panelIndex,std::function<void (void)> refresh,std::function<void (void)> updateDcLhbm)25 BrightnessController::BrightnessController(int32_t panelIndex, std::function<void(void)> refresh,
26                                            std::function<void(void)> updateDcLhbm)
27       : mPanelIndex(panelIndex),
28         mEnhanceHbmReq(false),
29         mLhbmReq(false),
30         mBrightnessFloatReq(-1),
31         mBrightnessLevel(0),
32         mGhbm(HbmMode::OFF),
33         mDimming(false),
34         mLhbm(false),
35         mSdrDim(false),
36         mPrevSdrDim(false),
37         mDimBrightnessReq(false),
38         mFrameRefresh(refresh),
39         mHdrLayerState(HdrLayerState::kHdrNone),
40         mUpdateDcLhbm(updateDcLhbm) {
41     initBrightnessSysfs();
42     initCabcSysfs();
43 }
44 
~BrightnessController()45 BrightnessController::~BrightnessController() {
46     if (mDimmingLooper) {
47         mDimmingLooper->removeMessages(mDimmingHandler);
48     }
49     if (mDimmingThreadRunning) {
50         mDimmingLooper->sendMessage(mDimmingHandler, DimmingMsgHandler::MSG_QUIT);
51         mDimmingThread.join();
52     }
53 }
54 
initDrm(const DrmDevice & drmDevice,const DrmConnector & connector)55 int BrightnessController::initDrm(const DrmDevice& drmDevice,
56                                   const DrmConnector& connector) {
57     initBrightnessTable(drmDevice, connector);
58 
59     initDimmingUsage();
60 
61     mLhbmSupported = connector.lhbm_on().id() != 0;
62     mGhbmSupported = connector.hbm_mode().id() != 0;
63 
64     /* allow the first brightness to apply */
65     mBrightnessFloatReq.set_dirty();
66     return NO_ERROR;
67 }
68 
initDimmingUsage()69 void BrightnessController::initDimmingUsage() {
70     String8 propName;
71     propName.appendFormat(kDimmingUsagePropName, mPanelIndex);
72 
73     mBrightnessDimmingUsage = static_cast<BrightnessDimmingUsage>(property_get_int32(propName, 0));
74 
75     propName.clear();
76     propName.appendFormat(kDimmingHbmTimePropName, mPanelIndex);
77     mHbmDimmingTimeUs = property_get_int32(propName, kHbmDimmingTimeUs);
78 
79     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) {
80         mDimming.store(true);
81     }
82 
83     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::HBM) {
84         mDimmingHandler = new DimmingMsgHandler(this);
85         mDimmingThread = std::thread(&BrightnessController::dimmingThread, this);
86     }
87 }
88 
initBrightnessSysfs()89 void BrightnessController::initBrightnessSysfs() {
90     String8 nodeName;
91     nodeName.appendFormat(BRIGHTNESS_SYSFS_NODE, mPanelIndex);
92     mBrightnessOfs.open(nodeName.string(), std::ofstream::out);
93     if (mBrightnessOfs.fail()) {
94         ALOGE("%s %s fail to open", __func__, nodeName.string());
95         mBrightnessOfs.close();
96         return;
97     }
98 
99     nodeName.clear();
100     nodeName.appendFormat(MAX_BRIGHTNESS_SYSFS_NODE, mPanelIndex);
101 
102     std::ifstream ifsMaxBrightness(nodeName.string());
103     if (ifsMaxBrightness.fail()) {
104         ALOGE("%s fail to open %s", __func__, nodeName.string());
105         return;
106     }
107 
108     ifsMaxBrightness >> mMaxBrightness;
109     ifsMaxBrightness.close();
110 }
111 
initCabcSysfs()112 void BrightnessController::initCabcSysfs() {
113     mCabcSupport = property_get_bool("vendor.display.cabc.supported", false);
114     if (!mCabcSupport) return;
115 
116     String8 nodeName;
117     nodeName.appendFormat(kLocalCabcModeFileNode, mPanelIndex);
118 
119     mCabcModeOfs.open(nodeName.string(), std::ofstream::out);
120     if (mCabcModeOfs.fail()) {
121         ALOGE("%s %s fail to open", __func__, nodeName.string());
122         mCabcModeOfs.close();
123         return;
124     }
125 }
126 
initBrightnessTable(const DrmDevice & drmDevice,const DrmConnector & connector)127 void BrightnessController::initBrightnessTable(const DrmDevice& drmDevice,
128                                                const DrmConnector& connector) {
129     if (connector.brightness_cap().id() == 0) {
130         ALOGD("the brightness_cap is not supported");
131         return;
132     }
133 
134     const auto [ret, blobId] = connector.brightness_cap().value();
135     if (ret) {
136         ALOGE("Fail to get brightness_cap (ret = %d)", ret);
137         return;
138     }
139 
140     if (blobId == 0) {
141         ALOGE("the brightness_cap is supported but blob is not valid");
142         return;
143     }
144 
145     drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(drmDevice.fd(), blobId);
146     if (blob == nullptr) {
147         ALOGE("Fail to get brightness_cap blob");
148         return;
149     }
150 
151     const struct brightness_capability *cap =
152             reinterpret_cast<struct brightness_capability *>(blob->data);
153     mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)] = BrightnessTable(cap->normal);
154     mBrightnessTable[toUnderlying(BrightnessRange::HBM)] = BrightnessTable(cap->hbm);
155 
156     parseHbmModeEnums(connector.hbm_mode());
157 
158     // init to min before SF sets the brightness
159     mDisplayWhitePointNits = cap->normal.nits.min;
160     mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
161     mBrightnessIntfSupported = true;
162 
163     drmModeFreePropertyBlob(blob);
164 
165     String8 nodeName;
166     nodeName.appendFormat(kDimBrightnessFileNode, mPanelIndex);
167 
168     std::ifstream ifsDimBrightness(nodeName.string());
169     if (ifsDimBrightness.fail()) {
170         ALOGW("%s fail to open %s", __func__, nodeName.string());
171     } else {
172         ifsDimBrightness >> mDimBrightness;
173         ifsDimBrightness.close();
174         if (mDimBrightness >= mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart)
175             mDimBrightness = 0;
176     }
177     mDbmSupported = !!mDimBrightness;
178     ALOGI("%s mDimBrightness=%d, mDbmSupported=%d", __func__, mDimBrightness, mDbmSupported);
179 }
180 
processEnhancedHbm(bool on)181 int BrightnessController::processEnhancedHbm(bool on) {
182     if (!mGhbmSupported) {
183         return HWC2_ERROR_UNSUPPORTED;
184     }
185 
186     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
187     mEnhanceHbmReq.store(on);
188     if (mEnhanceHbmReq.is_dirty()) {
189         updateStates();
190     }
191     return NO_ERROR;
192 }
193 
processDimmingOff()194 void BrightnessController::processDimmingOff() {
195     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
196     if (mHbmDimming) {
197         mHbmDimming = false;
198         updateStates();
199         mFrameRefresh();
200     }
201 }
202 
processDisplayBrightness(float brightness,const nsecs_t vsyncNs,bool waitPresent)203 int BrightnessController::processDisplayBrightness(float brightness, const nsecs_t vsyncNs,
204                                                    bool waitPresent) {
205     uint32_t level;
206     bool ghbm;
207 
208     if (brightness < -1.0f || brightness > 1.0f) {
209         return HWC2_ERROR_BAD_PARAMETER;
210     }
211 
212     ATRACE_CALL();
213     if (!mBrightnessIntfSupported) {
214         level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f);
215         return applyBrightnessViaSysfs(level);
216     }
217 
218     {
219         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
220         /* apply the first brightness */
221         if (mBrightnessFloatReq.is_dirty()) mBrightnessLevel.set_dirty();
222 
223         mBrightnessFloatReq.store(brightness);
224         if (!mBrightnessFloatReq.is_dirty()) {
225             return NO_ERROR;
226         }
227 
228         // check if it will go drm path for below cases.
229         // case 1: hbm state will change
230         // case 2: for hwc3, brightness command could apply at next present if possible
231         if (queryBrightness(brightness, &ghbm, &level) == NO_ERROR) {
232             // ghbm on/off always go drm path
233             // check if this will cause a hbm transition
234             if (mGhbmSupported && (mGhbm.get() != HbmMode::OFF) != ghbm) {
235                 // this brightness change will go drm path
236                 updateStates();
237                 mFrameRefresh(); // force next frame to update brightness
238                 return NO_ERROR;
239             }
240             // there will be a Present to apply this brightness change
241             if (waitPresent) {
242                 // this brightness change will go drm path
243                 updateStates();
244                 return NO_ERROR;
245             }
246         } else {
247             level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f);
248         }
249         // go sysfs path
250     }
251 
252     // Sysfs path is faster than drm path. If there is an unchecked drm path change, the sysfs
253     // path should check the sysfs content.
254     if (mUncheckedGbhmRequest) {
255         ATRACE_NAME("check_ghbm_mode");
256         checkSysfsStatus(kGlobalHbmModeFileNode,
257                          {std::to_string(toUnderlying(mPendingGhbmStatus.load()))}, vsyncNs * 5);
258         mUncheckedGbhmRequest = false;
259     }
260 
261     if (mUncheckedLhbmRequest) {
262         ATRACE_NAME("check_lhbm_mode");
263         checkSysfsStatus(kLocalHbmModeFileNode, {std::to_string(mPendingLhbmStatus)}, vsyncNs * 5);
264         mUncheckedLhbmRequest = false;
265     }
266 
267     return applyBrightnessViaSysfs(level);
268 }
269 
270 // In HWC3, brightness change could be applied via drm commit or sysfs path.
271 // If a brightness change command does not come with a frame update, this
272 // function wil be called to apply the brghtness change via sysfs path.
applyPendingChangeViaSysfs(const nsecs_t vsyncNs)273 int BrightnessController::applyPendingChangeViaSysfs(const nsecs_t vsyncNs) {
274     ATRACE_CALL();
275     uint32_t level;
276     {
277         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
278 
279         if (!mBrightnessLevel.is_dirty()) {
280             return NO_ERROR;
281         }
282 
283         // there will be a drm commit to apply this brightness change if a GHBM change is pending.
284         if (mGhbm.is_dirty()) {
285             ALOGI("%s standalone brightness change will be handled by next frame update for GHBM",
286                   __func__);
287             return NO_ERROR;
288         }
289 
290         // there will be a drm commit to apply this brightness change if a LHBM change is pending.
291         if (mLhbm.is_dirty()) {
292             ALOGI("%s standalone brightness change will be handled by next frame update for LHBM",
293                   __func__);
294             return NO_ERROR;
295         }
296 
297         level = mBrightnessLevel.get();
298     }
299 
300     if (mUncheckedBlRequest) {
301         ATRACE_NAME("check_bl_value");
302         checkSysfsStatus(BRIGHTNESS_SYSFS_NODE, {std::to_string(mPendingBl)}, vsyncNs * 5);
303         mUncheckedBlRequest = false;
304     }
305 
306     return applyBrightnessViaSysfs(level);
307 }
308 
processLocalHbm(bool on)309 int BrightnessController::processLocalHbm(bool on) {
310     if (!mLhbmSupported) {
311         return HWC2_ERROR_UNSUPPORTED;
312     }
313 
314     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
315     mLhbmReq.store(on);
316     if (mLhbmReq.is_dirty()) {
317         updateStates();
318     }
319 
320     return NO_ERROR;
321 }
322 
updateFrameStates(HdrLayerState hdrState,bool sdrDim)323 void BrightnessController::updateFrameStates(HdrLayerState hdrState, bool sdrDim) {
324     mHdrLayerState.store(hdrState);
325     if (!mGhbmSupported) {
326         return;
327     }
328 
329     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
330     mPrevSdrDim.store(mSdrDim.get());
331     mSdrDim.store(sdrDim);
332     if (mSdrDim.is_dirty() || mPrevSdrDim.is_dirty()) {
333         updateStates();
334     }
335 }
336 
processInstantHbm(bool on)337 int BrightnessController::processInstantHbm(bool on) {
338     if (!mGhbmSupported) {
339         return HWC2_ERROR_UNSUPPORTED;
340     }
341 
342     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
343     mInstantHbmReq.store(on);
344     if (mInstantHbmReq.is_dirty()) {
345         updateStates();
346     }
347     return NO_ERROR;
348 }
349 
processDimBrightness(bool on)350 int BrightnessController::processDimBrightness(bool on) {
351     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
352     mDimBrightnessReq.store(on);
353     if (mDimBrightnessReq.is_dirty()) {
354         updateStates();
355         ALOGI("%s request = %d", __func__, mDimBrightnessReq.get());
356     }
357     return NO_ERROR;
358 }
359 
getSdrDimRatioForInstantHbm()360 float BrightnessController::getSdrDimRatioForInstantHbm() {
361     if (!mBrightnessIntfSupported || !mGhbmSupported) {
362         return 1.0f;
363     }
364 
365     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
366     if (!mInstantHbmReq.get()) {
367         return 1.0f;
368     }
369 
370     float sdr = 0;
371     if (queryBrightness(mBrightnessFloatReq.get(), nullptr, nullptr, &sdr) != NO_ERROR) {
372         return 1.0f;
373     }
374 
375     float peak = mBrightnessTable[toUnderlying(BrightnessRange::MAX) - 1].mNitsEnd;
376     if (sdr == 0 || peak == 0) {
377         ALOGW("%s error luminance value sdr %f peak %f", __func__, sdr, peak);
378         return 1.0f;
379     }
380 
381     float ratio = sdr / peak;
382     if (ratio < kGhbmMinDimRatio) {
383         ALOGW("%s sdr dim ratio %f too small", __func__, ratio);
384         ratio = kGhbmMinDimRatio;
385     }
386 
387     return ratio;
388 }
389 
onClearDisplay(bool needModeClear)390 void BrightnessController::onClearDisplay(bool needModeClear) {
391     resetLhbmState();
392     mInstantHbmReq.reset(false);
393 
394     if (mBrightnessLevel.is_dirty()) applyBrightnessViaSysfs(mBrightnessLevel.get());
395 
396     if (!needModeClear) return;
397 
398     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
399     mEnhanceHbmReq.reset(false);
400     mBrightnessFloatReq.reset(-1);
401 
402     mBrightnessLevel.reset(0);
403     mDisplayWhitePointNits = 0;
404     mPrevDisplayWhitePointNits = 0;
405     mGhbm.reset(HbmMode::OFF);
406     mDimming.reset(false);
407     mHbmDimming = false;
408     if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) {
409         mDimming.store(true);
410     }
411 
412     std::lock_guard<std::recursive_mutex> lock1(mCabcModeMutex);
413     mCabcMode.reset(CabcMode::OFF);
414 }
415 
prepareFrameCommit(ExynosDisplay & display,const DrmConnector & connector,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const bool mixedComposition,bool & ghbmSync,bool & lhbmSync,bool & blSync)416 int BrightnessController::prepareFrameCommit(ExynosDisplay& display,
417                               const DrmConnector& connector,
418                               ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq,
419                               const bool mixedComposition,
420                               bool& ghbmSync, bool& lhbmSync, bool& blSync) {
421     int ret;
422 
423     ghbmSync = false;
424     lhbmSync = false;
425     blSync = false;
426 
427     ATRACE_CALL();
428     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
429 
430     bool sync = false;
431     if (mixedComposition && mPrevDisplayWhitePointNits > 0 && mDisplayWhitePointNits > 0) {
432         float diff = std::abs(mPrevDisplayWhitePointNits - mDisplayWhitePointNits);
433         float min = std::min(mPrevDisplayWhitePointNits, mDisplayWhitePointNits);
434         if (diff / min > kBrightnessSyncThreshold) {
435             sync = true;
436             ALOGD("%s: enable brightness sync for change from %f to %f", __func__,
437                   mPrevDisplayWhitePointNits, mDisplayWhitePointNits);
438         }
439     }
440 
441     if (mDimming.is_dirty()) {
442         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.dimming_on(),
443                                             mDimming.get())) < 0) {
444             ALOGE("%s: Fail to set dimming_on property", __func__);
445         }
446         mDimming.clear_dirty();
447     }
448 
449     if (mLhbm.is_dirty() && mLhbmSupported) {
450         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.lhbm_on(),
451                                             mLhbm.get())) < 0) {
452             ALOGE("%s: Fail to set lhbm_on property", __func__);
453         } else {
454             lhbmSync = true;
455         }
456 
457         auto dbv = mBrightnessLevel.get();
458         auto old_dbv = dbv;
459         if (mLhbm.get()) {
460             mUpdateDcLhbm();
461             uint32_t dbv_adj = 0;
462             if (display.getColorAdjustedDbv(dbv_adj)) {
463                 ALOGW("failed to get adjusted dbv");
464             } else if (dbv_adj != dbv && dbv_adj != 0) {
465                 dbv_adj = std::clamp(dbv_adj,
466                         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart,
467                         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklEnd);
468 
469                 ALOGI("lhbm: adjust dbv from %d to %d", dbv, dbv_adj);
470                 dbv = dbv_adj;
471                 mLhbmBrightnessAdj = (dbv != old_dbv);
472             }
473         }
474 
475         if (mLhbmBrightnessAdj) {
476             // case 1: lhbm on and dbv is changed, use the new dbv
477             // case 2: lhbm off and dbv was changed at lhbm on, use current dbv
478             if ((ret = drmReq.atomicAddProperty(connector.id(),
479                                                connector.brightness_level(), dbv)) < 0) {
480                 ALOGE("%s: Fail to set brightness_level property", __func__);
481             } else {
482                 blSync = true;
483                 mUncheckedBlRequest = true;
484                 mPendingBl = dbv;
485             }
486         }
487 
488         // mLhbmBrightnessAdj will last from LHBM on to off
489         if (!mLhbm.get() && mLhbmBrightnessAdj) {
490             mLhbmBrightnessAdj = false;
491         }
492 
493         mLhbm.clear_dirty();
494     }
495 
496     if (mBrightnessLevel.is_dirty()) {
497         // skip if lhbm has updated bl
498         if (!blSync) {
499             if ((ret = drmReq.atomicAddProperty(connector.id(),
500                                                 connector.brightness_level(),
501                                                 mBrightnessLevel.get())) < 0) {
502                 ALOGE("%s: Fail to set brightness_level property", __func__);
503             } else {
504                 mUncheckedBlRequest = true;
505                 mPendingBl = mBrightnessLevel.get();
506                 blSync = sync;
507             }
508         }
509         mBrightnessLevel.clear_dirty();
510         mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
511     }
512 
513     if (mGhbm.is_dirty() && mGhbmSupported) {
514         HbmMode hbmMode = mGhbm.get();
515         auto [hbmEnum, ret] = DrmEnumParser::halToDrmEnum(static_cast<int32_t>(hbmMode),
516                                                           mHbmModeEnums);
517         if (ret < 0) {
518             ALOGE("Fail to convert hbm mode(%d)", hbmMode);
519             return ret;
520         }
521 
522         if ((ret = drmReq.atomicAddProperty(connector.id(), connector.hbm_mode(),
523                                             hbmEnum)) < 0) {
524             ALOGE("%s: Fail to set hbm_mode property", __func__);
525         } else {
526             ghbmSync = sync;
527         }
528         mGhbm.clear_dirty();
529     }
530 
531     mHdrLayerState.clear_dirty();
532     return NO_ERROR;
533 }
534 
handleMessage(const::android::Message & message)535 void BrightnessController::DimmingMsgHandler::handleMessage(const ::android::Message& message) {
536     ALOGI("%s %d", __func__, message.what);
537 
538     switch (message.what) {
539         case MSG_DIMMING_OFF:
540             mBrightnessController->processDimmingOff();
541             break;
542 
543         case MSG_QUIT:
544             mBrightnessController->mDimmingThreadRunning = false;
545             break;
546     }
547 }
548 
dimmingThread()549 void BrightnessController::dimmingThread() {
550     mDimmingLooper = new Looper(false);
551     Looper::setForThread(mDimmingLooper);
552     mDimmingThreadRunning = true;
553     while (mDimmingThreadRunning.load(std::memory_order_relaxed)) {
554         mDimmingLooper->pollOnce(-1);
555     }
556 }
557 
558 // Process all requests to update states for next commit
updateStates()559 int BrightnessController::updateStates() {
560     bool ghbm;
561     uint32_t level;
562     float brightness = mInstantHbmReq.get() ? 1.0f : mBrightnessFloatReq.get();
563     if (queryBrightness(brightness, &ghbm, &level, &mDisplayWhitePointNits)) {
564         ALOGW("%s failed to convert brightness %f", __func__, mBrightnessFloatReq.get());
565         return HWC2_ERROR_UNSUPPORTED;
566     }
567 
568     mBrightnessLevel.store(level);
569     mLhbm.store(mLhbmReq.get());
570 
571     // turn off irc for sun light visibility
572     bool irc = !mEnhanceHbmReq.get();
573     if (ghbm) {
574         mGhbm.store(irc ? HbmMode::ON_IRC_ON : HbmMode::ON_IRC_OFF);
575     } else {
576         mGhbm.store(HbmMode::OFF);
577     }
578 
579     if (mLhbm.is_dirty()) {
580         // Next sysfs path should verify this change has been applied.
581         mUncheckedLhbmRequest = true;
582         mPendingLhbmStatus = mLhbm.get();
583     }
584     if (mGhbm.is_dirty()) {
585         // Next sysfs path should verify this change has been applied.
586         mUncheckedGbhmRequest = true;
587         mPendingGhbmStatus = mGhbm.get();
588     }
589 
590     // no dimming for instant hbm
591     // no dimming if current or previous frame is mixed composition
592     //  - frame N-1: no HDR, HBM off, no sdr dim
593     //  - frame N: HDR visible HBM on, sdr dim is enabled
594     //  - frame N+1, HDR gone, HBM off, no sdr dim.
595     //  We don't need panel dimming for HBM on at frame N and HBM off at frame N+1
596     bool dimming = !mInstantHbmReq.get() && !mSdrDim.get() && !mPrevSdrDim.get();
597     switch (mBrightnessDimmingUsage) {
598         case BrightnessDimmingUsage::HBM:
599             // turn on dimming at HBM on/off
600             // turn off dimming after mHbmDimmingTimeUs or there is an instant hbm on/off
601             if (mGhbm.is_dirty() && dimming) {
602                 mHbmDimming = true;
603                 if (mDimmingLooper) {
604                     mDimmingLooper->removeMessages(mDimmingHandler,
605                                                    DimmingMsgHandler::MSG_DIMMING_OFF);
606                     mDimmingLooper->sendMessageDelayed(us2ns(mHbmDimmingTimeUs), mDimmingHandler,
607                                                        DimmingMsgHandler::MSG_DIMMING_OFF);
608                 }
609             }
610 
611             dimming = dimming && (mHbmDimming);
612             break;
613 
614         case BrightnessDimmingUsage::NONE:
615             dimming = false;
616             break;
617 
618         default:
619             break;
620     }
621     mDimming.store(dimming);
622 
623     mEnhanceHbmReq.clear_dirty();
624     mLhbmReq.clear_dirty();
625     mBrightnessFloatReq.clear_dirty();
626     mInstantHbmReq.clear_dirty();
627     mSdrDim.clear_dirty();
628     mPrevSdrDim.clear_dirty();
629     mDimBrightnessReq.clear_dirty();
630 
631     if (mBrightnessLevel.is_dirty() || mDimming.is_dirty() || mGhbm.is_dirty() ||
632         mLhbm.is_dirty()) {
633         printBrightnessStates("drm");
634     }
635     return NO_ERROR;
636 }
637 
queryBrightness(float brightness,bool * ghbm,uint32_t * level,float * nits)638 int BrightnessController::queryBrightness(float brightness, bool *ghbm, uint32_t *level,
639                                                float *nits) {
640     if (!mBrightnessIntfSupported) {
641         return HWC2_ERROR_UNSUPPORTED;
642     }
643 
644     if (mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart == 0 &&
645         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklEnd == 0 &&
646         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBriStart == 0 &&
647         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBriEnd == 0 &&
648         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsStart == 0 &&
649         mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsEnd == 0) {
650         return HWC2_ERROR_UNSUPPORTED;
651     }
652 
653     if (brightness < 0) {
654         // screen off
655         if (ghbm) {
656             *ghbm = false;
657         }
658         if (level) {
659             *level = 0;
660         }
661         if (nits) {
662             *nits = 0;
663         }
664         return NO_ERROR;
665     }
666 
667     for (uint32_t i = 0; i < toUnderlying(BrightnessRange::MAX); ++i) {
668         if (brightness <= mBrightnessTable[i].mBriEnd) {
669             if (ghbm) {
670                 *ghbm = (i == toUnderlying(BrightnessRange::HBM));
671             }
672 
673             if (level || nits) {
674                 auto fSpan = mBrightnessTable[i].mBriEnd - mBrightnessTable[i].mBriStart;
675                 auto norm = fSpan == 0 ? 1 : (brightness - mBrightnessTable[i].mBriStart) / fSpan;
676 
677                 if (level) {
678                     auto iSpan = mBrightnessTable[i].mBklEnd - mBrightnessTable[i].mBklStart;
679                     auto bl = norm * iSpan + mBrightnessTable[i].mBklStart;
680                     *level = static_cast<uint32_t>(bl + 0.5);
681                 }
682 
683                 if (nits) {
684                     auto nSpan = mBrightnessTable[i].mNitsEnd - mBrightnessTable[i].mNitsStart;
685                     *nits = norm * nSpan + mBrightnessTable[i].mNitsStart;
686                 }
687             }
688             if ((i == toUnderlying(BrightnessRange::NORMAL)) && mDbmSupported &&
689                 (mDimBrightnessReq.get() == true) && (*level == mBrightnessTable[i].mBklStart)) {
690                 *level = mDimBrightness;
691             }
692             return NO_ERROR;
693         }
694     }
695 
696     return -EINVAL;
697 }
698 
699 // Return immediately if it's already in the status. Otherwise poll the status
checkSysfsStatus(const char * file,const std::vector<std::string> & expectedValue,const nsecs_t timeoutNs)700 int BrightnessController::checkSysfsStatus(const char* file,
701                                            const std::vector<std::string>& expectedValue,
702                                            const nsecs_t timeoutNs) {
703     ATRACE_CALL();
704 
705     if (expectedValue.size() == 0) return false;
706 
707     char buf[16];
708     String8 nodeName;
709     nodeName.appendFormat(file, mPanelIndex);
710     UniqueFd fd = open(nodeName.string(), O_RDONLY);
711 
712     int size = read(fd.get(), buf, sizeof(buf));
713     if (size <= 0) {
714         ALOGE("%s failed to read from %s", __func__, kLocalHbmModeFileNode);
715         return false;
716     }
717 
718     // '- 1' to remove trailing '\n'
719     std::string val = std::string(buf, size - 1);
720     if (std::find(expectedValue.begin(), expectedValue.end(), val) != expectedValue.end()) {
721         return true;
722     } else if (timeoutNs == 0) {
723         return false;
724     }
725 
726     struct pollfd pfd;
727     int ret = EINVAL;
728 
729     auto startTime = systemTime(SYSTEM_TIME_MONOTONIC);
730     pfd.fd = fd.get();
731     pfd.events = POLLPRI;
732     while (true) {
733         auto currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
734         // int64_t for nsecs_t
735         auto remainTimeNs = timeoutNs - (currentTime - startTime);
736         if (remainTimeNs <= 0) {
737             remainTimeNs = ms2ns(1);
738         }
739         int pollRet = poll(&pfd, 1, ns2ms(remainTimeNs));
740         if (pollRet == 0) {
741             ALOGW("%s poll timeout", __func__);
742             // time out
743             ret = ETIMEDOUT;
744             break;
745         } else if (pollRet > 0) {
746             if (!(pfd.revents & POLLPRI)) {
747                 continue;
748             }
749 
750             lseek(fd.get(), 0, SEEK_SET);
751             size = read(fd.get(), buf, sizeof(buf));
752             if (size > 0) {
753                 val = std::string(buf, size - 1);
754                 if (std::find(expectedValue.begin(), expectedValue.end(), val) !=
755                     expectedValue.end()) {
756                     ret = 0;
757                 } else {
758                     std::string values;
759                     for (auto& s : expectedValue) {
760                         values += s + std::string(" ");
761                     }
762                     if (values.size() > 0) {
763                         values.resize(values.size() - 1);
764                     }
765                     ALOGE("%s read %s expected %s after notified", __func__, val.c_str(),
766                           values.c_str());
767                     ret = EINVAL;
768                 }
769             } else {
770                 ret = EIO;
771                 ALOGE("%s failed to read after notified %d", __func__, errno);
772             }
773             break;
774         } else {
775             if (errno == EAGAIN || errno == EINTR) {
776                 continue;
777             }
778 
779             ALOGE("%s poll failed %d", __func__, errno);
780             ret = errno;
781             break;
782         }
783     };
784 
785     return ret == NO_ERROR;
786 }
787 
resetLhbmState()788 void BrightnessController::resetLhbmState() {
789     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
790     mLhbmReq.reset(false);
791     mLhbm.reset(false);
792     mLhbmBrightnessAdj = false;
793 }
794 
setOutdoorVisibility(LbeState state)795 void BrightnessController::setOutdoorVisibility(LbeState state) {
796     std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex);
797     mOutdoorVisibility = (state != LbeState::OFF);
798 }
799 
updateCabcMode()800 int BrightnessController::updateCabcMode() {
801     if (!mCabcSupport || mCabcModeOfs.fail()) return HWC2_ERROR_UNSUPPORTED;
802 
803     std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex);
804     CabcMode mode;
805     if (mOutdoorVisibility)
806         mode = CabcMode::OFF;
807     else
808         mode = isHdrLayerOn() ? CabcMode::CABC_MOVIE_MODE : CabcMode::CABC_UI_MODE;
809     mCabcMode.store(mode);
810 
811     if (mCabcMode.is_dirty()) {
812         applyCabcModeViaSysfs(static_cast<uint8_t>(mode));
813         ALOGD("%s, isHdrLayerOn: %d, mOutdoorVisibility: %d.", __func__, isHdrLayerOn(),
814               mOutdoorVisibility);
815         mCabcMode.clear_dirty();
816     }
817     return NO_ERROR;
818 }
819 
applyBrightnessViaSysfs(uint32_t level)820 int BrightnessController::applyBrightnessViaSysfs(uint32_t level) {
821     if (mBrightnessOfs.is_open()) {
822         ATRACE_NAME("write_bl_sysfs");
823         mBrightnessOfs.seekp(std::ios_base::beg);
824         mBrightnessOfs << std::to_string(level);
825         mBrightnessOfs.flush();
826         if (mBrightnessOfs.fail()) {
827             ALOGE("%s fail to write brightness %d", __func__, level);
828             mBrightnessOfs.clear();
829             return HWC2_ERROR_NO_RESOURCES;
830         }
831 
832         {
833             std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
834             mBrightnessLevel.reset(level);
835             mPrevDisplayWhitePointNits = mDisplayWhitePointNits;
836             printBrightnessStates("sysfs");
837         }
838 
839         return NO_ERROR;
840     }
841 
842     return HWC2_ERROR_UNSUPPORTED;
843 }
844 
applyCabcModeViaSysfs(uint8_t mode)845 int BrightnessController::applyCabcModeViaSysfs(uint8_t mode) {
846     if (!mCabcModeOfs.is_open()) return HWC2_ERROR_UNSUPPORTED;
847 
848     ATRACE_NAME("write_cabc_mode_sysfs");
849     mCabcModeOfs.seekp(std::ios_base::beg);
850     mCabcModeOfs << std::to_string(mode);
851     mCabcModeOfs.flush();
852     if (mCabcModeOfs.fail()) {
853         ALOGE("%s fail to write CabcMode %d", __func__, mode);
854         mCabcModeOfs.clear();
855         return HWC2_ERROR_NO_RESOURCES;
856     }
857     ALOGI("%s Cabc_Mode=%d", __func__, mode);
858     return NO_ERROR;
859 }
860 
861 // brightness is normalized to current display brightness
validateLayerBrightness(float brightness)862 bool BrightnessController::validateLayerBrightness(float brightness) {
863     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
864     if (!std::isfinite(brightness)) {
865         ALOGW("%s layer brightness %f is not a valid floating value", __func__, brightness);
866         return false;
867     }
868 
869     if (brightness > 1.f || brightness < 0.f) {
870         ALOGW("%s Brightness is out of [0, 1] range: %f", __func__, brightness);
871         return false;
872     }
873 
874     return true;
875 }
876 
parseHbmModeEnums(const DrmProperty & property)877 void BrightnessController::parseHbmModeEnums(const DrmProperty& property) {
878     const std::vector<std::pair<uint32_t, const char *>> modeEnums = {
879             {static_cast<uint32_t>(HbmMode::OFF), "Off"},
880             {static_cast<uint32_t>(HbmMode::ON_IRC_ON), "On IRC On"},
881             {static_cast<uint32_t>(HbmMode::ON_IRC_OFF), "On IRC Off"},
882     };
883 
884     DrmEnumParser::parseEnums(property, modeEnums, mHbmModeEnums);
885     for (auto &e : mHbmModeEnums) {
886         ALOGD("hbm mode [hal: %d, drm: %" PRId64 ", %s]", e.first, e.second,
887               modeEnums[e.first].second);
888     }
889 }
890 
891 /*
892  * WARNING: This print is parsed by Battery Historian. Consult with the Battery
893  *   Historian team before modifying (b/239640926).
894  */
printBrightnessStates(const char * path)895 void BrightnessController::printBrightnessStates(const char* path) {
896     ALOGI("path=%s, id=%d, level=%d, DimmingOn=%d, Hbm=%d, LhbmOn=%d", path ?: "unknown",
897           mPanelIndex, mBrightnessLevel.get(), mDimming.get(), mGhbm.get(), mLhbm.get());
898 }
899 
dump(String8 & result)900 void BrightnessController::dump(String8& result) {
901     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
902 
903     result.appendFormat("BrightnessController:\n");
904     result.appendFormat("\tsysfs support %d, max %d, valid brightness table %d, "
905                         "lhbm supported %d, ghbm supported %d\n", mBrightnessOfs.is_open(),
906                         mMaxBrightness, mBrightnessIntfSupported, mLhbmSupported, mGhbmSupported);
907     result.appendFormat("\trequests: enhance hbm %d, lhbm %d, "
908                         "brightness %f, instant hbm %d, DimBrightness %d\n",
909                         mEnhanceHbmReq.get(), mLhbmReq.get(), mBrightnessFloatReq.get(),
910                         mInstantHbmReq.get(), mDimBrightnessReq.get());
911     result.appendFormat("\tstates: brighntess level %d, ghbm %d, dimming %d, lhbm %d",
912                         mBrightnessLevel.get(), mGhbm.get(), mDimming.get(), mLhbm.get());
913     result.appendFormat("\thdr layer state %d, unchecked lhbm request %d(%d), "
914                         "unchecked ghbm request %d(%d)\n",
915                         mHdrLayerState.get(), mUncheckedLhbmRequest.load(),
916                         mPendingLhbmStatus.load(), mUncheckedGbhmRequest.load(),
917                         mPendingGhbmStatus.load());
918     result.appendFormat("\tdimming usage %d, hbm dimming %d, time us %d\n", mBrightnessDimmingUsage,
919                         mHbmDimming, mHbmDimmingTimeUs);
920     result.appendFormat("\twhite point nits current %f, previous %f\n", mDisplayWhitePointNits,
921                         mPrevDisplayWhitePointNits);
922     result.appendFormat("\tcabc supported %d, cabcMode %d\n", mCabcModeOfs.is_open(),
923                         mCabcMode.get());
924 
925     result.appendFormat("\n");
926 }
927