• 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 
17 #include "ExynosExternalDisplay.h"
18 #include <errno.h>
19 #include <hardware/hwcomposer_defs.h>
20 #include <linux/fb.h>
21 #include "ExynosDevice.h"
22 #include "ExynosDisplayDrmInterface.h"
23 #include "ExynosDisplayDrmInterfaceModule.h"
24 #include "ExynosHWCDebug.h"
25 #include "ExynosHWCHelper.h"
26 #include "ExynosLayer.h"
27 #include "pixelstats-display.h"
28 
29 #define SKIP_FRAME_COUNT 3
30 extern struct exynos_hwc_control exynosHWCControl;
31 
32 using namespace SOC_VERSION;
33 
ExynosExternalDisplay(uint32_t index,ExynosDevice * device,const std::string & displayName)34 ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice* device,
35                                              const std::string& displayName)
36       : ExynosDisplay(HWC_DISPLAY_EXTERNAL, index, device, displayName) {
37     DISPLAY_LOGD(eDebugExternalDisplay, "");
38 
39     mEnabled = false;
40     mBlanked = false;
41 
42 	mXres = 0;
43     mYres = 0;
44     mXdpi = 0;
45     mYdpi = 0;
46     mVsyncPeriod = 0;
47     mSkipStartFrame = 0;
48     mSkipFrameCount = -1;
49     mIsSkipFrame = false;
50     mVirtualDisplayState = 0;
51 
52     mDRDefault = true;
53     mDREnable = false;
54 
55     //TODO : Hard coded currently
56     mNumMaxPriorityAllowed = 1;
57     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
58 }
59 
~ExynosExternalDisplay()60 ExynosExternalDisplay::~ExynosExternalDisplay()
61 {
62 
63 }
64 
init()65 void ExynosExternalDisplay::init()
66 {
67 
68 }
69 
deInit()70 void ExynosExternalDisplay::deInit()
71 {
72 
73 }
74 
openExternalDisplay()75 int ExynosExternalDisplay::openExternalDisplay()
76 {
77     DISPLAY_LOGD(eDebugExternalDisplay, "");
78 
79     int ret = 0;
80 
81     mSkipFrameCount = SKIP_FRAME_COUNT;
82     mSkipStartFrame = 0;
83     mPlugState = true;
84 
85     if (mLayers.size() != 0) {
86         mLayers.clear();
87     }
88 
89     DISPLAY_LOGD(eDebugExternalDisplay, "open fd for External Display(%d)", ret);
90 
91     return ret;
92 }
93 
closeExternalDisplay()94 void ExynosExternalDisplay::closeExternalDisplay()
95 {
96     DISPLAY_LOGD(eDebugExternalDisplay, "");
97 
98     setVsyncEnabledInternal(HWC2_VSYNC_DISABLE);
99 
100     if (mPowerModeState.has_value() &&
101         (*mPowerModeState != (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) {
102         if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_OFF) < 0) {
103             DISPLAY_LOGE("%s: set powermode ioctl failed errno : %d", __func__, errno);
104             return;
105         }
106     }
107 
108     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
109 
110     DISPLAY_LOGD(eDebugExternalDisplay, "Close fd for External Display");
111 
112     mPlugState = false;
113     mEnabled = false;
114     mBlanked = false;
115     mSkipFrameCount = SKIP_FRAME_COUNT;
116 
117     for (size_t i = 0; i < mLayers.size(); i++) {
118         ExynosLayer *layer = mLayers[i];
119         layer->mAcquireFence = fence_close(layer->mAcquireFence, this, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER);
120         layer->mReleaseFence = -1;
121         layer->mLayerBuffer = NULL;
122     }
123 
124     mClientCompositionInfo.initializeInfosComplete(this);
125     mExynosCompositionInfo.initializeInfosComplete(this);
126 }
127 
getDisplayConfigs(uint32_t * outNumConfigs,hwc2_config_t * outConfigs)128 int ExynosExternalDisplay::getDisplayConfigs(uint32_t* outNumConfigs, hwc2_config_t* outConfigs)
129 {
130     DISPLAY_LOGD(eDebugExternalDisplay, "");
131 
132     int32_t ret = mDisplayInterface->getDisplayConfigs(outNumConfigs, outConfigs);
133     if (ret)
134         DISPLAY_LOGE("%s: failed to getDisplayConfigs, ret(%d)", __func__, ret);
135 
136     if (outConfigs) {
137         char modeStr[PROPERTY_VALUE_MAX] = "\0";
138         int32_t width, height, fps, config;
139         int32_t err = HWC2_ERROR_BAD_CONFIG;
140 
141         if (property_get("vendor.display.external.preferred_mode", modeStr, "") > 0) {
142             if (sscanf(modeStr, "%dx%d@%d", &width, &height, &fps) == 3) {
143                 err = lookupDisplayConfigs(width, height, fps, fps, &config);
144                 if (err != HWC2_ERROR_NONE) {
145                     DISPLAY_LOGW("%s: display does not support preferred mode %dx%d@%d",
146                                  __func__, width, height, fps);
147                 }
148             } else {
149                 DISPLAY_LOGW("%s: vendor.display.external.preferred_mode: bad format",
150                              __func__);
151             }
152         }
153 
154         if (err == HWC2_ERROR_NONE) {
155             mActiveConfig = config;
156         } else {
157             err = lookupDisplayConfigsRelaxed(1920, 1080, 60, &config);
158             if (err == HWC2_ERROR_NONE) {
159                 mActiveConfig = config;
160             } else {
161                 mActiveConfig = outConfigs[0];
162             }
163         }
164 
165         displayConfigs_t displayConfig = mDisplayConfigs[mActiveConfig];
166         mXres = displayConfig.width;
167         mYres = displayConfig.height;
168         mVsyncPeriod = displayConfig.vsyncPeriod;
169         mRefreshRate = displayConfig.refreshRate;
170 
171         if (mDisplayInterface->mType == INTERFACE_TYPE_DRM) {
172             ret = mDisplayInterface->setActiveConfig(mActiveConfig);
173             if (ret) {
174                 DISPLAY_LOGE("%s: failed to setActiveConfigs, ret(%d)", __func__, ret);
175                 return ret;
176             }
177         }
178     }
179 
180     return ret;
181 }
182 
getActiveConfig(hwc2_config_t * outConfig)183 int32_t ExynosExternalDisplay::getActiveConfig(hwc2_config_t* outConfig) {
184     DISPLAY_LOGD(eDebugExternalDisplay, "");
185 
186     if (!mHpdStatus)
187         return HWC2_ERROR_BAD_DISPLAY;
188 
189     if (mActiveConfig == UINT_MAX)
190         return HWC2_ERROR_BAD_CONFIG;
191 
192     *outConfig = mActiveConfig;
193 
194     return HWC2_ERROR_NONE;
195 }
196 
handleRotate()197 bool ExynosExternalDisplay::handleRotate()
198 {
199     // FIXME: HWC2_COMPOSITION_SCREENSHOT is not dfeind in AOSP
200     //        HWC guys should fix this.
201     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
202 #if 0
203         for (size_t i = 0; i < mLayers.size(); i++) {
204             ExynosLayer *layer = mLayers[i];
205             if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT)
206                 layer->mCompositionType = HWC2_COMPOSITION_DEVICE;
207         }
208 #endif
209         mIsSkipFrame = false;
210         return false;
211     }
212 
213 #if 0
214     for (size_t i = 0; i < mLayers.size(); i++) {
215         ExynosLayer *layer = mLayers[i];
216         if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT) {
217             DISPLAY_LOGD(eDebugExternalDisplay, "include rotation animation layer");
218             layer->mOverlayInfo = eSkipRotateAnim;
219             for (size_t j = 0; j < mLayers.size(); j++) {
220                 ExynosLayer *skipLayer = mLayers[j];
221                 skipLayer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
222             }
223             mIsSkipFrame = true;
224             return true;
225         }
226     }
227 #endif
228     mIsSkipFrame = false;
229     return false;
230 }
231 
checkRotate()232 bool ExynosExternalDisplay::checkRotate()
233 {
234     // FIXME: HWC2_COMPOSITION_SCREENSHOT is not dfeind in AOSP
235     //        HWC guys should fix this.
236 #if 0
237     for (size_t i = 0; i < mLayers.size(); i++) {
238         ExynosLayer *layer = mLayers[i];
239 
240         if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT) {
241             return true;
242         }
243     }
244 #endif
245     return false;
246 }
247 
validateDisplay(uint32_t * outNumTypes,uint32_t * outNumRequests)248 int32_t ExynosExternalDisplay::validateDisplay(
249         uint32_t* outNumTypes, uint32_t* outNumRequests) {
250     Mutex::Autolock lock(mExternalMutex);
251     DISPLAY_LOGD(eDebugExternalDisplay, "");
252 
253     int32_t ret;
254     mSkipFrame = false;
255 
256     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
257         ALOGI("[ExternalDisplay] %s : setGeometryChanged [%d/%d]", __func__, mSkipStartFrame, SKIP_EXTERNAL_FRAME);
258         initDisplay();
259         /*
260          * geometry should be set before ExynosDisplay::validateDisplay is called
261          * not to skip resource assignment
262          */
263         if (mPlugState)
264             setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_ADDED);
265         else
266             setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_REMOVED);
267     }
268 
269     if (handleRotate()) {
270         if ((ret = mResourceManager->initResourcesState(this)) != NO_ERROR)
271             DISPLAY_LOGE("[ExternalDisplay] %s : initResourcesState fail, ret(%d)", __func__, ret);
272         mDevice->setGeometryChanged(GEOMETRY_LAYER_UNKNOWN_CHANGED);
273         mClientCompositionInfo.initializeInfos(this);
274         mExynosCompositionInfo.initializeInfos(this);
275         mRenderingState = RENDERING_STATE_VALIDATED;
276         return HWC2_ERROR_NONE;
277     }
278 
279     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
280         /*
281          * Set mIsSkipFrame before calling ExynosDisplay::validateDisplay()
282          * startPostProcessing() that is called by ExynosDisplay::validateDisplay()
283          * checks mIsSkipFrame.
284          */
285         mIsSkipFrame = true;
286     }
287 
288     ret = ExynosDisplay::validateDisplay(outNumTypes, outNumRequests);
289 
290     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
291         initDisplay();
292         mRenderingState = RENDERING_STATE_VALIDATED;
293         uint32_t changed_count = 0;
294         for (size_t i = 0; i < mLayers.size(); i++) {
295             ExynosLayer *layer = mLayers[i];
296             if (layer && (layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE ||
297                 layer->mValidateCompositionType == HWC2_COMPOSITION_EXYNOS)) {
298                 layer->mValidateCompositionType = HWC2_COMPOSITION_CLIENT;
299                 layer->mReleaseFence = layer->mAcquireFence;
300                 changed_count++;
301             }
302         }
303         mSkipStartFrame++;
304         *outNumTypes += changed_count;
305 
306         ALOGI("[ExternalDisplay] %s : Skip start frame [%d/%d]", __func__, mSkipStartFrame, SKIP_EXTERNAL_FRAME);
307     }
308 
309     return ret;
310 }
311 
canSkipValidate()312 int32_t ExynosExternalDisplay::canSkipValidate() {
313 
314     /*
315      * SurfaceFlinger may call vadlidate, present for a few frame
316      * even though external display is disconnected.
317      * Cammands for primary display can be discarded if validate is skipped
318      * in this case. HWC should return error not to skip validate.
319      */
320     if ((mHpdStatus == false) || (mBlanked == true))
321         return SKIP_ERR_DISP_NOT_CONNECTED;
322 
323     if ((mSkipStartFrame > (SKIP_EXTERNAL_FRAME - 1)) && (mEnabled == false) &&
324         (mPowerModeState.has_value() &&
325          (*mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL)))
326         return SKIP_ERR_DISP_NOT_POWER_ON;
327 
328     if (checkRotate() || (mIsSkipFrame) ||
329         (mSkipStartFrame < SKIP_EXTERNAL_FRAME))
330         return SKIP_ERR_FORCE_VALIDATE;
331 
332     return ExynosDisplay::canSkipValidate();
333 }
334 
presentDisplay(int32_t * outRetireFence)335 int32_t ExynosExternalDisplay::presentDisplay(
336     int32_t* outRetireFence)
337 {
338     Mutex::Autolock lock(mExternalMutex);
339     DISPLAY_LOGD(eDebugExternalDisplay, "");
340     int32_t ret;
341 
342     if (mSkipFrame) {
343         ALOGI("[%d] presentDisplay is skipped by mSkipFrame", mDisplayId);
344         closeFencesForSkipFrame(RENDERING_STATE_PRESENTED);
345         setGeometryChanged(GEOMETRY_DISPLAY_FORCE_VALIDATE);
346         *outRetireFence = -1;
347         for (size_t i=0; i < mLayers.size(); i++) {
348             mLayers[i]->mReleaseFence = -1;
349         }
350         if (mRenderingState == RENDERING_STATE_NONE) {
351             ALOGD("\tThis is the first frame after power on");
352             ret = HWC2_ERROR_NONE;
353         } else {
354             ALOGD("\tThis is the second frame after power on");
355             ret = HWC2_ERROR_NOT_VALIDATED;
356         }
357         mRenderingState = RENDERING_STATE_PRESENTED;
358         mDevice->onRefresh(mDisplayId);
359         return ret;
360     }
361 
362     if ((mIsSkipFrame) || (mHpdStatus == false) || (mBlanked == true)) {
363         if ((exynosHWCControl.skipValidate == true) &&
364             ((mRenderingState == RENDERING_STATE_PRESENTED) ||
365              (mRenderingState == RENDERING_STATE_NONE))) {
366 
367             if (mDevice->canSkipValidate() == false) {
368                 mRenderingState = RENDERING_STATE_NONE;
369                 return HWC2_ERROR_NOT_VALIDATED;
370             } else {
371                 DISPLAY_LOGD(eDebugSkipValidate, "validate is skipped");
372             }
373         }
374 
375         *outRetireFence = -1;
376         for (size_t i = 0; i < mLayers.size(); i++) {
377             ExynosLayer *layer = mLayers[i];
378             layer->mAcquireFence = fence_close(layer->mAcquireFence, this,
379                     FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER);
380             layer->mReleaseFence = -1;
381         }
382         mClientCompositionInfo.mAcquireFence =
383             fence_close(mClientCompositionInfo.mAcquireFence, this,
384                     FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_FB);
385         mClientCompositionInfo.mReleaseFence = -1;
386 
387         /* this frame is not presented, but mRenderingState is updated to RENDERING_STATE_PRESENTED */
388         initDisplay();
389 
390         /*
391          * Resource assignment information was initialized during skipping frames
392          * So resource assignment for the first displayed frame after skpping frames
393          * should not be skipped
394          */
395         setGeometryChanged(GEOMETRY_DISPLAY_FORCE_VALIDATE);
396 
397         mDevice->onRefresh(mDisplayId);
398 
399         return HWC2_ERROR_NONE;
400     }
401 
402     ret = ExynosDisplay::presentDisplay(outRetireFence);
403 
404     return ret;
405 }
setClientTarget(buffer_handle_t target,int32_t acquireFence,int32_t dataspace)406 int32_t ExynosExternalDisplay::setClientTarget(
407         buffer_handle_t target,
408         int32_t acquireFence, int32_t /*android_dataspace_t*/ dataspace) {
409     buffer_handle_t handle = NULL;
410     if (target != NULL)
411         handle = target;
412     if ((mClientCompositionInfo.mHasCompositionLayer == true) &&
413         (handle == NULL) &&
414         (mClientCompositionInfo.mSkipFlag == false)) {
415         /*
416          * openExternalDisplay() can be called between validateDisplay and getChangedCompositionTypes.
417          * Then getChangedCompositionTypes() returns no layer because openExternalDisplay() clears mLayers.
418          * SurfaceFlinger might not change compositionType to HWC2_COMPOSITION_CLIENT.
419          * Handle can be NULL in this case. It is not error case.
420          */
421         if (mSkipStartFrame == 0) {
422             if (acquireFence >= 0)
423                 fence_close(acquireFence, this, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_FB);
424             acquireFence = -1;
425             mClientCompositionInfo.setTargetBuffer(this, handle, acquireFence, (android_dataspace)dataspace);
426             return NO_ERROR;
427         }
428     }
429     return ExynosDisplay::setClientTarget(target, acquireFence, dataspace);
430 }
431 
enable()432 int ExynosExternalDisplay::enable()
433 {
434     ALOGI("[ExternalDisplay] %s +", __func__);
435 
436     if (mEnabled)
437         return HWC2_ERROR_NONE;
438 
439     if (mHpdStatus == false) {
440         ALOGI("HPD is not connected");
441         return HWC2_ERROR_NONE;
442     }
443 
444     if (openExternalDisplay() < 0)
445         return HWC2_ERROR_UNSUPPORTED;
446 
447     if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_NORMAL) < 0) {
448         DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
449         return HWC2_ERROR_UNSUPPORTED;
450     }
451 
452     mEnabled = true;
453     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL;
454 
455     reportUsage(true);
456 
457     ALOGI("[ExternalDisplay] %s -", __func__);
458 
459     return HWC2_ERROR_NONE;
460 }
461 
disable()462 int ExynosExternalDisplay::disable()
463 {
464     ALOGI("[ExternalDisplay] %s +", __func__);
465 
466     if (mHpdStatus) {
467         /*
468          * DP cable is connected and link is up
469          *
470          * Currently, we don't power down here for two reasons:
471          * - power up would require DP link re-training (slow)
472          * - DP audio can continue playing while display is blank
473          */
474         if (mEnabled)
475             clearDisplay(false);
476         return HWC2_ERROR_NONE;
477     }
478 
479     if (mSkipStartFrame > (SKIP_EXTERNAL_FRAME - 1)) {
480         clearDisplay(true);
481     } else {
482         ALOGI("Skip clearDisplay to avoid resource conflict");
483     }
484 
485     if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_OFF) < 0) {
486         DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
487         return HWC2_ERROR_UNSUPPORTED;
488     }
489 
490     if (mEnabled) reportUsage(false);
491 
492     mEnabled = false;
493     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
494 
495     ALOGI("[ExternalDisplay] %s -", __func__);
496 
497     return HWC2_ERROR_NONE;
498 }
499 
setPowerMode(int32_t mode)500 int32_t ExynosExternalDisplay::setPowerMode(
501         int32_t /*hwc2_power_mode_t*/ mode) {
502     Mutex::Autolock lock(mExternalMutex);
503     {
504         Mutex::Autolock lock(mDisplayMutex);
505 
506         /* TODO state check routine should be added */
507 
508         int fb_blank = 0;
509         int err = 0;
510         if (mode == HWC_POWER_MODE_OFF) {
511             fb_blank = FB_BLANK_POWERDOWN;
512             err = disable();
513         } else if (mode == HWC_POWER_MODE_NORMAL) {
514             fb_blank = FB_BLANK_UNBLANK;
515             err = enable();
516         } else {
517             DISPLAY_LOGE("unsupported powermode: %d", mode);
518             return HWC2_ERROR_UNSUPPORTED;
519         }
520 
521         if (err != 0) {
522             DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
523             return HWC2_ERROR_UNSUPPORTED;
524         }
525 
526         if (fb_blank == FB_BLANK_POWERDOWN)
527             mDREnable = false;
528         else if (fb_blank == FB_BLANK_UNBLANK)
529             mDREnable = mDRDefault;
530 
531         // check the dynamic recomposition thread by following display power status
532         mDevice->checkDynamicRecompositionThread();
533 
534         DISPLAY_LOGD(eDebugExternalDisplay, "%s:: mode(%d), blank(%d)", __func__, mode, fb_blank);
535 
536         if (mode == HWC_POWER_MODE_OFF) {
537             /* It should be called from validate() when the screen is on */
538             mSkipFrame = true;
539             setGeometryChanged(GEOMETRY_DISPLAY_POWER_OFF);
540             if ((mRenderingState >= RENDERING_STATE_VALIDATED) &&
541                 (mRenderingState < RENDERING_STATE_PRESENTED))
542                 closeFencesForSkipFrame(RENDERING_STATE_VALIDATED);
543             mRenderingState = RENDERING_STATE_NONE;
544         } else {
545             setGeometryChanged(GEOMETRY_DISPLAY_POWER_ON);
546         }
547     }
548     return HWC2_ERROR_NONE;
549 }
550 
startPostProcessing()551 int32_t ExynosExternalDisplay::startPostProcessing() {
552     if ((mHpdStatus == false) || (mBlanked == true) || mIsSkipFrame) {
553         ALOGI("%s:: skip startPostProcessing display(%d) mHpdStatus(%d)",
554                 __func__, mDisplayId, mHpdStatus);
555         return NO_ERROR;
556     }
557     return ExynosDisplay::startPostProcessing();
558 }
559 
getHDRException(ExynosLayer * __unused layer)560 bool ExynosExternalDisplay::getHDRException(ExynosLayer* __unused layer)
561 {
562     bool ret = false;
563 
564     if (mExternalHdrSupported) {
565         ret = true;
566     }
567     return ret;
568 }
569 
handleHotplugEvent(bool hpdStatus)570 void ExynosExternalDisplay::handleHotplugEvent(bool hpdStatus)
571 {
572     mHpdStatus = hpdStatus;
573     if (mHpdStatus) {
574         if (openExternalDisplay() < 0) {
575             ALOGE("Failed to openExternalDisplay");
576             mHpdStatus = false;
577             return;
578         }
579         mDREnable = mDRDefault;
580     } else {
581         disable();
582         closeExternalDisplay();
583         mDREnable = false;
584     }
585     mDevice->checkDynamicRecompositionThread();
586 
587     ALOGI("HPD status changed to %s, mDisplayId %d, mDisplayFd %d", mHpdStatus ? "enabled" : "disabled", mDisplayId, mDisplayInterface->getDisplayFd());
588 }
589 
initDisplayInterface(uint32_t interfaceType)590 void ExynosExternalDisplay::initDisplayInterface(uint32_t interfaceType)
591 {
592     if (interfaceType == INTERFACE_TYPE_DRM)
593         mDisplayInterface = std::make_unique<ExynosExternalDisplayDrmInterfaceModule>((ExynosDisplay *)this);
594     else
595         LOG_ALWAYS_FATAL("%s::Unknown interface type(%d)",
596                 __func__, interfaceType);
597     mDisplayInterface->init(this);
598 }
599 
reportUsage(bool enabled)600 void ExynosExternalDisplay::reportUsage(bool enabled) {
601     auto refreshRate = nanoSec2Hz(mVsyncPeriod);
602     auto manufacturerInfo = mDisplayInterface->getManufacturerInfo();
603     auto productId = mDisplayInterface->getProductId();
604 
605     ATRACE_NAME("report ext usage");
606     reportDisplayPortUsage(mXres, mYres, refreshRate, manufacturerInfo, productId, enabled);
607 }
608