Merge "hwc: Add msm8x09 version checks in HAL."
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 582b102..67cca88 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -96,7 +96,7 @@
         int fbWidth =  ctx->dpyAttr[dpy].xres;
         int fbHeight =  ctx->dpyAttr[dpy].yres;
         unsigned int fbArea = (fbWidth * fbHeight);
-        unsigned int renderArea = getRGBRenderingArea(list);
+        unsigned int renderArea = getRGBRenderingArea(ctx, list);
             ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u",
                                   __FUNCTION__, renderArea, fbArea);
         if (renderArea < (mDynThreshold * fbArea)) {
@@ -112,8 +112,8 @@
     return false;
 }
 
-unsigned int CopyBit::getRGBRenderingArea
-                                    (const hwc_display_contents_1_t *list) {
+unsigned int CopyBit::getRGBRenderingArea (const hwc_context_t *ctx,
+                                     const hwc_display_contents_1_t *list) {
     //Calculates total rendering area for RGB layers
     unsigned int renderArea = 0;
     unsigned int w=0, h=0;
@@ -122,7 +122,7 @@
     for (unsigned int i=0; i<list->numHwLayers -1; i++) {
          private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
          if (hnd) {
-             if (BUFFER_TYPE_UI == hnd->bufferType) {
+             if (BUFFER_TYPE_UI == hnd->bufferType && !ctx->copybitDrop[i]) {
                  getLayerResolution(&list->hwLayers[i], w, h);
                  renderArea += (w*h);
              }
@@ -316,6 +316,9 @@
         for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
             int dst_h, dst_w, src_h, src_w;
             float dx, dy;
+            if(ctx->copybitDrop[i]) {
+                continue;
+            }
             hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
             if (layer->planeAlpha != 0xFF)
                 return true;
@@ -544,6 +547,9 @@
             ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
             continue;
         }
+        if(ctx->copybitDrop[i]) {
+            continue;
+        }
         //skip non updating layers
         if((mDirtyLayerIndex != -1) && (mDirtyLayerIndex != i) )
             continue;
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 99a39c8..a7ce43e 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -101,8 +101,8 @@
     // flag that indicates whether CopyBit composition is enabled for this cycle
     bool mCopyBitDraw;
 
-    unsigned int getRGBRenderingArea
-                            (const hwc_display_contents_1_t *list);
+    unsigned int getRGBRenderingArea (const hwc_context_t *ctx,
+                                         const hwc_display_contents_1_t *list);
 
     void getLayerResolution(const hwc_layer_1_t* layer,
                                    unsigned int &width, unsigned int& height);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 82d1f05..e24925a 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -36,7 +36,7 @@
 
 //==============MDPComp========================================================
 
-IdleInvalidator *MDPComp::idleInvalidator = NULL;
+IdleInvalidator *MDPComp::sIdleInvalidator = NULL;
 bool MDPComp::sIdleFallBack = false;
 bool MDPComp::sHandleTimeout = false;
 bool MDPComp::sDebugLogs = false;
@@ -46,6 +46,7 @@
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
 bool MDPComp::sEnableYUVsplit = false;
 bool MDPComp::sSrcSplitEnabled = false;
+bool MDPComp::enablePartialUpdateForMDP3 = false;
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
         sSrcSplitEnabled = true;
@@ -110,7 +111,7 @@
         return false;
     }
 
-    char property[PROPERTY_VALUE_MAX];
+    char property[PROPERTY_VALUE_MAX] = {0};
 
     sEnabled = false;
     if((property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) &&
@@ -134,23 +135,10 @@
     }
 
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
-        // Idle invalidation is not necessary on command mode panels
-        long idle_timeout = DEFAULT_IDLE_TIME;
-        if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
-            if(atoi(property) != 0)
-                idle_timeout = atoi(property);
-        }
-
-        //create Idle Invalidator only when not disabled through property
-        if(idle_timeout != -1)
-            idleInvalidator = IdleInvalidator::getInstance();
-
-        if(idleInvalidator == NULL) {
-            ALOGE("%s: failed to instantiate idleInvalidator object",
-                  __FUNCTION__);
-        } else {
-            idleInvalidator->init(timeout_handler, ctx,
-                                  (unsigned int)idle_timeout);
+        sIdleInvalidator = IdleInvalidator::getInstance();
+        if(sIdleInvalidator->init(timeout_handler, ctx) < 0) {
+            delete sIdleInvalidator;
+            sIdleInvalidator = NULL;
         }
     }
 
@@ -162,13 +150,32 @@
         sEnableYUVsplit = true;
     }
 
-    if ((property_get("persist.hwc.ptor.enable", property, NULL) > 0) &&
-            ((!strncasecmp(property, "true", PROPERTY_VALUE_MAX )) ||
-             (!strncmp(property, "1", PROPERTY_VALUE_MAX )))) {
+    bool defaultPTOR = false;
+    //Enable PTOR when "persist.hwc.ptor.enable" is not defined for
+    //8x16 and 8x39 targets by default
+    if((property_get("persist.hwc.ptor.enable", property, NULL) <= 0) &&
+            (qdutils::MDPVersion::getInstance().is8x16() ||
+                qdutils::MDPVersion::getInstance().is8x39())) {
+        defaultPTOR = true;
+    }
+
+    if (defaultPTOR || (!strncasecmp(property, "true", PROPERTY_VALUE_MAX)) ||
+                (!strncmp(property, "1", PROPERTY_VALUE_MAX ))) {
         ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
                                                     HWC_DISPLAY_PRIMARY);
     }
 
+    if((property_get("persist.mdp3.partialUpdate", property, NULL) <= 0) &&
+          (ctx->mMDP.version == qdutils::MDP_V3_0_5)) {
+       enablePartialUpdateForMDP3 = true;
+    }
+
+    if(!enablePartialUpdateForMDP3 &&
+          (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+           (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+       enablePartialUpdateForMDP3 = true;
+    }
+
     return true;
 }
 
@@ -206,6 +213,25 @@
     ctx->proc->invalidate(ctx->proc);
 }
 
+void MDPComp::setIdleTimeout(const uint32_t& timeout) {
+    enum { ONE_REFRESH_PERIOD_MS = 17, ONE_BILLION_MS = 1000000000 };
+
+    if(sIdleInvalidator) {
+        if(timeout <= ONE_REFRESH_PERIOD_MS) {
+            //If the specified timeout is < 1 draw cycle worth, "virtually"
+            //disable idle timeout. The ideal way for clients to disable
+            //timeout is to set it to 0
+            sIdleInvalidator->setIdleTimeout(ONE_BILLION_MS);
+            ALOGI("Disabled idle timeout");
+            return;
+        }
+        sIdleInvalidator->setIdleTimeout(timeout);
+        ALOGI("Idle timeout set to %u", timeout);
+    } else {
+        ALOGW("Cannot set idle timeout, IdleInvalidator not enabled");
+    }
+}
+
 void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx,
                                    hwc_display_contents_1_t* list) {
     LayerProp *layerProp = ctx->layerProp[mDpy];
@@ -684,9 +710,11 @@
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
 
-    // No Idle fall back, if secure display or secure RGB layers are present
+    // No Idle fall back, if secure display or secure RGB layers are present or
+    // if there's only a single layer being composed
     if(sIdleFallBack && (!ctx->listStats[mDpy].secureUI &&
-                    !ctx->listStats[mDpy].secureRGBCount)) {
+                    !ctx->listStats[mDpy].secureRGBCount) &&
+                    (ctx->listStats[mDpy].numAppLayers != 1)) {
         ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
         return false;
     }
