display: Add BufferMirrorMode support for External

- In Buffer mirror mode, the output on the external should be rotated
  based on the primary orientation.
- this is used for the side sync feature.
- buffermirrormode has higher precedence over external orientation
- Add binder interface to enable/disable buffermirror mode

Change-Id: I1768dbfac239ae663927358ca9b8e5510b683385
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7c2e643..a0f5faa 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -116,6 +116,10 @@
 
         ovutils::eTransform orient =
                     static_cast<ovutils::eTransform>(transform);
+        // use ext orientation if any
+        int extOrient = ctx->mExtOrientation;
+        if(ctx->mBufferMirrorMode)
+            extOrient = getMirrorModeOrientation(ctx);
 
         // Do not use getNonWormholeRegion() function to calculate the
         // sourceCrop during animation on external display and
@@ -125,7 +129,7 @@
             sourceCrop = layer->displayFrame;
             displayFrame = sourceCrop;
         } else if((!mDpy ||
-                   (mDpy && !ctx->mExtOrientation
+                   (mDpy && !extOrient
                    && !ctx->dpyAttr[mDpy].mDownScaleMode))
                    && (extOnlyLayerIndex == -1)) {
             if(!qdutils::MDPVersion::getInstance().is8x26()) {
@@ -134,13 +138,12 @@
             }
         }
         if(mDpy && !qdutils::MDPVersion::getInstance().is8x26()) {
-            if(ctx->mExtOrientation || ctx->dpyAttr[mDpy].mDownScaleMode) {
+            if(extOrient || ctx->dpyAttr[mDpy].mDownScaleMode) {
                 calcExtDisplayPosition(ctx, mDpy, sourceCrop, displayFrame);
                 // If there is a external orientation set, use that
-                if(ctx->mExtOrientation) {
-                    transform = ctx->mExtOrientation;
-                    orient =
-                        static_cast<ovutils::eTransform >(ctx->mExtOrientation);
+                if(extOrient) {
+                    transform = extOrient;
+                    orient = static_cast<ovutils::eTransform >(extOrient);
                 }
             }
             // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
@@ -148,7 +151,7 @@
         }
         setMdpFlags(layer, mdpFlags, 0, transform);
         // For External use rotator if there is a rotation value set
-        if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
+        if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
             mRot = ctx->mRotMgr->getNext();
             if(mRot == NULL) return -1;
             //Configure rotator for pre-rotation
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index b27a88c..6704db7 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -64,6 +64,9 @@
         case IQService::EXTERNAL_ORIENTATION:
             setExtOrientation(value);
             break;
+        case IQService::BUFFER_MIRRORMODE:
+            setBufferMirrorMode(value);
+            break;
         default:
             return NO_ERROR;
     }
@@ -115,4 +118,8 @@
     mHwcContext->mExtOrientation = orientation;
 }
 
+void QClient::setBufferMirrorMode(uint32_t enable) {
+    mHwcContext->mBufferMirrorMode = enable;
+}
+
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 4cbabef..848d8d2 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -61,6 +61,7 @@
     void unsecuring(uint32_t startEnd);
     android::status_t screenRefresh();
     void setExtOrientation(uint32_t orientation);
+    void setBufferMirrorMode(uint32_t enable);
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e013876..fa3c15f 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -196,6 +196,8 @@
         ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
     ctx->mPrevTransformVideo = 0;
 
+    ctx->mBufferMirrorMode = false;
+
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -297,7 +299,11 @@
     float fbHeight = ctx->dpyAttr[dpy].yres;
 
     // Since external is rotated 90, need to swap width/height
-    if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)
+    int extOrient = ctx->mExtOrientation;
+    if(ctx->mBufferMirrorMode)
+        extOrient = getMirrorModeOrientation(ctx);
+
+    if(extOrient & HWC_TRANSFORM_ROT_90)
         swap(fbWidth, fbHeight);
 
     float asX = 0;
@@ -496,7 +502,10 @@
                                hwc_rect_t& sourceCrop,
                                hwc_rect_t& displayFrame) {
     // Swap width and height when there is a 90deg transform
-    if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90) {
+    int extOrient = ctx->mExtOrientation;
+    if(ctx->mBufferMirrorMode)
+        extOrient = getMirrorModeOrientation(ctx);
+    if(extOrient & HWC_TRANSFORM_ROT_90) {
         int dstWidth = ctx->dpyAttr[dpy].xres;
         int dstHeight = ctx->dpyAttr[dpy].yres;;
         int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
@@ -538,7 +547,26 @@
         displayFrame.right *= wRatio;
         displayFrame.bottom *= hRatio;
     }
+}
 
