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