Merge "gralloc: use new API for Ion handles"
diff --git a/common.mk b/common.mk
index cfe84be..47c455f 100644
--- a/common.mk
+++ b/common.mk
@@ -31,12 +31,12 @@
 endif
 
 ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
-        mpq8092 msm_bronze), true)
+        mpq8092 msm_bronze msm8916), true)
     common_flags += -DVENUS_COLOR_FORMAT
     common_flags += -DMDSS_TARGET
 endif
 
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze), true)
+ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
     #XXX: Replace with check from MDP when available
     common_flags += -DVPU_TARGET
 endif
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 29c5aa5..f6d244a 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -108,7 +108,8 @@
     HAL_PIXEL_FORMAT_BGRX_8888              = 0x112,
     HAL_PIXEL_FORMAT_NV21_ZSL               = 0x113,
     HAL_PIXEL_FORMAT_INTERLACE              = 0x180,
-
+    //v4l2_fourcc('Y', 'U', 'Y', 'L'). 24 bpp YUYV 4:2:2 10 bit per component
+    HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT      = 0x4C595559,
 };
 
 /* possible formats for 3D content*/
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 4ef4286..7b2092d 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -25,7 +25,7 @@
                                  hwc_dump_layers.cpp \
                                  hwc_ad.cpp
 
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze), true)
+ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
     LOCAL_SRC_FILES += hwc_vpuclient.cpp
 endif
 
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 02b9317..22e69f3 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -138,15 +138,6 @@
     ctx->layerProp[dpy] = new LayerProp[numAppLayers];
 }
 
-static void handleGeomChange(hwc_context_t *ctx, int dpy,
-        hwc_display_contents_1_t *list) {
-    /* No point to calling overlay_set on MDP3 */
-    if(list->flags & HWC_GEOMETRY_CHANGED &&
-            ctx->mMDP.version >= qdutils::MDP_V4_0) {
-        ctx->mOverlay->forceSet(dpy);
-    }
-}
-
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     ATRACE_CALL();
@@ -155,7 +146,6 @@
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
-        handleGeomChange(ctx, dpy, list);
         setListStats(ctx, list, dpy);
 #ifdef VPU_TARGET
         ctx->mVPUClient->prepare(ctx, list);
@@ -182,7 +172,6 @@
             ctx->dpyAttr[dpy].isActive &&
             ctx->dpyAttr[dpy].connected) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
-        handleGeomChange(ctx, dpy, list);
         if(!ctx->dpyAttr[dpy].isPause) {
             ctx->dpyAttr[dpy].isConfiguring = false;
             setListStats(ctx, list, dpy);
@@ -190,21 +179,15 @@
                 const int fbZ = 0;
                 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
             }
-
-            if(ctx->listStats[dpy].isDisplayAnimating) {
-                // Mark all app layers as HWC_OVERLAY for external during
-                // animation, so that SF doesnt draw it on FB
-                for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
-                    hwc_layer_1_t *layer = &list->hwLayers[i];
-                    layer->compositionType = HWC_OVERLAY;
-                }
-            }
         } else {
-            // External Display is in Pause state.
-            // ToDo:
-            // Mark all application layers as OVERLAY so that
-            // GPU will not compose. This is done for power
-            // optimization
+            /* External Display is in Pause state.
+             * Mark all application layers as OVERLAY so that
+             * GPU will not compose.
+             */
+            for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+                hwc_layer_1_t *layer = &list->hwLayers[i];
+                layer->compositionType = HWC_OVERLAY;
+            }
         }
     }
     return 0;
@@ -221,7 +204,6 @@
             ctx->dpyAttr[dpy].isActive &&
             ctx->dpyAttr[dpy].connected) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
-        handleGeomChange(ctx, dpy, list);
         if(!ctx->dpyAttr[dpy].isPause) {
             ctx->dpyAttr[dpy].isConfiguring = false;
             setListStats(ctx, list, dpy);
@@ -229,21 +211,15 @@
                 const int fbZ = 0;
                 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
             }
-
-            if(ctx->listStats[dpy].isDisplayAnimating) {
-                // Mark all app layers as HWC_OVERLAY for virtual during
-                // animation, so that SF doesnt draw it on FB
-                for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
-                    hwc_layer_1_t *layer = &list->hwLayers[i];
-                    layer->compositionType = HWC_OVERLAY;
-                }
-            }
         } else {
-            // Virtual Display is in Pause state.
-            // ToDo:
-            // Mark all application layers as OVERLAY so that
-            // GPU will not compose. This is done for power
-            // optimization
+            /* Virtual Display is in Pause state.
+             * Mark all application layers as OVERLAY so that
+             * GPU will not compose.
+             */
+            for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+                hwc_layer_1_t *layer = &list->hwLayers[i];
+                layer->compositionType = HWC_OVERLAY;
+            }
         }
     }
     return 0;
@@ -315,8 +291,6 @@
             if(dpy == HWC_DISPLAY_PRIMARY) {
                 Locker::Autolock _l(ctx->mDrawLock);
                 // store the primary display orientation
-                // will be used in hwc_video::configure to disable
-                // rotation animation on external display
                 ctx->deviceOrientation = enable;
             }
             break;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 0ad1b14..4695a4f 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -316,9 +316,10 @@
         copybit_device_t *copybit = getCopyBitDevice();
         // Async mode
         copybit->flush_get_fence(copybit, fd);
-        if(mRelFd[0] >=0 && ctx->mMDP.version == qdutils::MDP_V3_0_4) {
-            close(mRelFd[0]);
-            mRelFd[0] = -1;
+        if(mRelFd[mCurRenderBufferIndex] >=0 &&
+           ctx->mMDP.version == qdutils::MDP_V3_0_4) {
+            close(mRelFd[mCurRenderBufferIndex]);
+            mRelFd[mCurRenderBufferIndex] = -1;
         }
     }
     return true;
@@ -426,8 +427,7 @@
     float copybitsMinScale =
                        (float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT);
 
-    if((layer->transform == HWC_TRANSFORM_ROT_90) ||
-                           (layer->transform == HWC_TRANSFORM_ROT_270)) {
+    if (layer->transform & HWC_TRANSFORM_ROT_90) {
         //swap screen width and height
         int tmp = screen_w;
         screen_w  = screen_h;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index bb9adbf..0ca5ad9 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -78,13 +78,17 @@
     if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
         mRot = ctx->mRotMgr->getNext();
         if(mRot == NULL) return false;
+        // Composed FB content will have black bars, if the viewFrame of the
+        // external is different from {0, 0, fbWidth, fbHeight}, so intersect
+        // viewFrame with sourceCrop to avoid those black bars
+        sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]);
         //Configure rotator for pre-rotation
         if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
             ALOGE("%s: configRotator Failed!", __FUNCTION__);
             mRot = NULL;
             return false;
         }
-       ctx->mLayerRotMap[mDpy]->add(layer, mRot);
+        ctx->mLayerRotMap[mDpy]->add(layer, mRot);
         info.format = (mRot)->getDstFormat();
         updateSource(orient, info, sourceCrop);
         rotFlags |= ovutils::ROT_PREROTATED;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 431136e..63b4aa5 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -449,7 +449,7 @@
             /* Reset frame ROI when any layer which needs scaling also needs ROI
              * cropping */
             if((res_w != dst_w || res_h != dst_h) &&
-               needsScaling (ctx, layer, mDpy)) {
+                    needsScaling (layer)) {
                 ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
                 memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
                 mCurrentFrame.dropCount = 0;
@@ -530,12 +530,6 @@
         return false;
     }
 
-    if(ctx->listStats[mDpy].needsAlphaScale
-       && ctx->mMDP.version < qdutils::MDSS_V5) {
-        ALOGD_IF(isDebug(), "%s: frame needs alpha downscaling",__FUNCTION__);
-        return false;
-    }
-
     for(int i = 0; i < numAppLayers; ++i) {
         hwc_layer_1_t* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -568,6 +562,12 @@
     } else if(partialMDPComp(ctx, list)) {
         ret = true;
     }
+
+    if(!hwLimitationsCheck(ctx, list)) {
+        ALOGD_IF(isDebug(), "%s: HW limitations",__FUNCTION__);
+        return false;
+    }
+
     return ret;
 }
 
@@ -593,7 +593,7 @@
         //pipe and error is reported.
         if(qdutils::MDPVersion::getInstance().is8x26() &&
                                 mDpy >= HWC_DISPLAY_EXTERNAL &&
-                                qhwc::needsScaling(ctx, layer, mDpy))
+                                qhwc::needsScaling(layer))
             return false;
     }
     mCurrentFrame.fbCount = 0;
@@ -604,7 +604,7 @@
         mCurrentFrame.dropCount;
 
     if(sEnable4k2kYUVSplit){
-        modifymdpCountfor4k2k(ctx, list);
+        adjustForSourceSplit(ctx, list);
     }
 
     if(!resourceCheck(ctx, list)) {
@@ -623,15 +623,16 @@
     }
 
     bool ret = false;
-    if(isLoadBasedCompDoable(ctx, list)) {
-        ret = loadBasedCompPreferGPU(ctx, list) ||
+    if(list->flags & HWC_GEOMETRY_CHANGED) { //Try load based first
+        ret =   loadBasedCompPreferGPU(ctx, list) or
+                loadBasedCompPreferMDP(ctx, list) or
+                cacheBasedComp(ctx, list);
+    } else {
+        ret =   cacheBasedComp(ctx, list) or
+                loadBasedCompPreferGPU(ctx, list) or
                 loadBasedCompPreferMDP(ctx, list);
     }
 
-    if(!ret) {
-        ret = cacheBasedComp(ctx, list);
-    }
-
     return ret;
 }
 
@@ -663,7 +664,7 @@
     int mdpCount = mCurrentFrame.mdpCount;
 
     if(sEnable4k2kYUVSplit){
-        modifymdpCountfor4k2k(ctx, list);
+        adjustForSourceSplit(ctx, list);
     }
 
     //Will benefit cases where a video has non-updating background.
