Merge "hwc: Simplify vsync code"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 3e92f53..73e145f 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -746,6 +746,11 @@
             height = 1024;
             fps = 60;
             break;
+        case HDMI_VFRMT_1024x768p60_4_3:
+            width = 1024;
+            height = 768;
+            fps = 60;
+            break;
         case HDMI_VFRMT_1920x1080p24_16_9:
             width = 1920;
             height = 1080;
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 08d95be..3d4e462 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -54,6 +54,9 @@
      * cannot be used with noncontiguous heaps */
     GRALLOC_USAGE_PRIVATE_UNCACHED        =       0x02000000,
 
+    /* Buffer content should be displayed on an primary display only */
+    GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY   =       0x04000000,
+
     /* Buffer content should be displayed on an external display only */
     GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY   =       0x08000000,
 
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index c5a864e..6d6cd0d 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -173,6 +173,10 @@
                 ctx->mExtDispConfiguring = false;
                 setListStats(ctx, list, dpy);
                 int fbZOrder = ctx->mMDPComp[dpy]->prepare(ctx, list);
+                if(ctx->deviceOrientation &&
+                    ctx->listStats[dpy].isDisplayAnimating) {
+                    fbZOrder = 0;
+                }
                 if(fbZOrder >= 0)
                     ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZOrder);
 
@@ -182,6 +186,14 @@
                 if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
                     ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
                 */
+                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.
@@ -244,6 +256,14 @@
             ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s",
                       (enable)?"ENABLED":"DISABLED");
             break;
+        case  HWC_EVENT_ORIENTATION:
+            if(dpy == HWC_DISPLAY_PRIMARY) {
+                // store the primary display orientation
+                // will be used in hwc_video::configure to disable
+                // rotation animation on external display
+                ctx->deviceOrientation = enable;
+            }
+            break;
         default:
             ret = -EINVAL;
     }
@@ -385,7 +405,7 @@
 
         if (display_commit(ctx, dpy) < 0) {
             ALOGE("%s: display commit fail!", __FUNCTION__);
-            return -1;
+            ret = -1;
         }
     }
 
@@ -422,12 +442,18 @@
             ret = -1;
         }
 
