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