@@ -683,6 +684,10 @@
 
 bool MDPComp::loadBasedCompPreferGPU(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
+    if(not isLoadBasedCompDoable(ctx, list)) {
+        return false;
+    }
+
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     mCurrentFrame.reset(numAppLayers);
 
@@ -737,7 +742,7 @@
     mCurrentFrame.mdpCount = mCurrentFrame.layerCount - batchSize;
 
     if(sEnable4k2kYUVSplit){
-        modifymdpCountfor4k2k(ctx, list);
+        adjustForSourceSplit(ctx, list);
     }
 
     if(!resourceCheck(ctx, list)) {
@@ -752,8 +757,13 @@
 
 bool MDPComp::loadBasedCompPreferMDP(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
+    if(not isLoadBasedCompDoable(ctx, list)) {
+        return false;
+    }
+
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-    //TODO get the ib from sysfs node.
+    mCurrentFrame.reset(numAppLayers);
+
     //Full screen is from ib perspective, not actual full screen
     const int bpp = 4;
     double panelRefRate =
@@ -792,7 +802,7 @@
     mCurrentFrame.mdpCount = mCurrentFrame.layerCount - fbBatchSize;
 
     if(sEnable4k2kYUVSplit){
-        modifymdpCountfor4k2k(ctx, list);
+        adjustForSourceSplit(ctx, list);
     }
 
     if(!resourceCheck(ctx, list)) {
@@ -809,8 +819,7 @@
 
 bool MDPComp::isLoadBasedCompDoable(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
-    if(mDpy or isSecurePresent(ctx, mDpy) or
-            not (list->flags & HWC_GEOMETRY_CHANGED)) {
+    if(mDpy or isSecurePresent(ctx, mDpy)) {
         return false;
     }
     return true;
@@ -847,9 +856,7 @@
 
 /* Checks for conditions where YUV layers cannot be bypassed */
 bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
-    bool extAnimBlockFeature = mDpy && ctx->listStats[mDpy].isDisplayAnimating;
-
-    if(isSkipLayer(layer) && !extAnimBlockFeature) {
+    if(isSkipLayer(layer)) {
         ALOGD_IF(isDebug(), "%s: Video marked SKIP dpy %d", __FUNCTION__, mDpy);
         return false;
     }
@@ -915,7 +922,6 @@
         int& maxBatchStart, int& maxBatchEnd,
         int& maxBatchCount) {
     int i = 0;
-    int updatingLayersAbove = 0;//Updating layer count in middle of batch
     int fbZOrder =-1;
     while (i < mCurrentFrame.layerCount) {
         int batchCount = 0;
@@ -923,6 +929,7 @@
         int batchEnd = i;
         int fbZ = batchStart;
         int firstZReverseIndex = -1;
+        int updatingLayersAbove = 0;//Updating layer count in middle of batch
         while(i < mCurrentFrame.layerCount) {
             if(!mCurrentFrame.isFBComposed[i]) {
                 if(!batchCount) {
@@ -1069,15 +1076,6 @@
 void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
         bool secureOnly) {
     int nYuvCount = ctx->listStats[mDpy].yuvCount;
-    if(!nYuvCount && mDpy) {
-        //Reset "No animation on external display" related  parameters.
-        ctx->mPrevCropVideo.left = ctx->mPrevCropVideo.top =
-            ctx->mPrevCropVideo.right = ctx->mPrevCropVideo.bottom = 0;
-        ctx->mPrevDestVideo.left = ctx->mPrevDestVideo.top =
-            ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
-        ctx->mPrevTransformVideo = 0;
-        return;
-     }
     for(int index = 0;index < nYuvCount; index++){
         int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
         hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
@@ -1105,6 +1103,15 @@
 }
 
 bool MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    //Configure framebuffer first if applicable
+    if(mCurrentFrame.fbZ >= 0) {
+        if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
+            ALOGD_IF(isDebug(), "%s configure framebuffer failed",
+                    __FUNCTION__);
+            return false;
+        }
+    }
+
     if(!allocLayerPipes(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
         return false;
@@ -1148,46 +1155,6 @@
     return true;
 }
 
-bool MDPComp::programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
-    if(!allocLayerPipes(ctx, list)) {
-        ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
-        return false;
-    }
-    //If we are in this block, it means we have yuv + rgb layers both
-    int mdpIdx = 0;
-    for (int index = 0; index < mCurrentFrame.layerCount; index++) {
-        if(!mCurrentFrame.isFBComposed[index]) {
-            hwc_layer_1_t* layer = &list->hwLayers[index];
-            int mdpIndex = mCurrentFrame.layerToMDP[index];
-            MdpPipeInfo* cur_pipe =
-                    mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
-            cur_pipe->zOrder = mdpIdx++;
-
-            private_handle_t *hnd = (private_handle_t *)layer->handle;
-            if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
-                if(configure4k2kYuv(ctx, layer,
-                            mCurrentFrame.mdpToLayer[mdpIndex])
-                        != 0 ){
-                    ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
-                            for layer %d",__FUNCTION__, index);
-                    return false;
-                }
-                else{
-                    mdpIdx++;
-                }
-                continue;
-            }
-            if(configure(ctx, layer,
-                        mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
-                ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
-                        layer %d",__FUNCTION__, index);
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
 bool MDPComp::resourceCheck(hwc_context_t *ctx,
         hwc_display_contents_1_t *list) {
     const bool fbUsed = mCurrentFrame.fbCount;
@@ -1262,6 +1229,48 @@
     return true;
 }
 
+bool MDPComp::hwLimitationsCheck(hwc_context_t* ctx,
+        hwc_display_contents_1_t* list) {
+
+    //A-family hw limitation:
+    //If a layer need alpha scaling, MDP can not support.
+    if(ctx->mMDP.version < qdutils::MDSS_V5) {
+        for(int i = 0; i < mCurrentFrame.layerCount; ++i) {
+            if(!mCurrentFrame.isFBComposed[i] &&
+                    isAlphaScaled( &list->hwLayers[i])) {
+                ALOGD_IF(isDebug(), "%s:frame needs alphaScaling",__FUNCTION__);
+                return false;
+            }
+        }
+    }
+
+    // On 8x26 & 8974 hw, we have a limitation of downscaling+blending.
+    //If multiple layers requires downscaling and also they are overlapping
+    //fall back to GPU since MDSS can not handle it.
+    if(qdutils::MDPVersion::getInstance().is8x74v2() ||
+            qdutils::MDPVersion::getInstance().is8x26()) {
+        for(int i = 0; i < mCurrentFrame.layerCount-1; ++i) {
+            hwc_layer_1_t* botLayer = &list->hwLayers[i];
+            if(!mCurrentFrame.isFBComposed[i] &&
+                    isDownscaleRequired(botLayer)) {
+                //if layer-i is marked for MDP and needs downscaling
+                //check if any MDP layer on top of i & overlaps with layer-i
+                for(int j = i+1; j < mCurrentFrame.layerCount; ++j) {
+                    hwc_layer_1_t* topLayer = &list->hwLayers[j];
+                    if(!mCurrentFrame.isFBComposed[j] &&
+                            isDownscaleRequired(topLayer)) {
+                        hwc_rect_t r = getIntersection(botLayer->displayFrame,
+                                topLayer->displayFrame);
+                        if(isValidRect(r))
+                            return false;
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int ret = 0;
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
@@ -1282,6 +1291,22 @@
         return ret;
     }
 
+    // Detect the start of animation and fall back to GPU only once to cache
+    // all the layers in FB and display FB content untill animation completes.
+    if(ctx->listStats[mDpy].isDisplayAnimating) {
+        mCurrentFrame.needsRedraw = false;
+        if(ctx->mAnimationState[mDpy] == ANIMATION_STOPPED) {
+            mCurrentFrame.needsRedraw = true;
+            ctx->mAnimationState[mDpy] = ANIMATION_STARTED;
+        }
+        setMDPCompLayerFlags(ctx, list);
+        mCachedFrame.updateCounts(mCurrentFrame);
+        ret = -1;
+        return ret;
+    } else {
+        ctx->mAnimationState[mDpy] = ANIMATION_STOPPED;
+    }
+
     //Hard conditions, if not met, cannot do MDP comp
     if(!isFrameDoable(ctx)) {
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
@@ -1302,35 +1327,11 @@
     //Check whether layers marked for MDP Composition is actually doable.
     if(isFullFrameDoable(ctx, list)) {
         mCurrentFrame.map();
-        //Configure framebuffer first if applicable
-        if(mCurrentFrame.fbZ >= 0) {
-            //If 4k2k Yuv layer split is possible,  and if
-            //fbz is above 4k2k layer, increment fb zorder by 1
-            //as we split 4k2k layer and increment zorder for right half
-            //of the layer
-            if(sEnable4k2kYUVSplit){
-                int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
-                for(int index = 0; index < n4k2kYuvCount; index++){
-                    int n4k2kYuvIndex =
-                            ctx->listStats[mDpy].yuv4k2kIndices[index];
-                    if(mCurrentFrame.fbZ > n4k2kYuvIndex){
-                        mCurrentFrame.fbZ += 1;
-                    }
-                }
-            }
-            if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
-                        mCurrentFrame.fbZ)) {
-                ALOGE("%s configure framebuffer failed", __func__);
-                reset(numLayers, list);
-                ctx->mOverlay->clear(mDpy);
-                ret = -1;
-                goto exit;
-            }
-        }
         //Acquire and Program MDP pipes
         if(!programMDP(ctx, list)) {
             reset(numLayers, list);
             ctx->mOverlay->clear(mDpy);
+            ctx->mLayerRotMap[mDpy]->clear();
             ret = -1;
             goto exit;
         } else { //Success
@@ -1349,29 +1350,20 @@
         //all the RGB layers compose in FB
         //Destination over
 
-        if(sEnable4k2kYUVSplit){
-            modifymdpCountfor4k2k(ctx, list);
-        }
-
         mCurrentFrame.fbZ = -1;
         if(mCurrentFrame.fbCount)
             mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
 
+        if(sEnable4k2kYUVSplit){
+            adjustForSourceSplit(ctx, list);
+        }
+
         mCurrentFrame.map();
 
-        //Configure framebuffer first if applicable
-        if(mCurrentFrame.fbZ >= 0) {
-            if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
-                ALOGE("%s configure framebuffer failed", __func__);
-                reset(numLayers, list);
-                ctx->mOverlay->clear(mDpy);
-                ret = -1;
-                goto exit;
-            }
-        }
-        if(!programYUV(ctx, list)) {
+        if(!programMDP(ctx, list)) {
             reset(numLayers, list);
             ctx->mOverlay->clear(mDpy);
+            ctx->mLayerRotMap[mDpy]->clear();
             ret = -1;
             goto exit;
         }
@@ -1434,11 +1426,26 @@
 }
 //=============MDPCompNonSplit===================================================
 
-void MDPCompNonSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+void MDPCompNonSplit::adjustForSourceSplit(hwc_context_t *ctx,
          hwc_display_contents_1_t* list){
     //As we split 4kx2k yuv layer and program to 2 VG pipes
     //(if available) increase mdpcount accordingly
     mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
+
+    //If 4k2k Yuv layer split is possible,  and if
+    //fbz is above 4k2k layer, increment fb zorder by 1
+    //as we split 4k2k layer and increment zorder for right half
+    //of the layer
+    if(mCurrentFrame.fbZ >= 0) {
+        int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
+        for(int index = 0; index < n4k2kYuvCount; index++){
+            int n4k2kYuvIndex =
+                    ctx->listStats[mDpy].yuv4k2kIndices[index];
+            if(mCurrentFrame.fbZ > n4k2kYuvIndex){
+                mCurrentFrame.fbZ += 1;
+            }
+        }
+    }
 }
 
 /*
@@ -1535,7 +1542,7 @@
 
         if(isYuvBuffer(hnd)) {
             type = MDPCOMP_OV_VG;
-        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
+        } else if(!qhwc::needsScaling(layer)
             && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
             && ctx->mMDP.version >= qdutils::MDSS_V5) {
             type = MDPCOMP_OV_DMA;
@@ -1686,7 +1693,7 @@
 
 //=============MDPCompSplit===================================================
 
-void MDPCompSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+void MDPCompSplit::adjustForSourceSplit(hwc_context_t *ctx,
          hwc_display_contents_1_t* list){
     //if 4kx2k yuv layer is totally present in either in left half
     //or right half then try splitting the yuv layer to avoid decimation
@@ -1696,10 +1703,12 @@
         int n4k2kYuvIndex = ctx->listStats[mDpy].yuv4k2kIndices[index];
         hwc_layer_1_t* layer = &list->hwLayers[n4k2kYuvIndex];
         hwc_rect_t dst = layer->displayFrame;
-
-        if((dst.left > lSplit)||(dst.right < lSplit)){
+        if((dst.left > lSplit) || (dst.right < lSplit)) {
             mCurrentFrame.mdpCount += 1;
         }
+        if(mCurrentFrame.fbZ > n4k2kYuvIndex){
+            mCurrentFrame.fbZ += 1;
+        }
     }
 }
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7e646d7..7e52679 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -139,8 +139,9 @@
     /* Checks for pipes needed versus pipes available */
     virtual bool arePipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list) = 0;
-    /* increments mdpCount if 4k2k yuv layer split is enabled*/
-    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+    /* Increments mdpCount if 4k2k yuv layer split is enabled.
+     * updates framebuffer z order if fb lies above source-split layer */
+    virtual void adjustForSourceSplit(hwc_context_t *ctx,
             hwc_display_contents_1_t* list) = 0;
     /* configures 4kx2k yuv layer*/
     virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
@@ -181,6 +182,9 @@
             hwc_display_contents_1_t* list);
     /* checks if the required bandwidth exceeds a certain max */
     bool bandwidthCheck(hwc_context_t *ctx, const double& size);
+    /* checks if MDP/MDSS can process current list w.r.to HW limitations
+     * All peculiar HW limitations should go here */
+    bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
     /* generates ROI based on the modified area of the frame */
     void generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     bool validateAndApplyROI(hwc_context_t *ctx, hwc_display_contents_1_t* list,
@@ -209,7 +213,6 @@
     void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
             bool secureOnly);
     bool programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-    bool programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     void reset(const int& numAppLayers, hwc_display_contents_1_t* list);
     bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
     bool resourceCheck(hwc_context_t *ctx, hwc_display_contents_1_t *list);
@@ -264,8 +267,9 @@
     virtual bool areVGPipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
 
-    /* increments mdpCount if 4k2k yuv layer split is enabled*/
-    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+    /* Increments mdpCount if 4k2k yuv layer split is enabled.
+     * updates framebuffer z order if fb lies above source-split layer */
+    virtual void adjustForSourceSplit(hwc_context_t *ctx,
              hwc_display_contents_1_t* list);
 
     /* configures 4kx2k yuv layer to 2 VG pipes*/
@@ -304,8 +308,9 @@
     virtual bool areVGPipesAvailable(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
 
-    /* increments mdpCount if 4k2k yuv layer split is enabled*/
-    virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+    /* Increments mdpCount if 4k2k yuv layer split is enabled.
+     * updates framebuffer z order if fb lies above source-split layer */
+    virtual void adjustForSourceSplit(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
 
     /* configures 4kx2k yuv layer*/
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 3b98788..a3f6b5b 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -86,12 +86,10 @@
 
 static android::status_t screenRefresh(hwc_context_t *ctx) {
     status_t result = NO_INIT;
-#ifdef QCOM_BSP
     if(ctx->proc) {
         ctx->proc->invalidate(ctx->proc);
         result = NO_ERROR;
     }
-#endif
     return result;
 }
 
@@ -100,11 +98,9 @@
         const Parcel* inParcel,
         Parcel* outParcel) {
     status_t result = NO_INIT;
-#ifdef QCOM_BSP
 #ifdef VPU_TARGET
     result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
 #endif
-#endif
     return result;
 }
 
@@ -112,6 +108,34 @@
     ctx->mExtOrientation = orientation;
 }
 
+static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
+    int connected;
+    connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
+    outParcel->writeInt32(connected);
+}
+
+static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
+        Parcel* outParcel) {
+    int dpy = inParcel->readInt32();
+    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
+    outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+    outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
+    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
+    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
+    //XXX: Need to check what to return for HDMI
+    outParcel->writeInt32(ctx->mMDP.panel);
+}
+static void setHSIC(hwc_context_t* ctx, const Parcel* inParcel) {
+    int dpy = inParcel->readInt32();
+    HSICData_t hsic_data;
+    hsic_data.hue = inParcel->readInt32();
+    hsic_data.saturation = inParcel->readFloat();
+    hsic_data.intensity = inParcel->readInt32();
+    hsic_data.contrast = inParcel->readFloat();
+    //XXX: Actually set the HSIC data through ABL lib
+}
+
+
 static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
     ctx->mBufferMirrorMode = enable;
 }
@@ -140,6 +164,15 @@
         case IQService::BUFFER_MIRRORMODE:
             setBufferMirrorMode(mHwcContext, inParcel->readInt32());
             break;
+        case IQService::CHECK_EXTERNAL_STATUS:
+            isExternalConnected(mHwcContext, outParcel);
+            break;
+        case IQService::GET_DISPLAY_ATTRIBUTES:
+            getDisplayAttributes(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::SET_HSIC_DATA:
+            setHSIC(mHwcContext, inParcel);
+            break;
         default:
             return NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 6f2cb9c..f2ab7e6 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -134,7 +134,7 @@
     ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
     overlay::Overlay::initOverlay();
     ctx->mOverlay = overlay::Overlay::getInstance();
-    ctx->mRotMgr = new RotMgr();
+    ctx->mRotMgr = RotMgr::getInstance();
 
     //Is created and destroyed only once for primary
     //For external it could get created and destroyed multiple times depending
@@ -172,6 +172,7 @@
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         ctx->mHwcDebug[i] = new HwcDebug(i);
         ctx->mLayerRotMap[i] = new LayerRotMap();
+        ctx->mAnimationState[i] = ANIMATION_STOPPED;
     }
 
     MDPComp::init(ctx);
@@ -189,13 +190,8 @@
             defaultServiceManager()->getService(
             String16("display.qservice")))->connect(client);
 
-    // Initialize "No animation on external display" related  parameters.
+    // Initialize device orientation to its default orientation
     ctx->deviceOrientation = 0;
-    ctx->mPrevCropVideo.left = ctx->mPrevCropVideo.top =
-        ctx->mPrevCropVideo.right = ctx->mPrevCropVideo.bottom = 0;
-    ctx->mPrevDestVideo.left = ctx->mPrevDestVideo.top =
-        ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
-    ctx->mPrevTransformVideo = 0;
     ctx->mBufferMirrorMode = false;
 #ifdef VPU_TARGET
     ctx->mVPUClient = new VPUClient();
@@ -311,12 +307,12 @@
     float xRatio = 1.0;
     float yRatio = 1.0;
 
-    float fbWidth = ctx->dpyAttr[dpy].xres;
-    float fbHeight = ctx->dpyAttr[dpy].yres;
+    int fbWidth = ctx->dpyAttr[dpy].xres;
+    int fbHeight = ctx->dpyAttr[dpy].yres;
     if(ctx->dpyAttr[dpy].mDownScaleMode) {
         // if downscale Mode is enabled for external, need to query
         // the actual width and height, as that is the physical w & h
-        ctx->mExtDisplay->getAttributes((int&)fbWidth, (int&)fbHeight);
+         ctx->mExtDisplay->getAttributes(fbWidth, fbHeight);
     }
 
 
@@ -329,7 +325,7 @@
     float asX = 0;
     float asY = 0;
     float asW = fbWidth;
-    float asH= fbHeight;
+    float asH = fbHeight;
 
     // based on the action safe ratio, get the Action safe rectangle
     asW = fbWidth * (1.0f -  asWidthRatio / 100.0f);
@@ -390,6 +386,7 @@
 // based on the position and aspect ratio with orientation
 void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
                             hwc_rect_t& inRect, hwc_rect_t& outRect) {
+    hwc_rect_t viewFrame = ctx->mViewFrame[dpy];
     // Physical display resolution
     float fbWidth  = ctx->dpyAttr[dpy].xres;
     float fbHeight = ctx->dpyAttr[dpy].yres;
@@ -427,14 +424,20 @@
         yPos = rect.top;
         width = rect.right - rect.left;
         height = rect.bottom - rect.top;
+        // swap viewframe coordinates for 90 degree rotation.
+        swap(viewFrame.left, viewFrame.top);
+        swap(viewFrame.right, viewFrame.bottom);
     }
+    // if viewframe left and top coordinates are non zero value then exclude it
+    // during the computation of xRatio and yRatio
+    xRatio = (inPos.x - viewFrame.left)/actualWidth;
+    yRatio = (inPos.y - viewFrame.top)/actualHeight;
+    // Use viewframe width and height to compute wRatio and hRatio.
+    wRatio = inPos.w/(viewFrame.right - viewFrame.left);
+    hRatio = inPos.h/(viewFrame.bottom - viewFrame.top);
+
 
     //Calculate the position...
-    xRatio = inPos.x/actualWidth;
-    yRatio = inPos.y/actualHeight;
-    wRatio = inPos.w/actualWidth;
-    hRatio = inPos.h/actualHeight;
-
     outPos.x = (xRatio * width) + xPos;
     outPos.y = (yRatio * height) + yPos;
     outPos.w = wRatio * width;
@@ -607,8 +610,21 @@
     return extOrientation;
 }
 
-bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
-        const int& dpy) {
+bool isDownscaleRequired(hwc_layer_1_t const* layer) {
+    hwc_rect_t displayFrame  = layer->displayFrame;
+    hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+    int dst_w, dst_h, src_w, src_h;
+    dst_w = displayFrame.right - displayFrame.left;
+    dst_h = displayFrame.bottom - displayFrame.top;
+    src_w = sourceCrop.right - sourceCrop.left;
+    src_h = sourceCrop.bottom - sourceCrop.top;
+
+    if(((src_w > dst_w) || (src_h > dst_h)))
+        return true;
+
+    return false;
+}
+bool needsScaling(hwc_layer_1_t const* layer) {
     int dst_w, dst_h, src_w, src_h;
 
     hwc_rect_t displayFrame  = layer->displayFrame;
@@ -644,11 +660,13 @@
     cropL = sourceCrop;
     dstL = displayFrame;
     hwc_rect_t scissorL = { 0, 0, lSplit, hw_h };
+    scissorL = getIntersection(ctx->mViewFrame[dpy], scissorL);
     qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
 
     cropR = sourceCrop;
     dstR = displayFrame;
     hwc_rect_t scissorR = { lSplit, 0, hw_w, hw_h };
+    scissorR = getIntersection(ctx->mViewFrame[dpy], scissorR);
     qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
 
     // Sanitize Crop to stitch
@@ -677,9 +695,8 @@
     return false;
 }
 
-bool isAlphaScaled(hwc_context_t* ctx, hwc_layer_1_t const* layer,
-        const int& dpy) {
-    if(needsScaling(ctx, layer, dpy) && isAlphaPresent(layer)) {
+bool isAlphaScaled(hwc_layer_1_t const* layer) {
+    if(needsScaling(layer) && isAlphaPresent(layer)) {
         return true;
     }
     return false;
@@ -707,6 +724,7 @@
     if(dst.left < 0 || dst.top < 0 ||
             dst.right > hw_w || dst.bottom > hw_h) {
         hwc_rect_t scissor = {0, 0, hw_w, hw_h };
+        scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
         qhwc::calculate_crop_rects(crop, dst, scissor, transform);
     }
 }
@@ -734,7 +752,6 @@
     ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
     ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
     ctx->listStats[dpy].skipCount = 0;
-    ctx->listStats[dpy].needsAlphaScale = false;
     ctx->listStats[dpy].preMultipliedAlpha = false;
     ctx->listStats[dpy].isSecurePresent = false;
     ctx->listStats[dpy].yuvCount = 0;
@@ -745,6 +762,7 @@
                       (int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
     ctx->listStats[dpy].secureUI = false;
     ctx->listStats[dpy].yuv4k2kCount = 0;
+    ctx->mViewFrame[dpy] = (hwc_rect_t){0, 0, 0, 0};
 
     trimList(ctx, list, dpy);
     optimizeLayerRects(ctx, list, dpy);
@@ -753,6 +771,9 @@
         hwc_layer_1_t const* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
 
+        // Calculate view frame of each display from the layer displayframe
+        ctx->mViewFrame[dpy] = getUnion(ctx->mViewFrame[dpy],
+                                        layer->displayFrame);
 #ifdef QCOM_BSP
         if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
             ctx->listStats[dpy].isDisplayAnimating = true;
@@ -800,9 +821,6 @@
         if(layer->blending == HWC_BLENDING_PREMULT)
             ctx->listStats[dpy].preMultipliedAlpha = true;
 
-        if(!ctx->listStats[dpy].needsAlphaScale)
-            ctx->listStats[dpy].needsAlphaScale =
-                    isAlphaScaled(ctx, layer, dpy);
 
         if(UNLIKELY(isExtOnly(hnd))){
             ctx->listStats[dpy].extOnlyLayerIndex = i;
@@ -1057,7 +1075,7 @@
             hwc_rect_t& topframe =
                 (hwc_rect_t&)list->hwLayers[i].displayFrame;
             while(j >= 0) {
-               if(!needsScaling(ctx, &list->hwLayers[j], dpy)) {
+               if(!needsScaling(&list->hwLayers[j])) {
                   hwc_layer_1_t* layer = (hwc_layer_1_t*)&list->hwLayers[j];
                   hwc_rect_t& bottomframe = layer->displayFrame;
                   hwc_rect_t& bottomCrop = layer->sourceCrop;
@@ -1065,10 +1083,11 @@
 
                   hwc_rect_t irect = getIntersection(bottomframe, topframe);
                   if(isValidRect(irect)) {
+                     hwc_rect_t dest_rect;
                      //if intersection is valid rect, deduct it
-                     bottomframe = deductRect(bottomframe, irect);
+                     dest_rect  = deductRect(bottomframe, irect);
                      qhwc::calculate_crop_rects(bottomCrop, bottomframe,
-                                                bottomframe, transform);
+                                                dest_rect, transform);
 
                   }
                }
@@ -1218,12 +1237,7 @@
             } else if(isExtAnimating) {
                 // Release all the app layer fds immediately,
                 // if animation is in progress.
-                hwc_layer_1_t const* layer = &list->hwLayers[i];
-                private_handle_t *hnd = (private_handle_t *)layer->handle;
-                if(isYuvBuffer(hnd)) {
-                    list->hwLayers[i].releaseFenceFd = dup(releaseFd);
-                } else
-                    list->hwLayers[i].releaseFenceFd = -1;
+                list->hwLayers[i].releaseFenceFd = -1;
             } else if(list->hwLayers[i].releaseFenceFd < 0) {
                 //If rotator has not already populated this field.
                 list->hwLayers[i].releaseFenceFd = dup(releaseFd);
@@ -1470,29 +1484,7 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
-    if(dpy && isYuvBuffer(hnd)) {
-        if(!ctx->listStats[dpy].isDisplayAnimating) {
-            ctx->mPrevCropVideo = crop;
-            ctx->mPrevDestVideo = dst;
-            ctx->mPrevTransformVideo = transform;
-        } else {
-            // Restore the previous crop, dest rect and transform values, during
-            // animation to avoid displaying videos at random coordinates.
-            crop = ctx->mPrevCropVideo;
-            dst = ctx->mPrevDestVideo;
-            transform = ctx->mPrevTransformVideo;
-            orient = static_cast<eTransform>(transform);
-            //In you tube use case when a device rotated from landscape to
-            // portrait, set the isFg flag and zOrder to avoid displaying UI on
-            // hdmi during animation
-            if(ctx->deviceOrientation) {
-                isFg = ovutils::IS_FG_SET;
-                z = ZORDER_1;
-            }
-        }
-        calcExtDisplayPosition(ctx, hnd, dpy, crop, dst,
-                                           transform, orient);
-    }
+    calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
 
     if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
        ctx->mMDP.version < qdutils::MDSS_V5) {
@@ -1517,8 +1509,6 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
-            ctx->mOverlay->clear(dpy);
-            ctx->mLayerRotMap[dpy]->clear();
             return -1;
         }
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1536,7 +1526,6 @@
 
     if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
         ALOGE("%s: commit failed for low res panel", __FUNCTION__);
-        ctx->mLayerRotMap[dpy]->clear();
         return -1;
     }
     return 0;
@@ -1603,28 +1592,6 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
-    if(dpy && isYuvBuffer(hnd)) {
-        if(!ctx->listStats[dpy].isDisplayAnimating) {
-            ctx->mPrevCropVideo = crop;
-            ctx->mPrevDestVideo = dst;
-            ctx->mPrevTransformVideo = transform;
-        } else {
-            // Restore the previous crop, dest rect and transform values, during
-            // animation to avoid displaying videos at random coordinates.
-            crop = ctx->mPrevCropVideo;
-            dst = ctx->mPrevDestVideo;
-            transform = ctx->mPrevTransformVideo;
-            orient = static_cast<eTransform>(transform);
-            //In you tube use case when a device rotated from landscape to
-            // portrait, set the isFg flag and zOrder to avoid displaying UI on
-            // hdmi during animation
-            if(ctx->deviceOrientation) {
-                isFg = ovutils::IS_FG_SET;
-                z = ZORDER_1;
-            }
-        }
-    }
-
     setMdpFlags(layer, mdpFlagsL, 0, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
@@ -1645,8 +1612,6 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
-            ctx->mOverlay->clear(dpy);
-            ctx->mLayerRotMap[dpy]->clear();
             return -1;
         }
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1667,12 +1632,14 @@
         tmp_cropL = crop;
         tmp_dstL = dst;
         hwc_rect_t scissor = {0, 0, lSplit, hw_h };
+        scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
         qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
     }
     if(rDest != OV_INVALID) {
         tmp_cropR = crop;
         tmp_dstR = dst;
         hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h };
+        scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
         qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
     }
 
@@ -1712,7 +1679,6 @@
         if(configMdp(ctx->mOverlay, pargL, orient,
                 tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
-            ctx->mLayerRotMap[dpy]->clear();
             return -1;
         }
     }
@@ -1728,7 +1694,6 @@
         if(configMdp(ctx->mOverlay, pargR, orient,
                 tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
-            ctx->mLayerRotMap[dpy]->clear();
             return -1;
         }
     }
@@ -1775,7 +1740,6 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
-            ctx->mOverlay->clear(dpy);
             return -1;
         }
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1954,17 +1918,7 @@
 }
 
 void LayerRotMap::clear() {
-    for (uint32_t i = 0; i < mCount; i++) {
-        //mCount represents rotator objects for just this display.
-        //We could have popped mCount topmost objects from mRotMgr, but if each
-        //round has the same failure, typical of stability runs, it would lead
-        //to unnecessary memory allocation, deallocation each time. So we let
-        //the rotator objects be around, but just knock off the fences they
-        //hold. Ultimately the rotator objects will be GCed when not required.
-        //Also resetting fences is required if at least one rotation round has
-        //succeeded before. It'll be a NOP otherwise.
-        mRot[i]->resetReleaseFd();
-    }
+    RotMgr::getInstance()->markUnusedTop(mCount);
     reset();
 }
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 2503e43..872b306 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -97,7 +97,6 @@
     int yuvCount;
     int yuvIndices[MAX_NUM_APP_LAYERS];
     int extOnlyLayerIndex;
-    bool needsAlphaScale;
     bool preMultipliedAlpha;
     int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
     int yuv4k2kCount;
@@ -205,8 +204,9 @@
 bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
 bool isSecureModePolicy(int mdpVersion);
 bool isExternalActive(hwc_context_t* ctx);
-bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
-                  const int& dpy);
+bool isAlphaScaled(hwc_layer_1_t const* layer);
+bool needsScaling(hwc_layer_1_t const* layer);
+bool isDownscaleRequired(hwc_layer_1_t const* layer);
 bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
                            const int& dpy);
 void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
@@ -410,6 +410,11 @@
 
 }; //qhwc namespace
 
+enum eAnimationState{
+    ANIMATION_STOPPED,
+    ANIMATION_STARTED,
+};
+
 // -----------------------------------------------------------------------------
 // HWC context
 // This structure contains overall state
@@ -437,16 +442,13 @@
     qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
     qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
     qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
+    hwc_rect_t mViewFrame[HWC_NUM_DISPLAY_TYPES];
     qhwc::AssertiveDisplay *mAD;
     qhwc::VPUClient *mVPUClient;
+    eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
 
-    // No animation on External display feature
-    // Notifies hwcomposer about the device orientation before animation.
+    // stores the primary device orientation
     int deviceOrientation;
-    // Stores the crop, dest rect and transform value of video before animation.
-    hwc_rect_t mPrevCropVideo;
-    hwc_rect_t mPrevDestVideo;
-    int mPrevTransformVideo;
     //Securing in progress indicator
     bool mSecuring;
     //WFD on proprietary stack
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index e6da3c5..ad23e84 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -68,7 +68,6 @@
         PipeBook::resetUse(i);
         PipeBook::resetAllocation(i);
     }
-    sForceSetBitmap = 0;
     mDumpStr[0] = '\0';
 
 #ifdef USES_QSEED_SCALAR
@@ -197,19 +196,14 @@
     if(mPipeBook[index].mPipe->commit()) {
         ret = true;
         PipeBook::setUse((int)dest);
-        if(sForceSetBitmap & (1 << mPipeBook[index].mDisplay)) {
-            mPipeBook[index].mPipe->forceSet();
-        }
     } else {
         int dpy = mPipeBook[index].mDisplay;
-        for(int i = 0; i < PipeBook::NUM_PIPES; i++)
+        for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
             if (mPipeBook[i].mDisplay == dpy) {
                 PipeBook::resetAllocation(i);
                 PipeBook::resetUse(i);
-                if(mPipeBook[i].valid()) {
-                    mPipeBook[i].mPipe->forceSet();
-                }
             }
+        }
     }
     return ret;
 }
@@ -437,9 +431,6 @@
             // Mark as available for this round
             PipeBook::resetUse(i);
             PipeBook::resetAllocation(i);
-            if(mPipeBook[i].valid()) {
-                mPipeBook[i].mPipe->forceSet();
-            }
         }
     }
 }
@@ -500,7 +491,6 @@
 int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
 int Overlay::sDMAMode = DMA_LINE_MODE;
 bool Overlay::sDMAMultiplexingSupported = false;
-int Overlay::sForceSetBitmap = 0;
 int Overlay::PipeBook::NUM_PIPES = 0;
 int Overlay::PipeBook::sPipeUsageBitmap = 0;
 int Overlay::PipeBook::sLastUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 48825ea..fe855c1 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -120,8 +120,6 @@
     void getDump(char *buf, size_t len);
     /* Reset usage and allocation bits on all pipes for given display */
     void clear(int dpy);
-    /* Marks the display, whose pipes need to be forcibaly configured */
-    void forceSet(const int& dpy);
 
     /* Closes open pipes, called during startup */
     static int initOverlay();
@@ -212,7 +210,6 @@
     static int sDpyFbMap[DPY_MAX];
     static int sDMAMode;
     static bool sDMAMultiplexingSupported;
-    static int sForceSetBitmap;
     static void *sLibScaleHandle;
     static scale::Scale *sScale;
 };
@@ -289,10 +286,6 @@
     return sDpyFbMap[dpy];
 }
 
-inline void Overlay::forceSet(const int& dpy) {
-    sForceSetBitmap |= (1 << dpy);
-}
-
 inline scale::Scale *Overlay::getScalar() {
     return sScale;
 }
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 18ef5e6..1b26b66 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -87,7 +87,6 @@
     void dump() const;
     /* Return the dump in the specified buffer */
     void getDump(char *buf, size_t len);
-    void forceSet();
 
 private:
     // mdp ctrl struct(info e.g.)
@@ -232,10 +231,6 @@
     mMdp.getDump(buf, len);
 }
 
-inline void Ctrl::forceSet() {
-    mMdp.forceSet();
-}
-
 inline Data::Data() {
     mMdp.reset();
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index fbb173e..006e05d 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -69,7 +69,6 @@
     mLkgo.id = MSMFB_NEW_REQUEST;
     mOrientation = utils::OVERLAY_TRANSFORM_0;
     mDownscale = 0;
-    mForceSet = false;
     mDpy = 0;
 #ifdef USES_POST_PROCESSING
     mPPChanged = false;
@@ -211,8 +210,7 @@
 
     doDownscale();
 
-    if(this->ovChanged() || mForceSet) {
-        mForceSet = false;
+    if(this->ovChanged()) {
         if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
             ALOGE("MdpCtrl failed to setOverlay, restoring last known "
                   "good ov info");
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 6dd3976..3cb6a41 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -83,7 +83,6 @@
     utils::Dim getSrcRectDim() const;
     /* setVisualParam */
     bool setVisualParams(const MetaData_t& data);
-    void forceSet();
 
 private:
     /* Perform transformation calculations */
@@ -133,7 +132,6 @@
     /* FD for the mdp fbnum */
     OvFD          mFd;
     int mDownscale;
-    bool mForceSet;
     int mDpy;
 
 #ifdef USES_POST_PROCESSING
@@ -348,10 +346,6 @@
         mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
 }
 
-inline void MdpCtrl::forceSet() {
-    mForceSet = true;
-}
-
 ///////    MdpCtrl3D //////
 
 inline MdpCtrl3D::MdpCtrl3D() { reset(); }
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 4b6a8bc..d912dc7 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -107,13 +107,15 @@
     mRelFence[mCurrOffset] = fence;
 }
 
-void RotMem::Mem::resetReleaseFd() {
-    //Will wait for previous offline rotation to finish, close fence fd
-    //and reset
-    setReleaseFd(-1);
-}
-
 //============RotMgr=========================
+RotMgr * RotMgr::sRotMgr = NULL;
+
+RotMgr* RotMgr::getInstance() {
+    if(sRotMgr == NULL) {
+        sRotMgr = new RotMgr();
+    }
+    return sRotMgr;
+}
 
 RotMgr::RotMgr() {
     for(int i = 0; i < MAX_ROT_SESS; i++) {
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 6bb94a6..2bbfb91 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -56,7 +56,6 @@
         bool close() { return m.close(); }
         uint32_t size() const { return m.bufSz(); }
         void setReleaseFd(const int& fence);
-        void resetReleaseFd();
         // Max rotator buffers
         enum { ROT_NUM_BUFS = 2 };
         // rotator data info dst offset
@@ -73,7 +72,6 @@
     Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; }
     RotMem& operator++() { ++_curr; return *this; }
     void setReleaseFd(const int& fence) { curr().setReleaseFd(fence); }
-    void resetReleaseFd() { curr().resetReleaseFd(); }
     bool close();
     uint32_t _curr;
     Mem m[MAX_ROT_MEM];
@@ -98,7 +96,6 @@
     virtual void dump() const = 0;
     virtual void getDump(char *buf, size_t len) const = 0;
     void setReleaseFd(const int& fence) { mMem.setReleaseFd(fence); }
-    void resetReleaseFd() { mMem.resetReleaseFd(); }
     static Rotator *getRotator();
 
 protected:
@@ -230,21 +227,29 @@
     //Maximum sessions based on VG pipes, since rotator is used only for videos.
     //Even though we can have 4 mixer stages, that much may be unnecessary.
     enum { MAX_ROT_SESS = 3 };
-    RotMgr();
+
     ~RotMgr();
     void configBegin();
     void configDone();
     overlay::Rotator *getNext();
     void clear(); //Removes all instances
+    //Resets the usage of top count objects, making them available for reuse
+    void markUnusedTop(const uint32_t& count) { mUseCount -= count; }
     /* Returns rot dump.
      * Expects a NULL terminated buffer of big enough size.
      */
     void getDump(char *buf, size_t len);
     int getRotDevFd();
     int getNumActiveSessions() { return mUseCount; }
+
+    static RotMgr *getInstance();
+
 private:
+    RotMgr();
+    static RotMgr *sRotMgr;
+
     overlay::Rotator *mRot[MAX_ROT_SESS];
-    int mUseCount;
+    uint32_t mUseCount;
     int mRotDevFd;
 };
 
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index c03378b..e0b580b 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -167,10 +167,6 @@
     return true;
 }
 
-void GenericPipe::forceSet() {
-    mCtrlData.ctrl.forceSet();
-}
-
 int GenericPipe::getPipeId() {
     return mCtrlData.ctrl.getPipeId();
 }
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 5c963bc..ecdd001 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -75,10 +75,6 @@
     void dump() const;
     /* Return the dump in the specified buffer */
     void getDump(char *buf, size_t len);
-    /* Marks the pipe for forcible setting of params
-     * even if they haven't changed
-     */
-    void forceSet();
     int getPipeId();
 
 private:
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index d514405..06f4f00 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -4,14 +4,16 @@
 
 LOCAL_MODULE                  := libqdutils
 LOCAL_MODULE_TAGS             := optional
-LOCAL_SHARED_LIBRARIES        := $(common_libs) libui
+LOCAL_SHARED_LIBRARIES        := $(common_libs) libui libbinder libqservice
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdutils\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
+LOCAL_COPY_HEADERS            := display_config.h mdp_version.h
 LOCAL_SRC_FILES               := profiler.cpp mdp_version.cpp \
                                  idle_invalidator.cpp \
                                  comptype.cpp qd_utils.cpp \
-                                 cb_utils.cpp
+                                 cb_utils.cpp display_config.cpp
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
new file mode 100644
index 0000000..eaf5384
--- /dev/null
+++ b/libqdutils/display_config.cpp
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <display_config.h>
+#include <QServiceUtils.h>
+
+using namespace android;
+using namespace qService;
+
+namespace qdutils {
+
+int isExternalConnected(void) {
+    int ret;
+    status_t err = FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+    if(binder != NULL) {
+        err = binder->dispatch(IQService::CHECK_EXTERNAL_STATUS,
+                &inParcel , &outParcel);
+    }
+    if(err) {
+        ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
+        ret = err;
+    } else {
+        ret = outParcel.readInt32();
+    }
+    return ret;
+}
+
+int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr) {
+    status_t err = FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+    inParcel.writeInt32(dpy);
+    if(binder != NULL) {
+        err = binder->dispatch(IQService::GET_DISPLAY_ATTRIBUTES,
+                &inParcel, &outParcel);
+    }
+    if(!err) {
+        dpyattr.vsync_period = outParcel.readInt32();
+        dpyattr.xres = outParcel.readInt32();
+        dpyattr.yres = outParcel.readInt32();
+        dpyattr.xdpi = outParcel.readFloat();
+        dpyattr.ydpi = outParcel.readFloat();
+        dpyattr.panel_type = (char) outParcel.readInt32();
+    } else {
+        ALOGE("%s: Failed to get display attributes err=%d", __FUNCTION__, err);
+    }
+    return err;
+}
+
+int setHSIC(int dpy, const HSICData_t& hsic_data) {
+    status_t err = FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+    inParcel.writeInt32(dpy);
+    inParcel.writeInt32(hsic_data.hue);
+    inParcel.writeFloat(hsic_data.saturation);
+    inParcel.writeInt32(hsic_data.intensity);
+    inParcel.writeFloat(hsic_data.contrast);
+    if(binder != NULL) {
+        err = binder->dispatch(IQService::SET_HSIC_DATA, &inParcel, &outParcel);
+    }
+    if(err)
+        ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
+    return err;
+}
+}; //namespace
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
new file mode 100644
index 0000000..c7d8ce9
--- /dev/null
+++ b/libqdutils/display_config.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <gralloc_priv.h>
+#include <qdMetaData.h>
+#include <mdp_version.h>
+
+// This header is for clients to use to set/get global display configuration
+// The functions in this header run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+// Only primary and external displays are supported here.
+// WiFi/virtual displays are not supported.
+
+namespace qdutils {
+
+// Use this enum to specify the dpy parameters where needed
+enum {
+    DISPLAY_PRIMARY = 0,
+    DISPLAY_EXTERNAL,
+};
+
+// Display Attributes that are available to clients of this library
+// Not to be confused with a similar struct in hwc_utils (in the hwc namespace)
+struct DisplayAttributes_t {
+    uint32_t vsync_period; //nanoseconds
+    uint32_t xres;
+    uint32_t yres;
+    float xdpi;
+    float ydpi;
+    char panel_type;
+};
+
+// Check if external display is connected. Useful to check before making
+// calls for external displays
+// Returns 1 if connected, 0 if disconnected, negative values on errors
+int isExternalConnected(void);
+
+// Get display vsync period which is in nanoseconds
+// i.e vsync_period = 1000000000l / fps
+// Returns 0 on success, negative values on errors
+int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr);
+
+// Set HSIC data on a given display ID
+// Returns 0 on success, negative values on errors
+int setHSIC(int dpy, const HSICData_t& hsic_data);
+
+}; //namespace
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index 17b2eda..0c6123b 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_MODULE_PATH             := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES        := $(common_libs) libexternal libbinder
+LOCAL_SHARED_LIBRARIES        := $(common_libs) libbinder
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdqservice\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := QService.cpp \
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 7ad443d..d6e525a 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -45,6 +45,9 @@
         SCREEN_REFRESH,          // Refresh screen through SF invalidate
         EXTERNAL_ORIENTATION,    // Set external orientation
         BUFFER_MIRRORMODE,       // Buffer mirrormode
+        CHECK_EXTERNAL_STATUS,   // Check status of external display
+        GET_DISPLAY_ATTRIBUTES,  // Get display attributes
+        SET_HSIC_DATA,           // Set HSIC on dspp
         VPU_COMMAND_LIST_START = 100, //Reserved block for VPU commands
         VPU_COMMAND_LIST_END   = 200,
         COMMAND_LIST_END = 400,