Merge "hwc: On downscale check swap on 90 transform"
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index b1d7616..59f6245 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -474,9 +474,18 @@
 
     ovutils::eDest destR = ovutils::OV_INVALID;
 
-    //Request right pipe (2 pipes needed only if dim > 2048)
-    if((fbUpdatingRect.right - fbUpdatingRect.left) >
-            qdutils::MAX_DISPLAY_DIM) {
+    /*  Use 2 pipes IF
+        a) FB's width is > 2048 or
+        b) On primary, driver has indicated with caps to split always. This is
+           based on an empirically derived value of panel height.
+    */
+
+    bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+            qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+
+    if(((fbUpdatingRect.right - fbUpdatingRect.left) >
+            qdutils::MAX_DISPLAY_DIM) or
+            primarySplitAlways) {
         destR = ov.getPipe(pipeSpecs);
         if(destR == ovutils::OV_INVALID) {
             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index b80046e..b0953da 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -2185,9 +2185,23 @@
         return false;
     }
 
-    //If layer's crop width or dest width > 2048, use 2 pipes
-    if((dst.right - dst.left) > qdutils::MAX_DISPLAY_DIM or
-            (crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+    /* Use 2 pipes IF
+        a) Layer's crop width is > 2048 or
+        b) Layer's dest width > 2048 or
+        c) On primary, driver has indicated with caps to split always. This is
+           based on an empirically derived value of panel height. Applied only
+           if the layer's width is > mixer's width
+    */
+
+    bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+            qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+    int lSplit = getLeftSplit(ctx, mDpy);
+    int dstWidth = dst.right - dst.left;
+    int cropWidth = crop.right - crop.left;
+
+    if(dstWidth > qdutils::MAX_DISPLAY_DIM or
+            cropWidth > qdutils::MAX_DISPLAY_DIM or
+            (primarySplitAlways and (cropWidth > lSplit))) {
         pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
         if(pipe_info.rIndex == ovutils::OV_INVALID) {
             return false;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 0bb71f0..77215ca 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -193,6 +193,26 @@
     }
 }
 
+
+static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
+    int dpy = inParcel->readInt32();
+    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+        Locker::Autolock _sl(ctx->mDrawLock);
+        ctx->mViewFrame[dpy].left   = inParcel->readInt32();
+        ctx->mViewFrame[dpy].top    = inParcel->readInt32();
+        ctx->mViewFrame[dpy].right  = inParcel->readInt32();
+        ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
+        ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
+            __FUNCTION__, dpy,
+            ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
+            ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
+        return NO_ERROR;
+    } else {
+        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
+        return BAD_VALUE;
+    }
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -232,6 +252,9 @@
         case IQService::SET_WFD_STATUS:
             setWfdStatus(mHwcContext,inParcel->readInt32());
             break;
+        case IQService::SET_VIEW_FRAME:
+            setViewFrame(mHwcContext, inParcel);
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 94a396c..671388b 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -292,7 +292,7 @@
 
     ctx->mGPUHintInfo.mEGLDisplay = NULL;
     ctx->mGPUHintInfo.mEGLContext = NULL;
-    ctx->mGPUHintInfo.mPrevCompositionGLES = false;
+    ctx->mGPUHintInfo.mCompositionState = COMPOSITION_STATE_MDP;
     ctx->mGPUHintInfo.mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
 #endif
     ALOGI("Initializing Qualcomm Hardware Composer");
@@ -810,28 +810,6 @@
     }
 }
 
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy) {
-    int dstWidth = ctx->dpyAttr[dpy].xres;
-    int dstHeight = ctx->dpyAttr[dpy].yres;
-    int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
-    int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
-    // default we assume viewframe as a full frame for primary display
-    hwc_rect outRect = {0, 0, dstWidth, dstHeight};
-    if(dpy) {
-        // swap srcWidth and srcHeight, if the device orientation is 90 or 270.
-        if(ctx->deviceOrientation & 0x1) {
-            swap(srcWidth, srcHeight);
-        }
-        // Get Aspect Ratio for external
-        getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
-                            srcHeight, outRect);
-    }
-    ALOGD_IF(HWC_UTILS_DEBUG, "%s: view frame for dpy %d is [%d %d %d %d]",
-        __FUNCTION__, dpy, outRect.left, outRect.top,
-        outRect.right, outRect.bottom);
-    return outRect;
-}
-
 void setListStats(hwc_context_t *ctx,
         hwc_display_contents_1_t *list, int dpy) {
     const int prevYuvCount = ctx->listStats[dpy].yuvCount;
@@ -847,19 +825,13 @@
     ctx->listStats[dpy].isDisplayAnimating = false;
     ctx->listStats[dpy].secureUI = false;
     ctx->listStats[dpy].yuv4k2kCount = 0;
-    ctx->mViewFrame[dpy] = (hwc_rect_t){0, 0, 0, 0};
     ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
     ctx->listStats[dpy].renderBufIndexforABC = -1;
 
     resetROI(ctx, dpy);
 
-    // Calculate view frame of ext display from primary resolution
-    // and primary device orientation.
-    ctx->mViewFrame[dpy] = calculateDisplayViewFrame(ctx, dpy);
-
     trimList(ctx, list, dpy);
     optimizeLayerRects(list);
-
     for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) {
         hwc_layer_1_t const* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -2139,7 +2111,8 @@
         }
     }
     if(isGLESComp(ctx, list)) {
-        if(!gpuHint->mPrevCompositionGLES && !MDPComp::isIdleFallback()) {
+        if(gpuHint->mCompositionState != COMPOSITION_STATE_GPU
+            && !MDPComp::isIdleFallback()) {
             EGLint attr_list[] = {EGL_GPU_HINT_1,
                                   EGL_GPU_LEVEL_3,
                                   EGL_NONE };
@@ -2149,7 +2122,7 @@
                 ALOGW("eglGpuPerfHintQCOM failed for Built in display");
             } else {
                 gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_3;
-                gpuHint->mPrevCompositionGLES = true;
+                gpuHint->mCompositionState = COMPOSITION_STATE_GPU;
             }
         } else {
             EGLint attr_list[] = {EGL_GPU_HINT_1,
@@ -2162,6 +2135,9 @@
             } else {
                 gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
             }
+            if(MDPComp::isIdleFallback()) {
+                gpuHint->mCompositionState = COMPOSITION_STATE_IDLE_FALLBACK;
+            }
         }
     } else {
         /* set the GPU hint flag to default for MDP composition */
@@ -2175,7 +2151,7 @@
         } else {
             gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
         }
-        gpuHint->mPrevCompositionGLES = false;
+        gpuHint->mCompositionState = COMPOSITION_STATE_MDP;
     }
 #endif
 }
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 5086d72..06f7f9f 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -224,11 +224,6 @@
 // -----------------------------------------------------------------------------
 // Utility functions - implemented in hwc_utils.cpp
 void dumpLayer(hwc_layer_1_t const* l);
-
-// Calculate viewframe for external/primary display from primary resolution and
-// primary device orientation
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy);
-
 void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
         int dpy);
 void initContext(hwc_context_t *ctx);
@@ -478,14 +473,20 @@
     ANIMATION_STARTED,
 };
 
+enum eCompositionState {
+    COMPOSITION_STATE_MDP = 0,        // Set if composition type is MDP
+    COMPOSITION_STATE_GPU,            // Set if composition type is GPU or MIXED
+    COMPOSITION_STATE_IDLE_FALLBACK,  // Set if it is idlefallback
+};
+
 // Structure holds the information about the GPU hint.
 struct gpu_hint_info {
     // system level flag to enable gpu_perf_mode
     bool mGpuPerfModeEnable;
     // Stores the current GPU performance mode DEFAULT/HIGH
     bool mCurrGPUPerfMode;
-    // true if previous composition used GPU
-    bool mPrevCompositionGLES;
+    // Stores the compositon state GPU, MDP or IDLE_FALLBACK
+    bool mCompositionState;
     // Stores the EGLContext of current process
     EGLContext mEGLContext;
     // Stores the EGLDisplay of current process
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 60f1f68..7ff106f 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -113,4 +113,25 @@
     return err;
 }
 
