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