• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 //#define LOG_NDEBUG 0
17 
18 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
19 
20 #include "ExynosPrimaryDisplay.h"
21 
22 #include <linux/fb.h>
23 #include <poll.h>
24 
25 #include <chrono>
26 #include <fstream>
27 
28 #include "BrightnessController.h"
29 #include "ExynosDevice.h"
30 #include "ExynosDisplayDrmInterface.h"
31 #include "ExynosDisplayDrmInterfaceModule.h"
32 #include "ExynosExternalDisplay.h"
33 #include "ExynosHWCDebug.h"
34 #include "ExynosHWCHelper.h"
35 #include "ExynosLayer.h"
36 #include "HistogramController.h"
37 
38 extern struct exynos_hwc_control exynosHWCControl;
39 
40 using namespace SOC_VERSION;
41 constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count();
42 
43 static const std::map<const DisplayType, const std::string> panelSysfsPath =
44         {{DisplayType::DISPLAY_PRIMARY, "/sys/devices/platform/exynos-drm/primary-panel/"},
45          {DisplayType::DISPLAY_SECONDARY, "/sys/devices/platform/exynos-drm/secondary-panel/"}};
46 
getPropertyBootModeStr(const int32_t dispId)47 static String8 getPropertyBootModeStr(const int32_t dispId) {
48     String8 str;
49     if (dispId == 0) {
50         str.appendFormat("persist.vendor.display.primary.boot_config");
51     } else {
52         str.appendFormat("persist.vendor.display.%d.primary.boot_config", dispId);
53     }
54     return str;
55 }
56 
loadPanelGammaCalibration(const std::string & file)57 static std::string loadPanelGammaCalibration(const std::string &file) {
58     std::ifstream ifs(file);
59 
60     if (!ifs.is_open()) {
61         ALOGW("Unable to open gamma calibration '%s', error = %s", file.c_str(), strerror(errno));
62         return {};
63     }
64 
65     std::string raw_data, gamma;
66     char ch;
67     while (std::getline(ifs, raw_data, '\r')) {
68         gamma.append(raw_data);
69         gamma.append(1, ' ');
70         ifs.get(ch);
71         if (ch != '\n') {
72             gamma.append(1, ch);
73         }
74     }
75     ifs.close();
76 
77     /* eliminate space character in the last byte */
78     if (!gamma.empty()) {
79         gamma.pop_back();
80     }
81 
82     return gamma;
83 }
84 
ExynosPrimaryDisplay(uint32_t index,ExynosDevice * device,const std::string & displayName)85 ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device,
86                                            const std::string &displayName)
87       : ExynosDisplay(HWC_DISPLAY_PRIMARY, index, device, displayName),
88         mUseBlockingZoneForMinIdleRefreshRate(false),
89         mMinIdleRefreshRate(0),
90         mVrrThrottleFps{0},
91         mVrrThrottleNanos{0},
92         mRefreshRateDelayNanos(0),
93         mLastRefreshRateAppliedNanos(0),
94         mAppliedActiveConfig(0),
95         mDisplayIdleTimerEnabled(false),
96         mDisplayIdleTimerNanos{0},
97         mDisplayNeedHandleIdleExit(false) {
98     // TODO : Hard coded here
99     mNumMaxPriorityAllowed = 5;
100 
101     /* Initialization */
102     mFramesToReachLhbmPeakBrightness =
103             property_get_int32("vendor.primarydisplay.lhbm.frames_to_reach_peak_brightness", 3);
104 
105     /* TODO(b/274705046): use drm properties instead of system properties */
106     mDefaultMinIdleRefreshRate =
107             property_get_int32("vendor.primarydisplay.min_idle_refresh_rate.default", 0);
108     mMinIdleRefreshRateForBlockingZone =
109             property_get_int32("vendor.primarydisplay.min_idle_refresh_rate.blocking_zone", 0);
110     mDbvThresholdForBlockingZone =
111             property_get_int32("vendor.primarydisplay.min_idle_refresh_rate.blocking_zone_dbv", 0);
112     if (mDefaultMinIdleRefreshRate && mMinIdleRefreshRateForBlockingZone &&
113         mDbvThresholdForBlockingZone) {
114         mUseBlockingZoneForMinIdleRefreshRate = true;
115         ALOGI("%s min_default=%d min_blocking_zone=%d dbv_blocking_zone=%d", __func__,
116               mDefaultMinIdleRefreshRate, mMinIdleRefreshRateForBlockingZone,
117               mDbvThresholdForBlockingZone);
118     }
119 
120     // Allow to enable dynamic recomposition after every power on
121     // since it will always be disabled for every power off
122     // TODO(b/268474771): to enable DR by default if video mode panel is detected
123     if (property_get_int32("vendor.display.dynamic_recomposition", 0) & (1 << index)) {
124         mDRDefault = true;
125         mDREnable = true;
126     }
127 
128     // Prepare multi resolution
129     // Will be exynosHWCControl.multiResoultion
130     mResolutionInfo.nNum = 1;
131     mResolutionInfo.nResolution[0].w = 1440;
132     mResolutionInfo.nResolution[0].h = 2960;
133     mResolutionInfo.nDSCYSliceSize[0] = 40;
134     mResolutionInfo.nDSCXSliceSize[0] = 1440 / 2;
135     mResolutionInfo.nPanelType[0] = PANEL_DSC;
136     mResolutionInfo.nResolution[1].w = 1080;
137     mResolutionInfo.nResolution[1].h = 2220;
138     mResolutionInfo.nDSCYSliceSize[1] = 30;
139     mResolutionInfo.nDSCXSliceSize[1] = 1080 / 2;
140     mResolutionInfo.nPanelType[1] = PANEL_DSC;
141     mResolutionInfo.nResolution[2].w = 720;
142     mResolutionInfo.nResolution[2].h = 1480;
143     mResolutionInfo.nDSCYSliceSize[2] = 74;
144     mResolutionInfo.nDSCXSliceSize[2] = 720;
145     mResolutionInfo.nPanelType[2] = PANEL_LEGACY;
146 
147     char value[PROPERTY_VALUE_MAX];
148     const char *earlyWakeupNodeBase = early_wakeup_node_0_base;
149     if (getDisplayTypeFromIndex(mIndex) == DisplayType::DISPLAY_SECONDARY &&
150         property_get("vendor.display.secondary_early_wakeup_node", value, "") > 0) {
151         earlyWakeupNodeBase = value;
152     }
153     mEarlyWakeupDispFd = fopen(earlyWakeupNodeBase, "w");
154     if (mEarlyWakeupDispFd == nullptr)
155         ALOGE("open %s failed! %s", earlyWakeupNodeBase, strerror(errno));
156     mBrightnessController = std::make_unique<BrightnessController>(
__anonca01fe500102() 157             mIndex, [this]() { mDevice->onRefresh(mDisplayId); },
__anonca01fe500202() 158             [this]() { updatePresentColorConversionInfo(); });
159     mHistogramController = std::make_unique<HistogramController>(this);
160 
161     mDisplayControl.multiThreadedPresent = true;
162 }
163 
~ExynosPrimaryDisplay()164 ExynosPrimaryDisplay::~ExynosPrimaryDisplay()
165 {
166     if (mEarlyWakeupDispFd) {
167         fclose(mEarlyWakeupDispFd);
168         mEarlyWakeupDispFd = nullptr;
169     }
170 
171     if (mDisplayNeedHandleIdleExitOfs.is_open()) {
172         mDisplayNeedHandleIdleExitOfs.close();
173     }
174 }
175 
setDDIScalerEnable(int width,int height)176 void ExynosPrimaryDisplay::setDDIScalerEnable(int width, int height) {
177 
178     if (exynosHWCControl.setDDIScaler == false) return;
179 
180     ALOGI("DDISCALER Info : setDDIScalerEnable(w=%d,h=%d)", width, height);
181     mNewScaledWidth = width;
182     mNewScaledHeight = height;
183     mXres = width;
184     mYres = height;
185 }
186 
getDDIScalerMode(int width,int height)187 int ExynosPrimaryDisplay::getDDIScalerMode(int width, int height) {
188 
189     if (exynosHWCControl.setDDIScaler == false) return 1;
190 
191     // Check if panel support support resolution or not.
192     for (uint32_t i=0; i < mResolutionInfo.nNum; i++) {
193         if (mResolutionInfo.nResolution[i].w * mResolutionInfo.nResolution[i].h ==
194                 static_cast<uint32_t>(width * height))
195             return i + 1;
196     }
197 
198     return 1; // WQHD
199 }
200 
doDisplayConfigInternal(hwc2_config_t config)201 int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
202     if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
203         !isConfigSettingEnabled()) {
204         mPendingConfig = config;
205         mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
206         DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config);
207         return NO_ERROR;
208     }
209     return ExynosDisplay::doDisplayConfigInternal(config);
210 }
211 
getActiveConfigInternal(hwc2_config_t * outConfig)212 int32_t ExynosPrimaryDisplay::getActiveConfigInternal(hwc2_config_t *outConfig) {
213     if (outConfig && mPendingConfig != UINT_MAX) {
214         *outConfig = mPendingConfig;
215         return HWC2_ERROR_NONE;
216     }
217     return ExynosDisplay::getActiveConfigInternal(outConfig);
218 }
219 
setActiveConfigInternal(hwc2_config_t config,bool force)220 int32_t ExynosPrimaryDisplay::setActiveConfigInternal(hwc2_config_t config, bool force) {
221     hwc2_config_t cur_config;
222 
223     getActiveConfigInternal(&cur_config);
224     if (cur_config == config) {
225         ALOGI("%s:: Same display config is set", __func__);
226         return HWC2_ERROR_NONE;
227     }
228     if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
229         !isConfigSettingEnabled()) {
230         mPendingConfig = config;
231         return HWC2_ERROR_NONE;
232     }
233     return ExynosDisplay::setActiveConfigInternal(config, force);
234 }
235 
applyPendingConfig()236 int32_t ExynosPrimaryDisplay::applyPendingConfig() {
237     if (!isConfigSettingEnabled()) return HWC2_ERROR_NONE;
238 
239     hwc2_config_t config;
240     if (mPendingConfig != UINT_MAX) {
241         config = mPendingConfig;
242         mPendingConfig = UINT_MAX;
243     } else {
244         getActiveConfigInternal(&config);
245     }
246 
247     return ExynosDisplay::setActiveConfigInternal(config, true);
248 }
249 
setBootDisplayConfig(int32_t config)250 int32_t ExynosPrimaryDisplay::setBootDisplayConfig(int32_t config) {
251     auto hwcConfig = static_cast<hwc2_config_t>(config);
252 
253     const auto &it = mDisplayConfigs.find(hwcConfig);
254     if (it == mDisplayConfigs.end()) {
255         DISPLAY_LOGE("%s: invalid config %d", __func__, config);
256         return HWC2_ERROR_BAD_CONFIG;
257     }
258 
259     const auto &mode = it->second;
260     if (mode.vsyncPeriod == 0)
261         return HWC2_ERROR_BAD_CONFIG;
262 
263     int refreshRate = round(nsecsPerSec / mode.vsyncPeriod * 0.1f) * 10;
264     char modeStr[PROPERTY_VALUE_MAX];
265     int ret = snprintf(modeStr, sizeof(modeStr), "%dx%d@%d",
266              mode.width, mode.height, refreshRate);
267     if (ret <= 0)
268         return HWC2_ERROR_BAD_CONFIG;
269 
270     ALOGD("%s: mode=%s (%d) vsyncPeriod=%d", __func__, modeStr, config,
271             mode.vsyncPeriod);
272     ret = property_set(getPropertyBootModeStr(mDisplayId).string(), modeStr);
273 
274     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
275 }
276 
clearBootDisplayConfig()277 int32_t ExynosPrimaryDisplay::clearBootDisplayConfig() {
278     auto ret = property_set(getPropertyBootModeStr(mDisplayId).string(), nullptr);
279 
280     ALOGD("%s: clearing boot mode", __func__);
281     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
282 }
283 
getPreferredDisplayConfigInternal(int32_t * outConfig)284 int32_t ExynosPrimaryDisplay::getPreferredDisplayConfigInternal(int32_t *outConfig) {
285     char modeStr[PROPERTY_VALUE_MAX];
286     auto ret = property_get(getPropertyBootModeStr(mDisplayId).string(), modeStr, "");
287 
288     if (ret <= 0) {
289         return mDisplayInterface->getDefaultModeId(outConfig);
290     }
291 
292     int width, height;
293     int fps = 0;
294 
295     ret = sscanf(modeStr, "%dx%d@%d", &width, &height, &fps);
296     if ((ret < 3) || !fps) {
297         ALOGD("%s: unable to find boot config for mode: %s", __func__, modeStr);
298         return HWC2_ERROR_BAD_CONFIG;
299     }
300 
301     return lookupDisplayConfigs(width, height, fps, outConfig);
302 }
303 
setPowerOn()304 int32_t ExynosPrimaryDisplay::setPowerOn() {
305     ATRACE_CALL();
306     updateAppliedActiveConfig(0, 0);
307     int ret = NO_ERROR;
308     if (mDisplayId != 0 || !mFirstPowerOn) {
309         if (mDevice->hasOtherDisplayOn(this)) {
310             // TODO: This is useful for cmd mode, and b/282094671 tries to handles video mode
311             mDisplayInterface->triggerClearDisplayPlanes();
312         }
313         ret = applyPendingConfig();
314     }
315 
316     if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF)) {
317         // check the dynamic recomposition thread by following display
318         mDevice->checkDynamicRecompositionThread();
319         if (ret) {
320             mDisplayInterface->setPowerMode(HWC2_POWER_MODE_ON);
321         }
322         setGeometryChanged(GEOMETRY_DISPLAY_POWER_ON);
323     }
324 
325     {
326         std::lock_guard<std::mutex> lock(mPowerModeMutex);
327         mPowerModeState = HWC2_POWER_MODE_ON;
328         if (mNotifyPowerOn) {
329             mPowerOnCondition.notify_one();
330             mNotifyPowerOn = false;
331         }
332     }
333 
334     if (mFirstPowerOn) {
335         firstPowerOn();
336     }
337 
338     return HWC2_ERROR_NONE;
339 }
340 
setPowerOff()341 int32_t ExynosPrimaryDisplay::setPowerOff() {
342     ATRACE_CALL();
343 
344     clearDisplay(true);
345 
346     // check the dynamic recomposition thread by following display
347     mDevice->checkDynamicRecompositionThread();
348 
349     mDisplayInterface->setPowerMode(HWC2_POWER_MODE_OFF);
350 
351     {
352         std::lock_guard<std::mutex> lock(mPowerModeMutex);
353         mPowerModeState = HWC2_POWER_MODE_OFF;
354     }
355 
356     /* It should be called from validate() when the screen is on */
357     mSkipFrame = true;
358     setGeometryChanged(GEOMETRY_DISPLAY_POWER_OFF);
359     if ((mRenderingState >= RENDERING_STATE_VALIDATED) &&
360         (mRenderingState < RENDERING_STATE_PRESENTED))
361         closeFencesForSkipFrame(RENDERING_STATE_VALIDATED);
362     mRenderingState = RENDERING_STATE_NONE;
363 
364     // in the case user turns off screen when LHBM is on
365     // TODO: b/236433238 considering a lock for mLhbmOn state
366     mLhbmOn = false;
367     return HWC2_ERROR_NONE;
368 }
369 
setPowerDoze(hwc2_power_mode_t mode)370 int32_t ExynosPrimaryDisplay::setPowerDoze(hwc2_power_mode_t mode) {
371     ATRACE_CALL();
372 
373     if (!mDisplayInterface->isDozeModeAvailable()) {
374         return HWC2_ERROR_UNSUPPORTED;
375     }
376 
377     if (mPowerModeState.has_value() &&
378         ((*mPowerModeState == HWC2_POWER_MODE_OFF) || (*mPowerModeState == HWC2_POWER_MODE_ON))) {
379         if (mDisplayInterface->setLowPowerMode()) {
380             ALOGI("Not support LP mode.");
381             return HWC2_ERROR_UNSUPPORTED;
382         }
383     }
384 
385     {
386         std::lock_guard<std::mutex> lock(mPowerModeMutex);
387         mPowerModeState = mode;
388     }
389 
390     // LHBM will be disabled in the kernel while entering AOD mode if it's
391     // already enabled. Reset the state to avoid the sync problem.
392     mBrightnessController->resetLhbmState();
393     mLhbmOn = false;
394 
395     ExynosDisplay::updateRefreshRateHint();
396 
397     return HWC2_ERROR_NONE;
398 }
399 
setPowerMode(int32_t mode)400 int32_t ExynosPrimaryDisplay::setPowerMode(int32_t mode) {
401     Mutex::Autolock lock(mDisplayMutex);
402 
403     if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::PAUSE)) {
404         mode = HWC2_POWER_MODE_OFF;
405         mPauseDisplay = true;
406     } else if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) {
407         mode = HWC2_POWER_MODE_ON;
408         mPauseDisplay = false;
409     } else if (mPauseDisplay) {
410         ALOGI("Skip power mode transition due to pause display.");
411         return HWC2_ERROR_NONE;
412     }
413 
414     if (mPowerModeState.has_value() && (mode == static_cast<int32_t>(mPowerModeState.value()))) {
415         ALOGI("Skip power mode transition due to the same power state.");
416         return HWC2_ERROR_NONE;
417     }
418 
419     int fb_blank = (mode != HWC2_POWER_MODE_OFF) ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
420     ALOGD("%s:: FBIOBLANK mode(%d), blank(%d)", __func__, mode, fb_blank);
421 
422     if (fb_blank == FB_BLANK_POWERDOWN)
423         mDREnable = false;
424     else
425         mDREnable = mDRDefault;
426 
427     if (mOperationRateManager) {
428         mOperationRateManager->onPowerMode(mode);
429         mBrightnessController->processOperationRate(
430                 mOperationRateManager->getTargetOperationRate());
431     }
432 
433     switch (mode) {
434         case HWC2_POWER_MODE_DOZE:
435         case HWC2_POWER_MODE_DOZE_SUSPEND:
436             if (mode == HWC2_POWER_MODE_DOZE && mDisplayInterface->needRefreshOnLP()) {
437                 ALOGI("Refresh before setting power doze.");
438                 mDevice->onRefresh(mDisplayId);
439             }
440             return setPowerDoze(static_cast<hwc2_power_mode_t>(mode));
441         case HWC2_POWER_MODE_OFF:
442             setPowerOff();
443             break;
444         case HWC2_POWER_MODE_ON:
445             setPowerOn();
446             break;
447         default:
448             return HWC2_ERROR_BAD_PARAMETER;
449     }
450 
451     ExynosDisplay::updateRefreshRateHint();
452 
453     return HWC2_ERROR_NONE;
454 }
455 
firstPowerOn()456 void ExynosPrimaryDisplay::firstPowerOn() {
457     SetCurrentPanelGammaSource(DisplayType::DISPLAY_PRIMARY, PanelGammaSource::GAMMA_CALIBRATION);
458     mFirstPowerOn = false;
459     getDisplayIdleTimerEnabled(mDisplayIdleTimerEnabled);
460     initDisplayHandleIdleExit();
461 }
462 
getHDRException(ExynosLayer * __unused layer)463 bool ExynosPrimaryDisplay::getHDRException(ExynosLayer* __unused layer)
464 {
465     return false;
466 }
467 
initDisplayInterface(uint32_t interfaceType)468 void ExynosPrimaryDisplay::initDisplayInterface(uint32_t interfaceType)
469 {
470     if (interfaceType == INTERFACE_TYPE_DRM)
471         mDisplayInterface = std::make_unique<ExynosPrimaryDisplayDrmInterfaceModule>((ExynosDisplay *)this);
472     else
473         LOG_ALWAYS_FATAL("%s::Unknown interface type(%d)",
474                 __func__, interfaceType);
475     mDisplayInterface->init(this);
476 
477     mDpuData.init(mMaxWindowNum, mDevice->getSpecialPlaneNum(mDisplayId));
478     mLastDpuData.init(mMaxWindowNum, mDevice->getSpecialPlaneNum(mDisplayId));
479     ALOGI("window configs size(%zu) rcd configs zie(%zu)", mDpuData.configs.size(),
480           mDpuData.rcdConfigs.size());
481 }
482 
getPanelSysfsPath(const DisplayType & type)483 std::string ExynosPrimaryDisplay::getPanelSysfsPath(const DisplayType &type) {
484     if ((type < DisplayType::DISPLAY_PRIMARY) || (type >= DisplayType::DISPLAY_MAX)) {
485         ALOGE("Invalid display panel type %d", type);
486         return {};
487     }
488 
489     auto iter = panelSysfsPath.find(type);
490     if (iter == panelSysfsPath.end()) {
491         return {};
492     }
493 
494     return iter->second;
495 }
496 
SetCurrentPanelGammaSource(const DisplayType type,const PanelGammaSource & source)497 int32_t ExynosPrimaryDisplay::SetCurrentPanelGammaSource(const DisplayType type,
498                                                          const PanelGammaSource &source) {
499     std::string &&panel_sysfs_path = getPanelSysfsPath(type);
500     if (panel_sysfs_path.empty()) {
501         return HWC2_ERROR_UNSUPPORTED;
502     }
503 
504     std::ifstream ifs;
505     std::string &&path = panel_sysfs_path + "panel_name";
506     ifs.open(path, std::ifstream::in);
507     if (!ifs.is_open()) {
508         ALOGW("Unable to access panel name path '%s' (%s)", path.c_str(), strerror(errno));
509         return HWC2_ERROR_UNSUPPORTED;
510     }
511     std::string panel_name;
512     std::getline(ifs, panel_name);
513     ifs.close();
514 
515     path = panel_sysfs_path + "serial_number";
516     ifs.open(path, std::ifstream::in);
517     if (!ifs.is_open()) {
518         ALOGW("Unable to access panel id path '%s' (%s)", path.c_str(), strerror(errno));
519         return HWC2_ERROR_UNSUPPORTED;
520     }
521     std::string panel_id;
522     std::getline(ifs, panel_id);
523     ifs.close();
524 
525     std::string gamma_node = panel_sysfs_path + "gamma";
526     if (access(gamma_node.c_str(), W_OK)) {
527         ALOGW("Unable to access panel gamma calibration node '%s' (%s)", gamma_node.c_str(),
528               strerror(errno));
529         return HWC2_ERROR_UNSUPPORTED;
530     }
531 
532     std::string &&gamma_data = "default";
533     if (source == PanelGammaSource::GAMMA_CALIBRATION) {
534         std::string gamma_cal_file(kDisplayCalFilePath);
535         gamma_cal_file.append(kPanelGammaCalFilePrefix)
536                 .append(1, '_')
537                 .append(panel_name)
538                 .append(1, '_')
539                 .append(panel_id)
540                 .append(".cal");
541         if (access(gamma_cal_file.c_str(), R_OK)) {
542             ALOGI("Fail to access `%s` (%s), try golden gamma calibration", gamma_cal_file.c_str(),
543                   strerror(errno));
544             gamma_cal_file = kDisplayCalFilePath;
545             gamma_cal_file.append(kPanelGammaCalFilePrefix)
546                     .append(1, '_')
547                     .append(panel_name)
548                     .append(".cal");
549         }
550         gamma_data = loadPanelGammaCalibration(gamma_cal_file);
551     }
552 
553     if (gamma_data.empty()) {
554         return HWC2_ERROR_UNSUPPORTED;
555     }
556 
557     std::ofstream ofs(gamma_node);
558     if (!ofs.is_open()) {
559         ALOGW("Unable to open gamma node '%s', error = %s", gamma_node.c_str(), strerror(errno));
560         return HWC2_ERROR_UNSUPPORTED;
561     }
562     ofs.write(gamma_data.c_str(), gamma_data.size());
563     ofs.close();
564 
565     currentPanelGammaSource = source;
566     return HWC2_ERROR_NONE;
567 }
568 
isLhbmSupported()569 bool ExynosPrimaryDisplay::isLhbmSupported() {
570     return mBrightnessController->isLhbmSupported();
571 }
572 
isConfigSettingEnabled()573 bool ExynosPrimaryDisplay::isConfigSettingEnabled() {
574     int64_t msSinceDisabled =
575             (systemTime(SYSTEM_TIME_MONOTONIC) - mConfigSettingDisabledTimestamp) / 1000000;
576     return !mConfigSettingDisabled || msSinceDisabled > kConfigDisablingMaxDurationMs;
577 }
578 
enableConfigSetting(bool en)579 void ExynosPrimaryDisplay::enableConfigSetting(bool en) {
580     DISPLAY_ATRACE_INT("ConfigSettingDisabled", !en);
581 
582     if (!en) {
583         mConfigSettingDisabled = true;
584         mConfigSettingDisabledTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
585         return;
586     }
587 
588     mConfigSettingDisabled = false;
589 }
590 
setLhbmDisplayConfigLocked(uint32_t peakRate)591 int32_t ExynosPrimaryDisplay::setLhbmDisplayConfigLocked(uint32_t peakRate) {
592     auto hwConfig = mDisplayInterface->getActiveModeId();
593     auto config = getConfigId(peakRate, mDisplayConfigs[hwConfig].width,
594                               mDisplayConfigs[hwConfig].height);
595     if (config == UINT_MAX) {
596         DISPLAY_LOGE("%s: failed to get config for rate=%d", __func__, peakRate);
597         return -EINVAL;
598     }
599 
600     if (mPendingConfig == UINT_MAX && mActiveConfig != config) mPendingConfig = mActiveConfig;
601     if (config != hwConfig) {
602         if (ExynosDisplay::setActiveConfigInternal(config, true) == HWC2_ERROR_NONE) {
603             DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, config, peakRate);
604         } else {
605             DISPLAY_LOGW("%s: failed to set config=%d rate=%d", __func__, config, peakRate);
606         }
607     } else {
608         DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, config, peakRate);
609     }
610     enableConfigSetting(false);
611     return OK;
612 }
613 
restoreLhbmDisplayConfigLocked()614 void ExynosPrimaryDisplay::restoreLhbmDisplayConfigLocked() {
615     enableConfigSetting(true);
616     hwc2_config_t pendingConfig = mPendingConfig;
617     auto hwConfig = mDisplayInterface->getActiveModeId();
618     if (pendingConfig != UINT_MAX && pendingConfig != hwConfig) {
619         if (applyPendingConfig() == HWC2_ERROR_NONE) {
620             DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, pendingConfig,
621                          getRefreshRate(pendingConfig));
622         } else {
623             DISPLAY_LOGE("%s: failed to set config=%d rate=%d", __func__, pendingConfig,
624                          getRefreshRate(pendingConfig));
625         }
626     } else {
627         mPendingConfig = UINT_MAX;
628         DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, hwConfig, getRefreshRate(hwConfig));
629     }
630 }
631 
632 // This function should be called by other threads (e.g. sensor HAL).
633 // HWCService can call this function but it should be for test purpose only.
setLhbmState(bool enabled)634 int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
635     int ret = OK;
636     // NOTE: mLhbmOn could be set to false at any time by setPowerOff in another
637     // thread. Make sure no side effect if that happens. Or add lock if we have
638     // to when new code is added.
639     DISPLAY_ATRACE_CALL();
640     DISPLAY_LOGI("%s: enabled=%d", __func__, enabled);
641     {
642         ATRACE_NAME("wait_for_power_on");
643         std::unique_lock<std::mutex> lock(mPowerModeMutex);
644         if (mPowerModeState != HWC2_POWER_MODE_ON) {
645             mNotifyPowerOn = true;
646             if (!mPowerOnCondition.wait_for(lock, std::chrono::milliseconds(2000), [this]() {
647                     return (mPowerModeState == HWC2_POWER_MODE_ON);
648                 })) {
649                 DISPLAY_LOGW("%s: wait for power mode on timeout !", __func__);
650                 return TIMED_OUT;
651             }
652         }
653     }
654 
655     auto lhbmSysfs = mBrightnessController->GetPanelSysfileByIndex(
656             BrightnessController::kLocalHbmModeFileNode);
657     ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
658                                          {std::to_string(static_cast<int>(
659                                                  BrightnessController::LhbmMode::DISABLED))},
660                                          0);
661     bool wasDisabled = ret == OK;
662     if (!enabled && wasDisabled) {
663         DISPLAY_LOGW("%s: lhbm is at DISABLED state, skip disabling", __func__);
664         return NO_ERROR;
665     } else if (enabled && !wasDisabled) {
666         requestLhbm(true);
667         DISPLAY_LOGI("%s: lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer",
668                      __func__);
669         return NO_ERROR;
670     }
671 
672     std::vector<std::string> checkingValue;
673     if (!enabled) {
674         ATRACE_NAME("disable_lhbm");
675         requestLhbm(false);
676         {
677             ATRACE_NAME("wait_for_lhbm_off_cmd");
678             checkingValue = {
679                     std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
680             ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
681                                                           ms2ns(kSysfsCheckTimeoutMs));
682             if (ret != OK) {
683                 DISPLAY_LOGW("%s: failed to send lhbm-off cmd", __func__);
684             }
685         }
686         {
687             Mutex::Autolock lock(mDisplayMutex);
688             restoreLhbmDisplayConfigLocked();
689         }
690         setLHBMRefreshRateThrottle(0);
691         mLhbmOn = false;
692         return NO_ERROR;
693     }
694 
695     ATRACE_NAME("enable_lhbm");
696     int64_t lhbmWaitForRrNanos, lhbmEnablingNanos, lhbmEnablingDoneNanos;
697     bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
698     uint32_t peakRate = 0;
699     auto rrSysfs = mBrightnessController->GetPanelRefreshRateSysfile();
700     lhbmWaitForRrNanos = systemTime(SYSTEM_TIME_MONOTONIC);
701     {
702         Mutex::Autolock lock(mDisplayMutex);
703         peakRate = getPeakRefreshRate();
704         if (peakRate < 60) {
705             DISPLAY_LOGE("%s: invalid peak rate=%d", __func__, peakRate);
706             return -EINVAL;
707         }
708         ret = setLhbmDisplayConfigLocked(peakRate);
709         if (ret != OK) return ret;
710     }
711 
712     if (mBrightnessController->fileExists(rrSysfs)) {
713         ATRACE_NAME("wait_for_peak_rate_cmd");
714         ret = mBrightnessController->checkSysfsStatus(rrSysfs, {std::to_string(peakRate)},
715                                                       ms2ns(kLhbmWaitForPeakRefreshRateMs));
716         if (ret != OK) {
717             DISPLAY_LOGW("%s: failed to poll peak refresh rate=%d, ret=%d", __func__, peakRate,
718                          ret);
719         }
720     } else {
721         ATRACE_NAME("wait_for_peak_rate_blindly");
722         DISPLAY_LOGW("%s: missing refresh rate path: %s", __func__, rrSysfs.c_str());
723         // blindly wait for (3 full frames + 1 frame uncertainty) to ensure DM finishes
724         // switching refresh rate
725         for (int32_t i = 0; i < 4; i++) {
726             if (mDisplayInterface->waitVBlank()) {
727                 DISPLAY_LOGE("%s: failed to blindly wait for peak refresh rate=%d, i=%d", __func__,
728                              peakRate, i);
729                 ret = -ENODEV;
730                 goto enable_err;
731             }
732         }
733     }
734 
735     setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
736     checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
737                      std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
738     lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
739     requestLhbm(true);
740     {
741         ATRACE_NAME("wait_for_lhbm_on_cmd");
742         ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
743                                                       ms2ns(kSysfsCheckTimeoutMs));
744         if (ret != OK) {
745             DISPLAY_LOGE("%s: failed to enable lhbm", __func__);
746             setLHBMRefreshRateThrottle(0);
747             goto enable_err;
748         }
749     }
750 
751     lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
752     {
753         ATRACE_NAME("wait_for_peak_brightness");
754         if (enablingStateSupported) {
755             ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
756                                             {std::to_string(static_cast<int>(
757                                                     BrightnessController::LhbmMode::ENABLED))},
758                                             ms2ns(kSysfsCheckTimeoutMs));
759             if (ret != OK) {
760                 DISPLAY_LOGE("%s: failed to wait for lhbm becoming effective", __func__);
761                 goto enable_err;
762             }
763         } else {
764             // lhbm takes effect at next vblank
765             for (int32_t i = mFramesToReachLhbmPeakBrightness + 1; i > 0; i--) {
766                 ret = mDisplayInterface->waitVBlank();
767                 if (ret) {
768                     DISPLAY_LOGE("%s: failed to wait vblank for peak brightness, %d", __func__, i);
769                     goto enable_err;
770                 }
771             }
772         }
773     }
774     DISPLAY_LOGI("%s: latency: %04d = %03d|rr@%03d + %03d|en + %03d|boost@%s", __func__,
775                  getTimestampDeltaMs(0, lhbmWaitForRrNanos),
776                  getTimestampDeltaMs(lhbmEnablingNanos, lhbmWaitForRrNanos), peakRate,
777                  getTimestampDeltaMs(lhbmEnablingDoneNanos, lhbmEnablingNanos),
778                  getTimestampDeltaMs(0, lhbmEnablingDoneNanos),
779                  enablingStateSupported ? "polling" : "fixed");
780 
781     mLhbmOn = true;
782     if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn)) {
783         mLhbmOn = false;
784         DISPLAY_LOGE("%s: power off during request lhbm on", __func__);
785         return -EINVAL;
786     }
787     return NO_ERROR;
788 enable_err:
789     Mutex::Autolock lock(mDisplayMutex);
790     restoreLhbmDisplayConfigLocked();
791     return ret;
792 }
793 
getLhbmState()794 bool ExynosPrimaryDisplay::getLhbmState() {
795     return mLhbmOn;
796 }
797 
setLHBMRefreshRateThrottle(const uint32_t delayMs)798 void ExynosPrimaryDisplay::setLHBMRefreshRateThrottle(const uint32_t delayMs) {
799     ATRACE_CALL();
800 
801     if (delayMs) {
802         // make new throttle take effect
803         mLastRefreshRateAppliedNanos = systemTime(SYSTEM_TIME_MONOTONIC);
804         DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos));
805     }
806 
807     setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>(
808                                         std::chrono::milliseconds(delayMs))
809                                         .count(),
810                                 VrrThrottleRequester::LHBM);
811 }
812 
setEarlyWakeupDisplay()813 void ExynosPrimaryDisplay::setEarlyWakeupDisplay() {
814     if (mEarlyWakeupDispFd) {
815         writeFileNode(mEarlyWakeupDispFd, 1);
816     }
817 }
818 
setExpectedPresentTime(uint64_t timestamp)819 void ExynosPrimaryDisplay::setExpectedPresentTime(uint64_t timestamp) {
820     mExpectedPresentTime.store(timestamp);
821 }
822 
getPendingExpectedPresentTime()823 uint64_t ExynosPrimaryDisplay::getPendingExpectedPresentTime() {
824     if (mExpectedPresentTime.is_dirty()) {
825         return mExpectedPresentTime.get();
826     }
827 
828     return 0;
829 }
830 
applyExpectedPresentTime()831 void ExynosPrimaryDisplay::applyExpectedPresentTime() {
832     mExpectedPresentTime.clear_dirty();
833 }
834 
setDisplayIdleTimer(const int32_t timeoutMs)835 int32_t ExynosPrimaryDisplay::setDisplayIdleTimer(const int32_t timeoutMs) {
836     bool support = false;
837     if (getDisplayIdleTimerSupport(support) || support == false) {
838         return HWC2_ERROR_UNSUPPORTED;
839     }
840 
841     if (timeoutMs < 0) {
842         return HWC2_ERROR_BAD_PARAMETER;
843     }
844 
845     if (timeoutMs > 0) {
846         setDisplayIdleDelayNanos(std::chrono::duration_cast<std::chrono::nanoseconds>(
847                                          std::chrono::milliseconds(timeoutMs))
848                                          .count(),
849                                  DispIdleTimerRequester::SF);
850     }
851 
852     bool enabled = (timeoutMs > 0);
853     if (enabled != mDisplayIdleTimerEnabled) {
854         if (setDisplayIdleTimerEnabled(enabled) == NO_ERROR) {
855             mDisplayIdleTimerEnabled = enabled;
856         }
857     }
858 
859     return HWC2_ERROR_NONE;
860 }
861 
getDisplayIdleTimerEnabled(bool & enabled)862 int32_t ExynosPrimaryDisplay::getDisplayIdleTimerEnabled(bool &enabled) {
863     bool support = false;
864     if (getDisplayIdleTimerSupport(support) || support == false) {
865         return HWC2_ERROR_UNSUPPORTED;
866     }
867 
868     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle";
869     std::ifstream ifs(path);
870     if (!ifs.is_open()) {
871         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
872         return errno;
873     } else {
874         std::string panel_idle;
875         std::getline(ifs, panel_idle);
876         ifs.close();
877         enabled = (panel_idle == "1");
878         ALOGI("%s() get panel_idle(%d) from the sysfs node", __func__, enabled);
879     }
880     return NO_ERROR;
881 }
882 
setDisplayIdleTimerEnabled(const bool enabled)883 int32_t ExynosPrimaryDisplay::setDisplayIdleTimerEnabled(const bool enabled) {
884     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle";
885     std::ofstream ofs(path);
886     if (!ofs.is_open()) {
887         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
888         return errno;
889     } else {
890         ofs << enabled;
891         ofs.close();
892         ALOGI("%s() writes panel_idle(%d) to the sysfs node", __func__, enabled);
893     }
894     return NO_ERROR;
895 }
896 
setDisplayIdleDelayNanos(const int32_t delayNanos,const DispIdleTimerRequester requester)897 int32_t ExynosPrimaryDisplay::setDisplayIdleDelayNanos(const int32_t delayNanos,
898                                                        const DispIdleTimerRequester requester) {
899     std::lock_guard<std::mutex> lock(mDisplayIdleDelayMutex);
900 
901     int64_t maxDelayNanos = 0;
902     mDisplayIdleTimerNanos[toUnderlying(requester)] = delayNanos;
903     for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) {
904         if (mDisplayIdleTimerNanos[i] > maxDelayNanos) {
905             maxDelayNanos = mDisplayIdleTimerNanos[i];
906         }
907     }
908 
909     if (mDisplayIdleDelayNanos == maxDelayNanos) {
910         return NO_ERROR;
911     }
912 
913     mDisplayIdleDelayNanos = maxDelayNanos;
914 
915     const int32_t displayIdleDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>(
916                                                std::chrono::nanoseconds(mDisplayIdleDelayNanos))
917                                                .count();
918     const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "idle_delay_ms";
919     std::ofstream ofs(path);
920     if (!ofs.is_open()) {
921         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
922         return errno;
923     } else {
924         ofs << displayIdleDelayMs;
925         ALOGI("%s() writes idle_delay_ms(%d) to the sysfs node (0x%x)", __func__,
926               displayIdleDelayMs, ofs.rdstate());
927         ofs.close();
928     }
929     return NO_ERROR;
930 }
931 
initDisplayHandleIdleExit()932 void ExynosPrimaryDisplay::initDisplayHandleIdleExit() {
933     if (bool support; getDisplayIdleTimerSupport(support) || support == false) {
934         return;
935     }
936 
937     const std::string path =
938             getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_need_handle_idle_exit";
939     mDisplayNeedHandleIdleExitOfs.open(path, std::ofstream::out);
940     if (!mDisplayNeedHandleIdleExitOfs.is_open()) {
941         ALOGI("%s() '%s' doesn't exist(%s)", __func__, path.c_str(), strerror(errno));
942     }
943 
944     setDisplayNeedHandleIdleExit(false, true);
945 }
946 
setDisplayNeedHandleIdleExit(const bool needed,const bool force)947 void ExynosPrimaryDisplay::setDisplayNeedHandleIdleExit(const bool needed, const bool force) {
948     if (!mDisplayNeedHandleIdleExitOfs.is_open()) {
949         return;
950     }
951 
952     if (needed == mDisplayNeedHandleIdleExit && !force) {
953         return;
954     }
955 
956     mDisplayNeedHandleIdleExitOfs << needed;
957     if (mDisplayNeedHandleIdleExitOfs.fail()) {
958         ALOGW("%s() failed to write panel_need_handle_idle_exit(%d) to sysfs node %s", __func__,
959               needed, strerror(errno));
960         return;
961     }
962 
963     mDisplayNeedHandleIdleExitOfs.flush();
964     if (mDisplayNeedHandleIdleExitOfs.fail()) {
965         ALOGW("%s() failed to flush panel_need_handle_idle_exit(%d) to sysfs node %s", __func__,
966               needed, strerror(errno));
967         return;
968     }
969 
970     ALOGI("%s() writes panel_need_handle_idle_exit(%d) to sysfs node", __func__, needed);
971     mDisplayNeedHandleIdleExit = needed;
972 }
973 
handleDisplayIdleEnter(const uint32_t idleTeRefreshRate)974 void ExynosPrimaryDisplay::handleDisplayIdleEnter(const uint32_t idleTeRefreshRate) {
975     Mutex::Autolock lock(mDisplayMutex);
976     uint32_t btsRefreshRate = getBtsRefreshRate();
977     if (idleTeRefreshRate <= btsRefreshRate) {
978         return;
979     }
980 
981     bool needed = false;
982     for (size_t i = 0; i < mLayers.size(); i++) {
983         if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr &&
984             !mLayers[i]->checkBtsCap(idleTeRefreshRate)) {
985             needed = true;
986             break;
987         }
988     }
989 
990     setDisplayNeedHandleIdleExit(needed, false);
991 }
992 
setMinIdleRefreshRate(const int targetFps,const VrrThrottleRequester requester)993 int ExynosPrimaryDisplay::setMinIdleRefreshRate(const int targetFps,
994                                                 const VrrThrottleRequester requester) {
995     int fps = (targetFps <= 0) ? mDefaultMinIdleRefreshRate : targetFps;
996     if (requester == VrrThrottleRequester::BRIGHTNESS && mUseBlockingZoneForMinIdleRefreshRate) {
997         uint32_t level = mBrightnessController->getBrightnessLevel();
998         fps = (level < mDbvThresholdForBlockingZone) ? mMinIdleRefreshRateForBlockingZone
999                                                      : mDefaultMinIdleRefreshRate;
1000     }
1001 
1002     std::lock_guard<std::mutex> lock(mMinIdleRefreshRateMutex);
1003     if (fps == mVrrThrottleFps[toUnderlying(requester)]) return NO_ERROR;
1004 
1005     ALOGD("%s requester %u, fps %d", __func__, toUnderlying(requester), fps);
1006     mVrrThrottleFps[toUnderlying(requester)] = fps;
1007     int maxMinIdleFps = 0;
1008     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
1009         if (mVrrThrottleFps[i] > maxMinIdleFps) {
1010             maxMinIdleFps = mVrrThrottleFps[i];
1011         }
1012     }
1013     if (maxMinIdleFps == mMinIdleRefreshRate) return NO_ERROR;
1014 
1015     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "min_vrefresh";
1016     std::ofstream ofs(path);
1017     if (!ofs.is_open()) {
1018         ALOGW("%s Unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
1019         return errno;
1020     } else {
1021         ofs << maxMinIdleFps;
1022         ofs.close();
1023         ALOGI("ExynosPrimaryDisplay::%s() writes min_vrefresh(%d) to the sysfs node", __func__,
1024               maxMinIdleFps);
1025     }
1026     mMinIdleRefreshRate = maxMinIdleFps;
1027     return NO_ERROR;
1028 }
1029 
setRefreshRateThrottleNanos(const int64_t delayNanos,const VrrThrottleRequester requester)1030 int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos,
1031                                                       const VrrThrottleRequester requester) {
1032     ATRACE_CALL();
1033     if (delayNanos < 0) {
1034         ALOGW("%s() set invalid delay(%" PRId64 ")", __func__, delayNanos);
1035         return BAD_VALUE;
1036     }
1037 
1038     std::lock_guard<std::mutex> lock(mIdleRefreshRateThrottleMutex);
1039     if (delayNanos == mVrrThrottleNanos[toUnderlying(requester)]) return NO_ERROR;
1040 
1041     ALOGI("%s() requester(%u) set delay to %" PRId64 "ns", __func__, toUnderlying(requester),
1042           delayNanos);
1043     mVrrThrottleNanos[toUnderlying(requester)] = delayNanos;
1044     int64_t maxDelayNanos = 0;
1045     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
1046         if (mVrrThrottleNanos[i] > maxDelayNanos) {
1047             maxDelayNanos = mVrrThrottleNanos[i];
1048         }
1049     }
1050 
1051     DISPLAY_ATRACE_INT64("RefreshRateDelay", ns2ms(maxDelayNanos));
1052     if (mRefreshRateDelayNanos == maxDelayNanos) {
1053         return NO_ERROR;
1054     }
1055 
1056     mRefreshRateDelayNanos = maxDelayNanos;
1057     return setDisplayIdleDelayNanos(mRefreshRateDelayNanos, DispIdleTimerRequester::VRR_THROTTLE);
1058 }
1059 
dump(String8 & result)1060 void ExynosPrimaryDisplay::dump(String8 &result) {
1061     ExynosDisplay::dump(result);
1062     result.appendFormat("Display idle timer: %s\n",
1063                         (mDisplayIdleTimerEnabled) ? "enabled" : "disabled");
1064     for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) {
1065         result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mDisplayIdleTimerNanos[i]);
1066     }
1067 
1068     result.appendFormat("Min idle refresh rate: %d, default: %d", mMinIdleRefreshRate,
1069                         mDefaultMinIdleRefreshRate);
1070     if (mUseBlockingZoneForMinIdleRefreshRate) {
1071         result.appendFormat(", blocking zone level: %d, min refresh rate: %d\n",
1072                             mDbvThresholdForBlockingZone, mMinIdleRefreshRateForBlockingZone);
1073     } else {
1074         result.appendFormat("\n");
1075     }
1076 
1077     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
1078         result.appendFormat("\t[%u] vote to %d hz\n", i, mVrrThrottleFps[i]);
1079     }
1080 
1081     result.appendFormat("Refresh rate delay: %" PRId64 " ns\n", mRefreshRateDelayNanos);
1082     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
1083         result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mVrrThrottleNanos[i]);
1084     }
1085     result.appendFormat("\n");
1086 }
1087 
calculateTimeline(hwc2_config_t config,hwc_vsync_period_change_constraints_t * vsyncPeriodChangeConstraints,hwc_vsync_period_change_timeline_t * outTimeline)1088 void ExynosPrimaryDisplay::calculateTimeline(
1089         hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
1090         hwc_vsync_period_change_timeline_t *outTimeline) {
1091     ATRACE_CALL();
1092     int64_t desiredUpdateTime = vsyncPeriodChangeConstraints->desiredTimeNanos;
1093     const int64_t origDesiredUpdateTime = desiredUpdateTime;
1094     const int64_t threshold = mRefreshRateDelayNanos;
1095     int64_t lastUpdateDelta = 0;
1096     int64_t actualChangeTime = 0;
1097     bool isDelayed = false;
1098 
1099     /* actualChangeTime includes transient duration */
1100     mDisplayInterface->getVsyncAppliedTime(config, &actualChangeTime);
1101 
1102     outTimeline->refreshRequired = true;
1103 
1104     /* when refresh rate is from high to low */
1105     if (threshold != 0 && mLastRefreshRateAppliedNanos != 0 &&
1106         mDisplayConfigs[mActiveConfig].vsyncPeriod < mDisplayConfigs[config].vsyncPeriod) {
1107         lastUpdateDelta = desiredUpdateTime - mLastRefreshRateAppliedNanos;
1108         if (lastUpdateDelta < threshold) {
1109             /* in this case, the active config change needs to be delayed */
1110             isDelayed = true;
1111             desiredUpdateTime += threshold - lastUpdateDelta;
1112         }
1113     }
1114     mVsyncPeriodChangeConstraints.desiredTimeNanos = desiredUpdateTime;
1115 
1116     getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime,
1117                          outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos);
1118 
1119     const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
1120     DISPLAY_LOGD_AND_ATRACE_NAME(eDebugDisplayConfig,
1121                                  "requested config : %d(%d)->%d(%d), isDelay:%d,"
1122                                  " delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", "
1123                                  "now:%" PRId64 ", desired %" PRId64 "->%" PRId64
1124                                  ", newVsyncAppliedTimeNanos : %" PRId64
1125                                  ", refreshTimeNanos:%" PRId64
1126                                  ", mLastRefreshRateAppliedNanos:%" PRId64,
1127                                  mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
1128                                  mDisplayConfigs[config].vsyncPeriod, isDelayed,
1129                                  ns2ms(lastUpdateDelta), ns2ms(threshold - lastUpdateDelta),
1130                                  ns2ms(threshold), ns2ms(now), ns2ms(origDesiredUpdateTime),
1131                                  ns2ms(mVsyncPeriodChangeConstraints.desiredTimeNanos),
1132                                  ns2ms(outTimeline->newVsyncAppliedTimeNanos),
1133                                  ns2ms(outTimeline->refreshTimeNanos),
1134                                  ns2ms(mLastRefreshRateAppliedNanos));
1135 
1136     const int64_t diffMs = ns2ms(outTimeline->refreshTimeNanos - now);
1137     DISPLAY_ATRACE_INT64("TimeToChangeConfig", diffMs);
1138 }
1139 
updateAppliedActiveConfig(const hwc2_config_t newConfig,const int64_t ts)1140 void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConfig,
1141                                                      const int64_t ts) {
1142     ATRACE_CALL();
1143     if (mAppliedActiveConfig == 0 ||
1144         getDisplayVsyncPeriodFromConfig(mAppliedActiveConfig) !=
1145                 getDisplayVsyncPeriodFromConfig(newConfig)) {
1146         DISPLAY_LOGD(eDebugDisplayConfig,
1147                      "%s mAppliedActiveConfig(%d->%d), mLastRefreshRateAppliedNanos(%" PRIu64
1148                      " -> %" PRIu64 ")",
1149                      __func__, mAppliedActiveConfig, newConfig, mLastRefreshRateAppliedNanos, ts);
1150         mLastRefreshRateAppliedNanos = ts;
1151         DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos));
1152     }
1153 
1154     mAppliedActiveConfig = newConfig;
1155 }
1156 
checkBtsReassignResource(const uint32_t vsyncPeriod,const uint32_t btsVsyncPeriod)1157 void ExynosPrimaryDisplay::checkBtsReassignResource(const uint32_t vsyncPeriod,
1158                                                     const uint32_t btsVsyncPeriod) {
1159     ATRACE_CALL();
1160     uint32_t refreshRate = static_cast<uint32_t>(round(nsecsPerSec / vsyncPeriod * 0.1f) * 10);
1161 
1162     Mutex::Autolock lock(mDRMutex);
1163     if (vsyncPeriod < btsVsyncPeriod) {
1164         for (size_t i = 0; i < mLayers.size(); i++) {
1165             if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr &&
1166                 !mLayers[i]->checkBtsCap(refreshRate)) {
1167                 mLayers[i]->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
1168                 break;
1169             }
1170         }
1171     } else if (vsyncPeriod > btsVsyncPeriod) {
1172         for (size_t i = 0; i < mLayers.size(); i++) {
1173             if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP) {
1174                 float srcWidth = mLayers[i]->mSourceCrop.right - mLayers[i]->mSourceCrop.left;
1175                 float srcHeight = mLayers[i]->mSourceCrop.bottom - mLayers[i]->mSourceCrop.top;
1176                 float resolution = srcWidth * srcHeight * refreshRate / 1000;
1177                 float ratioVertical = static_cast<float>(mLayers[i]->mDisplayFrame.bottom -
1178                                                          mLayers[i]->mDisplayFrame.top) /
1179                         mYres;
1180 
1181                 if (mLayers[i]->mOtfMPP->checkDownscaleCap(resolution, ratioVertical)) {
1182                     mLayers[i]->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
1183                     break;
1184                 }
1185             }
1186         }
1187     }
1188 }
1189 
isDbmSupported()1190 bool ExynosPrimaryDisplay::isDbmSupported() {
1191     return mBrightnessController->isDbmSupported();
1192 }
1193 
setDbmState(bool enabled)1194 int32_t ExynosPrimaryDisplay::setDbmState(bool enabled) {
1195     mBrightnessController->processDimBrightness(enabled);
1196     return NO_ERROR;
1197 }
1198