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