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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
18
19 #include "ExynosDevice.h"
20
21 #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
22 #include <sync/sync.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25
26 #include "BrightnessController.h"
27 #include "ExynosDeviceDrmInterface.h"
28 #include "ExynosDisplay.h"
29 #include "ExynosExternalDisplayModule.h"
30 #include "ExynosHWCDebug.h"
31 #include "ExynosHWCHelper.h"
32 #include "ExynosLayer.h"
33 #include "ExynosPrimaryDisplayModule.h"
34 #include "ExynosResourceManagerModule.h"
35 #include "ExynosVirtualDisplayModule.h"
36 #include "VendorGraphicBuffer.h"
37
38 using namespace vendor::graphics;
39 using namespace SOC_VERSION;
40 using aidl::android::hardware::graphics::composer3::IComposerCallback;
41
42 /**
43 * ExynosDevice implementation
44 */
45
46 class ExynosDevice;
47
48 extern void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str);
49
50 static const std::map<const uint32_t, const std::string_view> pixelDisplayIntfName =
51 {{getDisplayId(HWC_DISPLAY_PRIMARY, 0), "default"},
52 #ifdef USES_IDISPLAY_INTF_SEC
53 {getDisplayId(HWC_DISPLAY_PRIMARY, 1), "secondary"}
54 #endif
55 };
56
57 int hwcDebug;
58 int hwcFenceDebug[FENCE_IP_ALL];
59 struct exynos_hwc_control exynosHWCControl;
60 struct update_time_info updateTimeInfo;
61 char fence_names[FENCE_MAX][32];
62
getDeviceInterfaceType()63 uint32_t getDeviceInterfaceType()
64 {
65 if (access(DRM_DEVICE_PATH, F_OK) == NO_ERROR)
66 return INTERFACE_TYPE_DRM;
67 else
68 return INTERFACE_TYPE_FB;
69 }
70
ExynosDevice(bool vrrApiSupported)71 ExynosDevice::ExynosDevice(bool vrrApiSupported)
72 : mGeometryChanged(0),
73 mVsyncFd(-1),
74 mExtVsyncFd(-1),
75 mVsyncDisplayId(getDisplayId(HWC_DISPLAY_PRIMARY, 0)),
76 mTimestamp(0),
77 mDisplayMode(0),
78 mInterfaceType(INTERFACE_TYPE_FB),
79 mIsInTUI(false),
80 mVrrApiSupported(vrrApiSupported) {
81 exynosHWCControl.forceGpu = false;
82 exynosHWCControl.windowUpdate = true;
83 exynosHWCControl.forcePanic = false;
84 exynosHWCControl.skipStaticLayers = true;
85 exynosHWCControl.skipM2mProcessing = true;
86 exynosHWCControl.skipResourceAssign = true;
87 exynosHWCControl.multiResolution = true;
88 exynosHWCControl.dumpMidBuf = false;
89 exynosHWCControl.displayMode = DISPLAY_MODE_NUM;
90 exynosHWCControl.setDDIScaler = false;
91 exynosHWCControl.skipWinConfig = false;
92 exynosHWCControl.skipValidate = true;
93 exynosHWCControl.doFenceFileDump = false;
94 exynosHWCControl.fenceTracer = 0;
95 exynosHWCControl.sysFenceLogging = false;
96 exynosHWCControl.useDynamicRecomp = false;
97
98 hwcDebug = 0;
99
100 mInterfaceType = getDeviceInterfaceType();
101 ALOGD("HWC2 : %s : interface type(%d)", __func__, mInterfaceType);
102
103 /*
104 * This order should not be changed
105 * new ExynosResourceManager ->
106 * create displays and add them to the list ->
107 * initDeviceInterface() ->
108 * ExynosResourceManager::updateRestrictions()
109 */
110 mResourceManager = new ExynosResourceManagerModule(this);
111
112 for (size_t i = 0; i < AVAILABLE_DISPLAY_UNITS.size(); i++) {
113 exynos_display_t display_t = AVAILABLE_DISPLAY_UNITS[i];
114 ExynosDisplay *exynos_display = NULL;
115 ALOGD("Create display[%zu] type: %d, index: %d", i, display_t.type, display_t.index);
116 switch(display_t.type) {
117 case HWC_DISPLAY_PRIMARY:
118 exynos_display =
119 (ExynosDisplay *)(new ExynosPrimaryDisplayModule(display_t.index, this,
120 display_t.display_name));
121 if(display_t.index == 0) {
122 exynos_display->mPlugState = true;
123 ExynosMPP::mainDisplayWidth = exynos_display->mXres;
124 if (ExynosMPP::mainDisplayWidth <= 0) {
125 ExynosMPP::mainDisplayWidth = 1440;
126 }
127 ExynosMPP::mainDisplayHeight = exynos_display->mYres;
128 if (ExynosMPP::mainDisplayHeight <= 0) {
129 ExynosMPP::mainDisplayHeight = 2560;
130 }
131 }
132 break;
133 case HWC_DISPLAY_EXTERNAL:
134 exynos_display =
135 (ExynosDisplay *)(new ExynosExternalDisplayModule(display_t.index, this,
136 display_t.display_name));
137 break;
138 case HWC_DISPLAY_VIRTUAL:
139 exynos_display =
140 (ExynosDisplay *)(new ExynosVirtualDisplayModule(display_t.index, this,
141 display_t.display_name));
142 mNumVirtualDisplay = 0;
143 break;
144 default:
145 ALOGE("Unsupported display type(%d)", display_t.type);
146 break;
147 }
148 exynos_display->mDeconNodeName.appendFormat("%s", display_t.decon_node_name.c_str());
149 mDisplays.add(exynos_display);
150 mDisplayMap.insert(std::make_pair(exynos_display->mDisplayId, exynos_display));
151
152 #ifndef FORCE_DISABLE_DR
153 if (exynos_display->mDRDefault) exynosHWCControl.useDynamicRecomp = true;
154 #endif
155 }
156
157 memset(mCallbackInfos, 0, sizeof(mCallbackInfos));
158
159 dynamicRecompositionThreadCreate();
160
161 for (uint32_t i = 0; i < FENCE_IP_ALL; i++)
162 hwcFenceDebug[i] = 0;
163
164 for (uint32_t i = 0; i < FENCE_MAX; i++) {
165 memset(fence_names[i], 0, sizeof(fence_names[0]));
166 sprintf(fence_names[i], "_%2dh", i);
167 }
168
169 for (auto it : mDisplays) {
170 std::string displayName = std::string(it->mDisplayName.c_str());
171 it->mErrLogFileWriter.setPrefixName(displayName + "_hwc_error_log");
172 it->mDebugDumpFileWriter.setPrefixName(displayName + "_hwc_debug");
173 it->mFenceFileWriter.setPrefixName(displayName + "_hwc_fence_state");
174 String8 saveString;
175 saveString.appendFormat("ExynosDisplay %s is initialized", it->mDisplayName.c_str());
176 saveErrorLog(saveString, it);
177 }
178
179 if (mInterfaceType == INTERFACE_TYPE_DRM) {
180 setVBlankOffDelay(1);
181 }
182
183 mDisplayOffAsync = property_get_bool("vendor.display.async_off.supported", false);
184 initDeviceInterface(mInterfaceType);
185
186 // registerRestrictions();
187 mResourceManager->updateRestrictions();
188 mResourceManager->initDisplays(mDisplays, mDisplayMap);
189
190 char value[PROPERTY_VALUE_MAX];
191 property_get("vendor.display.lbe.supported", value, "0");
192 const bool lbe_supported = atoi(value) ? true : false;
193
194 mNumPrimaryDisplays = 0;
195 for (size_t i = 0; i < mDisplays.size(); i++) {
196 if (mDisplays[i]->mType == HWC_DISPLAY_PRIMARY) {
197 ++mNumPrimaryDisplays;
198 auto iter = pixelDisplayIntfName.find(getDisplayId(HWC_DISPLAY_PRIMARY, i));
199 if (iter != pixelDisplayIntfName.end()) {
200 PixelDisplayInit(mDisplays[i], iter->second);
201 if (lbe_supported) {
202 mDisplays[i]->initLbe();
203 }
204 }
205 }
206 }
207 }
208
initDeviceInterface(uint32_t interfaceType)209 void ExynosDevice::initDeviceInterface(uint32_t interfaceType)
210 {
211 if (interfaceType == INTERFACE_TYPE_DRM) {
212 mDeviceInterface = std::make_unique<ExynosDeviceDrmInterface>(this);
213 } else {
214 LOG_ALWAYS_FATAL("%s::Unknown interface type(%d)",
215 __func__, interfaceType);
216 }
217
218 mDeviceInterface->init(this);
219
220 /* Remove display when display interface is not valid */
221 for (uint32_t i = 0; i < mDisplays.size();) {
222 ExynosDisplay* display = mDisplays[i];
223 display->initDisplayInterface(interfaceType);
224 if (mDeviceInterface->initDisplayInterface(display->mDisplayInterface) != NO_ERROR) {
225 ALOGD("Remove display[%d], Failed to initialize display interface", i);
226 mDisplays.removeAt(i);
227 mDisplayMap.erase(display->mDisplayId);
228 delete display;
229 } else {
230 i++;
231 }
232 }
233
234 // Call handleHotplug() to capture the initial coldplug state of each display.
235 // This is necessary because the hotplug uevent handler created in postInit()
236 // below does not get always triggered when HWC is restarting.
237 handleHotplug();
238 mDeviceInterface->postInit();
239 }
240
~ExynosDevice()241 ExynosDevice::~ExynosDevice() {
242 mDRLoopStatus = false;
243 mDRThread.join();
244 for(auto& display : mDisplays) {
245 delete display;
246 }
247 mDisplays.clear();
248 }
249
isFirstValidate()250 bool ExynosDevice::isFirstValidate()
251 {
252 for (uint32_t i = 0; i < mDisplays.size(); i++) {
253 if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) &&
254 (!mDisplays[i]->mPowerModeState.has_value() ||
255 (mDisplays[i]->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)))
256 continue;
257 if ((mDisplays[i]->mPlugState == true) &&
258 ((mDisplays[i]->mRenderingState != RENDERING_STATE_NONE) &&
259 (mDisplays[i]->mRenderingState != RENDERING_STATE_PRESENTED)))
260 return false;
261 }
262
263 return true;
264 }
265
isLastValidate(ExynosDisplay * display)266 bool ExynosDevice::isLastValidate(ExynosDisplay *display)
267 {
268 for (uint32_t i = 0; i < mDisplays.size(); i++) {
269 if (mDisplays[i] == display)
270 continue;
271 if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) &&
272 (!mDisplays[i]->mPowerModeState.has_value() ||
273 (mDisplays[i]->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)))
274 continue;
275 if ((mDisplays[i]->mPlugState == true) &&
276 (mDisplays[i]->mRenderingState != RENDERING_STATE_VALIDATED) &&
277 (mDisplays[i]->mRenderingState != RENDERING_STATE_ACCEPTED_CHANGE))
278 return false;
279 }
280 return true;
281 }
282
hasOtherDisplayOn(ExynosDisplay * display)283 bool ExynosDevice::hasOtherDisplayOn(ExynosDisplay *display) {
284 for (uint32_t i = 0; i < mDisplays.size(); i++) {
285 if (mDisplays[i] == display) continue;
286 if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) &&
287 mDisplays[i]->mPowerModeState.has_value() &&
288 (mDisplays[i]->mPowerModeState.value() != (hwc2_power_mode_t)HWC_POWER_MODE_OFF))
289 return true;
290 }
291 return false;
292 }
293
isDynamicRecompositionThreadAlive()294 bool ExynosDevice::isDynamicRecompositionThreadAlive()
295 {
296 android_atomic_acquire_load(&mDRThreadStatus);
297 return (mDRThreadStatus > 0);
298 }
299
checkDynamicRecompositionThread()300 void ExynosDevice::checkDynamicRecompositionThread()
301 {
302 ATRACE_CALL();
303 // If thread was destroyed, create thread and run. (resume status)
304 if (isDynamicRecompositionThreadAlive() == false) {
305 for (uint32_t i = 0; i < mDisplays.size(); i++) {
306 if (mDisplays[i]->mDREnable) {
307 dynamicRecompositionThreadCreate();
308 return;
309 }
310 }
311 } else {
312 // If thread is running and all displays turnned off DR, destroy the thread.
313 for (uint32_t i = 0; i < mDisplays.size(); i++) {
314 if (mDisplays[i]->mDREnable)
315 return;
316 }
317 ALOGI("Destroying dynamic recomposition thread");
318 mDRLoopStatus = false;
319 mDRWakeUpCondition.notify_one();
320 mDRThread.join();
321 }
322 }
323
dynamicRecompositionThreadCreate()324 void ExynosDevice::dynamicRecompositionThreadCreate()
325 {
326 if (exynosHWCControl.useDynamicRecomp == true) {
327 ALOGI("Creating dynamic recomposition thread");
328 mDRLoopStatus = true;
329 mDRThread = std::thread(&dynamicRecompositionThreadLoop, this);
330 }
331 }
332
dynamicRecompositionThreadLoop(void * data)333 void *ExynosDevice::dynamicRecompositionThreadLoop(void *data)
334 {
335 ExynosDevice *dev = (ExynosDevice *)data;
336 ExynosDisplay *display[dev->mDisplays.size()];
337 uint64_t event_cnt[dev->mDisplays.size()];
338
339 for (uint32_t i = 0; i < dev->mDisplays.size(); i++) {
340 display[i] = dev->mDisplays[i];
341 event_cnt[i] = 0;
342 }
343 android_atomic_inc(&(dev->mDRThreadStatus));
344
345 while (dev->mDRLoopStatus) {
346 for (uint32_t i = 0; i < dev->mDisplays.size(); i++)
347 event_cnt[i] = display[i]->mUpdateEventCnt;
348
349 /*
350 * If there is no update for more than 5s, favor the client composition mode.
351 * If all other conditions are met, mode will be switched to client composition.
352 */
353 {
354 std::unique_lock<std::mutex> lock(dev->mDRWakeUpMutex);
355 dev->mDRWakeUpCondition.wait_for(lock, std::chrono::seconds(5));
356 if (!dev->mDRLoopStatus) {
357 break;
358 }
359 }
360 for (uint32_t i = 0; i < dev->mDisplays.size(); i++) {
361 if (display[i]->mDREnable &&
362 display[i]->mPlugState == true &&
363 event_cnt[i] == display[i]->mUpdateEventCnt) {
364 if (display[i]->checkDynamicReCompMode() == DEVICE_2_CLIENT) {
365 display[i]->mUpdateEventCnt = 0;
366 display[i]->setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION);
367 dev->onRefresh(display[i]->mDisplayId);
368 }
369 }
370 }
371 }
372
373 android_atomic_dec(&(dev->mDRThreadStatus));
374
375 return NULL;
376 }
377
378 /**
379 * Device Functions for HWC 2.0
380 */
381
createVirtualDisplay(uint32_t width,uint32_t height,int32_t * format,ExynosDisplay * display)382 int32_t ExynosDevice::createVirtualDisplay(
383 uint32_t width, uint32_t height, int32_t* /*android_pixel_format_t*/ format, ExynosDisplay* display) {
384 ((ExynosVirtualDisplay*)display)->createVirtualDisplay(width, height, format);
385 return 0;
386 }
387
388 /**
389 * @param *display
390 * @return int32_t
391 */
destroyVirtualDisplay(ExynosDisplay * display)392 int32_t ExynosDevice::destroyVirtualDisplay(ExynosDisplay* display) {
393 ((ExynosVirtualDisplay *)display)->destroyVirtualDisplay();
394 return 0;
395 }
396
dump(uint32_t * outSize,char * outBuffer)397 void ExynosDevice::dump(uint32_t *outSize, char *outBuffer) {
398 if (outSize == NULL) {
399 ALOGE("%s:: outSize is null", __func__);
400 return;
401 }
402
403 String8 result;
404 dump(result);
405
406 if (outBuffer == NULL) {
407 *outSize = static_cast<uint32_t>(result.length());
408 } else {
409 if (*outSize == 0) {
410 ALOGE("%s:: outSize is 0", __func__);
411 return;
412 }
413 size_t copySize = min(static_cast<size_t>(*outSize), result.size());
414 ALOGI("HWC dump:: resultSize(%zu), outSize(%d), copySize(%zu)", result.size(), *outSize,
415 copySize);
416 strlcpy(outBuffer, result.c_str(), copySize);
417 }
418 }
419
dump(String8 & result)420 void ExynosDevice::dump(String8 &result) {
421 result.append("\n\n");
422
423 struct tm* localTime = (struct tm*)localtime((time_t*)&updateTimeInfo.lastUeventTime.tv_sec);
424 result.appendFormat("lastUeventTime(%02d:%02d:%02d.%03lu) lastTimestamp(%" PRIu64 ")\n",
425 localTime->tm_hour, localTime->tm_min,
426 localTime->tm_sec, updateTimeInfo.lastUeventTime.tv_usec/1000, mTimestamp);
427
428 localTime = (struct tm*)localtime((time_t*)&updateTimeInfo.lastEnableVsyncTime.tv_sec);
429 result.appendFormat("lastEnableVsyncTime(%02d:%02d:%02d.%03lu)\n",
430 localTime->tm_hour, localTime->tm_min,
431 localTime->tm_sec, updateTimeInfo.lastEnableVsyncTime.tv_usec/1000);
432
433 localTime = (struct tm*)localtime((time_t*)&updateTimeInfo.lastDisableVsyncTime.tv_sec);
434 result.appendFormat("lastDisableVsyncTime(%02d:%02d:%02d.%03lu)\n",
435 localTime->tm_hour, localTime->tm_min,
436 localTime->tm_sec, updateTimeInfo.lastDisableVsyncTime.tv_usec/1000);
437
438 localTime = (struct tm*)localtime((time_t*)&updateTimeInfo.lastValidateTime.tv_sec);
439 result.appendFormat("lastValidateTime(%02d:%02d:%02d.%03lu)\n",
440 localTime->tm_hour, localTime->tm_min,
441 localTime->tm_sec, updateTimeInfo.lastValidateTime.tv_usec/1000);
442
443 localTime = (struct tm*)localtime((time_t*)&updateTimeInfo.lastPresentTime.tv_sec);
444 result.appendFormat("lastPresentTime(%02d:%02d:%02d.%03lu)\n",
445 localTime->tm_hour, localTime->tm_min,
446 localTime->tm_sec, updateTimeInfo.lastPresentTime.tv_usec/1000);
447
448 result.appendFormat("\n");
449 mResourceManager->dump(result);
450
451 result.appendFormat("special plane num: %d:\n", getSpecialPlaneNum());
452 for (uint32_t index = 0; index < getSpecialPlaneNum(); index++) {
453 result.appendFormat("\tindex: %d attribute 0x%" PRIx64 "\n", getSpecialPlaneId(index),
454 getSpecialPlaneAttr(index));
455 }
456 result.append("\n");
457
458 for (size_t i = 0;i < mDisplays.size(); i++) {
459 ExynosDisplay *display = mDisplays[i];
460 if (display->mPlugState == true)
461 display->dump(result);
462 }
463 }
464
getMaxVirtualDisplayCount()465 uint32_t ExynosDevice::getMaxVirtualDisplayCount() {
466 #ifdef USES_VIRTUAL_DISPLAY
467 return 1;
468 #else
469 return 0;
470 #endif
471 }
472
registerCallback(int32_t descriptor,hwc2_callback_data_t callbackData,hwc2_function_pointer_t point)473 int32_t ExynosDevice::registerCallback (
474 int32_t descriptor, hwc2_callback_data_t callbackData,
475 hwc2_function_pointer_t point) {
476 if (descriptor < 0 || descriptor > HWC2_CALLBACK_SEAMLESS_POSSIBLE)
477 return HWC2_ERROR_BAD_PARAMETER;
478
479 Mutex::Autolock lock(mDeviceCallbackMutex);
480 mCallbackInfos[descriptor].callbackData = callbackData;
481 mCallbackInfos[descriptor].funcPointer = point;
482
483 /* Call hotplug callback for primary display*/
484 if (descriptor == HWC2_CALLBACK_HOTPLUG) {
485 HWC2_PFN_HOTPLUG callbackFunc =
486 reinterpret_cast<HWC2_PFN_HOTPLUG>(mCallbackInfos[descriptor].funcPointer);
487 if (callbackFunc != nullptr) {
488 for (auto it : mDisplays) {
489 if (it->mPlugState)
490 callbackFunc(callbackData, getDisplayId(it->mType, it->mIndex),
491 HWC2_CONNECTION_CONNECTED);
492 }
493 } else {
494 // unregistering callback can be used as a sign of ComposerClient's death
495 for (auto it : mDisplays) {
496 it->cleanupAfterClientDeath();
497 }
498 }
499 }
500 /* TODO(b/265244856): called by register callback vsync. it's only hwc2. */
501 if (descriptor == HWC2_CALLBACK_VSYNC)
502 mResourceManager->doPreProcessing();
503
504 return HWC2_ERROR_NONE;
505 }
506
isCallbackRegisteredLocked(int32_t descriptor)507 bool ExynosDevice::isCallbackRegisteredLocked(int32_t descriptor) {
508 if (descriptor < 0 || descriptor > HWC2_CALLBACK_SEAMLESS_POSSIBLE) {
509 ALOGE("%s:: %d callback is unknown", __func__, descriptor);
510 return false;
511 }
512
513 if (mCallbackInfos[descriptor].callbackData == nullptr ||
514 mCallbackInfos[descriptor].funcPointer == nullptr) {
515 ALOGE("%s:: %d callback is not registered", __func__, descriptor);
516 return false;
517 }
518
519 return true;
520 }
521
isCallbackAvailable(int32_t descriptor)522 bool ExynosDevice::isCallbackAvailable(int32_t descriptor) {
523 Mutex::Autolock lock(mDeviceCallbackMutex);
524 return isCallbackRegisteredLocked(descriptor);
525 }
526
527 using DisplayHotplugEvent = aidl::android::hardware::graphics::common::DisplayHotplugEvent;
hotplug_event_to_aidl(bool connected,int hotplugErrorCode)528 DisplayHotplugEvent hotplug_event_to_aidl(bool connected, int hotplugErrorCode) {
529 switch (hotplugErrorCode) {
530 case 0:
531 return connected ? DisplayHotplugEvent::CONNECTED : DisplayHotplugEvent::DISCONNECTED;
532 case 1:
533 return DisplayHotplugEvent::ERROR_INCOMPATIBLE_CABLE;
534 default:
535 return DisplayHotplugEvent::ERROR_UNKNOWN;
536 }
537 }
538
findPoweredOffPrimaryDisplay(ExynosDisplay * excludeDisplay)539 ExynosDisplay* ExynosDevice::findPoweredOffPrimaryDisplay(ExynosDisplay* excludeDisplay) {
540 for (auto disp : mDisplays) {
541 if (disp != excludeDisplay && disp->mType == HWC_DISPLAY_PRIMARY &&
542 disp->mPowerModeState == HWC_POWER_MODE_OFF)
543 return disp;
544 }
545 return nullptr;
546 }
547
onHotPlug(uint32_t displayId,bool status,int hotplugErrorCode)548 void ExynosDevice::onHotPlug(uint32_t displayId, bool status, int hotplugErrorCode) {
549 Mutex::Autolock lock(mDeviceCallbackMutex);
550
551 // If we detect a hotplug of an external display on a foldable device, and we have a
552 // primary/built-in display in a powered off state, we need to use the powered off display's
553 // crtc/decon for the external display, to ensure color management is working properly
554 // (color management is supported only on decon0/decon1). See b/329034082.
555 ExynosDisplay* hotpluggedDisplay = getDisplay(displayId);
556 if (mNumPrimaryDisplays >= 2 && hotpluggedDisplay &&
557 hotpluggedDisplay->mType == HWC_DISPLAY_EXTERNAL) {
558 ALOGD("%s: display %s pluggedIn=%d hotplugErrorCode=%d", __func__,
559 hotpluggedDisplay->mDisplayTraceName.c_str(), status, hotplugErrorCode);
560 auto hotpluggedDisplayIntf = hotpluggedDisplay->mDisplayInterface.get();
561 ExynosDisplay* borrowedCrtcFrom = hotpluggedDisplayIntf->borrowedCrtcFrom();
562 if (status && hotplugErrorCode == 0) {
563 // The external display has been connected successfully, check if we can find an
564 // available decon for it, before we start initializing it.
565 if (borrowedCrtcFrom) {
566 ALOGW("%s: external display is already using decon of %s", __func__,
567 borrowedCrtcFrom->mDisplayTraceName.c_str());
568 // Restore the original decon of the external display before proceeding.
569 hotpluggedDisplayIntf->swapCrtcs(borrowedCrtcFrom);
570 }
571 ExynosDisplay* poweredOffPrimaryDisplay = findPoweredOffPrimaryDisplay(nullptr);
572 if (poweredOffPrimaryDisplay) {
573 hotpluggedDisplayIntf->swapCrtcs(poweredOffPrimaryDisplay);
574 } else {
575 // There is no powered off primary display/available decon at the moment,
576 // this means hotplug of external display happened while the foldable device
577 // was in dual concurrent display mode. We will try to switch decon assignment
578 // for the external display later, when one of primary displays is turned off.
579 ALOGD("onHotPlug: No powered off primary displays found!");
580 }
581 } else {
582 // The external display has been unplugged, or plugged in, but ran into an error.
583 // Restore the original decon assigned to it, if we previously switched decons.
584 if (borrowedCrtcFrom) {
585 hotpluggedDisplayIntf->swapCrtcs(borrowedCrtcFrom);
586 }
587 }
588 }
589
590 // If the new HotplugEvent API is available, use it, otherwise fall back
591 // to the old V2 API with onVsync hack, if necessary.
592 const auto& hotplugEventCallback =
593 mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onHotplugEvent);
594 if (hotplugEventCallback != mHwc3CallbackInfos.end()) {
595 const auto& callbackInfo = hotplugEventCallback->second;
596 if (callbackInfo.funcPointer != nullptr && callbackInfo.callbackData != nullptr) {
597 auto callbackFunc = reinterpret_cast<
598 void (*)(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay,
599 aidl::android::hardware::graphics::common::DisplayHotplugEvent)>(
600 callbackInfo.funcPointer);
601 callbackFunc(callbackInfo.callbackData, displayId,
602 hotplug_event_to_aidl(status, hotplugErrorCode));
603 return;
604 }
605 }
606
607 if (!isCallbackRegisteredLocked(HWC2_CALLBACK_HOTPLUG)) return;
608
609 if (hotplugErrorCode) {
610 // We need to pass the error code to SurfaceFlinger, but we cannot modify the HWC
611 // HAL interface, so for now we'll send the hotplug error via a onVsync callback with
612 // a negative time value indicating the hotplug error.
613 if (isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC_2_4)) {
614 ALOGD("%s: hotplugErrorCode=%d sending to SF via onVsync_2_4", __func__,
615 hotplugErrorCode);
616 hwc2_callback_data_t vsyncCallbackData =
617 mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].callbackData;
618 HWC2_PFN_VSYNC_2_4 vsyncCallbackFunc = reinterpret_cast<HWC2_PFN_VSYNC_2_4>(
619 mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].funcPointer);
620 vsyncCallbackFunc(vsyncCallbackData, displayId, -hotplugErrorCode, ~0);
621 return;
622 } else {
623 ALOGW("%s: onVsync_2_4 is not registered, ignoring hotplugErrorCode=%d", __func__,
624 hotplugErrorCode);
625 return;
626 }
627 }
628
629 hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_HOTPLUG].callbackData;
630 HWC2_PFN_HOTPLUG callbackFunc =
631 reinterpret_cast<HWC2_PFN_HOTPLUG>(mCallbackInfos[HWC2_CALLBACK_HOTPLUG].funcPointer);
632 callbackFunc(callbackData, displayId,
633 status ? HWC2_CONNECTION_CONNECTED : HWC2_CONNECTION_DISCONNECTED);
634 }
635
onRefreshDisplays()636 void ExynosDevice::onRefreshDisplays() {
637 for (auto& display : mDisplays) {
638 onRefresh(display->mDisplayId);
639 }
640 }
641
onRefresh(uint32_t displayId)642 void ExynosDevice::onRefresh(uint32_t displayId) {
643 Mutex::Autolock lock(mDeviceCallbackMutex);
644
645 if (!isCallbackRegisteredLocked(HWC2_CALLBACK_REFRESH)) return;
646
647 if (!checkDisplayConnection(displayId)) return;
648
649 ExynosDisplay *display = (ExynosDisplay *)getDisplay(displayId);
650
651 if (!display->mPowerModeState.has_value() ||
652 (display->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF))
653 return;
654
655 hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_REFRESH].callbackData;
656 HWC2_PFN_REFRESH callbackFunc =
657 reinterpret_cast<HWC2_PFN_REFRESH>(mCallbackInfos[HWC2_CALLBACK_REFRESH].funcPointer);
658 callbackFunc(callbackData, displayId);
659 }
660
onVsync(uint32_t displayId,int64_t timestamp)661 void ExynosDevice::onVsync(uint32_t displayId, int64_t timestamp) {
662 Mutex::Autolock lock(mDeviceCallbackMutex);
663
664 if (!isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC)) return;
665
666 hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_VSYNC].callbackData;
667 HWC2_PFN_VSYNC callbackFunc =
668 reinterpret_cast<HWC2_PFN_VSYNC>(mCallbackInfos[HWC2_CALLBACK_VSYNC].funcPointer);
669 callbackFunc(callbackData, displayId, timestamp);
670 }
671
onVsync_2_4(uint32_t displayId,int64_t timestamp,uint32_t vsyncPeriod)672 bool ExynosDevice::onVsync_2_4(uint32_t displayId, int64_t timestamp, uint32_t vsyncPeriod) {
673 Mutex::Autolock lock(mDeviceCallbackMutex);
674
675 if (!isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC_2_4)) return false;
676
677 hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].callbackData;
678 HWC2_PFN_VSYNC_2_4 callbackFunc = reinterpret_cast<HWC2_PFN_VSYNC_2_4>(
679 mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].funcPointer);
680 callbackFunc(callbackData, displayId, timestamp, vsyncPeriod);
681
682 return true;
683 }
684
onVsyncPeriodTimingChanged(uint32_t displayId,hwc_vsync_period_change_timeline_t * timeline)685 void ExynosDevice::onVsyncPeriodTimingChanged(uint32_t displayId,
686 hwc_vsync_period_change_timeline_t *timeline) {
687 Mutex::Autolock lock(mDeviceCallbackMutex);
688
689 if (!timeline) {
690 ALOGE("vsync period change timeline is null");
691 return;
692 }
693
694 if (!isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED)) return;
695
696 hwc2_callback_data_t callbackData =
697 mCallbackInfos[HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED].callbackData;
698 HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED callbackFunc =
699 reinterpret_cast<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED>(
700 mCallbackInfos[HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED].funcPointer);
701 callbackFunc(callbackData, displayId, timeline);
702 }
703
onContentProtectionUpdated(uint32_t displayId,HdcpLevels hdcpLevels)704 void ExynosDevice::onContentProtectionUpdated(uint32_t displayId, HdcpLevels hdcpLevels) {
705 Mutex::Autolock lock(mDeviceCallbackMutex);
706
707 // Workaround to pass content protection updates to SurfaceFlinger
708 // without changing HWC HAL interface.
709 if (isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC_2_4)) {
710 ALOGI("%s: displayId=%u hdcpLevels=%s sending to SF via onVsync_2_4", __func__, displayId,
711 hdcpLevels.toString().c_str());
712 hwc2_callback_data_t vsyncCallbackData =
713 mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].callbackData;
714 HWC2_PFN_VSYNC_2_4 vsyncCallbackFunc = reinterpret_cast<HWC2_PFN_VSYNC_2_4>(
715 mCallbackInfos[HWC2_CALLBACK_VSYNC_2_4].funcPointer);
716 int32_t connectedLevel = static_cast<int32_t>(hdcpLevels.connectedLevel);
717 int32_t maxLevel = static_cast<int32_t>(hdcpLevels.maxLevel);
718 int32_t timestampValue = (connectedLevel & 0xFF) | ((maxLevel & 0xFF) << 8);
719 vsyncCallbackFunc(vsyncCallbackData, displayId, -timestampValue, ~1);
720 } else
721 ALOGW("%s: onVsync_2_4 is not registered, ignoring onContentProtectionUpdated", __func__);
722 }
723
setHWCDebug(unsigned int debug)724 void ExynosDevice::setHWCDebug(unsigned int debug)
725 {
726 hwcDebug = debug;
727 }
728
getHWCDebug()729 uint32_t ExynosDevice::getHWCDebug()
730 {
731 return hwcDebug;
732 }
733
setHWCFenceDebug(uint32_t typeNum,uint32_t ipNum,uint32_t mode)734 void ExynosDevice::setHWCFenceDebug(uint32_t typeNum, uint32_t ipNum, uint32_t mode)
735 {
736 if (typeNum > FENCE_TYPE_ALL || typeNum < 0 || ipNum > FENCE_IP_ALL || ipNum < 0
737 || mode > 1 || mode < 0) {
738 ALOGE("%s:: input is not valid type(%u), IP(%u), mode(%d)", __func__, typeNum, ipNum, mode);
739 return;
740 }
741
742 uint32_t value = 0;
743
744 if (typeNum == FENCE_TYPE_ALL)
745 value = (1 << FENCE_TYPE_ALL) - 1;
746 else
747 value = 1 << typeNum;
748
749 if (ipNum == FENCE_IP_ALL) {
750 for (uint32_t i = 0; i < FENCE_IP_ALL; i++) {
751 if (mode)
752 hwcFenceDebug[i] |= value;
753 else
754 hwcFenceDebug[i] &= (~value);
755 }
756 } else {
757 if (mode)
758 hwcFenceDebug[ipNum] |= value;
759 else
760 hwcFenceDebug[ipNum] &= (~value);
761 }
762
763 }
764
getHWCFenceDebug()765 void ExynosDevice::getHWCFenceDebug()
766 {
767 for (uint32_t i = 0; i < FENCE_IP_ALL; i++)
768 ALOGE("[HWCFenceDebug] IP_Number(%d) : Debug(%x)", i, hwcFenceDebug[i]);
769 }
770
setHWCControl(uint32_t displayId,uint32_t ctrl,int32_t val)771 void ExynosDevice::setHWCControl(uint32_t displayId, uint32_t ctrl, int32_t val) {
772 ExynosDisplay *exynosDisplay = NULL;
773 switch (ctrl) {
774 case HWC_CTL_FORCE_GPU:
775 ALOGI("%s::HWC_CTL_FORCE_GPU on/off=%d", __func__, val);
776 exynosHWCControl.forceGpu = (unsigned int)val;
777 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
778 onRefresh(displayId);
779 break;
780 case HWC_CTL_WINDOW_UPDATE:
781 ALOGI("%s::HWC_CTL_WINDOW_UPDATE on/off=%d", __func__, val);
782 exynosHWCControl.windowUpdate = (unsigned int)val;
783 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
784 onRefresh(displayId);
785 break;
786 case HWC_CTL_FORCE_PANIC:
787 ALOGI("%s::HWC_CTL_FORCE_PANIC on/off=%d", __func__, val);
788 exynosHWCControl.forcePanic = (unsigned int)val;
789 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
790 break;
791 case HWC_CTL_SKIP_STATIC:
792 ALOGI("%s::HWC_CTL_SKIP_STATIC on/off=%d", __func__, val);
793 exynosHWCControl.skipStaticLayers = (unsigned int)val;
794 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
795 break;
796 case HWC_CTL_SKIP_M2M_PROCESSING:
797 ALOGI("%s::HWC_CTL_SKIP_M2M_PROCESSING on/off=%d", __func__, val);
798 exynosHWCControl.skipM2mProcessing = (unsigned int)val;
799 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
800 break;
801 case HWC_CTL_SKIP_RESOURCE_ASSIGN:
802 ALOGI("%s::HWC_CTL_SKIP_RESOURCE_ASSIGN on/off=%d", __func__, val);
803 exynosHWCControl.skipResourceAssign = (unsigned int)val;
804 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
805 onRefreshDisplays();
806 break;
807 case HWC_CTL_SKIP_VALIDATE:
808 ALOGI("%s::HWC_CTL_SKIP_VALIDATE on/off=%d", __func__, val);
809 exynosHWCControl.skipValidate = (unsigned int)val;
810 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
811 onRefreshDisplays();
812 break;
813 case HWC_CTL_DUMP_MID_BUF:
814 ALOGI("%s::HWC_CTL_DUMP_MID_BUF on/off=%d", __func__, val);
815 exynosHWCControl.dumpMidBuf = (unsigned int)val;
816 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
817 onRefreshDisplays();
818 break;
819 case HWC_CTL_CAPTURE_READBACK:
820 captureScreenWithReadback(displayId);
821 break;
822 case HWC_CTL_DISPLAY_MODE:
823 ALOGI("%s::HWC_CTL_DISPLAY_MODE mode=%d", __func__, val);
824 setDisplayMode((uint32_t)val);
825 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
826 onRefreshDisplays();
827 break;
828 // Support DDI scalser {
829 case HWC_CTL_DDI_RESOLUTION_CHANGE:
830 ALOGI("%s::HWC_CTL_DDI_RESOLUTION_CHANGE mode=%d", __func__, val);
831 exynosDisplay = (ExynosDisplay *)getDisplay(displayId);
832 uint32_t width, height;
833
834 /* TODO: Add branch here for each resolution/index */
835 switch(val) {
836 case 1:
837 case 2:
838 case 3:
839 default:
840 width = 1440; height = 2960;
841 break;
842 }
843
844 if (exynosDisplay == NULL) {
845 for (uint32_t i = 0; i < mDisplays.size(); i++) {
846 mDisplays[i]->setDDIScalerEnable(width, height);
847 }
848 } else {
849 exynosDisplay->setDDIScalerEnable(width, height);
850 }
851 setGeometryChanged(GEOMETRY_DISPLAY_RESOLUTION_CHANGED);
852 onRefreshDisplays();
853 break;
854 // } Support DDI scaler
855 case HWC_CTL_ENABLE_COMPOSITION_CROP:
856 case HWC_CTL_ENABLE_EXYNOSCOMPOSITION_OPT:
857 case HWC_CTL_ENABLE_CLIENTCOMPOSITION_OPT:
858 case HWC_CTL_USE_MAX_G2D_SRC:
859 case HWC_CTL_ENABLE_HANDLE_LOW_FPS:
860 case HWC_CTL_ENABLE_EARLY_START_MPP:
861 exynosDisplay = (ExynosDisplay *)getDisplay(displayId);
862 if (exynosDisplay == NULL) {
863 for (uint32_t i = 0; i < mDisplays.size(); i++) {
864 mDisplays[i]->setHWCControl(ctrl, val);
865 }
866 } else {
867 exynosDisplay->setHWCControl(ctrl, val);
868 }
869 setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
870 onRefreshDisplays();
871 break;
872 case HWC_CTL_DYNAMIC_RECOMP:
873 ALOGI("%s::HWC_CTL_DYNAMIC_RECOMP on/off = %d", __func__, val);
874 setDynamicRecomposition(displayId, (unsigned int)val);
875 break;
876 case HWC_CTL_ENABLE_FENCE_TRACER:
877 ALOGI("%s::HWC_CTL_ENABLE_FENCE_TRACER on/off=%d", __func__, val);
878 exynosHWCControl.fenceTracer = (unsigned int)val;
879 break;
880 case HWC_CTL_SYS_FENCE_LOGGING:
881 ALOGI("%s::HWC_CTL_SYS_FENCE_LOGGING on/off=%d", __func__, val);
882 exynosHWCControl.sysFenceLogging = (unsigned int)val;
883 break;
884 case HWC_CTL_DO_FENCE_FILE_DUMP:
885 ALOGI("%s::HWC_CTL_DO_FENCE_FILE_DUMP on/off=%d", __func__, val);
886 exynosHWCControl.doFenceFileDump = (unsigned int)val;
887 break;
888 default:
889 ALOGE("%s: unsupported HWC_CTL (%d)", __func__, ctrl);
890 break;
891 }
892 }
893
setDisplayMode(uint32_t displayMode)894 void ExynosDevice::setDisplayMode(uint32_t displayMode)
895 {
896 exynosHWCControl.displayMode = displayMode;
897 }
898
setDynamicRecomposition(uint32_t displayId,unsigned int on)899 void ExynosDevice::setDynamicRecomposition(uint32_t displayId, unsigned int on) {
900 exynosHWCControl.useDynamicRecomp = on;
901 ExynosDisplay *display = getDisplay(displayId);
902 if (display) {
903 display->mDRDefault = on;
904 display->mDREnable = on;
905 onRefresh(displayId);
906 }
907 }
908
checkDisplayConnection(uint32_t displayId)909 bool ExynosDevice::checkDisplayConnection(uint32_t displayId)
910 {
911 ExynosDisplay *display = getDisplay(displayId);
912
913 if (!display)
914 return false;
915 else
916 return display->mPlugState;
917 }
918
checkNonInternalConnection()919 bool ExynosDevice::checkNonInternalConnection()
920 {
921 for (uint32_t i = 0; i < mDisplays.size(); i++) {
922 switch(mDisplays[i]->mType) {
923 case HWC_DISPLAY_PRIMARY:
924 break;
925 case HWC_DISPLAY_EXTERNAL:
926 case HWC_DISPLAY_VIRTUAL:
927 if (mDisplays[i]->mPlugState)
928 return true;
929 break;
930 default:
931 break;
932 }
933 }
934 return false;
935 }
936
getCapabilitiesLegacy(uint32_t * outCount,int32_t * outCapabilities)937 void ExynosDevice::getCapabilitiesLegacy(uint32_t *outCount, int32_t *outCapabilities) {
938 uint32_t capabilityNum = 0;
939 #ifdef HWC_SUPPORT_COLOR_TRANSFORM
940 capabilityNum++;
941 #endif
942 #ifndef HWC_NO_SUPPORT_SKIP_VALIDATE
943 capabilityNum++;
944 #endif
945 if (outCapabilities == NULL) {
946 *outCount = capabilityNum;
947 return;
948 }
949 if (capabilityNum != *outCount) {
950 ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum);
951 return;
952 }
953 #if defined(HWC_SUPPORT_COLOR_TRANSFORM) || !defined(HWC_NO_SUPPORT_SKIP_VALIDATE)
954 uint32_t index = 0;
955 #endif
956 #ifdef HWC_SUPPORT_COLOR_TRANSFORM
957 outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
958 #endif
959 #ifndef HWC_NO_SUPPORT_SKIP_VALIDATE
960 outCapabilities[index++] = HWC2_CAPABILITY_SKIP_VALIDATE;
961 #endif
962 return;
963 }
964
getCapabilities(uint32_t * outCount,int32_t * outCapabilities)965 void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t *outCapabilities) {
966 uint32_t capabilityNum = 0;
967 #ifdef HWC_SUPPORT_COLOR_TRANSFORM
968 capabilityNum++;
969 #endif
970 if (outCapabilities == NULL) {
971 *outCount = capabilityNum;
972 return;
973 }
974 if (capabilityNum != *outCount) {
975 ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum);
976 return;
977 }
978 #if defined(HWC_SUPPORT_COLOR_TRANSFORM)
979 uint32_t index = 0;
980 outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
981 #endif
982 return;
983 }
984
clearGeometryChanged()985 void ExynosDevice::clearGeometryChanged()
986 {
987 mGeometryChanged = 0;
988 }
989
canSkipValidate()990 bool ExynosDevice::canSkipValidate()
991 {
992 /*
993 * This should be called by presentDisplay()
994 * when presentDisplay() is called without validateDisplay() call
995 */
996
997 int ret = 0;
998 if (exynosHWCControl.skipValidate == false)
999 return false;
1000
1001 for (uint32_t i = 0; i < mDisplays.size(); i++) {
1002 /*
1003 * Check all displays.
1004 * Resource assignment can have problem if validateDisplay is skipped
1005 * on only some displays.
1006 * All display's validateDisplay should be skipped or all display's validateDisplay
1007 * should not be skipped.
1008 */
1009 if (mDisplays[i]->mPlugState && mDisplays[i]->mPowerModeState.has_value() &&
1010 mDisplays[i]->mPowerModeState.value() != HWC2_POWER_MODE_OFF) {
1011 /*
1012 * presentDisplay is called without validateDisplay.
1013 * Call functions that should be called in validateDiplay
1014 */
1015 mDisplays[i]->doPreProcessing();
1016 mDisplays[i]->checkLayerFps();
1017
1018 if ((ret = mDisplays[i]->canSkipValidate()) != NO_ERROR) {
1019 ALOGD_AND_ATRACE_NAME(eDebugSkipValidate,
1020 "Display[%d] can't skip validate (%d), renderingState(%d), "
1021 "geometryChanged(0x%" PRIx64 ")",
1022 mDisplays[i]->mDisplayId, ret, mDisplays[i]->mRenderingState,
1023 mGeometryChanged);
1024 return false;
1025 } else {
1026 HDEBUGLOGD(eDebugSkipValidate, "Display[%d] can skip validate (%d), renderingState(%d), geometryChanged(0x%" PRIx64 ")",
1027 mDisplays[i]->mDisplayId, ret,
1028 mDisplays[i]->mRenderingState, mGeometryChanged);
1029 }
1030 }
1031 }
1032 return true;
1033 }
1034
validateFences(ExynosDisplay * display)1035 bool ExynosDevice::validateFences(ExynosDisplay *display) {
1036 return mFenceTracker.validateFences(display);
1037 }
1038
compareVsyncPeriod()1039 void ExynosDevice::compareVsyncPeriod() {
1040 /* TODO(b/265244856): to clarify what purpose of the function */
1041 ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0));
1042 ExynosDisplay *external_display = getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0));
1043
1044 mVsyncDisplayId = getDisplayId(HWC_DISPLAY_PRIMARY, 0);
1045
1046 if ((external_display == nullptr) ||
1047 (!external_display->mPowerModeState.has_value() ||
1048 (external_display->mPowerModeState.value() == HWC2_POWER_MODE_OFF))) {
1049 return;
1050 } else if (!primary_display->mPowerModeState.has_value() ||
1051 (primary_display->mPowerModeState.value() == HWC2_POWER_MODE_OFF)) {
1052 mVsyncDisplayId = getDisplayId(HWC_DISPLAY_EXTERNAL, 0);
1053 return;
1054 } else if (primary_display->mPowerModeState.has_value() &&
1055 ((primary_display->mPowerModeState.value() == HWC2_POWER_MODE_DOZE) ||
1056 (primary_display->mPowerModeState.value() == HWC2_POWER_MODE_DOZE_SUSPEND)) &&
1057 (external_display->mVsyncPeriod >= DOZE_VSYNC_PERIOD)) { /*30fps*/
1058 mVsyncDisplayId = getDisplayId(HWC_DISPLAY_EXTERNAL, 0);
1059 return;
1060 } else if (primary_display->mVsyncPeriod <= external_display->mVsyncPeriod) {
1061 mVsyncDisplayId = getDisplayId(HWC_DISPLAY_EXTERNAL, 0);
1062 return;
1063 }
1064
1065 return;
1066 }
1067
captureReadbackClass(ExynosDevice * device)1068 ExynosDevice::captureReadbackClass::captureReadbackClass(
1069 ExynosDevice *device) :
1070 mDevice(device)
1071 {
1072 if (device == nullptr)
1073 return;
1074 }
1075
~captureReadbackClass()1076 ExynosDevice::captureReadbackClass::~captureReadbackClass()
1077 {
1078 VendorGraphicBufferMapper& gMapper(VendorGraphicBufferMapper::get());
1079 if (mBuffer != nullptr)
1080 gMapper.freeBuffer(mBuffer);
1081
1082 if (mDevice != nullptr)
1083 mDevice->clearWaitingReadbackReqDone();
1084 }
1085
1086
allocBuffer(uint32_t format,uint32_t w,uint32_t h)1087 int32_t ExynosDevice::captureReadbackClass::allocBuffer(
1088 uint32_t format, uint32_t w, uint32_t h)
1089 {
1090 VendorGraphicBufferAllocator& gAllocator(VendorGraphicBufferAllocator::get());
1091
1092 uint32_t dstStride = 0;
1093 uint64_t usage = static_cast<uint64_t>(GRALLOC1_CONSUMER_USAGE_HWCOMPOSER |
1094 GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN);
1095
1096 status_t error = NO_ERROR;
1097 error = gAllocator.allocate(w, h, format, 1, usage, &mBuffer, &dstStride, "HWC");
1098 if ((error != NO_ERROR) || (mBuffer == nullptr)) {
1099 ALOGE("failed to allocate destination buffer(%dx%d): %d",
1100 w, h, error);
1101 return static_cast<int32_t>(error);
1102 }
1103 return NO_ERROR;
1104 }
1105
saveToFile(const String8 & fileName)1106 void ExynosDevice::captureReadbackClass::saveToFile(const String8 &fileName)
1107 {
1108 if (mBuffer == nullptr) {
1109 ALOGE("%s:: buffer is null", __func__);
1110 return;
1111 }
1112
1113 char filePath[MAX_DEV_NAME] = {0};
1114 VendorGraphicBufferMeta gmeta(mBuffer);
1115
1116 snprintf(filePath, MAX_DEV_NAME,
1117 "%s/%s", WRITEBACK_CAPTURE_PATH, fileName.c_str());
1118 FILE *fp = fopen(filePath, "w");
1119 if (fp) {
1120 uint32_t writeSize =
1121 gmeta.stride * gmeta.vstride * formatToBpp(gmeta.format)/8;
1122 void *writebackData = mmap(0, writeSize,
1123 PROT_READ|PROT_WRITE, MAP_SHARED, gmeta.fd, 0);
1124 if (writebackData != MAP_FAILED && writebackData != NULL) {
1125 size_t result = fwrite(writebackData, writeSize, 1, fp);
1126 munmap(writebackData, writeSize);
1127 ALOGD("Success to write %zu data, size(%d)", result, writeSize);
1128 } else {
1129 ALOGE("Fail to mmap");
1130 }
1131 fclose(fp);
1132 } else {
1133 ALOGE("Fail to open %s", filePath);
1134 }
1135 }
1136
signalReadbackDone()1137 void ExynosDevice::signalReadbackDone()
1138 {
1139 if (mIsWaitingReadbackReqDone) {
1140 Mutex::Autolock lock(mCaptureMutex);
1141 mCaptureCondition.signal();
1142 }
1143 }
1144
captureScreenWithReadback(uint32_t displayId)1145 void ExynosDevice::captureScreenWithReadback(uint32_t displayId) {
1146 ExynosDisplay *display = getDisplay(displayId);
1147 if (display == nullptr) {
1148 ALOGE("There is no display(%d)", displayId);
1149 return;
1150 }
1151
1152 int32_t outFormat;
1153 int32_t outDataspace;
1154 int32_t ret = 0;
1155 if ((ret = display->getReadbackBufferAttributes(
1156 &outFormat, &outDataspace)) != HWC2_ERROR_NONE) {
1157 ALOGE("getReadbackBufferAttributes fail, ret(%d)", ret);
1158 return;
1159 }
1160
1161 captureReadbackClass captureClass(this);
1162 if ((ret = captureClass.allocBuffer(outFormat, display->mXres, display->mYres))
1163 != NO_ERROR) {
1164 return;
1165 }
1166
1167 mIsWaitingReadbackReqDone = true;
1168
1169 if (display->setReadbackBuffer(captureClass.getBuffer(), -1, true) != HWC2_ERROR_NONE) {
1170 ALOGE("setReadbackBuffer fail");
1171 return;
1172 }
1173
1174 /* Update screen */
1175 onRefresh(displayId);
1176
1177 /* Wait for handling readback */
1178 uint32_t waitPeriod = display->mVsyncPeriod * 3;
1179 {
1180 Mutex::Autolock lock(mCaptureMutex);
1181 status_t err = mCaptureCondition.waitRelative(
1182 mCaptureMutex, us2ns(waitPeriod));
1183 if (err == TIMED_OUT) {
1184 ALOGE("timeout, readback is not requested");
1185 return;
1186 } else if (err != NO_ERROR) {
1187 ALOGE("error waiting for readback request: %s (%d)", strerror(-err), err);
1188 return;
1189 } else {
1190 ALOGD("readback request is done");
1191 }
1192 }
1193
1194 int32_t fence = -1;
1195 if (display->getReadbackBufferFence(&fence) != HWC2_ERROR_NONE) {
1196 ALOGE("getReadbackBufferFence fail");
1197 return;
1198 }
1199 if (sync_wait(fence, 1000) < 0) {
1200 ALOGE("sync wait error, fence(%d)", fence);
1201 }
1202 hwcFdClose(fence);
1203
1204 String8 fileName;
1205 time_t curTime = time(NULL);
1206 struct tm *tm = localtime(&curTime);
1207 fileName.appendFormat("capture_format%d_%dx%d_%04d-%02d-%02d_%02d_%02d_%02d.raw",
1208 outFormat, display->mXres, display->mYres,
1209 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1210 tm->tm_hour, tm->tm_min, tm->tm_sec);
1211 captureClass.saveToFile(fileName);
1212 }
1213
setDisplayDeviceMode(int32_t display_id,int32_t mode)1214 int32_t ExynosDevice::setDisplayDeviceMode(int32_t display_id, int32_t mode)
1215 {
1216 int32_t ret = HWC2_ERROR_NONE;
1217
1218 for (size_t i = 0; i < mDisplays.size(); i++) {
1219 if (mDisplays[i]->mType == HWC_DISPLAY_PRIMARY && mDisplays[i]->mDisplayId == display_id) {
1220 if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::PAUSE) ||
1221 mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) {
1222 ret = mDisplays[i]->setPowerMode(mode);
1223 if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME) &&
1224 ret == HWC2_ERROR_NONE) {
1225 onRefresh(display_id);
1226 }
1227 return ret;
1228 } else {
1229 return HWC2_ERROR_UNSUPPORTED;
1230 }
1231 }
1232 }
1233 return HWC2_ERROR_UNSUPPORTED;
1234 }
1235
setPanelGammaTableSource(int32_t display_id,int32_t type,int32_t source)1236 int32_t ExynosDevice::setPanelGammaTableSource(int32_t display_id, int32_t type, int32_t source) {
1237 if (display_id < HWC_DISPLAY_PRIMARY || display_id >= HWC_NUM_DISPLAY_TYPES) {
1238 ALOGE("invalid display %d", display_id);
1239 return HWC2_ERROR_BAD_DISPLAY;
1240 }
1241
1242 if (type < static_cast<int32_t>(DisplayType::DISPLAY_PRIMARY) ||
1243 type >= static_cast<int32_t>(DisplayType::DISPLAY_MAX)) {
1244 ALOGE("invalid display type %d", type);
1245 return HWC2_ERROR_BAD_PARAMETER;
1246 }
1247
1248 if (source < static_cast<int32_t>(PanelGammaSource::GAMMA_DEFAULT) ||
1249 source >= static_cast<int32_t>(PanelGammaSource::GAMMA_TYPES)) {
1250 ALOGE("invalid gamma source %d", source);
1251 return HWC2_ERROR_BAD_PARAMETER;
1252 }
1253
1254 return mDisplays[display_id]->SetCurrentPanelGammaSource(static_cast<DisplayType>(type),
1255 static_cast<PanelGammaSource>(source));
1256 }
1257
getLayerGenericMetadataKey(uint32_t __unused keyIndex,uint32_t * outKeyLength,char * __unused outKey,bool * __unused outMandatory)1258 void ExynosDevice::getLayerGenericMetadataKey(uint32_t __unused keyIndex,
1259 uint32_t* outKeyLength, char* __unused outKey, bool* __unused outMandatory)
1260 {
1261 *outKeyLength = 0;
1262 return;
1263 }
1264
setVBlankOffDelay(const int vblankOffDelay)1265 void ExynosDevice::setVBlankOffDelay(const int vblankOffDelay) {
1266 static constexpr const char *kVblankOffDelayPath = "/sys/module/drm/parameters/vblankoffdelay";
1267
1268 writeIntToFile(kVblankOffDelayPath, vblankOffDelay);
1269 }
1270
getWindowPlaneNum()1271 uint32_t ExynosDevice::getWindowPlaneNum()
1272 {
1273 /*
1274 * ExynosDevice supports DPU Window Composition.
1275 * The number of windows can be composited is depends on the number of DPP planes.
1276 */
1277 return mDeviceInterface->getNumDPPChs();
1278 }
1279
getSpecialPlaneNum()1280 uint32_t ExynosDevice::getSpecialPlaneNum()
1281 {
1282 /*
1283 * ExynosDevice might support something special purpose planes.
1284 * These planes are different with DPP planes.
1285 */
1286 return mDeviceInterface->getNumSPPChs();
1287 }
1288
getSpecialPlaneNum(uint32_t)1289 uint32_t ExynosDevice::getSpecialPlaneNum(uint32_t /*displayId*/) {
1290 /*
1291 * TODO: create the query function for each display
1292 */
1293 return mDeviceInterface->getNumSPPChs();
1294 }
1295
getSpecialPlaneId(uint32_t index)1296 uint32_t ExynosDevice::getSpecialPlaneId(uint32_t index)
1297 {
1298 return mDeviceInterface->getSPPChId(index);
1299 }
1300
getSpecialPlaneAttr(uint32_t index)1301 uint64_t ExynosDevice::getSpecialPlaneAttr(uint32_t index)
1302 {
1303 return mDeviceInterface->getSPPChAttr(index);
1304 }
1305
registerHwc3Callback(uint32_t descriptor,hwc2_callback_data_t callbackData,hwc2_function_pointer_t point)1306 int32_t ExynosDevice::registerHwc3Callback(uint32_t descriptor, hwc2_callback_data_t callbackData,
1307 hwc2_function_pointer_t point) {
1308 Mutex::Autolock lock(mDeviceCallbackMutex);
1309 mHwc3CallbackInfos[descriptor].callbackData = callbackData;
1310 mHwc3CallbackInfos[descriptor].funcPointer = point;
1311
1312 return HWC2_ERROR_NONE;
1313 }
1314
onVsyncIdle(hwc2_display_t displayId)1315 void ExynosDevice::onVsyncIdle(hwc2_display_t displayId) {
1316 Mutex::Autolock lock(mDeviceCallbackMutex);
1317 const auto &idleCallback = mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onVsyncIdle);
1318
1319 if (idleCallback == mHwc3CallbackInfos.end()) return;
1320
1321 const auto &callbackInfo = idleCallback->second;
1322 if (callbackInfo.funcPointer == nullptr || callbackInfo.callbackData == nullptr) return;
1323
1324 auto callbackFunc =
1325 reinterpret_cast<void (*)(hwc2_callback_data_t callbackData,
1326 hwc2_display_t hwcDisplay)>(callbackInfo.funcPointer);
1327 callbackFunc(callbackInfo.callbackData, displayId);
1328 }
1329
handleHotplug()1330 void ExynosDevice::handleHotplug() {
1331 bool hpdStatus = false;
1332
1333 for (size_t i = 0; i < mDisplays.size(); i++) {
1334 if (mDisplays[i] == nullptr) {
1335 continue;
1336 }
1337
1338 // Lock mDisplayMutex during hotplug processing.
1339 // Must-have for unplug handling so that in-flight calls to
1340 // validateDisplay() and presentDisplay() don't race with
1341 // the display being removed.
1342 Mutex::Autolock lock(mDisplays[i]->mDisplayMutex);
1343
1344 if (mDisplays[i]->checkHotplugEventUpdated(hpdStatus)) {
1345 mDisplays[i]->handleHotplugEvent(hpdStatus);
1346 mDisplays[i]->hotplug();
1347 mDisplays[i]->invalidate();
1348 }
1349 }
1350 }
1351
onRefreshRateChangedDebug(hwc2_display_t displayId,uint32_t vsyncPeriod,uint32_t refreshPeriod)1352 void ExynosDevice::onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod,
1353 uint32_t refreshPeriod) {
1354 Mutex::Autolock lock(mDeviceCallbackMutex);
1355 const auto &refreshRateCallback =
1356 mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug);
1357
1358 if (refreshRateCallback == mHwc3CallbackInfos.end()) return;
1359
1360 const auto &callbackInfo = refreshRateCallback->second;
1361 if (callbackInfo.funcPointer == nullptr || callbackInfo.callbackData == nullptr) return;
1362
1363 ATRACE_INT("Refresh rate indicator callback",
1364 static_cast<int>(std::nano::den / (refreshPeriod ?: vsyncPeriod)));
1365
1366 auto callbackFunc =
1367 reinterpret_cast<void (*)(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay,
1368 hwc2_vsync_period_t, int32_t)>(callbackInfo.funcPointer);
1369 callbackFunc(callbackInfo.callbackData, displayId, vsyncPeriod, refreshPeriod ?: vsyncPeriod);
1370 }
1371