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 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 
     54 PhysicalDevice::~PhysicalDevice()
     55 {
     56     WARN_IF_NOT_DEINIT();
     57 }
     58 
     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 
     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 
    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 
    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 
    129     /* Sync the arguments of Frame Buffer Target layer updated in SurfaceFlinger. */
    130     mLayerList->updateFBT(display);
    131 
    132     return context->commitContents(display, mLayerList);
    133 }
    134 
    135 bool PhysicalDevice::vsyncControl(bool enabled)
    136 {
    137     RETURN_FALSE_IF_NOT_INIT();
    138 
    139     ALOGTRACE("disp = %d, enabled = %d", mDisp, enabled);
    140     return mVsyncObserver->control(enabled);
    141 }
    142 
    143 bool PhysicalDevice::blank(bool blank)
    144 {
    145     RETURN_FALSE_IF_NOT_INIT();
    146 
    147     mBlank = blank;
    148     bool ret = mBlankControl->blank(mDisp, blank);
    149     if (ret == false) {
    150         ELOGTRACE("failed to blank device");
    151         return false;
    152     }
    153 
    154     return true;
    155 }
    156 
    157 bool PhysicalDevice::getDisplaySize(int *width, int *height)
    158 {
    159     RETURN_FALSE_IF_NOT_INIT();
    160     Mutex::Autolock _l(mLock);
    161     if (!width || !height) {
    162         ELOGTRACE("invalid parameters");
    163         return false;
    164     }
    165 
    166     *width = 0;
    167     *height = 0;
    168     drmModeModeInfo mode;
    169     Drm *drm = Hwcomposer::getInstance().getDrm();
    170     bool ret = drm->getModeInfo(mType, mode);
    171     if (!ret) {
    172         return false;
    173     }
    174 
    175     *width = mode.hdisplay;
    176     *height = mode.vdisplay;
    177     return true;
    178 }
    179 
    180 template <typename T>
    181 static inline T min(T a, T b) {
    182     return a<b ? a : b;
    183 }
    184 
    185 bool PhysicalDevice::getDisplayConfigs(uint32_t *configs,
    186                                          size_t *numConfigs)
    187 {
    188     RETURN_FALSE_IF_NOT_INIT();
    189 
    190     Mutex::Autolock _l(mLock);
    191 
    192     if (!mConnected) {
    193         ILOGTRACE("device is not connected");
    194         return false;
    195     }
    196 
    197     if (!configs || !numConfigs || *numConfigs < 1) {
    198         ELOGTRACE("invalid parameters");
    199         return false;
    200     }
    201 
    202     // fill in all config handles
    203     *numConfigs = min(*numConfigs, mDisplayConfigs.size());
    204     for (int i = 0; i < static_cast<int>(*numConfigs); i++) {
    205         configs[i] = i;
    206     }
    207 
    208     return true;
    209 }
    210 
    211 bool PhysicalDevice::getDisplayAttributes(uint32_t config,
    212         const uint32_t *attributes,
    213         int32_t *values)
    214 {
    215     RETURN_FALSE_IF_NOT_INIT();
    216 
    217     Mutex::Autolock _l(mLock);
    218 
    219     if (!mConnected) {
    220         ILOGTRACE("device is not connected");
    221         return false;
    222     }
    223 
    224     if (!attributes || !values) {
    225         ELOGTRACE("invalid parameters");
    226         return false;
    227     }
    228 
    229     DisplayConfig *configChosen = mDisplayConfigs.itemAt(config);
    230     if  (!configChosen) {
    231         WLOGTRACE("failed to get display config");
    232         return false;
    233     }
    234 
    235     int i = 0;
    236     while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
    237         switch (attributes[i]) {
    238         case HWC_DISPLAY_VSYNC_PERIOD:
    239             if (configChosen->getRefreshRate()) {
    240                 values[i] = 1e9 / configChosen->getRefreshRate();
    241             } else {
    242                 ELOGTRACE("refresh rate is 0!!!");
    243                 values[i] = 0;
    244             }
    245             break;
    246         case HWC_DISPLAY_WIDTH:
    247             values[i] = configChosen->getWidth();
    248             break;
    249         case HWC_DISPLAY_HEIGHT:
    250             values[i] = configChosen->getHeight();
    251             break;
    252         case HWC_DISPLAY_DPI_X:
    253             values[i] = configChosen->getDpiX() * 1000.0f;
    254             break;
    255         case HWC_DISPLAY_DPI_Y:
    256             values[i] = configChosen->getDpiY() * 1000.0f;
    257             break;
    258         default:
    259             ELOGTRACE("unknown attribute %d", attributes[i]);
    260             break;
    261         }
    262         i++;
    263     }
    264 
    265     return true;
    266 }
    267 
    268 bool PhysicalDevice::compositionComplete()
    269 {
    270     CTRACE();
    271     // do nothing by default
    272     return true;
    273 }
    274 
    275 void PhysicalDevice::removeDisplayConfigs()
    276 {
    277     for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
    278         DisplayConfig *config = mDisplayConfigs.itemAt(i);
    279         delete config;
    280     }
    281 
    282     mDisplayConfigs.clear();
    283     mActiveDisplayConfig = -1;
    284 }
    285 
    286 bool PhysicalDevice::detectDisplayConfigs()
    287 {
    288     Mutex::Autolock _l(mLock);
    289 
    290     Drm *drm = Hwcomposer::getInstance().getDrm();
    291     if (!drm->detect(mType)) {
    292         ELOGTRACE("drm detection on device %d failed ", mType);
    293         return false;
    294     }
    295     return updateDisplayConfigs();
    296 }
    297 
    298 bool PhysicalDevice::updateDisplayConfigs()
    299 {
    300     bool ret;
    301     Drm *drm = Hwcomposer::getInstance().getDrm();
    302 
    303     // reset display configs
    304     removeDisplayConfigs();
    305 
    306     // update device connection status
    307     mConnected = drm->isConnected(mType);
    308     if (!mConnected) {
    309         return true;
    310     }
    311 
    312     // reset the number of display configs
    313     mDisplayConfigs.setCapacity(1);
    314 
    315     drmModeModeInfo mode;
    316     ret = drm->getModeInfo(mType, mode);
    317     if (!ret) {
    318         ELOGTRACE("failed to get mode info");
    319         mConnected = false;
    320         return false;
    321     }
    322 
    323     uint32_t mmWidth, mmHeight;
    324     ret = drm->getPhysicalSize(mType, mmWidth, mmHeight);
    325     if (!ret) {
    326         ELOGTRACE("failed to get physical size");
    327         mConnected = false;
    328         return false;
    329     }
    330 
    331     float physWidthInch = (float)mmWidth * 0.039370f;
    332     float physHeightInch = (float)mmHeight * 0.039370f;
    333 
    334     // use current drm mode, likely it's preferred mode
    335     int dpiX = 0;
    336     int dpiY = 0;
    337     if (physWidthInch && physHeightInch) {
    338         dpiX = mode.hdisplay / physWidthInch;
    339         dpiY = mode.vdisplay / physHeightInch;
    340     } else {
    341         ELOGTRACE("invalid physical size, EDID read error?");
    342         // don't bail out as it is not a fatal error
    343     }
    344     // use active fb dimension as config width/height
    345     DisplayConfig *config = new DisplayConfig(mode.vrefresh,
    346                                               mode.hdisplay,
    347                                               mode.vdisplay,
    348                                               dpiX, dpiY);
    349     // add it to the front of other configs
    350     mDisplayConfigs.push_front(config);
    351 
    352     // init the active display config
    353     mActiveDisplayConfig = 0;
    354 
    355     drmModeModeInfoPtr modes;
    356     drmModeModeInfoPtr compatMode;
    357     int modeCount = 0;
    358 
    359     modes = drm->detectAllConfigs(mType, &modeCount);
    360 
    361     for (int i = 0; i < modeCount; i++) {
    362         if (modes) {
    363             compatMode = &modes[i];
    364             if (!compatMode)
    365                 continue;
    366             if (compatMode->hdisplay == mode.hdisplay &&
    367                 compatMode->vdisplay == mode.vdisplay &&
    368                 compatMode->vrefresh != mode.vrefresh) {
    369 
    370                 bool found = false;
    371                 for (size_t j = 0; j < mDisplayConfigs.size(); j++) {
    372                      DisplayConfig *config = mDisplayConfigs.itemAt(j);
    373                      if (config->getRefreshRate() == (int)compatMode->vrefresh) {
    374                          found = true;
    375                          break;
    376                      }
    377                 }
    378 
    379                 if (found) {
    380                     continue;
    381                 }
    382 
    383                 DisplayConfig *config = new DisplayConfig(compatMode->vrefresh,
    384                                               compatMode->hdisplay,
    385                                               compatMode->vdisplay,
    386                                               dpiX, dpiY);
    387                 // add it to the end of configs
    388                 mDisplayConfigs.push_back(config);
    389             }
    390         }
    391     }
    392 
    393     return true;
    394 }
    395 
    396 bool PhysicalDevice::initialize()
    397 {
    398     CTRACE();
    399 
    400     if (mType != DEVICE_PRIMARY && mType != DEVICE_EXTERNAL) {
    401         ELOGTRACE("invalid device type");
    402         return false;
    403     }
    404 
    405     // detect display configs
    406     bool ret = detectDisplayConfigs();
    407     if (ret == false) {
    408         DEINIT_AND_RETURN_FALSE("failed to detect display config");
    409     }
    410 
    411     // create blank control
    412     mBlankControl = createBlankControl();
    413     if (!mBlankControl) {
    414         DEINIT_AND_RETURN_FALSE("failed to create blank control");
    415     }
    416 
    417     // create vsync event observer
    418     mVsyncObserver = new VsyncEventObserver(*this);
    419     if (!mVsyncObserver || !mVsyncObserver->initialize()) {
    420         DEINIT_AND_RETURN_FALSE("failed to create vsync observer");
    421     }
    422 
    423     mInitialized = true;
    424     return true;
    425 }
    426 
    427 void PhysicalDevice::deinitialize()
    428 {
    429     if (mLayerList) {
    430         DEINIT_AND_DELETE_OBJ(mLayerList);
    431     }
    432 
    433     DEINIT_AND_DELETE_OBJ(mVsyncObserver);
    434 
    435     // destroy blank control
    436     if (mBlankControl) {
    437         delete mBlankControl;
    438         mBlankControl = 0;
    439     }
    440 
    441     // remove configs
    442     removeDisplayConfigs();
    443 
    444     mInitialized = false;
    445 }
    446 
    447 bool PhysicalDevice::isConnected() const
    448 {
    449     RETURN_FALSE_IF_NOT_INIT();
    450 
    451     return mConnected;
    452 }
    453 
    454 const char* PhysicalDevice::getName() const
    455 {
    456     return mName;
    457 }
    458 
    459 int PhysicalDevice::getType() const
    460 {
    461     return mType;
    462 }
    463 
    464 void PhysicalDevice::onVsync(int64_t timestamp)
    465 {
    466     RETURN_VOID_IF_NOT_INIT();
    467     ALOGTRACE("timestamp = %lld", timestamp);
    468 
    469     if (!mConnected)
    470         return;
    471 
    472     // notify hwc
    473     mHwc.vsync(mType, timestamp);
    474 }
    475 
    476 void PhysicalDevice::dump(Dump& d)
    477 {
    478     d.append("-------------------------------------------------------------\n");
    479     d.append("Device Name: %s (%s)\n", mName,
    480             mConnected ? "connected" : "disconnected");
    481     d.append("Display configs (count = %d):\n", mDisplayConfigs.size());
    482     d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT | DPI_X | DPI_Y \n");
    483     d.append("--------+--------------+-------+--------+-------+-------\n");
    484     for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
    485         DisplayConfig *config = mDisplayConfigs.itemAt(i);
    486         if (config) {
    487             d.append("%s %2d   |     %4d     | %5d |  %4d  |  %3d  |  %3d  \n",
    488                      (i == (size_t)mActiveDisplayConfig) ? "* " : "  ",
    489                      i,
    490                      config->getRefreshRate(),
    491                      config->getWidth(),
    492                      config->getHeight(),
    493                      config->getDpiX(),
    494                      config->getDpiY());
    495         }
    496     }
    497     // dump layer list
    498     if (mLayerList)
    499         mLayerList->dump(d);
    500 }
    501 
    502 bool PhysicalDevice::setPowerMode(int mode)
    503 {
    504     // TODO: set proper blanking modes for HWC 1.4 modes
    505     switch (mode) {
    506         case HWC_POWER_MODE_OFF:
    507         case HWC_POWER_MODE_DOZE:
    508             return blank(true);
    509         case HWC_POWER_MODE_NORMAL:
    510         case HWC_POWER_MODE_DOZE_SUSPEND:
    511             return blank(false);
    512         default:
    513             return false;
    514     }
    515     return false;
    516 }
    517 
    518 int PhysicalDevice::getActiveConfig()
    519 {
    520     return mActiveDisplayConfig;
    521 }
    522 
    523 bool PhysicalDevice::setActiveConfig(int index)
    524 {
    525     // TODO: for now only implement in external
    526     if (index == 0)
    527         return true;
    528     return false;
    529 }
    530 
    531 } // namespace intel
    532 } // namespace android
    533