+int setViewFrame(int dpy, int l, int t, int r, int b) {
+    status_t err = (status_t) FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+    inParcel.writeInt32(dpy);
+    inParcel.writeInt32(l);
+    inParcel.writeInt32(t);
+    inParcel.writeInt32(r);
+    inParcel.writeInt32(b);
+
+    if(binder != NULL) {
+        err = binder->dispatch(IQService::SET_VIEW_FRAME,
+                &inParcel, &outParcel);
+    }
+    if(err)
+        ALOGE("%s: Failed to set view frame for dpy %d err=%d",
+                            __FUNCTION__, dpy, err);
+
+    return err;
+}
+
 }; //namespace
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 29edbef..a69265b 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -73,4 +73,7 @@
 // get the active visible region for the display
 // Returns 0 on success, negative values on errors
 int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect);
+
+// set the view frame information in hwc context from surfaceflinger
+int setViewFrame(int dpy, int l, int t, int r, int b);
 }; //namespace
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 96ed4d2..bc63ddf 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -88,6 +88,7 @@
     mLowBw = 0;
     mHighBw = 0;
     mSourceSplit = false;
+    mSourceSplitAlways = false;
     mRGBHasNoScalar = false;
 
     updatePanelInfo();
@@ -306,6 +307,30 @@
         free(line);
         fclose(sysfsFd);
     }
+
+    if(mSourceSplit) {
+        memset(sysfsPath, 0, sizeof(sysfsPath));
+        snprintf(sysfsPath , sizeof(sysfsPath),
+                "/sys/class/graphics/fb0/msm_fb_src_split_info");
+
+        sysfsFd = fopen(sysfsPath, "rb");
+        if (sysfsFd == NULL) {
+            ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__,
+                    sysfsPath, strerror(errno));
+            return false;
+        } else {
+            line = (char *) malloc(len);
+            if((read = getline(&line, &len, sysfsFd)) != -1) {
+                if(!strncmp(line, "src_split_always",
+                        strlen("src_split_always"))) {
+                    mSourceSplitAlways = true;
+                }
+            }
+            free(line);
+            fclose(sysfsFd);
+        }
+    }
+
     ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
                     "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
                     mRGBPipes, mVGPipes);
@@ -371,6 +396,10 @@
     return mSourceSplit;
 }
 
+bool MDPVersion::isSrcSplitAlways() const {
+    return mSourceSplitAlways;
+}
+
 bool MDPVersion::isRGBScalarSupported() const {
     return (!mRGBHasNoScalar);
 }
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index e862d2d..8bb9c39 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -140,6 +140,7 @@
     unsigned long getLowBw() { return mLowBw; }
     unsigned long getHighBw() { return mHighBw; }
     bool isSrcSplit() const;
+    bool isSrcSplitAlways() const;
     bool isRGBScalarSupported() const;
     bool is8x26();
     bool is8x74v2();
@@ -170,6 +171,8 @@
     unsigned long mLowBw; //kbps
     unsigned long mHighBw; //kbps
     bool mSourceSplit;
+    //Additional property on top of source split
+    bool mSourceSplitAlways;
     bool mRGBHasNoScalar;
 };
 }; //namespace qdutils
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 02f7341..5c9acf7 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -51,6 +51,7 @@
         GET_DISPLAY_VISIBLE_REGION,  // Get the visibleRegion for dpy
         PAUSE_WFD,               // Pause/Resume WFD
         SET_WFD_STATUS,          // Set if wfd connection is on/off
+        SET_VIEW_FRAME,          // Set view frame of display
         COMMAND_LIST_END = 400,
     };