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