libhwcomposer: Optimize layer crops when possible.

With in hwc list of layers if a layer above is opaque,
deduct the opaque layers crops from all the layers below
in z-order if deduction is possible with out creating
any hole.

Change-Id: I6391a13b0501cb972b134f72b58514cb807c7613
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9837bd1..ec0644f 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -709,6 +709,8 @@
     ctx->listStats[dpy].extOnlyLayerIndex = -1;
     ctx->listStats[dpy].isDisplayAnimating = false;
 
+    optimizeLayerRects(ctx, list, dpy);
+
     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;
@@ -915,6 +917,89 @@
     crop_b -= crop_h * bottomCutRatio;
 }
 
+bool isValidRect(hwc_rect_t& rect) {
+    return ((rect.bottom > rect.top) && (rect.right > rect.left)) ;
+}
+
+/* computes intersection of two rects into 3rd arg/rect */
+void getIntersection(hwc_rect_t& rect1,
+                        hwc_rect_t& rect2, hwc_rect_t& irect) {
+    irect.left   = max(rect1.left, rect2.left);
+    irect.top    = max(rect1.top, rect2.top);
+    irect.right  = min(rect1.right, rect2.right);
+    irect.bottom = min(rect1.bottom, rect2.bottom);
+}
+
+/* get union of two rects into 3rd rect */
+void getUnion(hwc_rect_t& rect1,
+                        hwc_rect_t& rect2, hwc_rect_t& irect) {
+    irect.left   = min(rect1.left, rect2.left);
+    irect.top    = min(rect1.top, rect2.top);
+    irect.right  = max(rect1.right, rect2.right);
+    irect.bottom = max(rect1.bottom, rect2.bottom);
+}
+
+/* deducts given rect from layers display-frame and source crop.
+   also it avoid hole creation.*/
+void deductRect(const hwc_layer_1_t* layer, hwc_rect_t& irect) {
+    hwc_rect_t& disprect = (hwc_rect_t&)layer->displayFrame;
+    hwc_rect_t& srcrect = (hwc_rect_t&)layer->sourceCrop;
+    int irect_w = irect.right - irect.left;
+    int irect_h = irect.bottom - irect.top;
+
+    if((disprect.left == irect.left) && (disprect.right == irect.right)) {
+        if((disprect.top == irect.top) && (irect.bottom <= disprect.bottom)) {
+            disprect.top = irect.bottom;
+            srcrect.top += irect_h;
+        }
+        else if((disprect.bottom == irect.bottom)
+                                && (irect.top >= disprect.top)) {
+            disprect.bottom = irect.top;
+            srcrect.bottom -= irect_h;
+        }
+    }
+    else if((disprect.top == irect.top) && (disprect.bottom == irect.bottom)) {
+        if((disprect.left == irect.left) && (irect.right <= disprect.right)) {
+            disprect.left = irect.right;
+            srcrect.left += irect_w;
+        }
+        else if((disprect.right == irect.right)
+                                && (irect.left >= disprect.left)) {
+            disprect.right = irect.left;
+            srcrect.right -= irect_w;
+        }
+    }
+}
+
+void optimizeLayerRects(hwc_context_t *ctx,
+                        const hwc_display_contents_1_t *list, const int& dpy) {
+    int i=list->numHwLayers-2;
+    hwc_rect_t irect;
+    while(i > 0) {
+
+        //see if there is no blending required.
+        //If it is opaque see if we can substract this region from below layers.
+        if(list->hwLayers[i].blending == HWC_BLENDING_NONE) {
+            int j= i-1;
+            hwc_rect_t& topframe =
+                (hwc_rect_t&)list->hwLayers[i].displayFrame;
+            while(j >= 0) {
+                if(!needsScaling(ctx, &list->hwLayers[j], dpy)) {
+                    hwc_rect_t& bottomframe =
+                        (hwc_rect_t&)list->hwLayers[j].displayFrame;
+                    getIntersection(bottomframe, topframe, (hwc_rect_t&)irect);
+                    if(isValidRect(irect)) {
+                        //if intersection is valid rect, deduct it
+                        deductRect(&list->hwLayers[j], irect);
+                    }
+                }
+                j--;
+            }
+        }
+        i--;
+    }
+}
+
 void getNonWormholeRegion(hwc_display_contents_1_t* list,
                               hwc_rect_t& nwr)
 {
@@ -928,18 +1013,11 @@
 
     for (uint32_t i = 1; i < last; i++) {
         hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
-        nwr.left   = min(nwr.left, displayFrame.left);
-        nwr.top    = min(nwr.top, displayFrame.top);
-        nwr.right  = max(nwr.right, displayFrame.right);
-        nwr.bottom = max(nwr.bottom, displayFrame.bottom);
+        getUnion(nwr, displayFrame, nwr);
     }
 
     //Intersect with the framebuffer
-    nwr.left   = max(nwr.left, fbDisplayFrame.left);
-    nwr.top    = max(nwr.top, fbDisplayFrame.top);
-    nwr.right  = min(nwr.right, fbDisplayFrame.right);
-    nwr.bottom = min(nwr.bottom, fbDisplayFrame.bottom);
-
+    getIntersection(nwr, fbDisplayFrame, nwr);
 }
 
 bool isExternalActive(hwc_context_t* ctx) {