+        int extOnlyLayerIndex =
+            ctx->listStats[dpy].extOnlyLayerIndex;
+
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
-        if(copybitDone) {
+        if(extOnlyLayerIndex!= -1) {
+            hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+            hnd = (private_handle_t *)extLayer->handle;
+        } else if(copybitDone) {
             hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
         }
 
-        if(hnd) {
+        if(hnd && !isYuvBuffer(hnd)) {
             if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7b34df9..893da72 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -19,12 +19,17 @@
  */
 
 #define DEBUG_FBUPDATE 0
+#include <cutils/properties.h>
 #include <gralloc_priv.h>
+#include <overlayRotator.h>
 #include "hwc_fbupdate.h"
 #include "mdp_version.h"
+#include "external.h"
 
 using namespace qdutils;
 
+using overlay::Rotator;
+
 namespace qhwc {
 
 namespace ovutils = overlay::utils;
@@ -38,6 +43,7 @@
 
 inline void IFBUpdate::reset() {
     mModeOn = false;
+    mRot = NULL;
 }
 
 //================= Low res====================================
@@ -65,6 +71,12 @@
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
+        int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
+        // ext only layer present..
+        if(extOnlyLayerIndex != -1) {
+            layer = &list->hwLayers[extOnlyLayerIndex];
+            layer->compositionType = HWC_OVERLAY;
+        }
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         ovutils::Whf info(hnd->width, hnd->height,
@@ -81,42 +93,76 @@
         mDest = dest;
 
         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
-
+        ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
 
-        ovutils::PipeArgs parg(mdpFlags,
-                               info,
-                               zOrder,
-                               ovutils::IS_FG_OFF,
-                               ovutils::ROT_FLAGS_NONE);
-        ov.setSource(parg, dest);
-
-        hwc_rect_t sourceCrop;
-        getNonWormholeRegion(list, sourceCrop);
-        // x,y,w,h
-        ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
-                           sourceCrop.right - sourceCrop.left,
-                           sourceCrop.bottom - sourceCrop.top);
-        ov.setCrop(dcrop, dest);
-
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t displayFrame = layer->displayFrame;
         int transform = layer->transform;
-        ovutils::eTransform orient =
-            static_cast<ovutils::eTransform>(transform);
-        ov.setTransform(orient, dest);
+        int fbWidth  = ctx->dpyAttr[mDpy].xres;
+        int fbHeight = ctx->dpyAttr[mDpy].yres;
+        int rotFlags = ovutils::ROT_FLAGS_NONE;
 
-        hwc_rect_t displayFrame = sourceCrop;
+        ovutils::eTransform orient =
+                    static_cast<ovutils::eTransform>(transform);
+        if(mDpy && ctx->mExtOrientation) {
+            // If there is a external orientation set, use that
+            transform = ctx->mExtOrientation;
+            orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
+        }
+
+        // Do not use getNonWormholeRegion() function to calculate the
+        // sourceCrop during animation on external display and
+        // Dont do wormhole calculation when extorientation is set on External
+        if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+            sourceCrop = layer->displayFrame;
+            displayFrame = sourceCrop;
+        } else if((!mDpy || (mDpy && !ctx->mExtOrientation))
+                               && extOnlyLayerIndex == -1) {
+            getNonWormholeRegion(list, sourceCrop);
+            displayFrame = sourceCrop;
+        }
         ovutils::Dim dpos(displayFrame.left,
                           displayFrame.top,
                           displayFrame.right - displayFrame.left,
                           displayFrame.bottom - displayFrame.top);
         // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-        if(mDpy)
+        if(mDpy && !ctx->mExtOrientation)
             getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
-        ov.setPosition(dpos, dest);
 
+        if(mDpy) {
+            getAspectRatioPosition(ctx, mDpy, ctx->mExtOrientation, dpos.x,
+                                    dpos.y, dpos.w, dpos.h);
+            // Convert dim to hwc_rect_t
+            displayFrame.left = dpos.x;
+            displayFrame.top = dpos.y;
+            displayFrame.right = dpos.w + displayFrame.left;
+            displayFrame.bottom = dpos.h + displayFrame.top;
+        }
+        setMdpFlags(layer, mdpFlags, 0, transform);
+        // For External use rotator if there is a rotation value set
+        if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
+            mRot = ctx->mRotMgr->getNext();
+            if(mRot == NULL) return -1;
+            //Configure rotator for pre-rotation
+            if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
+                ALOGE("%s: configRotator Failed!", __FUNCTION__);
+                mRot = NULL;
+                return -1;
+            }
+            info.format = (mRot)->getDstFormat();
+            updateSource(orient, info, sourceCrop);
+            rotFlags |= ovutils::ROT_PREROTATED;
+        }
+        //For the mdp, since either we are pre-rotating or MDP does flips
+        orient = ovutils::OVERLAY_TRANSFORM_0;
+        transform = 0;
+        ovutils::PipeArgs parg(mdpFlags, info, zOrder, isFg,
+                                static_cast<ovutils::eRotFlags>(rotFlags));
         ret = true;
-        if (!ov.commit(dest)) {
-            ALOGE("%s: commit fails", __FUNCTION__);
+        if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
+                    NULL, mDest) < 0) {
+            ALOGE("%s: ConfigMdp failed for low res", __FUNCTION__);
             ret = false;
         }
     }
@@ -131,7 +177,15 @@
     bool ret = true;
     overlay::Overlay& ov = *(ctx->mOverlay);
     ovutils::eDest dest = mDest;
-    if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
+    int fd = hnd->fd;
+    uint32_t offset = hnd->offset;
+    if(mRot) {
+        if(!mRot->queueBuffer(fd, offset))
+            return false;
+        fd = mRot->getDstMemId();
+        offset = mRot->getDstOffset();
+    }
+    if (!ov.queueBuffer(fd, offset, dest)) {
         ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
         ret = false;
     }
@@ -145,6 +199,7 @@
     IFBUpdate::reset();
     mDestLeft = ovutils::OV_INVALID;
     mDestRight = ovutils::OV_INVALID;
+    mRot = NULL;
 }
 
 bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
