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     return context->commitContents(display, mLayerList);
    129 }
    130 
    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 
    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 
    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>
    177 static inline T min(T a, T b) {
    178     return a<b ? a : b;
    179 }
    180 
    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 
    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 
    264 bool PhysicalDevice::compositionComplete()
    265 {
    266     CTRACE();
    267     // do nothing by default
    268     return true;
    269 }
    270 
    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 
    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 
    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 
    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 
    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 
    443 bool PhysicalDevice::isConnected() const
    444 {
    445     RETURN_FALSE_IF_NOT_INIT();
    446 
    447     return mConnected;
    448 }
    449 
    450 const char* PhysicalDevice::getName() const
    451 {
    452     return mName;
    453 }
    454 
    455 int PhysicalDevice::getType() const
    456 {
    457     return mType;
    458 }
    459 
    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 
    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 
    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 
    514 int PhysicalDevice::getActiveConfig()
    515 {
    516     return mActiveDisplayConfig;
    517 }
    518 
    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