hwc: Dynamic Resolution support on Primary

    * Useful to estimate GPU/MDP performance for different resolutions.
    * MDP:
      Every layer is downscaled/upscaled to primary panel resolution.
    * GPU:
      All layers will be composed in required resolution to FB.
      FB is downscaled/upscaled to primary panel resolution.
    * Steps to follow:
          step 1: adb root
          step 2: adb shell setprop debug.hwc.fbsize XRESxYRES
          step 3: adb shell stop
          step 4: adb shell start

Change-Id: I82a032df87c91549c49a9cdbd981ff02f105ff2e
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index dcad00b..8048f32 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * Not a Contribution, Apache license notifications and license are retained
  * for attribution purposes only.
@@ -132,6 +132,38 @@
         ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
 }
 
+bool isEqual(float f1, float f2) {
+        return ((int)(f1*100) == (int)(f2*100)) ? true : false;
+}
+
+static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
+                            hwc_display_contents_1_t *list) {
+    float origXres = ctx->dpyAttr[dpy].xres_orig;
+    float origYres = ctx->dpyAttr[dpy].yres_orig;
+    float fakeXres = ctx->dpyAttr[dpy].xres;
+    float fakeYres = ctx->dpyAttr[dpy].yres;
+    float xresRatio = origXres / fakeXres;
+    float yresRatio = origYres / fakeYres;
+    for (size_t i = 0; i < list->numHwLayers; i++) {
+        hwc_layer_1_t *layer = &list->hwLayers[i];
+        hwc_rect_t& displayFrame = layer->displayFrame;
+        hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+        float layerWidth = displayFrame.right - displayFrame.left;
+        float layerHeight = displayFrame.bottom - displayFrame.top;
+        float sourceWidth = sourceCrop.right - sourceCrop.left;
+        float sourceHeight = sourceCrop.bottom - sourceCrop.top;
+
+        if (isEqual(layerWidth / sourceWidth, xresRatio) &&
+                isEqual(layerHeight / sourceHeight, yresRatio))
+            break;
+
+        displayFrame.left = xresRatio * displayFrame.left;
+        displayFrame.top = yresRatio * displayFrame.top;
+        displayFrame.right = displayFrame.left + layerWidth * xresRatio;
+        displayFrame.bottom = displayFrame.top + layerHeight * yresRatio;
+    }
+}
+
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     ATRACE_CALL();
@@ -139,6 +171,10 @@
     const int dpy = HWC_DISPLAY_PRIMARY;
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive) {
+
+        if (ctx->dpyAttr[dpy].customFBSize)
+            scaleDisplayFrame(ctx, dpy, list);
+
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
         setListStats(ctx, list, dpy);
 #ifdef VPU_TARGET
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 6bc2e75..0123452 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * Not a Contribution, Apache license notifications and license are
  * retained for attribution purposes only.
@@ -167,12 +167,12 @@
         // Dont do wormhole calculation when extDownscale is enabled on External
         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
             sourceCrop = layer->displayFrame;
-            displayFrame = sourceCrop;
         } else if((!mDpy ||
-                   (mDpy && !extOrient
-                   && !ctx->dpyAttr[mDpy].mDownScaleMode))
-                   && (extOnlyLayerIndex == -1)) {
-            if(!qdutils::MDPVersion::getInstance().is8x26()) {
+                  (mDpy && !extOrient
+                  && !ctx->dpyAttr[mDpy].mDownScaleMode))
+                  && (extOnlyLayerIndex == -1)) {
+            if(!qdutils::MDPVersion::getInstance().is8x26() &&
+                !ctx->dpyAttr[mDpy].customFBSize) {
                 getNonWormholeRegion(list, sourceCrop);
                 displayFrame = sourceCrop;
             }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index d47e120..dce1e0e 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation All rights reserved.
  *
  * Not a Contribution, Apache license notifications and license are retained
  * for attribution purposes only.
@@ -54,6 +54,34 @@
 
 namespace qhwc {
 
+bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres)
+{
+    return !((xres > qdutils::MAX_DISPLAY_DIM &&
+                !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) ||
+            (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
+}
+
+void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig) {
+    //Store original display resolution.
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_orig = xres_orig;
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_orig = yres_orig;
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
+
+    char property[PROPERTY_VALUE_MAX] = {'\0'};
+    char *yptr = NULL;
+    if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
+        yptr = strcasestr(property,"x");
+        int xres = atoi(property);
+        int yres = atoi(yptr + 1);
+        if (isValidResolution(ctx,xres,yres) &&
+                 xres != xres_orig && yres != yres_orig) {
+            ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = xres;
+            ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = yres;
+            ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+        }
+    }
+}
+
 static int openFramebufferDevice(hwc_context_t *ctx)
 {
     struct fb_fix_screeninfo finfo;
@@ -117,6 +145,9 @@
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period = 1000000000l / fps;
 
+    //To change resolution of primary display
+    changeResolution(ctx, info.xres, info.yres);
+
     //Unblank primary on first boot
     if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
         ALOGE("%s: Failed to unblank display", __FUNCTION__);
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index e64f89c..22debaf 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -35,6 +35,8 @@
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 #define MAX_NUM_APP_LAYERS 32
+#define MIN_DISPLAY_XRES 200
+#define MIN_DISPLAY_YRES 200
 
 //Fwrd decls
 struct hwc_context_t;
@@ -95,6 +97,13 @@
     bool mActionSafePresent;
     int mAsWidthRatio;
     int mAsHeightRatio;
+
+    //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
+    //following fields are used.
+    bool customFBSize;
+    uint32_t xres_orig;
+    uint32_t yres_orig;
+
 };
 
 struct ListStats {