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 <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 
     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 
     55 PhysicalDevice::~PhysicalDevice()
     56 {
     57     WARN_IF_NOT_DEINIT();
     58 }
     59 
     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 
     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 
    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 
    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 
    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 
    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 
    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>
    183 static inline T min(T a, T b) {
    184     return a<b ? a : b;
    185 }
    186 
    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 }
    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 
    269 bool PhysicalDevice::compositionComplete()
    270 {
    271     CTRACE();
    272     // do nothing by default
    273     return true;
    274 }
    275 
    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 
    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 
    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 
    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 
    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 
    469 bool PhysicalDevice::isConnected() const
    470 {
    471     RETURN_FALSE_IF_NOT_INIT();
    472 
    473     return mConnected;
    474 }
    475 
    476 const char* PhysicalDevice::getName() const
    477 {
    478     return mName;
    479 }
    480 
    481 int PhysicalDevice::getType() const
    482 {
    483     return mType;
    484 }
    485 
    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 
    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 
    525 uint32_t PhysicalDevice::getFpsDivider()
    526 {
    527     return mFpsDivider;
    528 }
    529 
    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 
    548 int PhysicalDevice::getActiveConfig()
    549 {
    550     return mActiveDisplayConfig;
    551 }
    552 
    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