@@ -165,6 +220,12 @@
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
+        int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
+        // ext only layer present..
+        if(extOnlyLayerIndex != -1) {
+            layer = &list->hwLayers[extOnlyLayerIndex];
+            layer->compositionType = HWC_OVERLAY;
+        }
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         ovutils::Whf info(hnd->width, hnd->height,
@@ -208,8 +269,17 @@
                                 ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargR, destR);
 
-        hwc_rect_t sourceCrop;
-        getNonWormholeRegion(list, sourceCrop);
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t displayFrame = layer->displayFrame;
+        // Do not use getNonWormholeRegion() function to calculate the
+        // sourceCrop during animation on external display.
+        if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+            sourceCrop = layer->displayFrame;
+            displayFrame = sourceCrop;
+        } else if(extOnlyLayerIndex == -1) {
+            getNonWormholeRegion(list, sourceCrop);
+            displayFrame = sourceCrop;
+        }
         ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
                             (sourceCrop.right - sourceCrop.left) / 2,
                             sourceCrop.bottom - sourceCrop.top);
@@ -227,7 +297,6 @@
         ov.setTransform(orient, destL);
         ov.setTransform(orient, destR);
 
-        hwc_rect_t displayFrame = sourceCrop;
         const int halfWidth = (displayFrame.right - displayFrame.left) / 2;
         const int height = displayFrame.bottom - displayFrame.top;
 
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 4291a50..5cf75f7 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -25,6 +25,10 @@
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
+namespace overlay {
+    class Rotator;
+}
+
 namespace qhwc {
 namespace ovutils = overlay::utils;
 
@@ -46,6 +50,7 @@
 protected:
     const int mDpy; // display to update
     bool mModeOn; // if prepare happened
+    overlay::Rotator *mRot;
 };
 
 //Low resolution (<= 2048) panel handler.
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 8ccf362..b88674f 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -515,7 +515,7 @@
 /* Checks for conditions where YUV layers cannot be bypassed */
 bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
 
-    if(isSkipLayer(layer)) {
+    if(isSkipLayer(layer) && mDpy == HWC_DISPLAY_PRIMARY) {
         ALOGE("%s: Unable to bypass skipped YUV", __FUNCTION__);
         return false;
     }
@@ -626,6 +626,15 @@
 void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
 
     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];
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index edf579f..65667bd 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -107,4 +107,9 @@
 #endif
     return result;
 }
+
+void QClient::setExtOrientation(uint32_t orientation) {
+    mHwcContext->mExtOrientation = orientation;
+}
+
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 9cb2680..4cbabef 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -60,6 +60,7 @@
     void securing(uint32_t startEnd);
     void unsecuring(uint32_t startEnd);
     android::status_t screenRefresh();
+    void setExtOrientation(uint32_t orientation);
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 3fc3b3a..20cdf72 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -154,6 +154,7 @@
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
     ctx->mExtDispConfiguring = false;
+    ctx->mExtOrientation = 0;
 
     //Right now hwc starts the service but anybody could do it, or it could be
     //independent process as well.
@@ -163,6 +164,14 @@
             defaultServiceManager()->getService(
             String16("display.qservice")))->connect(client);
 
+    // Initialize "No animation on external display" related  parameters.
+    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;
+
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -272,6 +281,31 @@
     return;
 }
 
