blob: 50cd93accf8d4161dc4955dd0d8a2507ab736a00
1 | //#define LOG_NDEBUG 0 |
2 | #include <HwcTrace.h> |
3 | #include <binder/IServiceManager.h> |
4 | #include <utils/Tokenizer.h> |
5 | #include <thread> |
6 | #include <gui/SurfaceComposerClient.h> |
7 | #include <gui/ISurfaceComposer.h> |
8 | #include "DisplayHdmi.h" |
9 | #include <cutils/properties.h> |
10 | |
11 | namespace android { |
12 | namespace amlogic { |
13 | |
14 | void DisplayHdmi::SystemControlDeathRecipient::serviceDied( |
15 | uint64_t, const wp<::android::hidl::base::V1_0::IBase>&) { |
16 | ETRACE("system_control died, need reconnect it\n"); |
17 | } |
18 | |
19 | DisplayHdmi::DisplayHdmi(hwc2_display_t id) { |
20 | mDisplayId = id; |
21 | |
22 | mTrebleSystemControlEnable = property_get_bool("persist.system_control.treble", true); |
23 | |
24 | initModes(); |
25 | } |
26 | |
27 | DisplayHdmi::~DisplayHdmi() { |
28 | mAllModes.clear(); |
29 | } |
30 | |
31 | void DisplayHdmi::initBinderService() { |
32 | mTrebleSystemControl = nullptr; |
33 | sp<ISystemControl> control = nullptr; |
34 | |
35 | if (mTrebleSystemControlEnable) { |
36 | control = ISystemControl::getService(); |
37 | mDeathRecipient = new SystemControlDeathRecipient(); |
38 | Return<bool> linked = control->linkToDeath(mDeathRecipient, /*cookie*/ 0); |
39 | if (!linked.isOk()) { |
40 | ETRACE("Transaction error in linking to system service death: %s", linked.description().c_str()); |
41 | } else if (!linked) { |
42 | ETRACE("Unable to link to system service death notifications"); |
43 | } else { |
44 | ITRACE("Link to system service death notification successful"); |
45 | } |
46 | |
47 | mTrebleSystemControl = control; |
48 | } |
49 | else { |
50 | sp<IServiceManager> sm = defaultServiceManager(); |
51 | if (sm == NULL) { |
52 | ETRACE("Couldn't get default ServiceManager\n"); |
53 | return ; |
54 | } |
55 | |
56 | mSystemControlService = interface_cast<ISystemControlService>(sm->getService(String16("system_control"))); |
57 | if (mSystemControlService == NULL) { |
58 | ETRACE("Couldn't get connection to SystemControlService\n"); |
59 | return ; |
60 | } |
61 | } |
62 | } |
63 | |
64 | void DisplayHdmi::initialize() { |
65 | reset(); |
66 | } |
67 | |
68 | void DisplayHdmi::deinitialize() { |
69 | reset(); |
70 | } |
71 | |
72 | void DisplayHdmi::reset() { |
73 | mConnected = false; |
74 | mActiveDisplayConfigItem = 0; |
75 | mActiveRefreshRate = 60; |
76 | memset(mActiveDisplaymode, 0, HWC_DISPLAY_MODE_LENGTH); |
77 | mSupportDispModes.clear(); |
78 | for (size_t i = 0; i < mDisplayConfigs.size(); i++) { |
79 | DisplayConfig *config = mDisplayConfigs[i]; |
80 | if (config) |
81 | delete config; |
82 | } |
83 | mDisplayConfigs.clear(); |
84 | } |
85 | |
86 | bool DisplayHdmi::updateHotplug(bool connected, |
87 | framebuffer_info_t * framebufferInfo, |
88 | private_handle_t* framebufferHnd) { |
89 | bool ret = true; |
90 | int32_t rate; |
91 | initBinderService(); |
92 | |
93 | mConnected = connected; |
94 | |
95 | if (!isConnected()) { |
96 | ETRACE("disp: %d disconnect", (int32_t)mDisplayId); |
97 | return true; |
98 | } |
99 | |
100 | mFramebufferInfo = framebufferInfo; |
101 | mFramebufferHnd = framebufferHnd; |
102 | |
103 | if (-1 == updateDisplayModeList()) { |
104 | //hdmi plug out when system is starting up |
105 | std::string dispMode; |
106 | int width, height; |
107 | if (mTrebleSystemControlEnable) { |
108 | mTrebleSystemControl->getActiveDispMode([&dispMode](const Result &ret, const hidl_string& mode) { |
109 | if (Result::OK == ret) { |
110 | dispMode = mode.c_str(); |
111 | } |
112 | }); |
113 | } |
114 | else { |
115 | mSystemControlService->getActiveDispMode(&dispMode); |
116 | } |
117 | |
118 | ret = calcMode2Config(dispMode.c_str(), &rate, &width, &height); |
119 | if (!ret) { |
120 | dispMode = std::string("1080p60hz"); |
121 | rate = 60; |
122 | } |
123 | ETRACE("only init one display config: %s", dispMode.c_str()); |
124 | strcpy(mActiveDisplaymode, dispMode.c_str()); |
125 | |
126 | // reset display configs |
127 | for (size_t i = 0; i < mDisplayConfigs.size(); i++) { |
128 | DisplayConfig *config = mDisplayConfigs[i]; |
129 | if (config) |
130 | delete config; |
131 | } |
132 | mDisplayConfigs.clear(); |
133 | |
134 | // use active fb dimension as config width/height |
135 | DisplayConfig *config = new DisplayConfig(mActiveDisplaymode, |
136 | rate, |
137 | mFramebufferInfo->info.xres, |
138 | mFramebufferInfo->info.yres, |
139 | mFramebufferInfo->xdpi, |
140 | mFramebufferInfo->ydpi); |
141 | // add it to the front of other configs |
142 | mDisplayConfigs.push_back(config); |
143 | |
144 | // init the active display config |
145 | mActiveDisplayConfigItem = 0; |
146 | mActiveRefreshRate = rate; |
147 | //ETRACE("Active display mode %s, refresh rate: %d", mActiveDisplaymode, rate); |
148 | } else { |
149 | //hdmi plug in when system is starting up |
150 | updateActiveDisplayMode(); |
151 | updateDisplayConfigures(); |
152 | updateActiveDisplayConfigure(); |
153 | |
154 | std::string strmode(mActiveDisplaymode); |
155 | if (mTrebleSystemControlEnable) { |
156 | hidl_string mode(strmode); |
157 | Result ret = mTrebleSystemControl->setActiveDispMode(mode); |
158 | if (Result::OK == ret) { |
159 | } |
160 | } |
161 | else { |
162 | mSystemControlService->setActiveDispMode(strmode); |
163 | } |
164 | } |
165 | |
166 | std::thread t1(&DisplayHdmi::setSurfaceFlingerActiveMode, this); |
167 | t1.detach(); |
168 | |
169 | return true; |
170 | } |
171 | |
172 | int DisplayHdmi::updateDisplayModeList() { |
173 | // clear display modes |
174 | mSupportDispModes.clear(); |
175 | |
176 | bool fullActiveMode = Utils::get_bool_prop("ro.sf.full_activemode"); |
177 | bool isConfiged = readConfigFile("/vendor/etc/displayModeList.cfg", &mSupportDispModes); |
178 | if (isConfiged) { |
179 | return 0; |
180 | } |
181 | |
182 | if (!fullActiveMode) { |
183 | ALOGD("Simple Active Mode!!!"); |
184 | return -1; |
185 | } |
186 | |
187 | std::vector<std::string> getSupportDispModes; |
188 | std::string::size_type pos; |
189 | if (mTrebleSystemControlEnable) { |
190 | mTrebleSystemControl->getSupportDispModeList( |
191 | [&getSupportDispModes](const Result &ret, const hidl_vec<hidl_string>& modeList) { |
192 | if (Result::OK == ret) { |
193 | for (size_t i = 0; i < modeList.size(); i++) { |
194 | getSupportDispModes.push_back(modeList[i]); |
195 | } |
196 | } |
197 | }); |
198 | } |
199 | else { |
200 | mSystemControlService->getSupportDispModeList(&getSupportDispModes); |
201 | } |
202 | |
203 | if (getSupportDispModes.size() == 0) { |
204 | ALOGD("SupportDispModeList null!!!"); |
205 | return -1; |
206 | } |
207 | |
208 | for (size_t i = 0; i < getSupportDispModes.size(); i++) { |
209 | //ALOGD("get support display mode:%s", getSupportDispModes[i].c_str()); |
210 | while (!getSupportDispModes[i].empty()) { |
211 | pos = getSupportDispModes[i].find('*'); |
212 | if (pos != std::string::npos) { |
213 | getSupportDispModes[i].erase(pos, 1); |
214 | //ALOGD("modify support display mode:%s", getSupportDispModes[i].c_str()); |
215 | } else { |
216 | break; |
217 | } |
218 | } |
219 | } |
220 | |
221 | |
222 | for (size_t k = 0; k < mAllModes.size(); k++) { |
223 | for (size_t j = 0; j < getSupportDispModes.size(); j++) { |
224 | if (!getSupportDispModes[j].empty()) { |
225 | if (mAllModes[k] == getSupportDispModes[j]) { |
226 | mSupportDispModes.push_back(getSupportDispModes[j]); |
227 | ALOGD("support display mode:%s", getSupportDispModes[j].c_str()); |
228 | } |
229 | } |
230 | } |
231 | } |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | int DisplayHdmi::updateActiveDisplayMode() { |
237 | std::string dispMode; |
238 | |
239 | if (mTrebleSystemControlEnable) { |
240 | mTrebleSystemControl->getActiveDispMode([&dispMode](const Result &ret, const hidl_string& mode) { |
241 | if (Result::OK == ret) { |
242 | dispMode = mode.c_str(); |
243 | } |
244 | }); |
245 | } |
246 | else { |
247 | mSystemControlService->getActiveDispMode(&dispMode); |
248 | } |
249 | |
250 | strcpy(mActiveDisplaymode, dispMode.c_str()); |
251 | |
252 | int refreshRate = 60; |
253 | if (strstr(mActiveDisplaymode, "60hz") != NULL) { |
254 | refreshRate = 60; |
255 | } else if (strstr(mActiveDisplaymode, "50hz") != NULL) { |
256 | refreshRate = 50; |
257 | } else if (strstr(mActiveDisplaymode, "30hz") != NULL) { |
258 | refreshRate = 30; |
259 | } else if (strstr(mActiveDisplaymode, "25hz") != NULL) { |
260 | refreshRate = 25; |
261 | } else if ((strstr(mActiveDisplaymode, "24hz") != NULL) |
262 | || (strstr(mActiveDisplaymode, "smpte") != NULL)) { |
263 | refreshRate = 24; |
264 | } else |
265 | ETRACE("displaymode (%s) doesn't specify HZ", mActiveDisplaymode); |
266 | |
267 | ALOGD("Active display mode: (%s), refresh rate: (%d)", mActiveDisplaymode, refreshRate); |
268 | |
269 | mActiveRefreshRate = refreshRate; |
270 | |
271 | return 0; |
272 | } |
273 | |
274 | int DisplayHdmi::setDisplayMode(const char* displaymode) { |
275 | ALOGD("setDisplayMode to %s", displaymode); |
276 | |
277 | std::string strmode(displaymode); |
278 | if (mTrebleSystemControlEnable) { |
279 | hidl_string mode(strmode); |
280 | Result ret = mTrebleSystemControl->setActiveDispMode(mode); |
281 | if (Result::OK == ret) { |
282 | } |
283 | } |
284 | else { |
285 | mSystemControlService->setActiveDispMode(strmode); |
286 | } |
287 | |
288 | updateActiveDisplayMode(); |
289 | |
290 | return 0; |
291 | } |
292 | |
293 | int DisplayHdmi::updateDisplayConfigures() { |
294 | size_t i; |
295 | |
296 | std::string dispMode; |
297 | int refreshRate, width, height; |
298 | |
299 | // reset display configs |
300 | for (i = 0; i < mDisplayConfigs.size(); i++) { |
301 | DisplayConfig *config = mDisplayConfigs[i]; |
302 | if (config) |
303 | delete config; |
304 | } |
305 | mDisplayConfigs.clear(); |
306 | |
307 | for (i =0; i < mSupportDispModes.size(); i ++) { |
308 | dispMode = mSupportDispModes[i]; |
309 | calcMode2Config(dispMode.c_str(), &refreshRate, &width, &height); |
310 | |
311 | // init dimension as config width/height, set xdpi/ydpi after |
312 | DisplayConfig *config = new DisplayConfig(dispMode.c_str(), |
313 | refreshRate, width, height, |
314 | mFramebufferInfo->xdpi, |
315 | mFramebufferInfo->ydpi); |
316 | // add it to the front of other configs |
317 | mDisplayConfigs.push_back(config); |
318 | } |
319 | return 0; |
320 | } |
321 | |
322 | int DisplayHdmi::updateActiveDisplayConfigure() { |
323 | size_t i; |
324 | |
325 | DisplayConfig *dispConfig = NULL; |
326 | for (i = 0; i < mDisplayConfigs.size(); i++) { |
327 | dispConfig = mDisplayConfigs[i]; |
328 | if (!dispConfig) { |
329 | continue; |
330 | } |
331 | if (0 == strncmp(mActiveDisplaymode, dispConfig->getDisplayMode(), |
332 | HWC_DISPLAY_MODE_LENGTH-1)) { |
333 | mActiveDisplayConfigItem = i; |
334 | ALOGD("updateActiveDisplayConfigure to config(%d)", mActiveDisplayConfigItem); |
335 | dispConfig->setDpi(mFramebufferInfo->xdpi, mFramebufferInfo->ydpi); |
336 | break; |
337 | } |
338 | } |
339 | return 0; |
340 | } |
341 | |
342 | int DisplayHdmi::getDisplayConfigs(uint32_t* outNumConfigs, |
343 | hwc2_config_t* outConfigs) { |
344 | size_t i; |
345 | |
346 | if (!isConnected()) { |
347 | //ETRACE("display %d is not connected.", (int32_t)mDisplayId); |
348 | } |
349 | |
350 | for (i = 0; i < mDisplayConfigs.size(); i++) { |
351 | if (NULL != outConfigs) |
352 | outConfigs[i] = i; |
353 | } |
354 | |
355 | *outNumConfigs = i; |
356 | |
357 | return HWC2_ERROR_NONE; |
358 | } |
359 | |
360 | int DisplayHdmi::getDisplayAttribute(hwc2_config_t config, |
361 | int32_t /*hwc2_attribute_t*/ attribute, |
362 | int32_t* outValue) { |
363 | |
364 | if (!isConnected()) { |
365 | //ETRACE("display %d is not connected.", (int32_t)mDisplayId); |
366 | } |
367 | |
368 | DisplayConfig *configChosen = mDisplayConfigs[config]; |
369 | if (!configChosen) { |
370 | ETRACE("failed to get display config: %d", config); |
371 | return HWC2_ERROR_NONE; |
372 | } |
373 | |
374 | switch (attribute) { |
375 | case HWC2_ATTRIBUTE_VSYNC_PERIOD: |
376 | if (configChosen->getRefreshRate()) { |
377 | *outValue = 1e9 / configChosen->getRefreshRate(); |
378 | } |
379 | break; |
380 | case HWC2_ATTRIBUTE_WIDTH: |
381 | *outValue = configChosen->getWidth(); |
382 | break; |
383 | case HWC2_ATTRIBUTE_HEIGHT: |
384 | *outValue = configChosen->getHeight(); |
385 | break; |
386 | case HWC2_ATTRIBUTE_DPI_X: |
387 | *outValue = configChosen->getDpiX() * 1000.0f; |
388 | break; |
389 | case HWC2_ATTRIBUTE_DPI_Y: |
390 | *outValue = configChosen->getDpiY() * 1000.0f; |
391 | break; |
392 | default: |
393 | ETRACE("unknown display attribute %u", attribute); |
394 | *outValue = -1; |
395 | break; |
396 | } |
397 | |
398 | return HWC2_ERROR_NONE; |
399 | } |
400 | |
401 | int DisplayHdmi::getActiveConfig(hwc2_config_t* outConfig) { |
402 | if (!isConnected()) { |
403 | //ETRACE("display %d is not connected.", (int32_t)mDisplayId); |
404 | } |
405 | //ALOGD("getActiveConfig to config(%d).", mActiveDisplayConfigItem); |
406 | *outConfig = mActiveDisplayConfigItem; |
407 | |
408 | return HWC2_ERROR_NONE; |
409 | } |
410 | |
411 | int DisplayHdmi::setActiveConfig(int id) { |
412 | DisplayConfig *dispConfig = NULL; |
413 | char *dispMode = NULL; |
414 | |
415 | if (!isConnected()) { |
416 | //ETRACE("display %d is not connected.", (int32_t)mDisplayId); |
417 | } |
418 | |
419 | ALOGD("setActiveConfig to config(%d).", id); |
420 | mActiveDisplayConfigItem = id; |
421 | dispConfig = mDisplayConfigs[id]; |
422 | if (!dispConfig) { |
423 | ETRACE("failed to get display config: %d", id); |
424 | return HWC2_ERROR_BAD_CONFIG; |
425 | } |
426 | |
427 | dispConfig->setDpi(mFramebufferInfo->xdpi, |
428 | mFramebufferInfo->ydpi); |
429 | |
430 | dispMode = dispConfig->getDisplayMode(); |
431 | if (!dispMode) { |
432 | ETRACE("failed to get display mode by config: %d", id); |
433 | return HWC2_ERROR_BAD_CONFIG; |
434 | } |
435 | |
436 | setDisplayMode(dispMode); |
437 | |
438 | return HWC2_ERROR_NONE; |
439 | } |
440 | |
441 | bool DisplayHdmi::calcMode2Config(const char *dispMode, int* refreshRate, |
442 | int* width, int* height) { |
443 | |
444 | if (NULL == dispMode) { |
445 | ETRACE("dispMode is NULL"); |
446 | return false; |
447 | } |
448 | |
449 | if (strstr(dispMode, "60hz") != NULL) { |
450 | *refreshRate = 60; |
451 | } else if (strstr(dispMode, "50hz") != NULL) { |
452 | *refreshRate = 50; |
453 | } else if (strstr(dispMode, "30hz") != NULL) { |
454 | *refreshRate = 30; |
455 | } else if (strstr(dispMode, "25hz") != NULL) { |
456 | *refreshRate = 25; |
457 | } else if ((strstr(dispMode, "24hz") != NULL) |
458 | || (strstr(dispMode, "smpte") != NULL)) { |
459 | *refreshRate = 24; |
460 | } else { |
461 | ETRACE("displaymode (%s) doesn't specify HZ", dispMode); |
462 | return false; |
463 | } |
464 | |
465 | if (strstr(dispMode, "2160") != NULL) { |
466 | *width = 3840; |
467 | *height = 2160; |
468 | } else if (strstr(dispMode, "1080") != NULL) { |
469 | *width = 1920; |
470 | *height = 1080; |
471 | } else if (strstr(dispMode, "720") != NULL) { |
472 | *width = 1280; |
473 | *height = 720; |
474 | } else if (strstr(dispMode, "576") != NULL) { |
475 | *width = 720; |
476 | *height = 576; |
477 | } else if (strstr(dispMode, "480") != NULL) { |
478 | *width = 640; |
479 | *height = 480; |
480 | } else { |
481 | // smpte and panle imcomplete!!!!! |
482 | ETRACE("calcMode2Config displaymode (%s) doesn't specify HZ", dispMode); |
483 | return false; |
484 | } |
485 | |
486 | //DTRACE("calcMode2Config (%s) refreshRate(%d), (%dx%d)", dispMode, *refreshRate, *width, *height); |
487 | return true; |
488 | } |
489 | |
490 | bool DisplayHdmi::readConfigFile(const char* configPath, std::vector<std::string>* supportDispModes) { |
491 | const char* WHITESPACE = " \t\r"; |
492 | |
493 | Tokenizer* tokenizer; |
494 | status_t status = Tokenizer::open(String8(configPath), &tokenizer); |
495 | |
496 | if (status) { |
497 | DTRACE("Error %d opening display config file %s.", status, configPath); |
498 | return false; |
499 | } else { |
500 | while (!tokenizer->isEof()) { |
501 | tokenizer->skipDelimiters(WHITESPACE); |
502 | if (!tokenizer->isEol() && tokenizer->peekChar() != '#') { |
503 | String8 token = tokenizer->nextToken(WHITESPACE); |
504 | const char* dispMode = token.string(); |
505 | if (strstr(dispMode, "hz")) { |
506 | ETRACE("dispMode %s.", dispMode); |
507 | (*supportDispModes).push_back(std::string(dispMode)); |
508 | } |
509 | } |
510 | |
511 | tokenizer->nextLine(); |
512 | } |
513 | delete tokenizer; |
514 | } |
515 | |
516 | size_t num = (*supportDispModes).size(); |
517 | |
518 | if (num <= 0) { |
519 | return false; |
520 | } else { |
521 | return true; |
522 | } |
523 | } |
524 | |
525 | void DisplayHdmi::setSurfaceFlingerActiveMode() { |
526 | /* |
527 | sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( |
528 | ISurfaceComposer::eDisplayIdMain)); |
529 | |
530 | SurfaceComposerClient::setActiveConfig(dtoken, mDisplayConfigs.size()-mActiveDisplayConfigItem-1); |
531 | */ |
532 | } |
533 | |
534 | void DisplayHdmi::initModes() { |
535 | //mAllModes.push_back("480p60hz"); |
536 | //mAllModes.push_back("576p50hz"); |
537 | //mAllModes.push_back("720p50hz"); |
538 | //mAllModes.push_back("720p60hz"); |
539 | mAllModes.push_back("1080p60hz"); |
540 | mAllModes.push_back("1080p50hz"); |
541 | mAllModes.push_back("1080p30hz"); |
542 | mAllModes.push_back("1080p25hz"); |
543 | mAllModes.push_back("1080p24hz"); |
544 | //mAllModes.push_back("2160p24hz"); |
545 | //mAllModes.push_back("2160p25hz"); |
546 | //mAllModes.push_back("2160p30hz"); |
547 | //mAllModes.push_back("2160p50hz"); |
548 | //mAllModes.push_back("2160p60hz"); |
549 | } |
550 | |
551 | void DisplayHdmi::dump(Dump& d) { |
552 | d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT |" |
553 | " DPI_X | DPI_Y \n"); |
554 | d.append("------------+------------------+-----------+------------+" |
555 | "-----------+-----------\n"); |
556 | for (size_t i = 0; i < mDisplayConfigs.size(); i++) { |
557 | DisplayConfig *config = mDisplayConfigs[i]; |
558 | if (config) { |
559 | d.append("%s %2d | %4d | %5d | %4d |" |
560 | " %3d | %3d \n", |
561 | (i == (size_t)mActiveDisplayConfigItem) ? "* " : " ", |
562 | i, |
563 | config->getRefreshRate(), |
564 | config->getWidth(), |
565 | config->getHeight(), |
566 | config->getDpiX(), |
567 | config->getDpiY()); |
568 | } |
569 | } |
570 | } |
571 | |
572 | } // namespace amlogic |
573 | } // namespace android |
574 | |
575 | |
576 | |
577 |