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