+/* Calculates the aspect ratio for external based on the primary */
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h) {
+    int fbWidth  = ctx->dpyAttr[dpy].xres;
+    int fbHeight = ctx->dpyAttr[dpy].yres;
+
+    switch(orientation) {
+        case HAL_TRANSFORM_ROT_90:
+        case HAL_TRANSFORM_ROT_270:
+            x = (fbWidth - (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres
+                        * fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres))/2;
+            y = 0;
+            w = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres *
+                    fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres);
+            h = fbHeight;
+            break;
+        default:
+            //Do nothing
+            break;
+     }
+    ALOGD_IF(HWC_UTILS_DEBUG, "%s: Position: x = %d, y = %d w = %d h = %d",
+                    __FUNCTION__, x, y, w ,h);
+}
+
+
 bool needsScaling(hwc_layer_1_t const* layer) {
     int dst_w, dst_h, src_w, src_h;
 
@@ -322,6 +356,8 @@
     ctx->listStats[dpy].preMultipliedAlpha = false;
     ctx->listStats[dpy].yuvCount = 0;
     char property[PROPERTY_VALUE_MAX];
+    ctx->listStats[dpy].extOnlyLayerIndex = -1;
+    ctx->listStats[dpy].isDisplayAnimating = false;
 
     for (size_t i = 0; i < list->numHwLayers; i++) {
         hwc_layer_1_t const* layer = &list->hwLayers[i];
@@ -335,7 +371,9 @@
         //We disregard FB being skip for now! so the else if
         } else if (isSkipLayer(&list->hwLayers[i])) {
             ctx->listStats[dpy].skipCount++;
-        } else if (UNLIKELY(isYuvBuffer(hnd))) {
+        }
+
+        if (UNLIKELY(isYuvBuffer(hnd))) {
             int& yuvCount = ctx->listStats[dpy].yuvCount;
             ctx->listStats[dpy].yuvIndices[yuvCount] = i;
             yuvCount++;
@@ -352,6 +390,13 @@
 
         if(!ctx->listStats[dpy].needsAlphaScale)
             ctx->listStats[dpy].needsAlphaScale = isAlphaScaled(layer);
+
+        if(UNLIKELY(isExtOnly(hnd))){
+            ctx->listStats[dpy].extOnlyLayerIndex = i;
+        }
+        if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
+            ctx->listStats[dpy].isDisplayAnimating = true;
+        }
     }
     if(ctx->listStats[dpy].yuvCount > 0) {
         if (property_get("hw.cabl.yuv", property, NULL) > 0) {
@@ -366,6 +411,24 @@
             }
         }
     }
+    if(dpy) {
+        //uncomment the below code for testing purpose.
+        /* char value[PROPERTY_VALUE_MAX];
+        property_get("sys.ext_orientation", value, "0");
+        // Assuming the orientation value is in terms of HAL_TRANSFORM,
+        // This needs mapping to HAL, if its in different convention
+        ctx->mExtOrientation = atoi(value); */
+        // Assuming the orientation value is in terms of HAL_TRANSFORM,
+        // This needs mapping to HAL, if its in different convention
+        if(ctx->mExtOrientation) {
+            ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d",
+                     __FUNCTION__, ctx->mExtOrientation);
+            if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+                ctx->isPaddingRound = true;
+            }
+            Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+        }
+    }
 }
 
 
@@ -534,6 +597,9 @@
         if(atoi(property) == 0)
             swapzero = true;
     }
+    bool isExtAnimating = false;
+    if(dpy)
+       isExtAnimating = ctx->listStats[dpy].isDisplayAnimating;
 
     //Accumulate acquireFenceFds
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
@@ -582,7 +648,16 @@
             //Populate releaseFenceFds.
             if(UNLIKELY(swapzero))
                 list->hwLayers[i].releaseFenceFd = -1;
-            else
+            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;
+            } else
                 list->hwLayers[i].releaseFenceFd = dup(releaseFd);
         }
     }
@@ -594,6 +669,11 @@
 
     if (ctx->mCopyBit[dpy])
         ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+    // if external is animating, close the relaseFd
+    if(isExtAnimating) {
+        close(releaseFd);
+        releaseFd = -1;
+    }
     if(UNLIKELY(swapzero)){
         list->retireFenceFd = -1;
         close(releaseFd);
@@ -617,10 +697,9 @@
 
 void setMdpFlags(hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
-        int rotDownscale) {
+        int rotDownscale, int transform) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
-    const int& transform = layer->transform;
 
     if(layer->blending == HWC_BLENDING_PREMULT) {
         ovutils::setMdpFlags(mdpFlags,
@@ -652,12 +731,12 @@
 
     //No 90 component and no rot-downscale then flips done by MDP
     //If we use rot then it might as well do flips
-    if(!(layer->transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
-        if(layer->transform & HWC_TRANSFORM_FLIP_H) {
+    if(!(transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
+        if(transform & HWC_TRANSFORM_FLIP_H) {
             ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_H);
         }
 
-        if(layer->transform & HWC_TRANSFORM_FLIP_V) {
+        if(transform & HWC_TRANSFORM_FLIP_V) {
             ovutils::setMdpFlags(mdpFlags,  ovutils::OV_MDP_FLIP_V);
         }
     }
@@ -670,13 +749,24 @@
     }
 }
 
-static inline int configRotator(Rotator *rot, const Whf& whf,
-        const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
+inline int configRotator(Rotator *rot, const Whf& whf,
+        hwc_rect_t& crop, const eMdpFlags& mdpFlags,
         const eTransform& orient, const int& downscale) {
-    Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
-        (crop.bottom - crop.top));
+
     rot->setSource(whf);
-    rot->setCrop(rotCrop);
+
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+        qdutils::MDSS_V5) {
+        uint32_t crop_w = (crop.right - crop.left);
+        uint32_t crop_h = (crop.bottom - crop.top);
+        ovutils::normalizeCrop((uint32_t&)crop.left, crop_w);
+        ovutils::normalizeCrop((uint32_t&)crop.top, crop_h);
+        crop.right = crop.left + crop_w;
+        crop.bottom = crop.top + crop_h;
+        Dim rotCrop(crop.left, crop.top, crop_w, crop_h);
+        rot->setCrop(rotCrop);
+    }
+
     rot->setFlags(mdpFlags);
     rot->setTransform(orient);
     rot->setDownscale(downscale);
@@ -684,7 +774,7 @@
     return 0;
 }
 
-static inline int configMdp(Overlay *ov, const PipeArgs& parg,
+inline int configMdp(Overlay *ov, const PipeArgs& parg,
         const eTransform& orient, const hwc_rect_t& crop,
         const hwc_rect_t& pos, const MetaData_t *metadata,
         const eDest& dest) {
@@ -710,7 +800,7 @@
     return 0;
 }
 
-static inline void updateSource(eTransform& orient, Whf& whf,
+inline void updateSource(eTransform& orient, Whf& whf,
         hwc_rect_t& crop) {
     Dim srcCrop(crop.left, crop.top,
             crop.right - crop.left,
@@ -736,8 +826,8 @@
 }
 
 int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
-        const int& dpy, eMdpFlags& mdpFlags, const eZorder& z,
-        const eIsFg& isFg, const eDest& dest, Rotator **rot) {
+        const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+        eIsFg& isFg, const eDest& dest, Rotator **rot) {
 
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if(!hnd) {
@@ -756,6 +846,42 @@
     Whf whf(hnd->width, hnd->height,
             getMdpFormat(hnd->format), hnd->size);
 
+    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;
+            //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;
+            }
+        }
+    }
+
+    uint32_t x = dst.left, y  = dst.right;
+    uint32_t w = dst.right - dst.left;
+    uint32_t h = dst.bottom - dst.top;
+
+    if(dpy && ctx->mExtOrientation) {
+        // Just need to set the position to portrait as the transformation
+        // will already be set to required orientation on TV
+        getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, x, y, w, h);
+        // Convert position to hwc_rect_t
+        dst.left = x;
+        dst.top = y;
+        dst.right = w + dst.left;
+        dst.bottom = h + dst.top;
+    }
+
     if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
        ctx->mMDP.version < qdutils::MDSS_V5) {
         downscale =  getDownscaleFactor(
@@ -768,7 +894,7 @@
         }
     }
 
-    setMdpFlags(layer, mdpFlags, downscale);
+    setMdpFlags(layer, mdpFlags, downscale, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
     if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
@@ -778,6 +904,7 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
+            ctx->mOverlay->clear(dpy);
             return -1;
         }
         whf.format = (*rot)->getDstFormat();
@@ -788,7 +915,6 @@
     //For the mdp, since either we are pre-rotating or MDP does flips
     orient = OVERLAY_TRANSFORM_0;
     transform = 0;
-
     PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(rotFlags));
     if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
         ALOGE("%s: commit failed for low res panel", __FUNCTION__);
@@ -798,8 +924,8 @@
 }
 
 int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
-        const int& dpy, eMdpFlags& mdpFlagsL, const eZorder& z,
-        const eIsFg& isFg, const eDest& lDest, const eDest& rDest,
+        const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+        eIsFg& isFg, const eDest& lDest, const eDest& rDest,
         Rotator **rot) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if(!hnd) {
@@ -821,7 +947,29 @@
     Whf whf(hnd->width, hnd->height,
             getMdpFormat(hnd->format), hnd->size);
 
-    setMdpFlags(layer, mdpFlagsL);
+    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;
+            //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);
     trimLayer(ctx, dpy, transform, crop, dst);
 
     if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
@@ -830,6 +978,7 @@
         //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;
         }
         whf.format = (*rot)->getDstFormat();
@@ -907,4 +1056,5 @@
 
     return 0;
 }
+
 };//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 91ad153..ccef284 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -91,8 +91,12 @@
     //Video specific
     int yuvCount;
     int yuvIndices[MAX_NUM_LAYERS];
+    int extOnlyLayerIndex;
     bool needsAlphaScale;
     bool preMultipliedAlpha;
+    // Notifies hwcomposer about the start and end of animation
+    // This will be set to true during animation, otherwise false.
+    bool isDisplayAnimating;
 };
 
 struct LayerProp {
@@ -137,6 +141,10 @@
 void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
                                         uint32_t& y, uint32_t& w, uint32_t& h);
 
+
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h);
+
 //Close acquireFenceFds of all layers of incoming list
 void closeAcquireFds(hwc_display_contents_1_t* list);
 
@@ -151,18 +159,32 @@
 //Sets appropriate mdp flags for a layer.
 void setMdpFlags(hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
-        int rotDownscale = 0);
+        int rotDownscale, int transform);
+
+int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+        hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
+        const ovutils::eTransform& orient, const int& downscale);
+
+int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
+        const ovutils::eTransform& orient, const hwc_rect_t& crop,
+        const hwc_rect_t& pos, const MetaData_t *metadata,
+        const ovutils::eDest& dest);
+
+void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
+        hwc_rect_t& crop);
+
+
 
 //Routine to configure low resolution panels (<= 2048 width)
 int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
-        ovutils::eMdpFlags& mdpFlags, const ovutils::eZorder& z,
-        const ovutils::eIsFg& isFg, const ovutils::eDest& dest,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        ovutils::eIsFg& isFg, const ovutils::eDest& dest,
         overlay::Rotator **rot);
 
 //Routine to configure high resolution panels (> 2048 width)
 int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
-        ovutils::eMdpFlags& mdpFlags, const ovutils::eZorder& z,
-        const ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
 
 // Inline utility functions
@@ -260,6 +282,14 @@
     qhwc::MDPComp *mMDPComp[MAX_DISPLAYS];
     qhwc::HwcDebug *mHwcDebug[MAX_DISPLAYS];
 
+    // No animation on External display feature
+    // Notifies hwcomposer about the device orientation before animation.
+    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;
     //External Display configuring progress indicator
@@ -272,6 +302,8 @@
     mutable Locker mExtLock;
     //Drawing round when we use GPU
     bool isPaddingRound;
+    // External Orientation
+    int mExtOrientation;
 };
 
 namespace qhwc {
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 97905d5..9b91760 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -311,6 +311,16 @@
     strncat(buf, str_pipes, strlen(str_pipes));
 }
 
+void Overlay::clear(int dpy) {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if (mPipeBook[i].mDisplay == dpy) {
+            // Mark as available for this round
+            PipeBook::resetUse(i);
+            PipeBook::resetAllocation(i);
+        }
+    }
+}
+
 void Overlay::PipeBook::init() {
     mPipe = NULL;
     mDisplay = DPY_UNUSED;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index bf85b70..cfceaff 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -90,6 +90,8 @@
      * to populate.
      */
     void getDump(char *buf, size_t len);
+    /* Reset usage and allocation bits on all pipes for given display */
+    void clear(int dpy);
     static void setDMAMode(const int& mode);
     static int getDMAMode();
 
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 4578115..4c77f2e 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -37,20 +37,6 @@
 namespace ovutils = overlay::utils;
 namespace overlay {
 
-//Helper to even out x,w and y,h pairs
-//x,y are always evened to ceil and w,h are evened to floor
-static void normalizeCrop(uint32_t& xy, uint32_t& wh) {
-    if(xy & 1) {
-        utils::even_ceil(xy);
-        if(wh & 1)
-            utils::even_floor(wh);
-        else
-            wh -= 2;
-    } else {
-        utils::even_floor(wh);
-    }
-}
-
 bool MdpCtrl::init(uint32_t fbnum) {
     // FD init
     if(!utils::openDev(mFd, fbnum,
@@ -189,8 +175,8 @@
     doDownscale();
     utils::Whf whf = getSrcWhf();
     if(utils::isYuv(whf.format)) {
-        normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
-        normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
+        utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
+        utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
         if(mdpVersion < MDSS_V5) {
             utils::even_floor(mOVInfo.dst_rect.w);
             utils::even_floor(mOVInfo.dst_rect.h);
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 6f2b564..30d7ccd 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -96,7 +96,7 @@
 void MdssRot::setDownscale(int ds) {}
 
 void MdssRot::setFlags(const utils::eMdpFlags& flags) {
-    mRotInfo.flags |= flags;
+    mRotInfo.flags = flags;
 }
 
 void MdssRot::setTransform(const utils::eTransform& rot)
@@ -111,6 +111,7 @@
 }
 
 void MdssRot::doTransform() {
+    mRotInfo.flags |= mOrientation;
     if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
         utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
 }
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index e595cef..4b81ed3 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -428,6 +428,20 @@
     getDump(buf, len, "\tdst", rot.dst);
 }
 
+//Helper to even out x,w and y,h pairs
+//x,y are always evened to ceil and w,h are evened to floor
+void normalizeCrop(uint32_t& xy, uint32_t& wh) {
+    if(xy & 1) {
+        even_ceil(xy);
+        if(wh & 1)
+            even_floor(wh);
+        else
+            wh -= 2;
+    } else {
+        even_floor(wh);
+    }
+}
+
 } // utils
 
 } // overlay
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 0893328..3fa0979 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -143,6 +143,7 @@
 bool enableBarrier (uint32_t orientation);
 uint32_t getS3DFormat(uint32_t fmt);
 bool isMdssRotator();
+void normalizeCrop(uint32_t& xy, uint32_t& wh);
 
 template <int CHAN>
 bool getPositionS3D(const Whf& whf, Dim& out);
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 86e744d..e328d23 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -93,10 +93,14 @@
         } else {
             mdp_version = MDP_V_UNKNOWN;
         }
-        int len = strlen("msmfbXX_");
-        if (mdp_version == MDP_V3_0_3)
-            len++;
-        panel_type = fb_finfo.id[len];
+
+        /* Assumes panel type is 2nd element in '_' delimited id string */
+        char * ptype = strstr(fb_finfo.id, "_");
+        if (!ptype || (*(++ptype) == '\0')) {
+            ALOGE("Invalid framebuffer info string: %s", fb_finfo.id);
+            ptype = fb_finfo.id;
+        }
+        panel_type = *ptype;
 
     }
     close(fb_fd);
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index 53b05e3..af11f88 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -71,6 +71,13 @@
         status_t result = reply.readInt32();
         return result;
     }
+
+    virtual void setExtOrientation(uint32_t orientation) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+        data.writeInt32(orientation);
+        remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 79e831d..ff034be 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -41,6 +41,7 @@
         UNSECURING, // Hardware unsecuring start/end notification
         CONNECT,
         SCREEN_REFRESH,
+        EXTERNAL_ORIENTATION,
     };
     enum {
         END = 0,
@@ -50,6 +51,7 @@
     virtual void unsecuring(uint32_t startEnd) = 0;
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     virtual android::status_t screenRefresh() = 0;
+    virtual void setExtOrientation(uint32_t orientation) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 54e285c..f780a75 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -71,6 +71,12 @@
     return result;
 }
 
+void QService::setExtOrientation(uint32_t orientation) {
+    if(mClient.get()) {
+        mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
+    }
+}
+
 void QService::init()
 {
     if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 268bf81..8eefa21 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -49,6 +49,7 @@
     virtual void unsecuring(uint32_t startEnd);
     virtual void connect(const android::sp<qClient::IQClient>& client);
     virtual android::status_t screenRefresh();
+    virtual void setExtOrientation(uint32_t orientation);
     static void init();
 private:
     QService();