Home | History | Annotate | Download | only in libhwcomposer
      1 /*
      2  *  Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *     * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above
     10  *       copyright notice, this list of conditions and the following
     11  *       disclaimer in the documentation and/or other materials provided
     12  *       with the distribution.
     13  *     * Neither the name of The Linux Foundation nor the names of its
     14  *       contributors may be used to endorse or promote products derived
     15  *       from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <hwc_qclient.h>
     31 #include <IQService.h>
     32 #include <hwc_utils.h>
     33 #include <mdp_version.h>
     34 #include <hwc_mdpcomp.h>
     35 #include <hwc_virtual.h>
     36 #include <overlay.h>
     37 #include <display_config.h>
     38 
     39 #define QCLIENT_DEBUG 0
     40 
     41 using namespace android;
     42 using namespace qService;
     43 using namespace qhwc;
     44 using namespace overlay;
     45 using namespace qdutils;
     46 
     47 namespace qClient {
     48 
     49 // ----------------------------------------------------------------------------
     50 QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
     51         mMPDeathNotifier(new MPDeathNotifier(ctx))
     52 {
     53     ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
     54 }
     55 
     56 QClient::~QClient()
     57 {
     58     ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
     59 }
     60 
     61 static void securing(hwc_context_t *ctx, uint32_t startEnd) {
     62     //The only way to make this class in this process subscribe to media
     63     //player's death.
     64     IMediaDeathNotifier::getMediaPlayerService();
     65 
     66     ctx->mDrawLock.lock();
     67     ctx->mSecuring = startEnd;
     68     //We're done securing
     69     if(startEnd == IQService::END)
     70         ctx->mSecureMode = true;
     71     ctx->mDrawLock.unlock();
     72 
     73     if(ctx->proc)
     74         ctx->proc->invalidate(ctx->proc);
     75 }
     76 
     77 static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
     78     ctx->mDrawLock.lock();
     79     ctx->mSecuring = startEnd;
     80     //We're done unsecuring
     81     if(startEnd == IQService::END)
     82         ctx->mSecureMode = false;
     83     ctx->mDrawLock.unlock();
     84 
     85     if(ctx->proc)
     86         ctx->proc->invalidate(ctx->proc);
     87 }
     88 
     89 void QClient::MPDeathNotifier::died() {
     90     mHwcContext->mDrawLock.lock();
     91     ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
     92     mHwcContext->mSecuring = false;
     93     mHwcContext->mSecureMode = false;
     94     mHwcContext->mDrawLock.unlock();
     95     if(mHwcContext->proc)
     96         mHwcContext->proc->invalidate(mHwcContext->proc);
     97 }
     98 
     99 static android::status_t screenRefresh(hwc_context_t *ctx) {
    100     status_t result = NO_INIT;
    101     if(ctx->proc) {
    102         ctx->proc->invalidate(ctx->proc);
    103         result = NO_ERROR;
    104     }
    105     return result;
    106 }
    107 
    108 static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
    109     ctx->mExtOrientation = orientation;
    110 }
    111 
    112 static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
    113     int connected;
    114     connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
    115     outParcel->writeInt32(connected);
    116 }
    117 
    118 static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
    119         Parcel* outParcel) {
    120     int dpy = inParcel->readInt32();
    121     outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
    122     if (ctx->dpyAttr[dpy].customFBSize) {
    123         outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
    124         outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
    125     } else {
    126         outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
    127         outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
    128     }
    129     outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
    130     outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
    131     //XXX: Need to check what to return for HDMI
    132     outParcel->writeInt32(ctx->mMDP.panel);
    133 }
    134 static void setHSIC(const Parcel* inParcel) {
    135     int dpy = inParcel->readInt32();
    136     ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
    137     HSICData_t hsic_data;
    138     hsic_data.hue = inParcel->readInt32();
    139     hsic_data.saturation = inParcel->readFloat();
    140     hsic_data.intensity = inParcel->readInt32();
    141     hsic_data.contrast = inParcel->readFloat();
    142     //XXX: Actually set the HSIC data through ABL lib
    143 }
    144 
    145 
    146 static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
    147     ctx->mBufferMirrorMode = enable;
    148 }
    149 
    150 static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
    151                                 Parcel* outParcel) {
    152     // Get the info only if the dpy is valid
    153     if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
    154         Locker::Autolock _sl(ctx->mDrawLock);
    155         if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
    156             // Return the destRect on external, if external orienation
    157             // is enabled
    158             outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
    159             outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
    160             outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
    161             outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
    162         } else {
    163             outParcel->writeInt32(ctx->mViewFrame[dpy].left);
    164             outParcel->writeInt32(ctx->mViewFrame[dpy].top);
    165             outParcel->writeInt32(ctx->mViewFrame[dpy].right);
    166             outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
    167         }
    168         return NO_ERROR;
    169     } else {
    170         ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
    171         return BAD_VALUE;
    172     }
    173 }
    174 
    175 // USed for setting the secondary(hdmi/wfd) status
    176 static void setSecondaryDisplayStatus(hwc_context_t *ctx,
    177                                       const Parcel* inParcel) {
    178     uint32_t dpy = inParcel->readInt32();
    179     uint32_t status = inParcel->readInt32();
    180     ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__,
    181                                         dpy, getExternalDisplayState(status));
    182 
    183     if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
    184         if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) {
    185             ctx->mWfdSyncLock.lock();
    186             ctx->mWfdSyncLock.signal();
    187             ctx->mWfdSyncLock.unlock();
    188         } else if(status == qdutils::EXTERNAL_PAUSE) {
    189             handle_pause(ctx, dpy);
    190         } else if(status == qdutils::EXTERNAL_RESUME) {
    191             handle_resume(ctx, dpy);
    192         }
    193     } else {
    194         ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy);
    195         return;
    196     }
    197 }
    198 
    199 
    200 static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
    201     int dpy = inParcel->readInt32();
    202     if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
    203         Locker::Autolock _sl(ctx->mDrawLock);
    204         ctx->mViewFrame[dpy].left   = inParcel->readInt32();
    205         ctx->mViewFrame[dpy].top    = inParcel->readInt32();
    206         ctx->mViewFrame[dpy].right  = inParcel->readInt32();
    207         ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
    208         ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
    209             __FUNCTION__, dpy,
    210             ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
    211             ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
    212         return NO_ERROR;
    213     } else {
    214         ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
    215         return BAD_VALUE;
    216     }
    217 }
    218 
    219 static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
    220     int debug_type = inParcel->readInt32();
    221     bool enable = !!inParcel->readInt32();
    222     ALOGD("%s: debug_type: %d enable:%d",
    223             __FUNCTION__, debug_type, enable);
    224     Locker::Autolock _sl(ctx->mDrawLock);
    225     switch (debug_type) {
    226         //break is ignored for DEBUG_ALL to toggle all of them at once
    227         case IQService::DEBUG_ALL:
    228         case IQService::DEBUG_MDPCOMP:
    229             qhwc::MDPComp::dynamicDebug(enable);
    230             if (debug_type != IQService::DEBUG_ALL)
    231                 break;
    232         case IQService::DEBUG_VSYNC:
    233             ctx->vstate.debug = enable;
    234             if (debug_type != IQService::DEBUG_ALL)
    235                 break;
    236         case IQService::DEBUG_VD:
    237             HWCVirtualVDS::dynamicDebug(enable);
    238             if (debug_type != IQService::DEBUG_ALL)
    239                 break;
    240         case IQService::DEBUG_PIPE_LIFECYCLE:
    241             Overlay::debugPipeLifecycle(enable);
    242             if (debug_type != IQService::DEBUG_ALL)
    243                 break;
    244     }
    245 }
    246 
    247 static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
    248     uint32_t timeout = (uint32_t)inParcel->readInt32();
    249     ALOGD("%s :%u ms", __FUNCTION__, timeout);
    250     Locker::Autolock _sl(ctx->mDrawLock);
    251     MDPComp::setIdleTimeout(timeout);
    252 }
    253 
    254 static void setMaxPipesPerMixer(hwc_context_t* ctx, const Parcel* inParcel) {
    255     uint32_t value = (uint32_t)inParcel->readInt32();
    256     ALOGD("%s : setting MaxPipesPerMixer: %d ", __FUNCTION__, value);
    257     Locker::Autolock _sl(ctx->mDrawLock);
    258     MDPComp::setMaxPipesPerMixer(value);
    259 }
    260 
    261 static void toggleBWC(hwc_context_t* ctx, const Parcel* inParcel) {
    262     uint32_t enable = (uint32_t)inParcel->readInt32();
    263     if(MDPVersion::getInstance().supportsBWC()) {
    264         Locker::Autolock _sl(ctx->mDrawLock);
    265         ctx->mBWCEnabled = (bool) enable;
    266         ALOGI("%s: Set BWC to %d", __FUNCTION__, enable);
    267     } else {
    268         ALOGI("%s: Target doesn't support BWC", __FUNCTION__);
    269     }
    270 }
    271 
    272 static void configureDynRefreshRate(hwc_context_t* ctx,
    273                                     const Parcel* inParcel) {
    274     uint32_t op = (uint32_t)inParcel->readInt32();
    275     uint32_t refresh_rate = (uint32_t)inParcel->readInt32();
    276     MDPVersion& mdpHw = MDPVersion::getInstance();
    277     uint32_t dpy = HWC_DISPLAY_PRIMARY;
    278 
    279     if(mdpHw.isDynFpsSupported()) {
    280         Locker::Autolock _sl(ctx->mDrawLock);
    281 
    282         switch (op) {
    283         case DISABLE_METADATA_DYN_REFRESH_RATE:
    284             ctx->mUseMetaDataRefreshRate = false;
    285             setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
    286             break;
    287         case ENABLE_METADATA_DYN_REFRESH_RATE:
    288             ctx->mUseMetaDataRefreshRate = true;
    289             setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
    290             break;
    291         case SET_BINDER_DYN_REFRESH_RATE:
    292             if(ctx->mUseMetaDataRefreshRate)
    293                 ALOGW("%s: Ignoring binder request to change refresh-rate",
    294                       __FUNCTION__);
    295             else {
    296                 uint32_t rate = roundOff(refresh_rate);
    297                 if((rate >= mdpHw.getMinFpsSupported() &&
    298                     rate <= mdpHw.getMaxFpsSupported())) {
    299                     setRefreshRate(ctx, dpy, rate);
    300                 } else {
    301                     ALOGE("%s: Requested refresh-rate should be between \
    302                           (%d) and (%d). Given (%d)", __FUNCTION__,
    303                           mdpHw.getMinFpsSupported(),
    304                           mdpHw.getMaxFpsSupported(), rate);
    305                 }
    306             }
    307             break;
    308         default:
    309             ALOGE("%s: Invalid op %d",__FUNCTION__,op);
    310         }
    311     }
    312 }
    313 
    314 static status_t setPartialUpdatePref(hwc_context_t *ctx, uint32_t enable) {
    315     ALOGD("%s: enable: %d", __FUNCTION__, enable);
    316     if(qhwc::MDPComp::setPartialUpdatePref(ctx, (bool)enable) < 0)
    317         return NO_INIT;
    318     return NO_ERROR;
    319 }
    320 
    321 static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
    322     ALOGD("%s: toggle update: %d", __FUNCTION__, on);
    323     if (on == 0) {
    324         ctx->mDrawLock.lock();
    325         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true;
    326         ctx->mOverlay->configBegin();
    327         ctx->mOverlay->configDone();
    328         ctx->mRotMgr->clear();
    329         if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) {
    330             ALOGE("%s: Display commit failed", __FUNCTION__);
    331         }
    332         ctx->mDrawLock.unlock();
    333     } else {
    334         ctx->mDrawLock.lock();
    335         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false;
    336         ctx->mDrawLock.unlock();
    337         ctx->proc->invalidate(ctx->proc);
    338     }
    339 }
    340 
    341 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
    342         Parcel* outParcel) {
    343     status_t ret = NO_ERROR;
    344 
    345     switch(command) {
    346         case IQService::SECURING:
    347             securing(mHwcContext, inParcel->readInt32());
    348             break;
    349         case IQService::UNSECURING:
    350             unsecuring(mHwcContext, inParcel->readInt32());
    351             break;
    352         case IQService::SCREEN_REFRESH:
    353             return screenRefresh(mHwcContext);
    354             break;
    355         case IQService::EXTERNAL_ORIENTATION:
    356             setExtOrientation(mHwcContext, inParcel->readInt32());
    357             break;
    358         case IQService::BUFFER_MIRRORMODE:
    359             setBufferMirrorMode(mHwcContext, inParcel->readInt32());
    360             break;
    361         case IQService::GET_DISPLAY_VISIBLE_REGION:
    362             ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
    363                                     outParcel);
    364             break;
    365         case IQService::CHECK_EXTERNAL_STATUS:
    366             isExternalConnected(mHwcContext, outParcel);
    367             break;
    368         case IQService::GET_DISPLAY_ATTRIBUTES:
    369             getDisplayAttributes(mHwcContext, inParcel, outParcel);
    370             break;
    371         case IQService::SET_HSIC_DATA:
    372             setHSIC(inParcel);
    373             break;
    374         case IQService::SET_SECONDARY_DISPLAY_STATUS:
    375             setSecondaryDisplayStatus(mHwcContext, inParcel);
    376             break;
    377         case IQService::SET_VIEW_FRAME:
    378             setViewFrame(mHwcContext, inParcel);
    379             break;
    380         case IQService::DYNAMIC_DEBUG:
    381             toggleDynamicDebug(mHwcContext, inParcel);
    382             break;
    383         case IQService::SET_IDLE_TIMEOUT:
    384             setIdleTimeout(mHwcContext, inParcel);
    385             break;
    386         case IQService::SET_MAX_PIPES_PER_MIXER:
    387             setMaxPipesPerMixer(mHwcContext, inParcel);
    388             break;
    389         case IQService::SET_PARTIAL_UPDATE:
    390             ret = setPartialUpdatePref(mHwcContext, inParcel->readInt32());
    391             break;
    392         case IQService::TOGGLE_BWC:
    393             toggleBWC(mHwcContext, inParcel);
    394             break;
    395         case IQService::CONFIGURE_DYN_REFRESH_RATE:
    396             configureDynRefreshRate(mHwcContext, inParcel);
    397             break;
    398         case IQService::TOGGLE_SCREEN_UPDATE:
    399             toggleScreenUpdate(mHwcContext, inParcel->readInt32());
    400             break;
    401         default:
    402             ret = NO_ERROR;
    403     }
    404     return ret;
    405 }
    406 
    407 }
    408