• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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