hwc: Partial update support for ping pong split.

ping-pong split needs source split to be enabled to stage two
pipes of a layer in the same Z order. This change adds partial
update support to generate ROI when source split is enabled.
When configured, ping-pong-split splits the layer mixer output equally
across two DSI's. To meet this limitation, the generated ROI is
adjusted to have equal widths from the panel mid point.

Change-Id: Ic307a1d5b902af9e352b0dfc6f5ab474ecd9c8a4
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 7f31ad0..f3cd5f7 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -525,9 +525,11 @@
     return ret;
 }
 
-void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect &crop,
+        hwc_rect &dst) {
     hwc_rect_t roi = ctx->listStats[mDpy].lRoi;
-    fbRect = getIntersection(fbRect, roi);
+    dst = getIntersection(dst, roi);
+    crop = dst;
 }
 
 /* 1) Identify layers that are not visible or lying outside the updating ROI and
@@ -622,14 +624,20 @@
             ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom);
 }
 
-void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
-    hwc_rect l_roi = ctx->listStats[mDpy].lRoi;
-    hwc_rect r_roi = ctx->listStats[mDpy].rRoi;
-
-    hwc_rect_t l_fbRect = getIntersection(fbRect, l_roi);
-    hwc_rect_t r_fbRect = getIntersection(fbRect, r_roi);
-    fbRect = getUnion(l_fbRect, r_fbRect);
+void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect &crop,
+        hwc_rect &dst) {
+    hwc_rect roi = getUnion(ctx->listStats[mDpy].lRoi,
+            ctx->listStats[mDpy].rRoi);
+    hwc_rect tmpDst = getIntersection(dst, roi);
+    if(!isSameRect(dst, tmpDst)) {
+        crop.left = crop.left + (tmpDst.left - dst.left);
+        crop.top = crop.top + (tmpDst.top - dst.top);
+        crop.right = crop.left + (tmpDst.right - tmpDst.left);
+        crop.bottom = crop.top + (tmpDst.bottom - tmpDst.top);
+        dst = tmpDst;
+    }
 }
+
 /* 1) Identify layers that are not visible or lying outside BOTH the updating
  *    ROI's and drop them from composition. If a layer is spanning across both
  *    the halves of the screen but needed by only ROI, the non-contributing
@@ -1761,7 +1769,7 @@
             fbRect = getUnion(fbRect, dst);
         }
     }
-    trimAgainstROI(ctx, fbRect);
+    trimAgainstROI(ctx, fbRect, fbRect);
     return fbRect;
 }
 
@@ -2608,6 +2616,122 @@
 }
 
 //================MDPCompSrcSplit==============================================
+
+bool MDPCompSrcSplit::validateAndApplyROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    hwc_rect_t visibleRect = ctx->listStats[mDpy].lRoi;
+
+    for(int i = numAppLayers - 1; i >= 0; i--) {
+        if(!isValidRect(visibleRect)) {
+            mCurrentFrame.drop[i] = true;
+            mCurrentFrame.dropCount++;
+            continue;
+        }
+
+        const hwc_layer_1_t* layer =  &list->hwLayers[i];
+        hwc_rect_t dstRect = layer->displayFrame;
+        hwc_rect_t res  = getIntersection(visibleRect, dstRect);
+
+        if(!isValidRect(res)) {
+            mCurrentFrame.drop[i] = true;
+            mCurrentFrame.dropCount++;
+        } else {
+            /* Reset frame ROI when any layer which needs scaling also needs ROI
+             * cropping */
+            if(!isSameRect(res, dstRect) && needsScaling (layer)) {
+                ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
+                memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+                mCurrentFrame.dropCount = 0;
+                return false;
+            }
+
+            /* deduct any opaque region from visibleRect */
+            if (layer->blending == HWC_BLENDING_NONE &&
+                    layer->planeAlpha == 0xFF)
+                visibleRect = deductRect(visibleRect, res);
+        }
+    }
+    return true;
+}
+
+/*
+ * HW Limitation: ping pong split can always split the ping pong output
+ * equally across two DSI's. So the ROI programmed should be of equal width
+ * for both the halves
+ */
+void MDPCompSrcSplit::generateROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+
+    if(!canPartialUpdate(ctx, list))
+        return;
+
+    struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
+    hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+        (int)ctx->dpyAttr[mDpy].yres};
+
+    for(int index = 0; index < numAppLayers; index++ ) {
+        hwc_layer_1_t* layer = &list->hwLayers[index];
+
+        // If we have a RGB layer which needs rotation, no partial update
+        if(!isYuvBuffer((private_handle_t *)layer->handle) && layer->transform)
+            return;
+
+        if ((mCachedFrame.hnd[index] != layer->handle) ||
+                isYuvBuffer((private_handle_t *)layer->handle)) {
+            hwc_rect_t dst = layer->displayFrame;
+            hwc_rect_t updatingRect = dst;
+
+#ifdef QCOM_BSP
+            if(!needsScaling(layer) && !layer->transform)
+            {
+                hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf);
+                int x_off = dst.left - src.left;
+                int y_off = dst.top - src.top;
+                updatingRect = moveRect(layer->dirtyRect, x_off, y_off);
+            }
+#endif
+
+            roi = getUnion(roi, updatingRect);
+        }
+    }
+
+    /* No layer is updating. Still SF wants a refresh.*/
+    if(!isValidRect(roi))
+        return;
+
+    roi = expandROIFromMidPoint(roi, fullFrame);
+
+    hwc_rect lFrame = fullFrame;
+    lFrame.right /= 2;
+    hwc_rect lRoi = getIntersection(roi, lFrame);
+
+    // Align ROI coordinates to panel restrictions
+    lRoi = getSanitizeROI(lRoi, lFrame);
+
+    hwc_rect rFrame = fullFrame;
+    rFrame.left = lFrame.right;
+    hwc_rect rRoi = getIntersection(roi, rFrame);
+
+    // Align ROI coordinates to panel restrictions
+    rRoi = getSanitizeROI(rRoi, rFrame);
+
+    roi = getUnion(lRoi, rRoi);
+
+    ctx->listStats[mDpy].lRoi = roi;
+    if(!validateAndApplyROI(ctx, list))
+        resetROI(ctx, mDpy);
+
+    ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d] [%d, %d, %d, %d]",
+            __FUNCTION__,
+            ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+            ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom,
+            ctx->listStats[mDpy].rRoi.left, ctx->listStats[mDpy].rRoi.top,
+            ctx->listStats[mDpy].rRoi.right, ctx->listStats[mDpy].rRoi.bottom);
+}
+
 bool MDPCompSrcSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
         MdpPipeInfoSplit& pipe_info) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -2616,6 +2740,9 @@
     pipe_info.lIndex = ovutils::OV_INVALID;
     pipe_info.rIndex = ovutils::OV_INVALID;
 
