display: Add support orientation control on ext display

- The required orientation on External can be set using the
  properyt sys.ext_orientation.
- Values can be HAL_TRANSFORM_ROT_90, HAL_TRANSFORM_ROT_270
- According to the value set, the FB_TARGET for External will
  be rotated and positioned as per aspect ratio on Ext
- For YUV(video layer) it just calculates the position, as the
  rotation should be the source orientation
- This feature is supported only for low resolution panel.

Change-Id: I3d532ee0cb8dca3c37869537b55cd8044fd9047e
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 439432e..b9be4d4 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====================================
@@ -87,46 +93,71 @@
         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 = layer->sourceCrop;
         hwc_rect_t displayFrame = layer->displayFrame;
-        if(extOnlyLayerIndex == -1) {
+        int transform = layer->transform;
+        int fbWidth  = ctx->dpyAttr[mDpy].xres;
+        int fbHeight = ctx->dpyAttr[mDpy].yres;
+        int rotFlags = ovutils::ROT_FLAGS_NONE;
+
+        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);
+        }
+
+        // Dont do wormhole calculation when extorientation is set on External
+        if((!mDpy || (mDpy && !ctx->mExtOrientation))
+                               && extOnlyLayerIndex == -1) {
             getNonWormholeRegion(list, sourceCrop);
             displayFrame = sourceCrop;
         }
-
-        // x,y,w,h
-        ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
-                           sourceCrop.right - sourceCrop.left,
-                           sourceCrop.bottom - sourceCrop.top);
-        ov.setCrop(dcrop, dest);
-
-        int transform = layer->transform;
-        ovutils::eTransform orient =
-            static_cast<ovutils::eTransform>(transform);
-        ov.setTransform(orient, dest);
-
         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);
+        // 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;
         }
     }
@@ -141,7 +172,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;
     }
@@ -155,6 +194,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,
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_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 fdaa1cb..5a00578 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -156,6 +156,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.
@@ -276,6 +277,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;
 
@@ -375,6 +401,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);
+        }
+    }
 }
 
 
@@ -679,7 +723,7 @@
     }
 }
 
-static inline int configRotator(Rotator *rot, const Whf& whf,
+inline int configRotator(Rotator *rot, const Whf& whf,
         const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
         const eTransform& orient, const int& downscale) {
     Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
@@ -693,7 +737,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) {
@@ -719,7 +763,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,
@@ -765,6 +809,21 @@
     Whf whf(hnd->width, hnd->height,
             getMdpFormat(hnd->format), hnd->size);
 
+    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(
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0e603ce..ab645bc 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -133,6 +133,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);
 
@@ -149,6 +153,20 @@
         ovutils::eMdpFlags &mdpFlags,
         int rotDownscale = 0);
 
+int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+        const 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,
@@ -276,6 +294,8 @@
     struct vsync_state vstate;
     //Drawing round when we use GPU
     bool isPaddingRound;
+    // External Orientation
+    int mExtOrientation;
 };
 
 namespace qhwc {
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();