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