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
129 /* Sync the arguments of Frame Buffer Target layer updated in SurfaceFlinger. */
130 mLayerList->updateFBT(display);
131
132 return context->commitContents(display, mLayerList);
133 }
134
vsyncControl(bool enabled)135 bool PhysicalDevice::vsyncControl(bool enabled)
136 {
137 RETURN_FALSE_IF_NOT_INIT();
138
139 ALOGTRACE("disp = %d, enabled = %d", mDisp, enabled);
140 return mVsyncObserver->control(enabled);
141 }
142
blank(bool blank)143 bool PhysicalDevice::blank(bool blank)
144 {
145 RETURN_FALSE_IF_NOT_INIT();
146
147 mBlank = blank;
148 bool ret = mBlankControl->blank(mDisp, blank);
149 if (ret == false) {
150 ELOGTRACE("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 ELOGTRACE("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 ILOGTRACE("device is not connected");
194 return false;
195 }
196
197 if (!configs || !numConfigs || *numConfigs < 1) {
198 ELOGTRACE("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 }
210
getDisplayAttributes(uint32_t config,const uint32_t * attributes,int32_t * values)211 bool PhysicalDevice::getDisplayAttributes(uint32_t config,
212 const uint32_t *attributes,
213 int32_t *values)
214 {
215 RETURN_FALSE_IF_NOT_INIT();
216
217 Mutex::Autolock _l(mLock);
218
219 if (!mConnected) {
220 ILOGTRACE("device is not connected");
221 return false;
222 }
223
224 if (!attributes || !values) {
225 ELOGTRACE("invalid parameters");
226 return false;
227 }
228
229 DisplayConfig *configChosen = mDisplayConfigs.itemAt(config);
230 if (!configChosen) {
231 WLOGTRACE("failed to get display config");
232 return false;
233 }
234
235 int i = 0;
236 while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
237 switch (attributes[i]) {
238 case HWC_DISPLAY_VSYNC_PERIOD:
239 if (configChosen->getRefreshRate()) {
240 values[i] = 1e9 / configChosen->getRefreshRate();
241 } else {
242 ELOGTRACE("refresh rate is 0!!!");
243 values[i] = 0;
244 }
245 break;
246 case HWC_DISPLAY_WIDTH:
247 values[i] = configChosen->getWidth();
248 break;
249 case HWC_DISPLAY_HEIGHT:
250 values[i] = configChosen->getHeight();
251 break;
252 case HWC_DISPLAY_DPI_X:
253 values[i] = configChosen->getDpiX() * 1000.0f;
254 break;
255 case HWC_DISPLAY_DPI_Y:
256 values[i] = configChosen->getDpiY() * 1000.0f;
257 break;
258 default:
259 ELOGTRACE("unknown attribute %d", attributes[i]);
260 break;
261 }
262 i++;
263 }
264
265 return true;
266 }
267
compositionComplete()268 bool PhysicalDevice::compositionComplete()
269 {
270 CTRACE();
271 // do nothing by default
272 return true;
273 }
274
removeDisplayConfigs()275 void PhysicalDevice::removeDisplayConfigs()
276 {
277 for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
278 DisplayConfig *config = mDisplayConfigs.itemAt(i);
279 delete config;
280 }
281
282 mDisplayConfigs.clear();
283 mActiveDisplayConfig = -1;
284 }
285
detectDisplayConfigs()286 bool PhysicalDevice::detectDisplayConfigs()
287 {
288 Mutex::Autolock _l(mLock);
289
290 Drm *drm = Hwcomposer::getInstance().getDrm();
291 if (!drm->detect(mType)) {
292 ELOGTRACE("drm detection on device %d failed ", mType);
293 return false;
294 }
295 return updateDisplayConfigs();
296 }
297
updateDisplayConfigs()298 bool PhysicalDevice::updateDisplayConfigs()
299 {
300 bool ret;
301 Drm *drm = Hwcomposer::getInstance().getDrm();
302
303 // reset display configs
304 removeDisplayConfigs();
305
306 // update device connection status
307 mConnected = drm->isConnected(mType);
308 if (!mConnected) {
309 return true;
310 }
311
312 // reset the number of display configs
313 mDisplayConfigs.setCapacity(1);
314
315 drmModeModeInfo mode;
316 ret = drm->getModeInfo(mType, mode);
317 if (!ret) {
318 ELOGTRACE("failed to get mode info");
319 mConnected = false;
320 return false;
321 }
322
323 uint32_t mmWidth, mmHeight;
324 ret = drm->getPhysicalSize(mType, mmWidth, mmHeight);
325 if (!ret) {
326 ELOGTRACE("failed to get physical size");
327 mConnected = false;
328 return false;
329 }
330
331 float physWidthInch = (float)mmWidth * 0.039370f;
332 float physHeightInch = (float)mmHeight * 0.039370f;
333
334 // use current drm mode, likely it's preferred mode
335 int dpiX = 0;
336 int dpiY = 0;
337 if (physWidthInch && physHeightInch) {
338 dpiX = mode.hdisplay / physWidthInch;
339 dpiY = mode.vdisplay / physHeightInch;
340 } else {
341 ELOGTRACE("invalid physical size, EDID read error?");
342 // don't bail out as it is not a fatal error
343 }
344 // use active fb dimension as config width/height
345 DisplayConfig *config = new DisplayConfig(mode.vrefresh,
346 mode.hdisplay,
347 mode.vdisplay,
348 dpiX, dpiY);
349 // add it to the front of other configs
350 mDisplayConfigs.push_front(config);
351
352 // init the active display config
353 mActiveDisplayConfig = 0;
354
355 drmModeModeInfoPtr modes;
356 drmModeModeInfoPtr compatMode;
357 int modeCount = 0;
358
359 modes = drm->detectAllConfigs(mType, &modeCount);
360
361 for (int i = 0; i < modeCount; i++) {
362 if (modes) {
363 compatMode = &modes[i];
364 if (!compatMode)
365 continue;
366 if (compatMode->hdisplay == mode.hdisplay &&
367 compatMode->vdisplay == mode.vdisplay &&
368 compatMode->vrefresh != mode.vrefresh) {
369
370 bool found = false;
371 for (size_t j = 0; j < mDisplayConfigs.size(); j++) {
372 DisplayConfig *config = mDisplayConfigs.itemAt(j);
373 if (config->getRefreshRate() == (int)compatMode->vrefresh) {
374 found = true;
375 break;
376 }
377 }
378
379 if (found) {
380 continue;
381 }
382
383 DisplayConfig *config = new DisplayConfig(compatMode->vrefresh,
384 compatMode->hdisplay,
385 compatMode->vdisplay,
386 dpiX, dpiY);
387 // add it to the end of configs
388 mDisplayConfigs.push_back(config);
389 }
390 }
391 }
392
393 return true;
394 }
395
initialize()396 bool PhysicalDevice::initialize()
397 {
398 CTRACE();
399
400 if (mType != DEVICE_PRIMARY && mType != DEVICE_EXTERNAL) {
401 ELOGTRACE("invalid device type");
402 return false;
403 }
404
405 // detect display configs
406 bool ret = detectDisplayConfigs();
407 if (ret == false) {
408 DEINIT_AND_RETURN_FALSE("failed to detect display config");
409 }
410
411 // create blank control
412 mBlankControl = createBlankControl();
413 if (!mBlankControl) {
414 DEINIT_AND_RETURN_FALSE("failed to create blank control");
415 }
416
417 // create vsync event observer
418 mVsyncObserver = new VsyncEventObserver(*this);
419 if (!mVsyncObserver || !mVsyncObserver->initialize()) {
420 DEINIT_AND_RETURN_FALSE("failed to create vsync observer");
421 }
422
423 mInitialized = true;
424 return true;
425 }
426
deinitialize()427 void PhysicalDevice::deinitialize()
428 {
429 if (mLayerList) {
430 DEINIT_AND_DELETE_OBJ(mLayerList);
431 }
432
433 DEINIT_AND_DELETE_OBJ(mVsyncObserver);
434
435 // destroy blank control
436 if (mBlankControl) {
437 delete mBlankControl;
438 mBlankControl = 0;
439 }
440
441 // remove configs
442 removeDisplayConfigs();
443
444 mInitialized = false;
445 }
446
isConnected() const447 bool PhysicalDevice::isConnected() const
448 {
449 RETURN_FALSE_IF_NOT_INIT();
450
451 return mConnected;
452 }
453
getName() const454 const char* PhysicalDevice::getName() const
455 {
456 return mName;
457 }
458
getType() const459 int PhysicalDevice::getType() const
460 {
461 return mType;
462 }
463
onVsync(int64_t timestamp)464 void PhysicalDevice::onVsync(int64_t timestamp)
465 {
466 RETURN_VOID_IF_NOT_INIT();
467 ALOGTRACE("timestamp = %lld", timestamp);
468
469 if (!mConnected)
470 return;
471
472 // notify hwc
473 mHwc.vsync(mType, timestamp);
474 }
475
dump(Dump & d)476 void PhysicalDevice::dump(Dump& d)
477 {
478 d.append("-------------------------------------------------------------\n");
479 d.append("Device Name: %s (%s)\n", mName,
480 mConnected ? "connected" : "disconnected");
481 d.append("Display configs (count = %d):\n", mDisplayConfigs.size());
482 d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT | DPI_X | DPI_Y \n");
483 d.append("--------+--------------+-------+--------+-------+-------\n");
484 for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
485 DisplayConfig *config = mDisplayConfigs.itemAt(i);
486 if (config) {
487 d.append("%s %2d | %4d | %5d | %4d | %3d | %3d \n",
488 (i == (size_t)mActiveDisplayConfig) ? "* " : " ",
489 i,
490 config->getRefreshRate(),
491 config->getWidth(),
492 config->getHeight(),
493 config->getDpiX(),
494 config->getDpiY());
495 }
496 }
497 // dump layer list
498 if (mLayerList)
499 mLayerList->dump(d);
500 }
501
setPowerMode(int mode)502 bool PhysicalDevice::setPowerMode(int mode)
503 {
504 // TODO: set proper blanking modes for HWC 1.4 modes
505 switch (mode) {
506 case HWC_POWER_MODE_OFF:
507 case HWC_POWER_MODE_DOZE:
508 return blank(true);
509 case HWC_POWER_MODE_NORMAL:
510 case HWC_POWER_MODE_DOZE_SUSPEND:
511 return blank(false);
512 default:
513 return false;
514 }
515 return false;
516 }
517
getActiveConfig()518 int PhysicalDevice::getActiveConfig()
519 {
520 return mActiveDisplayConfig;
521 }
522
setActiveConfig(int index)523 bool PhysicalDevice::setActiveConfig(int index)
524 {
525 // TODO: for now only implement in external
526 if (index == 0)
527 return true;
528 return false;
529 }
530
531 } // namespace intel
532 } // namespace android
533