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