Merge "hwc: Implement idle-fallback for videos"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 3e92f53..73e145f 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -746,6 +746,11 @@
             height = 1024;
             fps = 60;
             break;
+        case HDMI_VFRMT_1024x768p60_4_3:
+            width = 1024;
+            height = 768;
+            fps = 60;
+            break;
         case HDMI_VFRMT_1920x1080p24_16_9:
             width = 1920;
             height = 1080;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index bf997ee..cdcd247 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -244,16 +244,14 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    pthread_mutex_lock(&ctx->vstate.lock);
+    Locker::Autolock _l(ctx->mBlankLock);
     switch(event) {
         case HWC_EVENT_VSYNC:
             if (ctx->vstate.enable == enable)
                 break;
             ret = hwc_vsync_control(ctx, dpy, enable);
-            if(ret == 0) {
+            if(ret == 0)
                 ctx->vstate.enable = !!enable;
-                pthread_cond_signal(&ctx->vstate.cond);
-            }
             ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s",
                       (enable)?"ENABLED":"DISABLED");
             break;
@@ -268,7 +266,6 @@
         default:
             ret = -EINVAL;
     }
-    pthread_mutex_unlock(&ctx->vstate.lock);
     return ret;
 }
 
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 42d0741..893da72 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -139,7 +139,7 @@
             displayFrame.right = dpos.w + displayFrame.left;
             displayFrame.bottom = dpos.h + displayFrame.top;
         }
-        setMdpFlags(layer, mdpFlags, 0);
+        setMdpFlags(layer, mdpFlags, 0, transform);
         // For External use rotator if there is a rotation value set
         if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
             mRot = ctx->mRotMgr->getNext();
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 5df31b0..20cdf72 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -151,8 +151,6 @@
     }
     MDPComp::init(ctx);
 
-    pthread_mutex_init(&(ctx->vstate.lock), NULL);
-    pthread_cond_init(&(ctx->vstate.cond), NULL);
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
     ctx->mExtDispConfiguring = false;
@@ -223,8 +221,6 @@
     }
 
 
-    pthread_mutex_destroy(&(ctx->vstate.lock));
-    pthread_cond_destroy(&(ctx->vstate.cond));
 }
 
 
@@ -754,12 +750,23 @@
 }
 
 inline int configRotator(Rotator *rot, const Whf& whf,
-        const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
+        hwc_rect_t& crop, const eMdpFlags& mdpFlags,
         const eTransform& orient, const int& downscale) {
-    Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
-        (crop.bottom - crop.top));
+
     rot->setSource(whf);
-    rot->setCrop(rotCrop);
+
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+        qdutils::MDSS_V5) {
+        uint32_t crop_w = (crop.right - crop.left);
+        uint32_t crop_h = (crop.bottom - crop.top);
+        ovutils::normalizeCrop((uint32_t&)crop.left, crop_w);
+        ovutils::normalizeCrop((uint32_t&)crop.top, crop_h);
+        crop.right = crop.left + crop_w;
+        crop.bottom = crop.top + crop_h;
+        Dim rotCrop(crop.left, crop.top, crop_w, crop_h);
+        rot->setCrop(rotCrop);
+    }
+
     rot->setFlags(mdpFlags);
     rot->setTransform(orient);
     rot->setDownscale(downscale);
@@ -897,6 +904,7 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
+            ctx->mOverlay->clear(dpy);
             return -1;
         }
         whf.format = (*rot)->getDstFormat();
@@ -961,7 +969,7 @@
     }
 
 
-    setMdpFlags(layer, mdpFlagsL);
+    setMdpFlags(layer, mdpFlagsL, 0, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
     if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
@@ -970,6 +978,7 @@
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
+            ctx->mOverlay->clear(dpy);
             return -1;
         }
         whf.format = (*rot)->getDstFormat();
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index db5880a..ccef284 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -104,6 +104,11 @@
     LayerProp():mFlags(0) {};
 };
 
+struct VsyncState {
+    bool enable;
+    bool fakevsync;
+};
+
 // LayerProp::flag values
 enum {
     HWC_MDPCOMP = 0x00000001,
@@ -154,10 +159,10 @@
 //Sets appropriate mdp flags for a layer.
 void setMdpFlags(hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
-        int rotDownscale = 0, int transform = 0);
+        int rotDownscale, int transform);
 
 int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