+/* Returns the orientation which needs to be set on External for
+ *  SideSync/Buffer Mirrormode
+ */
+int getMirrorModeOrientation(hwc_context_t *ctx) {
+    int extOrientation = 0;
+    int deviceOrientation = ctx->deviceOrientation;
+    if(!isPrimaryPortrait(ctx))
+        deviceOrientation = (deviceOrientation + 1) % 4;
+     if (deviceOrientation == 0)
+         extOrientation = HWC_TRANSFORM_ROT_270;
+     else if (deviceOrientation == 1)//90
+         extOrientation = 0;
+     else if (deviceOrientation == 2)//180
+         extOrientation = HWC_TRANSFORM_ROT_90;
+     else if (deviceOrientation == 3)//270
+         extOrientation = HWC_TRANSFORM_FLIP_V | HWC_TRANSFORM_FLIP_H;
+
+    return extOrientation;
 }
 
 bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
@@ -663,9 +691,10 @@
         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->mExtOrientation || ctx->mBufferMirrorMode) {
+            ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d"
+                     "BufferMirrorMode = %d", __FUNCTION__,
+                     ctx->mExtOrientation, ctx->mBufferMirrorMode);
             if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
                 ctx->isPaddingRound = true;
             }
@@ -1165,12 +1194,15 @@
         }
     }
     if(dpy) {
+        int extOrient = ctx->mExtOrientation;
+        if(ctx->mBufferMirrorMode)
+            extOrient = getMirrorModeOrientation(ctx);
         // Just need to set the position to portrait as the transformation
         // will already be set to required orientation on TV
-        if(ctx->mExtOrientation || ctx->dpyAttr[dpy].mDownScaleMode) {
-            getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, dst, dst);
-            if(ctx->mExtOrientation) {
-                transform = ctx->mExtOrientation;
+        if(extOrient || ctx->dpyAttr[dpy].mDownScaleMode) {
+            getAspectRatioPosition(ctx, dpy, extOrient, dst, dst);
+            if(extOrient) {
+                transform = extOrient;
                 orient = static_cast<eTransform>(transform);
             }
         }
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 3908816..ef48e4a 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -193,6 +193,9 @@
                                int dpy,
                                hwc_rect_t& sourceCrop,
                                hwc_rect_t& displayFrame);
+// Returns the orientation that needs to be set on external for
+// BufferMirrirMode(Sidesync)
+int getMirrorModeOrientation(hwc_context_t *ctx);
 
 //Close acquireFenceFds of all layers of incoming list
 void closeAcquireFds(hwc_display_contents_1_t* list);
@@ -364,6 +367,11 @@
     int mExtOrientation;
     //Flags the transition of a video session
     bool mVideoTransFlag;
+
+    //Used for SideSync feature
+    //which overrides the mExtOrientation
+    bool mBufferMirrorMode;
+
     qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
 };
 
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index a3ff150..e45f42e 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -78,6 +78,13 @@
         data.writeInt32(orientation);
         remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
     }
+
+    virtual void setBufferMirrorMode(uint32_t enable) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+        data.writeInt32(enable);
+        remote()->transact(BUFFER_MIRRORMODE, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
@@ -160,6 +167,18 @@
             setExtOrientation(orientation);
             return NO_ERROR;
         } break;
+        case BUFFER_MIRRORMODE: {
+            CHECK_INTERFACE(IQService, data, reply);
+            if(callerUid != AID_SYSTEM) {
+                ALOGE("display.qservice BUFFER_MIRRORMODE access denied: \
+                      pid=%d uid=%d process=%s",callerPid,
+                      callerUid, callingProcName);
+                return PERMISSION_DENIED;
+            }
+            uint32_t enable = data.readInt32();
+            setBufferMirrorMode(enable);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index ff034be..149cd8b 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -42,6 +42,7 @@
         CONNECT,
         SCREEN_REFRESH,
         EXTERNAL_ORIENTATION,
+        BUFFER_MIRRORMODE,
     };
     enum {
         END = 0,
@@ -52,6 +53,7 @@
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     virtual android::status_t screenRefresh() = 0;
     virtual void setExtOrientation(uint32_t orientation) = 0;
+    virtual void setBufferMirrorMode(uint32_t enable) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index f780a75..a8c5dca 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -77,6 +77,12 @@
     }
 }
 
+void QService::setBufferMirrorMode(uint32_t enable) {
+    if(mClient.get()) {
+        mClient->notifyCallback(BUFFER_MIRRORMODE, enable);
+    }
+}
+
 void QService::init()
 {
     if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 8eefa21..a241d44 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -50,6 +50,7 @@
     virtual void connect(const android::sp<qClient::IQClient>& client);
     virtual android::status_t screenRefresh();
     virtual void setExtOrientation(uint32_t orientation);
+    virtual void setBufferMirrorMode(uint32_t enable);
     static void init();
 private:
     QService();