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