-        const hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
+        hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
         const ovutils::eTransform& orient, const int& downscale);
 
 int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
@@ -250,13 +255,6 @@
 
 }; //qhwc namespace
 
-struct vsync_state {
-    pthread_mutex_t lock;
-    pthread_cond_t  cond;
-    bool enable;
-    bool fakevsync;
-};
-
 // -----------------------------------------------------------------------------
 // HWC context
 // This structure contains overall state
@@ -277,6 +275,7 @@
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
     qhwc::MDPInfo mMDP;
+    qhwc::VsyncState vstate;
     qhwc::DisplayAttributes dpyAttr[MAX_DISPLAYS];
     qhwc::ListStats listStats[MAX_DISPLAYS];
     qhwc::LayerProp *layerProp[MAX_DISPLAYS];
@@ -301,8 +300,6 @@
     mutable Locker mBlankLock;
     //Lock to protect prepare & set when detaching external disp
     mutable Locker mExtLock;
-    //Vsync
-    struct vsync_state vstate;
     //Drawing round when we use GPU
     bool isPaddingRound;
     // External Orientation
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index b42043f..c0a33c1 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -60,7 +60,6 @@
                 android::PRIORITY_MORE_FAVORABLE);
 
     const int MAX_DATA = 64;
-    const int MAX_RETRY_COUNT = 100;
     static char vdata[MAX_DATA];
 
     uint64_t cur_timestamp=0;
@@ -86,6 +85,8 @@
        */
     fd_timestamp = open(vsync_timestamp_fb0, O_RDONLY);
     if (fd_timestamp < 0) {
+        // Make sure fb device is opened before starting this thread so this
+        // never happens.
         ALOGE ("FATAL:%s:not able to open file:%s, %s",  __FUNCTION__,
                (fb1_vsync) ? vsync_timestamp_fb1 : vsync_timestamp_fb0,
                strerror(errno));
@@ -93,46 +94,27 @@
     }
 
     do {
-        pthread_mutex_lock(&ctx->vstate.lock);
-        while (ctx->vstate.enable == false) {
-            pthread_cond_wait(&ctx->vstate.cond, &ctx->vstate.lock);
-        }
-        pthread_mutex_unlock(&ctx->vstate.lock);
-
-        if (!ctx->vstate.fakevsync) {
-            for(int i = 0; i < MAX_RETRY_COUNT; i++) {
-                len = pread(fd_timestamp, vdata, MAX_DATA, 0);
-                if(len < 0 && (errno == EAGAIN ||
-                               errno == EINTR  ||
-                               errno == EBUSY)) {
-                    ALOGW("%s: vsync read: %s, retry (%d/%d).",
-                          __FUNCTION__, strerror(errno), i, MAX_RETRY_COUNT);
-                    continue;
-                } else {
-                    break;
-                }
-            }
-
+        if (LIKELY(!ctx->vstate.fakevsync)) {
+            len = pread(fd_timestamp, vdata, MAX_DATA, 0);
             if (len < 0) {
-                ALOGE ("FATAL:%s:not able to read file:%s, %s", __FUNCTION__,
-                       vsync_timestamp_fb0, strerror(errno));
-                close (fd_timestamp);
-                ctx->vstate.fakevsync = true;
+                // If the read was just interrupted - it is not a fatal error
+                // In either case, just continue.
+                if (errno != EAGAIN &&
+                    errno != EINTR  &&
+                    errno != EBUSY) {
+                    ALOGE ("FATAL:%s:not able to read file:%s, %s",
+                           __FUNCTION__,
+                           vsync_timestamp_fb0, strerror(errno));
+                }
+                continue;
             }
-
             // extract timestamp
             const char *str = vdata;
             if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
                 cur_timestamp = strtoull(str + strlen("VSYNC="), NULL, 0);
-            } else {
-                ALOGE ("FATAL: %s: vsync timestamp not in correct format: [%s]",
-                       __FUNCTION__,
-                       str);
-                ctx->vstate.fakevsync = true;
             }
-
         } else {
-            usleep(16000);
+            usleep(16666);
             cur_timestamp = systemTime();
         }
         // send timestamp to HAL
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 97905d5..9b91760 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -311,6 +311,16 @@
     strncat(buf, str_pipes, strlen(str_pipes));
 }
 
+void Overlay::clear(int dpy) {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if (mPipeBook[i].mDisplay == dpy) {
+            // Mark as available for this round
+            PipeBook::resetUse(i);
+            PipeBook::resetAllocation(i);
+        }
+    }
+}
+
 void Overlay::PipeBook::init() {
     mPipe = NULL;
     mDisplay = DPY_UNUSED;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index bf85b70..cfceaff 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -90,6 +90,8 @@
      * to populate.
      */
     void getDump(char *buf, size_t len);
+    /* Reset usage and allocation bits on all pipes for given display */
+    void clear(int dpy);
     static void setDMAMode(const int& mode);
     static int getDMAMode();
 
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 4578115..4c77f2e 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -37,20 +37,6 @@
 namespace ovutils = overlay::utils;
 namespace overlay {
 
-//Helper to even out x,w and y,h pairs
-//x,y are always evened to ceil and w,h are evened to floor
-static void normalizeCrop(uint32_t& xy, uint32_t& wh) {
-    if(xy & 1) {
-        utils::even_ceil(xy);
-        if(wh & 1)
-            utils::even_floor(wh);
-        else
-            wh -= 2;
-    } else {
-        utils::even_floor(wh);
-    }
-}
-
 bool MdpCtrl::init(uint32_t fbnum) {
     // FD init
     if(!utils::openDev(mFd, fbnum,
@@ -189,8 +175,8 @@
     doDownscale();
     utils::Whf whf = getSrcWhf();
     if(utils::isYuv(whf.format)) {
-        normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
-        normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
+        utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
+        utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
         if(mdpVersion < MDSS_V5) {
             utils::even_floor(mOVInfo.dst_rect.w);
             utils::even_floor(mOVInfo.dst_rect.h);
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 6f2b564..30d7ccd 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -96,7 +96,7 @@
 void MdssRot::setDownscale(int ds) {}
 
 void MdssRot::setFlags(const utils::eMdpFlags& flags) {
-    mRotInfo.flags |= flags;
+    mRotInfo.flags = flags;
 }
 
 void MdssRot::setTransform(const utils::eTransform& rot)
@@ -111,6 +111,7 @@
 }
 
 void MdssRot::doTransform() {
+    mRotInfo.flags |= mOrientation;
     if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
         utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
 }
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index e595cef..4b81ed3 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -428,6 +428,20 @@
     getDump(buf, len, "\tdst", rot.dst);
 }
 
+//Helper to even out x,w and y,h pairs
+//x,y are always evened to ceil and w,h are evened to floor
+void normalizeCrop(uint32_t& xy, uint32_t& wh) {
+    if(xy & 1) {
+        even_ceil(xy);
+        if(wh & 1)
+            even_floor(wh);
+        else
+            wh -= 2;
+    } else {
+        even_floor(wh);
+    }
+}
+
 } // utils
 
 } // overlay
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 0893328..3fa0979 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -143,6 +143,7 @@
 bool enableBarrier (uint32_t orientation);
 uint32_t getS3DFormat(uint32_t fmt);
 bool isMdssRotator();
+void normalizeCrop(uint32_t& xy, uint32_t& wh);
 
 template <int CHAN>
 bool getPositionS3D(const Whf& whf, Dim& out);
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 86e744d..e328d23 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -93,10 +93,14 @@
         } else {
             mdp_version = MDP_V_UNKNOWN;
         }
-        int len = strlen("msmfbXX_");
-        if (mdp_version == MDP_V3_0_3)
-            len++;
-        panel_type = fb_finfo.id[len];
+
+        /* Assumes panel type is 2nd element in '_' delimited id string */
+        char * ptype = strstr(fb_finfo.id, "_");
+        if (!ptype || (*(++ptype) == '\0')) {
+            ALOGE("Invalid framebuffer info string: %s", fb_finfo.id);
+            ptype = fb_finfo.id;
+        }
+        panel_type = *ptype;
 
     }
     close(fb_fd);