Home | History | Annotate | Download | only in devices
      1 /*
      2 // Copyright(c)2014 IntelCorporation
      3 //
      4 // LicensedundertheApacheLicense,Version2.0(the"License");
      5 // youmaynotusethisfileexceptincompliancewiththeLicense.
      6 // YoumayobtainacopyoftheLicenseat
      7 //
      8 // http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software
     11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS,
     12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
     13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand
     14 // limitationsundertheLicense.
     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 
     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 
     53 PhysicalDevice::~PhysicalDevice()
     54 {
     55     WARN_IF_NOT_DEINIT();
     56 }
     57 
     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 
     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 
     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 
    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 
    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 
    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 
    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>
    176 static inline T min(T a, T b) {
    177     return a<b ? a : b;
    178 }
    179 
    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 
    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 
    263 bool PhysicalDevice::compositionComplete()
    264 {
    265     CTRACE();
    266     // do nothing by default
    267     return true;
    268 }
    269 
    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 
    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 
    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 
    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 
    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 
    442 bool PhysicalDevice::isConnected() const
    443 {
    444     RETURN_FALSE_IF_NOT_INIT();
    445 
    446     return mConnected;
    447 }
    448 
    449 const char* PhysicalDevice::getName() const
    450 {
    451     return mName;
    452 }
    453 
    454 int PhysicalDevice::getType() const
    455 {
    456     return mType;
    457 }
    458 
    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 
    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 
    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 
    513 int PhysicalDevice::getActiveConfig()
    514 {
    515     return mActiveDisplayConfig;
    516 }
    517 
    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