@@ -1862,6 +1890,13 @@
                     "MDP Composition Strategies Failed");
         }
     } else {
+        if ((ctx->mMDP.version == qdutils::MDP_V3_0_5) && ctx->mCopyBit[mDpy] &&
+                enablePartialUpdateForMDP3) {
+            generateROI(ctx, list);
+            for(int i = 0; i < ctx->listStats[mDpy].numAppLayers; i++) {
+                ctx->copybitDrop[i] = mCurrentFrame.drop[i];
+            }
+        }
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                 __FUNCTION__);
         ret = -1;
@@ -2055,7 +2090,7 @@
     }
 
     // Set the Handle timeout to true for MDP or MIXED composition.
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
         sHandleTimeout = true;
     }
 
@@ -2310,7 +2345,7 @@
     }
 
     // Set the Handle timeout to true for MDP or MIXED composition.
-    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
         sHandleTimeout = true;
     }
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index e43c4f4..3ed9186 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -25,7 +25,6 @@
 #include <cutils/properties.h>
 #include <overlay.h>
 
-#define DEFAULT_IDLE_TIME 70
 #define MAX_PIPES_PER_MIXER 4
 
 namespace overlay {
@@ -57,6 +56,7 @@
     static void resetIdleFallBack() { sIdleFallBack = false; }
     static bool isIdleFallback() { return sIdleFallBack; }
     static void dynamicDebug(bool enable){ sDebugLogs = enable; }
+    static void setIdleTimeout(const uint32_t& timeout);
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -255,13 +255,15 @@
     static bool sHandleTimeout;
     static int sMaxPipesPerMixer;
     static bool sSrcSplitEnabled;
-    static IdleInvalidator *idleInvalidator;
+    static IdleInvalidator *sIdleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
     //Enable 4kx2k yuv layer split
     static bool sEnableYUVsplit;
     bool mModeOn; // if prepare happened
     bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
+    //Enable Partial Update for MDP3 targets
+    static bool enablePartialUpdateForMDP3;
 };
 
 class MDPCompNonSplit : public MDPComp {
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 8490058..6bde3d2 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -245,6 +245,13 @@
     }
 }
 
+static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
+    uint32_t timeout = (uint32_t)inParcel->readInt32();
+    ALOGD("%s :%u ms", __FUNCTION__, timeout);
+    Locker::Autolock _sl(ctx->mDrawLock);
+    MDPComp::setIdleTimeout(timeout);
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -290,6 +297,9 @@
         case IQService::DYNAMIC_DEBUG:
             toggleDynamicDebug(mHwcContext, inParcel);
             break;
+        case IQService::SET_IDLE_TIMEOUT:
+            setIdleTimeout(mHwcContext, inParcel);
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 52572b0..c409db4 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -43,6 +43,7 @@
 #include "comptype.h"
 #include "hwc_virtual.h"
 #include "qd_utils.h"
+#include <sys/sysinfo.h>
 
 using namespace qClient;
 using namespace qService;
@@ -73,6 +74,11 @@
 #endif
 #endif
 
+#define PROP_DEFAULT_APPBUFFER  "ro.sf.default_app_buffer"
+#define MAX_RAM_SIZE  512*1024*1024
+#define qHD_WIDTH 540
+
+
 namespace qhwc {
 
 //Std refresh rates for digital videos- 24p, 30p and 48p
@@ -232,6 +238,25 @@
     return 0;
 }
 
+static void changeDefaultAppBufferCount() {
+    struct sysinfo info;
+    unsigned long int ramSize = 0;
+    if (!sysinfo(&info)) {
+           ramSize = info.totalram ;
+    }
+    int fb_fd = -1;
+    struct fb_var_screeninfo sInfo ={0};
+    fb_fd = open("/dev/graphics/fb0", O_RDONLY);
+    if (fb_fd >=0) {
+        ioctl(fb_fd, FBIOGET_VSCREENINFO, &sInfo);
+        close(fb_fd);
+    }
+    if ((ramSize && ramSize < MAX_RAM_SIZE) &&
+         (sInfo.xres &&  sInfo.xres <= qHD_WIDTH )) {
+                  property_set(PROP_DEFAULT_APPBUFFER, "2");
+    }
+}
+
 void initContext(hwc_context_t *ctx)
 {
     openFramebufferDevice(ctx);
@@ -243,6 +268,10 @@
     ctx->mOverlay = overlay::Overlay::getInstance();
     ctx->mRotMgr = RotMgr::getInstance();
 
+    //default_app_buffer for ferrum
+    if (ctx->mMDP.version ==  qdutils::MDP_V3_0_5) {
+       changeDefaultAppBufferCount();
+    }
     // Initialize composition objects for the primary display
     initCompositionResources(ctx, HWC_DISPLAY_PRIMARY);
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index cae22f1..3d97319 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -596,6 +596,8 @@
     qhwc::PtorInfo mPtorInfo;
     //Running in Thermal burst mode
     bool mThermalBurstMode;
+    //Layers out of ROI
+    bool copybitDrop[MAX_NUM_APP_LAYERS];
 };
 
 namespace qhwc {
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 86191e9..5850ce5 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -47,10 +47,13 @@
     ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
 }
 
