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