+    if(qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() && !mDpy)
+        trimAgainstROI(ctx,crop, dst);
+
     //If 2 pipes are staged on a single stage of a mixer, then the left pipe
     //should have a higher priority than the right one. Pipe priorities are
     //starting with VG0, VG1 ... , RGB0 ..., DMA1
@@ -2703,6 +2830,17 @@
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
              "dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
 
+    if(qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() && !mDpy) {
+        /* MDP driver crops layer coordinates against ROI in Non-Split
+         * and Split MDP comp. But HWC needs to crop them for source split.
+         * Reason: 1) Source split is efficient only when the final effective
+         *            load is distributed evenly across mixers.
+         *         2) We have to know the effective width of the layer that
+         *            the ROI needs to find the no. of pipes the layer needs.
+         */
+        trimAgainstROI(ctx, crop, dst);
+    }
+
     // Handle R/B swap
     if (layer->flags & HWC_FORMAT_RB_SWAP) {
         if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 302b047..7c46c1a 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -160,9 +160,9 @@
     /* validates the ROI generated for fallback conditions */
     virtual bool validateAndApplyROI(hwc_context_t *ctx,
             hwc_display_contents_1_t* list) = 0;
-    /* Trims fbRect calculated against ROI generated */
-    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) = 0;
-
+    /* Trims layer coordinates against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+            hwc_rect& dst) = 0;
     /* set/reset flags for MDPComp */
     void setMDPCompLayerFlags(hwc_context_t *ctx,
                               hwc_display_contents_1_t* list);
@@ -315,8 +315,9 @@
     /* validates the ROI generated for fallback conditions */
     virtual bool validateAndApplyROI(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
-    /* Trims fbRect calculated against ROI generated */
-    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
+    /* Trims layer coordinates against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+            hwc_rect& dst);
 };
 
 class MDPCompSplit : public MDPComp {
@@ -342,6 +343,9 @@
     /* allocates pipes to selected candidates */
     virtual bool allocLayerPipes(hwc_context_t *ctx,
                                  hwc_display_contents_1_t* list);
+    /* Trims layer coordinates against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+            hwc_rect& dst);
 private:
     /* Increments mdpCount if 4k2k yuv layer split is enabled.
      * updates framebuffer z order if fb lies above source-split layer */
@@ -357,8 +361,6 @@
     /* validates the ROI generated for fallback conditions */
     virtual bool validateAndApplyROI(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
-    /* Trims fbRect calculated against ROI generated */
-    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
 };
 
 class MDPCompSrcSplit : public MDPCompSplit {
@@ -371,6 +373,12 @@
 
     virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
             PipeLayerPair& pipeLayerPair);
+    /* generates ROI based on the modified area of the frame */
+    virtual void generateROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* validates the ROI generated for fallback conditions */
+    virtual bool validateAndApplyROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
 };
 
 }; //namespace
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index bc3491e..e3ba83d 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -2577,6 +2577,30 @@
     }
 }
 
+hwc_rect expandROIFromMidPoint(hwc_rect roi, hwc_rect fullFrame) {
+    int lRoiWidth = 0, rRoiWidth = 0;
+    int half_frame_width = fullFrame.right/2;
+
+    hwc_rect lFrame = fullFrame;
+    hwc_rect rFrame = fullFrame;
+    lFrame.right = (lFrame.right - lFrame.left)/2;
+    rFrame.left = lFrame.right;
+
+    hwc_rect lRoi = getIntersection(roi, lFrame);
+    hwc_rect rRoi = getIntersection(roi, rFrame);
+
+    lRoiWidth = lRoi.right - lRoi.left;
+    rRoiWidth = rRoi.right - rRoi.left;
+
+    if(lRoiWidth && rRoiWidth) {
+        if(lRoiWidth < rRoiWidth)
+            roi.left = half_frame_width - rRoiWidth;
+        else
+            roi.right = half_frame_width + lRoiWidth;
+    }
+    return roi;
+}
+
 void resetROI(hwc_context_t *ctx, const int dpy) {
     const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
     const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 797f9b0..d419213 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -352,6 +352,9 @@
 // Resets display ROI to full panel resoluion
 void resetROI(hwc_context_t *ctx, const int dpy);
 
+// Modifies ROI even from middle of the screen
+hwc_rect expandROIFromMidPoint(hwc_rect roi, hwc_rect fullFrame);
+
 // Aligns updating ROI to panel restrictions
 hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary);