1 /*
2 // Copyright (c) 2014 Intel Corporation
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 #include <HwcTrace.h>
17 #include <Hwcomposer.h>
18 #include <Drm.h>
19 #include <PhysicalDevice.h>
20 #include <cutils/properties.h>
21
22 namespace android {
23 namespace intel {
24
PhysicalDevice(uint32_t type,Hwcomposer & hwc,DeviceControlFactory * controlFactory)25 PhysicalDevice::PhysicalDevice(uint32_t type, Hwcomposer& hwc, DeviceControlFactory* controlFactory)
26 : mType(type),
27 mHwc(hwc),
28 mActiveDisplayConfig(-1),
29 mBlankControl(NULL),
30 mVsyncObserver(NULL),
31 mControlFactory(controlFactory),
32 mLayerList(NULL),
33 mConnected(false),
34 mBlank(false),
35 mDisplayState(DEVICE_DISPLAY_ON),
36 mInitialized(false),
37 mFpsDivider(1)
38 {
39 CTRACE();
40
41 switch (type) {
42 case DEVICE_PRIMARY:
43 mName = "Primary";
44 break;
45 case DEVICE_EXTERNAL:
46 mName = "External";
47 break;
48 default:
49 mName = "Unknown";
50 }
51
52 mDisplayConfigs.setCapacity(DEVICE_COUNT);
53 }
54
~PhysicalDevice()55 PhysicalDevice::~PhysicalDevice()
56 {
57 WARN_IF_NOT_DEINIT();
58 }
59
onGeometryChanged(hwc_display_contents_1_t * list)60 void PhysicalDevice::onGeometryChanged(hwc_display_contents_1_t *list)
61 {
62 if (!list) {
63 ETRACE("list is NULL");
64 return;
65 }
66
67 ATRACE("disp = %d, layer number = %d", mType, list->numHwLayers);
68
69 // NOTE: should NOT be here
70 if (mLayerList) {
71 WTRACE("mLayerList exists");
72 DEINIT_AND_DELETE_OBJ(mLayerList);
73 }
74
75 // create a new layer list
76 mLayerList = new HwcLayerList(list, mType);
77 if (!mLayerList) {
78 WTRACE("failed to create layer list");
79 }
80 }
81
prePrepare(hwc_display_contents_1_t * display)82 bool PhysicalDevice::prePrepare(hwc_display_contents_1_t *display)
83 {
84 RETURN_FALSE_IF_NOT_INIT();
85 Mutex::Autolock _l(mLock);
86
87 // for a null list, delete hwc list
88 if (!mConnected || !display || mBlank) {
89 if (mLayerList) {
90 DEINIT_AND_DELETE_OBJ(mLayerList);
91 }
92 return true;
93 }
94
95 // check if geometry is changed, if changed delete list
96 if ((display->flags & HWC_GEOMETRY_CHANGED) && mLayerList) {
97 DEINIT_AND_DELETE_OBJ(mLayerList);
98 }
99 return true;
100 }
101
prepare(hwc_display_contents_1_t * display)102 bool PhysicalDevice::prepare(hwc_display_contents_1_t *display)
103 {
104 RETURN_FALSE_IF_NOT_INIT();
105 Mutex::Autolock _l(mLock);
106
107 if (!mConnected || !display || mBlank)
108 return true;
109
110 // check if geometry is changed
111 if (display->flags & HWC_GEOMETRY_CHANGED) {
112 onGeometryChanged(display);
113 }
114 if (!mLayerList) {
115 WTRACE("null HWC layer list");
116 return true;
117 }
118
119 // update list with new list
120 return mLayerList->update(display);
121 }
122
123
commit(hwc_display_contents_1_t * display,IDisplayContext * context)124 bool PhysicalDevice::commit(hwc_display_contents_1_t *display, IDisplayContext *context)
125 {
126 RETURN_FALSE_IF_NOT_INIT();
127
128 if (!display || !context || !mLayerList || mBlank) {
129 return true;
130 }
131 return context->commitContents(display, mLayerList);
132 }
133
vsyncControl(bool enabled)134 bool PhysicalDevice::vsyncControl(bool enabled)
135 {
136 RETURN_FALSE_IF_NOT_INIT();
137
138 ATRACE("disp = %d, enabled = %d", mType, enabled);
139 return mVsyncObserver->control(enabled);
140 }
141
blank(bool blank)142 bool PhysicalDevice::blank(bool blank)
143 {
144 RETURN_FALSE_IF_NOT_INIT();
145
146 if (!mConnected)
147 return false;
148
149 mBlank = blank;
150 bool ret = mBlankControl->blank(mType, blank);
151 if (ret == false) {
152 ETRACE("failed to blank device");
153 return false;
154 }
155
156 return true;
157 }
158
getDisplaySize(int * width,int * height)159 bool PhysicalDevice::getDisplaySize(int *width, int *height)
160 {
161 RETURN_FALSE_IF_NOT_INIT();
162 Mutex::Autolock _l(mLock);
163 if (!width || !height) {
164 ETRACE("invalid parameters");
165 return false;
166 }
167
168 *width = 0;
169 *height = 0;
170 drmModeModeInfo mode;
171 Drm *drm = Hwcomposer::getInstance().getDrm();
172 bool ret = drm->getModeInfo(mType, mode);
173 if (!ret) {
174 return false;
175 }
176
177 *width = mode.hdisplay;
178 *height = mode.vdisplay;
179 return true;
180 }
181
182 template <typename T>
min(T a,T b)183 static inline T min(T a, T b) {
184 return a<b ? a : b;
185 }
186
getDisplayConfigs(uint32_t * configs,size_t * numConfigs)187 bool PhysicalDevice::getDisplayConfigs(uint32_t *configs,
188 size_t *numConfigs)
189 {
190 RETURN_FALSE_IF_NOT_INIT();
191
192 Mutex::Autolock _l(mLock);
193
194 if (!mConnected) {
195 ITRACE("device is not connected");
196 return false;
197 }
198
199 if (!configs || !numConfigs || *numConfigs < 1) {
200 ETRACE("invalid parameters");
201 return false;
202 }
203
204 // fill in all config handles
205 *numConfigs = min(*numConfigs, mDisplayConfigs.size());
206 for (int i = 0; i < static_cast<int>(*numConfigs); i++) {
207 configs[i] = i;
208 }
209
210 return true;
211 }
getDisplayAttributes(uint32_t config,const uint32_t * attributes,int32_t * values)212 bool PhysicalDevice::getDisplayAttributes(uint32_t config,
213 const uint32_t *attributes,
214 int32_t *values)
215 {
216 RETURN_FALSE_IF_NOT_INIT();
217
218 Mutex::Autolock _l(mLock);
219
220 if (!mConnected) {
221 ITRACE("device is not connected");
222 return false;
223 }
224
225 if (!attributes || !values) {
226 ETRACE("invalid parameters");
227 return false;
228 }
229
230 DisplayConfig *configChosen = mDisplayConfigs.itemAt(config);
231 if (!configChosen) {
232 WTRACE("failed to get display config");
233 return false;
234 }
235
236 int i = 0;
237 while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
238 switch (attributes[i]) {
239 case HWC_DISPLAY_VSYNC_PERIOD:
240 if (configChosen->getRefreshRate()) {
241 values[i] = 1e9 / configChosen->getRefreshRate();
242 } else {
243 ETRACE("refresh rate is 0!!!");
244 values[i] = 0;
245 }
246 break;
247 case HWC_DISPLAY_WIDTH:
248 values[i] = configChosen->getWidth();
249 break;
250 case HWC_DISPLAY_HEIGHT:
251 values[i] = configChosen->getHeight();
252 break;
253 case HWC_DISPLAY_DPI_X:
254 values[i] = configChosen->getDpiX() * 1000.0f;
255 break;
256 case HWC_DISPLAY_DPI_Y:
257 values[i] = configChosen->getDpiY() * 1000.0f;
258 break;
259 default:
260 ETRACE("unknown attribute %d", attributes[i]);
261 break;
262 }
263 i++;
264 }
265
266 return true;
267 }
268
compositionComplete()269 bool PhysicalDevice::compositionComplete()
270 {
271 CTRACE();
272 // do nothing by default
273 return true;
274 }
275
removeDisplayConfigs()276 void PhysicalDevice::removeDisplayConfigs()
277 {
278 for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
279 DisplayConfig *config = mDisplayConfigs.itemAt(i);
280 delete config;
281 }
282
283 mDisplayConfigs.clear();
284 mActiveDisplayConfig = -1;
285 }
286
detectDisplayConfigs()287 bool PhysicalDevice::detectDisplayConfigs()
288 {
289 Mutex::Autolock _l(mLock);
290
291 Drm *drm = Hwcomposer::getInstance().getDrm();
292 if (!drm->detect(mType)) {
293 ETRACE("drm detection on device %d failed ", mType);
294 return false;
295 }
296 return updateDisplayConfigs();
297 }
298
updateDisplayConfigs()299 bool PhysicalDevice::updateDisplayConfigs()
300 {
301 bool ret;
302 Drm *drm = Hwcomposer::getInstance().getDrm();
303
304 // reset display configs
305 removeDisplayConfigs();
306
307 // update device connection status
308 mConnected = drm->isConnected(mType);
309 if (!mConnected) {
310 return true;
311 }
312
313 // reset the number of display configs
314 mDisplayConfigs.setCapacity(1);
315
316 drmModeModeInfo mode;
317 ret = drm->getModeInfo(mType, mode);
318 if (!ret) {
319 ETRACE("failed to get mode info");
320 mConnected = false;
321 return false;
322 }
323
324 uint32_t mmWidth, mmHeight;
325 ret = drm->getPhysicalSize(mType, mmWidth, mmHeight);
326 if (!ret) {
327 ETRACE("failed to get physical size");
328 mConnected = false;
329 return false;
330 }
331
332 float physWidthInch = (float)mmWidth * 0.039370f;
333 float physHeightInch = (float)mmHeight * 0.039370f;
334
335 // use current drm mode, likely it's preferred mode
336 int dpiX = 0;
337 int dpiY = 0;
338 if (physWidthInch && physHeightInch) {
339 dpiX = mode.hdisplay / physWidthInch;
340 dpiY = mode.vdisplay / physHeightInch;
341 } else {
342 ETRACE("invalid physical size, EDID read error?");
343 // don't bail out as it is not a fatal error
344 }
345 // use active fb dimension as config width/height
346 // add display config vfresh/mFpsDivider to lower FPS
347 DisplayConfig *config = new DisplayConfig(mode.vrefresh/mFpsDivider,
348 mode.hdisplay,
349 mode.vdisplay,
350 dpiX, dpiY);
351 // add it to the front of other configs
352 mDisplayConfigs.push_front(config);
353
354 // init the active display config
355 mActiveDisplayConfig = 0;
356
357 drmModeModeInfoPtr modes;
358 drmModeModeInfoPtr compatMode;
359 int modeCount = 0;
360
361 modes = drm->detectAllConfigs(mType, &modeCount);
362
363 for (int i = 0; i < modeCount; i++) {
364 if (modes) {
365 compatMode = &modes[i];
366 if (!compatMode)
367 continue;
368 if (compatMode->hdisplay == mode.hdisplay &&
369 compatMode->vdisplay == mode.vdisplay &&
370 compatMode->vrefresh != mode.vrefresh) {
371
372 bool found = false;
373 for (size_t j = 0; j < mDisplayConfigs.size(); j++) {
374 DisplayConfig *config = mDisplayConfigs.itemAt(j);
375 if (config->getRefreshRate() == (int)compatMode->vrefresh) {
376 found = true;
377 break;
378 }
379 }
380
381 if (found) {
382 continue;
383 }
384
385 DisplayConfig *config = new DisplayConfig(compatMode->vrefresh,
386 compatMode->hdisplay,
387 compatMode->vdisplay,
388 dpiX, dpiY);
389 // add it to the end of configs
390 mDisplayConfigs.push_back(config);
391 }
392 }
393 }
394
395 return true;
396 }
397
initialize()398 bool PhysicalDevice::initialize()
399 {
400 CTRACE();
401 char prop[PROPERTY_VALUE_MAX];
402 char *retptr;
403
404 if (property_get("hwc.fps_divider", prop, "1") > 0) {
405 uint32_t divider = strtoul(prop, &retptr, 10);
406 if (*retptr == '\0' && divider > 1 && divider < 60) {
407 mFpsDivider = divider;
408 ALOGI("%s display, setting HWC FPS divider to %d", mName, mFpsDivider);
409 }
410 }
411
412 if (mType != DEVICE_PRIMARY && mType != DEVICE_EXTERNAL) {
413 ETRACE("invalid device type");
414 return false;
415 }
416
417 // detect display configs
418 bool ret = detectDisplayConfigs();
419 if (ret == false) {
420 DEINIT_AND_RETURN_FALSE("failed to detect display config");
421 }
422
423 if (!mControlFactory) {
424 DEINIT_AND_RETURN_FALSE("failed to provide a controlFactory ");
425 }
426
427 // create blank control
428 mBlankControl = mControlFactory->createBlankControl();
429 if (!mBlankControl) {
430 DEINIT_AND_RETURN_FALSE("failed to create blank control");
431 }
432
433 // create vsync event observer
434 mVsyncObserver = new VsyncEventObserver(*this);
435 if (!mVsyncObserver || !mVsyncObserver->initialize()) {
436 DEINIT_AND_RETURN_FALSE("failed to create vsync observer");
437 }
438
439 mInitialized = true;
440 return true;
441 }
442
deinitialize()443 void PhysicalDevice::deinitialize()
444 {
445 Mutex::Autolock _l(mLock);
446 if (mLayerList) {
447 DEINIT_AND_DELETE_OBJ(mLayerList);
448 }
449
450 DEINIT_AND_DELETE_OBJ(mVsyncObserver);
451
452 // destroy blank control
453 if (mBlankControl) {
454 delete mBlankControl;
455 mBlankControl = 0;
456 }
457
458 if (mControlFactory){
459 delete mControlFactory;
460 mControlFactory = 0;
461 }
462
463 // remove configs
464 removeDisplayConfigs();
465
466 mInitialized = false;
467 }
468
isConnected() const469 bool PhysicalDevice::isConnected() const
470 {
471 RETURN_FALSE_IF_NOT_INIT();
472
473 return mConnected;
474 }
475
getName() const476 const char* PhysicalDevice::getName() const
477 {
478 return mName;
479 }
480
getType() const481 int PhysicalDevice::getType() const
482 {
483 return mType;
484 }
485
onVsync(int64_t timestamp)486 void PhysicalDevice::onVsync(int64_t timestamp)
487 {
488 RETURN_VOID_IF_NOT_INIT();
489 ATRACE("timestamp = %lld", timestamp);
490
491 if (!mConnected)
492 return;
493
494 // notify hwc
495 mHwc.vsync(mType, timestamp);
496 }
497
dump(Dump & d)498 void PhysicalDevice::dump(Dump& d)
499 {
500 Mutex::Autolock _l(mLock);
501 d.append("-------------------------------------------------------------\n");
502 d.append("Device Name: %s (%s)\n", mName,
503 mConnected ? "connected" : "disconnected");
504 d.append("Display configs (count = %d):\n", mDisplayConfigs.size());
505 d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT | DPI_X | DPI_Y \n");
506 d.append("--------+--------------+-------+--------+-------+-------\n");
507 for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
508 DisplayConfig *config = mDisplayConfigs.itemAt(i);
509 if (config) {
510 d.append("%s %2d | %4d | %5d | %4d | %3d | %3d \n",
511 (i == (size_t)mActiveDisplayConfig) ? "* " : " ",
512 i,
513 config->getRefreshRate(),
514 config->getWidth(),
515 config->getHeight(),
516 config->getDpiX(),
517 config->getDpiY());
518 }
519 }
520 // dump layer list
521 if (mLayerList)
522 mLayerList->dump(d);
523 }
524
getFpsDivider()525 uint32_t PhysicalDevice::getFpsDivider()
526 {
527 return mFpsDivider;
528 }
529
setPowerMode(int mode)530 bool PhysicalDevice::setPowerMode(int mode)
531 {
532 // TODO: set proper power modes for HWC 1.4
533 ATRACE("mode = %d", mode);
534
535 bool ret;
536 int arg = mode;
537
538 Drm *drm = Hwcomposer::getInstance().getDrm();
539 ret = drm->writeIoctl(DRM_PSB_PM_SET, &arg, sizeof(arg));
540 if (ret == false) {
541 ETRACE("psb power mode set fail");
542 return false;
543 }
544
545 return true;
546 }
547
getActiveConfig()548 int PhysicalDevice::getActiveConfig()
549 {
550 return mActiveDisplayConfig;
551 }
552
setActiveConfig(int index)553 bool PhysicalDevice::setActiveConfig(int index)
554 {
555 // TODO: for now only implement in external
556 if (index == 0)
557 return true;
558 return false;
559 }
560
561 } // namespace intel
562 } // namespace android
563