-int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data,
-                         unsigned int idleSleepTime) {
-    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s idleSleepTime %d",
-        __FUNCTION__, idleSleepTime);
+IdleInvalidator::~IdleInvalidator() {
+    if(mTimeoutEventFd >= 0) {
+        close(mTimeoutEventFd);
+    }
+}
+
+int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) {
     mHandler = reg_handler;
     mHwcContext = user_data;
 
@@ -62,34 +65,47 @@
         return -1;
     }
 
-    // Open a sysfs node to send the timeout value to driver.
-    int fd = open(IDLE_TIME_PATH, O_WRONLY);
-    if (fd < 0) {
-        ALOGE ("%s:not able to open %s node %s",
-                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+    enum {DEFAULT_IDLE_TIME = 70}; //ms
+    if(not setIdleTimeout(DEFAULT_IDLE_TIME)) {
         close(mTimeoutEventFd);
         mTimeoutEventFd = -1;
         return -1;
     }
-    char strSleepTime[64];
-    snprintf(strSleepTime, sizeof(strSleepTime), "%d", idleSleepTime);
-    // Notify driver about the timeout value
-    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
-    if(len < -1) {
-        ALOGE ("%s:not able to write into %s node %s",
-                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
-        close(mTimeoutEventFd);
-        mTimeoutEventFd = -1;
-        close(fd);
-        return -1;
-    }
-    close(fd);
 
     //Triggers the threadLoop to run, if not already running.
     run(threadName, android::PRIORITY_LOWEST);
     return 0;
 }
 
+bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) {
+    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d",
+            __FUNCTION__, timeout);
+
+    // Open a sysfs node to send the timeout value to driver.
+    int fd = open(IDLE_TIME_PATH, O_WRONLY);
+
+    if (fd < 0) {
+        ALOGE ("%s:Unable to open %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        return false;
+    }
+
+    char strSleepTime[64];
+    snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout);
+
+    // Notify driver about the timeout value
+    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
+    if(len < -1) {
+        ALOGE ("%s:Unable to write into %s node %s",
+                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+        close(fd);
+        return false;
+    }
+
+    close(fd);
+    return true;
+}
+
 bool IdleInvalidator::threadLoop() {
     ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
     struct pollfd pFd;
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index a881c4b..52334a0 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -37,16 +37,18 @@
 typedef void (*InvalidatorHandler)(void*);
 
 class IdleInvalidator : public android::Thread {
+    IdleInvalidator();
     void *mHwcContext;
     int mTimeoutEventFd;
     static InvalidatorHandler mHandler;
     static android::sp<IdleInvalidator> sInstance;
 
-    public:
-    IdleInvalidator();
+public:
+    ~IdleInvalidator();
     /* init timer obj */
-    int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
-             idleSleepTime);
+    int init(InvalidatorHandler reg_handler, void* user_data);
+    bool setIdleTimeout(const uint32_t& timeout);
+
     /*Overrides*/
     virtual bool        threadLoop();
     virtual int         readyToRun();
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 30c064e..3be20f1 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -53,6 +53,7 @@
         SET_WFD_STATUS,          // Set if wfd connection is on/off
         SET_VIEW_FRAME,          // Set view frame of display
         DYNAMIC_DEBUG,           // Enable more logging on the fly
+        SET_IDLE_TIMEOUT,        // Set idle timeout for GPU fallback
         COMMAND_LIST_END = 400,
     };