hwc: Add support for uneven split primary displays

Add support for unevenly split primary displays.
The driver provides info about the split via msm_fb_split sysfs node

For external we assume even split. If driver doesn't specify any split
for primary, we default to even split.

Change-Id: I4d541f41de2d7a5d2b62653fa33cab079a6d5d30
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7ed0577..2ec6019 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -34,8 +34,9 @@
 
 namespace ovutils = overlay::utils;
 
-IFBUpdate* IFBUpdate::getObject(const int& width, const int& dpy) {
-    if(width > MAX_DISPLAY_DIM) {
+IFBUpdate* IFBUpdate::getObject(const int& width, const int& rightSplit,
+        const int& dpy) {
+    if(width > MAX_DISPLAY_DIM || rightSplit) {
         return new FBUpdateHighRes(dpy);
     }
     return new FBUpdateLowRes(dpy);
@@ -223,7 +224,7 @@
 
 // Configure
 bool FBUpdateHighRes::configure(hwc_context_t *ctx,
-                                hwc_display_contents_1 *list, int fbZorder) {
+        hwc_display_contents_1 *list, int fbZorder) {
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
@@ -287,14 +288,33 @@
             getNonWormholeRegion(list, sourceCrop);
             displayFrame = sourceCrop;
         }
-        ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
-                            (sourceCrop.right - sourceCrop.left) / 2,
-                            sourceCrop.bottom - sourceCrop.top);
+
+        const float xres = ctx->dpyAttr[mDpy].xres;
+        //Default even split for all displays with high res
+        float lSplit = xres / 2;
+        if(mDpy == HWC_DISPLAY_PRIMARY &&
+                qdutils::MDPVersion::getInstance().getLeftSplit()) {
+            //Override if split published by driver for primary
+            lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+        }
+
+        const float lSplitRatio = lSplit / xres;
+
+        const float lCropWidth =
+                (sourceCrop.right - sourceCrop.left) * lSplitRatio;
+
+        ovutils::Dim dcropL(
+                sourceCrop.left,
+                sourceCrop.top,
+                lCropWidth,
+                sourceCrop.bottom - sourceCrop.top);
+
         ovutils::Dim dcropR(
-            sourceCrop.left + (sourceCrop.right - sourceCrop.left) / 2,
-            sourceCrop.top,
-            (sourceCrop.right - sourceCrop.left) / 2,
-            sourceCrop.bottom - sourceCrop.top);
+                sourceCrop.left + lCropWidth,
+                sourceCrop.top,
+                (sourceCrop.right - sourceCrop.left) - lCropWidth,
+                sourceCrop.bottom - sourceCrop.top);
+
         ov.setCrop(dcropL, destL);
         ov.setCrop(dcropR, destR);
 
@@ -304,19 +324,19 @@
         ov.setTransform(orient, destL);
         ov.setTransform(orient, destR);
 
-        const int halfWidth = (displayFrame.right - displayFrame.left) / 2;
+        const int lWidth = (lSplit - displayFrame.left);
+        const int rWidth = (displayFrame.right - lSplit);
         const int height = displayFrame.bottom - displayFrame.top;
 
-        const int halfDpy = ctx->dpyAttr[mDpy].xres / 2;
-        ovutils::Dim dposL(halfDpy - halfWidth,
+        ovutils::Dim dposL(displayFrame.left,
                            displayFrame.top,
-                           halfWidth,
+                           lWidth,
                            height);
         ov.setPosition(dposL, destL);
 
         ovutils::Dim dposR(0,
                            displayFrame.top,
-                           halfWidth,
+                           rWidth,
                            height);
         ov.setPosition(dposR, destR);
 
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 5cf75f7..55cd655 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -45,7 +45,8 @@
     //Reset values
     virtual void reset();
     //Factory method that returns a low-res or high-res version
-    static IFBUpdate *getObject(const int& width, const int& dpy);
+    static IFBUpdate *getObject(const int& width, const int& rightSplit,
+            const int& dpy);
 
 protected:
     const int mDpy; // display to update
@@ -59,12 +60,12 @@
     explicit FBUpdateLowRes(const int& dpy);
     virtual ~FBUpdateLowRes() {};
     bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
-                                                          int fbZorder);
+            int fbZorder);
     bool draw(hwc_context_t *ctx, private_handle_t *hnd);
     void reset();
 private:
     bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
-                                                               int fbZorder);
+            int fbZorder);
     ovutils::eDest mDest; //pipe to draw on
 };
 
@@ -74,12 +75,12 @@
     explicit FBUpdateHighRes(const int& dpy);
     virtual ~FBUpdateHighRes() {};
     bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
-                                                             int fbZorder);
+            int fbZorder);
     bool draw(hwc_context_t *ctx, private_handle_t *hnd);
     void reset();
 private:
     bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
-                                                            int fbZorder);
+            int fbZorder);
     ovutils::eDest mDestLeft; //left pipe to draw on
     ovutils::eDest mDestRight; //right pipe to draw on
 };
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index ba6cae7..d4ce253 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -40,12 +40,12 @@
 bool MDPComp::sEnableMixedMode = true;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
 
-MDPComp* MDPComp::getObject(const int& width, int dpy) {
-    if(width <= MAX_DISPLAY_DIM) {
-        return new MDPCompLowRes(dpy);
-    } else {
+MDPComp* MDPComp::getObject(const int& width, const int& rightSplit,
+        const int& dpy) {
+    if(width > MAX_DISPLAY_DIM || rightSplit) {
         return new MDPCompHighRes(dpy);
     }
+    return new MDPCompLowRes(dpy);
 }
 
 MDPComp::MDPComp(int dpy):mDpy(dpy){};
@@ -954,17 +954,24 @@
 //=============MDPCompHighRes===================================================
 
 int MDPCompHighRes::pipesNeeded(hwc_context_t *ctx,
-                                hwc_display_contents_1_t* list) {
+        hwc_display_contents_1_t* list) {
     int pipesNeeded = 0;
-    int hw_w = ctx->dpyAttr[mDpy].xres;
+    const int xres = ctx->dpyAttr[mDpy].xres;
+    //Default even split for all displays with high res
+    int lSplit = xres / 2;
+    if(mDpy == HWC_DISPLAY_PRIMARY &&
+            qdutils::MDPVersion::getInstance().getLeftSplit()) {
+        //Override if split published by driver for primary
+        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+    }
 
     for(int i = 0; i < mCurrentFrame.layerCount; ++i) {
         if(!mCurrentFrame.isFBComposed[i]) {
             hwc_layer_1_t* layer = &list->hwLayers[i];
             hwc_rect_t dst = layer->displayFrame;
-            if(dst.left > hw_w/2) {
+            if(dst.left > lSplit) {
                 pipesNeeded++;
-            } else if(dst.right <= hw_w/2) {
+            } else if(dst.right <= lSplit) {
                 pipesNeeded++;
             } else {
                 pipesNeeded += 2;
@@ -975,17 +982,24 @@
 }
 
 bool MDPCompHighRes::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
-                                     MdpPipeInfoHighRes& pipe_info,
-                                     ePipeType type) {
-    int hw_w = ctx->dpyAttr[mDpy].xres;
+        MdpPipeInfoHighRes& pipe_info,
+        ePipeType type) {
+    const int xres = ctx->dpyAttr[mDpy].xres;
+    //Default even split for all displays with high res
+    int lSplit = xres / 2;
+    if(mDpy == HWC_DISPLAY_PRIMARY &&
+            qdutils::MDPVersion::getInstance().getLeftSplit()) {
+        //Override if split published by driver for primary
+        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+    }
 
     hwc_rect_t dst = layer->displayFrame;
-    if(dst.left > hw_w/2) {
+    if(dst.left > lSplit) {
         pipe_info.lIndex = ovutils::OV_INVALID;
         pipe_info.rIndex = getMdpPipe(ctx, type);
         if(pipe_info.rIndex == ovutils::OV_INVALID)
             return false;
-    } else if (dst.right <= hw_w/2) {
+    } else if (dst.right <= lSplit) {
         pipe_info.rIndex = ovutils::OV_INVALID;
         pipe_info.lIndex = getMdpPipe(ctx, type);
         if(pipe_info.lIndex == ovutils::OV_INVALID)
@@ -1035,7 +1049,7 @@
  * Configures pipe(s) for MDP composition
  */
 int MDPCompHighRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
-                              PipeLayerPair& PipeLayerPair) {
+        PipeLayerPair& PipeLayerPair) {
     MdpPipeInfoHighRes& mdp_info =
         *(static_cast<MdpPipeInfoHighRes*>(PipeLayerPair.pipeInfo));
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 6e04918..908a658 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -46,7 +46,8 @@
     /* dumpsys */
     void dump(android::String8& buf);
 
-    static MDPComp* getObject(const int& width, const int dpy);
+    static MDPComp* getObject(const int& width, const int& rightSplit,
+            const int& dpy);
     /* Handler to invoke frame redraw on Idle Timer expiry */
     static void timeout_handler(void *udata);
     /* Initialize MDP comp*/
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 1751cba..28b1849 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -31,6 +31,7 @@
 #include "hwc_copybit.h"
 #include "comptype.h"
 #include "external.h"
+#include "mdp_version.h"
 
 namespace qhwc {
 #define HWC_UEVENT_SWITCH_STR  "change@/devices/virtual/switch/"
@@ -53,8 +54,11 @@
 
 static void setup(hwc_context_t* ctx, int dpy, bool usecopybit)
 {
-    ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
-    ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx->dpyAttr[dpy].xres, dpy);
+    const int rSplit = 0; //Even split for external if at all
+    ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx->dpyAttr[dpy].xres,
+            rSplit, dpy);
+    ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx->dpyAttr[dpy].xres,
+            rSplit, dpy);
     if(usecopybit)
         ctx->mCopyBit[dpy] = new CopyBit();
 }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 1bb683a..7040251 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -126,6 +126,7 @@
     ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
     ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
     ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
+    const int rightSplit = qdutils::MDPVersion::getInstance().getRightSplit();
     overlay::Overlay::initOverlay();
     ctx->mOverlay = overlay::Overlay::getInstance();
     ctx->mRotMgr = new RotMgr();
@@ -135,7 +136,7 @@
     //on what external we connect to.
     ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
         IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
-        HWC_DISPLAY_PRIMARY);
+                rightSplit, HWC_DISPLAY_PRIMARY);
 
     // Check if the target supports copybit compostion (dyn/mdp/c2d) to
     // decide if we need to open the copybit module.
@@ -152,7 +153,7 @@
 
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
-         HWC_DISPLAY_PRIMARY);
+                rightSplit, HWC_DISPLAY_PRIMARY);
 
     for (uint32_t i = 0; i < MAX_DISPLAYS; i++) {
         ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -1035,16 +1036,17 @@
     hwc_rect_t tmp_cropL, tmp_dstL;
     hwc_rect_t tmp_cropR, tmp_dstR;
 
+    const int lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
     if(lDest != OV_INVALID) {
         tmp_cropL = crop;
         tmp_dstL = dst;
-        hwc_rect_t scissor = {0, 0, hw_w/2, hw_h };
+        hwc_rect_t scissor = {0, 0, lSplit, hw_h };
         qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
     }
     if(rDest != OV_INVALID) {
         tmp_cropR = crop;
         tmp_dstR = dst;
-        hwc_rect_t scissor = {hw_w/2, 0, hw_w, hw_h };
+        hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h };
         qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
     }
 
@@ -1088,8 +1090,8 @@
     if(rDest != OV_INVALID) {
         PipeArgs pargR(mdpFlagsR, whf, z, isFg,
                 static_cast<eRotFlags>(rotFlags));
-        tmp_dstR.right = tmp_dstR.right - hw_w/2;
-        tmp_dstR.left = tmp_dstR.left - hw_w/2;
+        tmp_dstR.right = tmp_dstR.right - lSplit;
+        tmp_dstR.left = tmp_dstR.left - lSplit;
         if(configMdp(ctx->mOverlay, pargR, orient,
                 tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index cac6b1d..16aee07 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -101,8 +101,8 @@
             ptype = fb_finfo.id;
         }
         panel_type = *ptype;
-
     }
+    mPanelType = panel_type;
     close(fb_fd);
     mMDPVersion = mdp_version;
     mHasOverlay = false;
@@ -113,9 +113,26 @@
     if(mMDPVersion >= MDSS_V5) {
         //TODO get this from driver
         mMDPDownscale = 4;
-    }
 
-    mPanelType = panel_type;
+        char split[64];
+        FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
+        if(fp){
+            //Format "left right" space as delimiter
+            if(fread(split, sizeof(char), 64, fp)) {
+                mSplit.mLeft = atoi(split);
+                ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft);
+                char *rght = strpbrk(split, " ");
+                if(rght)
+                    mSplit.mRight = atoi(rght + 1);
+                ALOGI_IF(rght, "Right Split=%d", mSplit.mRight);
+            }
+        } else {
+            ALOGE("Failed to open mdss_fb_split node");
+        }
+
+        if(fp)
+            fclose(fp);
+    }
 }
 
 bool MDPVersion::supportsDecimation() {
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index f7b16fa..e26f4d3 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -74,6 +74,16 @@
 #define WRITEBACK_PANEL  'a'
 #define LVDS_PANEL       'b'
 
+class MDPVersion;
+
+struct Split {
+    int mLeft;
+    int mRight;
+    Split() : mLeft(0), mRight(0){}
+    int left() { return mLeft; }
+    int right() { return mRight; }
+    friend class MDPVersion;
+};
 
 class MDPVersion : public Singleton <MDPVersion>
 {
@@ -91,6 +101,8 @@
     uint32_t getMaxMDPDownscale();
     bool supportsBWC();
     bool is8x26();
+    int getLeftSplit() { return mSplit.left(); }
+    int getRightSplit() { return mSplit.right(); }
 private:
     int mMDPVersion;
     char mPanelType;
@@ -101,6 +113,7 @@
     uint8_t mDMAPipes;
     uint32_t mFeatures;
     uint32_t mMDPDownscale;
+    Split mSplit;
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER