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