hwc/fb/overlay: wait for fbpost and pan display

Draw sequence in hwc_set
--eglSwapBuffers
--wait for fb_post. Its ok to draw to External only at this point.
--draw to external   | Parallel with PAN
--commit to external | Parallel with PAN
--wait for pan (happening in fb_post) to finish.

Call MSMFB_OVERLAY_SET ioctl only when params change.

These thing together ensure a correct sequence and should fix tearing and
stuttering, the latter assuming there are no other display pipeline delays.

Acked-by: Arun Kumar K.R <akumarkr@codeaurora.org>

Change-Id: Ibb0ad8485fa6b30dc6ac07ae8b25a760941c08ce
diff --git a/libgralloc/fb_priv.h b/libgralloc/fb_priv.h
index 48e5669..340968c 100644
--- a/libgralloc/fb_priv.h
+++ b/libgralloc/fb_priv.h
@@ -54,6 +54,9 @@
     pthread_mutex_t fbPostLock;
     //Condition to inform HWC that fb_post called
     pthread_cond_t fbPostCond;
+    bool fbPanDone;
+    pthread_mutex_t fbPanLock;
+    pthread_cond_t fbPanCond;
 };
 
 
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index 4f84011..dd630d5 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -136,6 +136,13 @@
             genlock_unlock_buffer(hnd);
             return -errno;
         }
+
+        //Signals the composition thread to unblock and loop over if necessary
+        pthread_mutex_lock(&m->fbPanLock);
+        m->fbPanDone = true;
+        pthread_cond_signal(&m->fbPanCond);
+        pthread_mutex_unlock(&m->fbPanLock);
+
         CALC_FPS();
         m->currentBuffer = hnd;
     }
@@ -365,6 +372,9 @@
     module->fbPostDone = false;
     pthread_mutex_init(&(module->fbPostLock), NULL);
     pthread_cond_init(&(module->fbPostCond), NULL);
+    module->fbPanDone = false;
+    pthread_mutex_init(&(module->fbPanLock), NULL);
+    pthread_cond_init(&(module->fbPanCond), NULL);
     return 0;
 }
 
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 4a73c64..a46a172 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -193,9 +193,14 @@
             MDPComp::draw(ctx, list);
             EGLBoolean success = eglSwapBuffers((EGLDisplay)list->dpy,
                                                 (EGLSurface)list->sur);
+            wait4fbPost(ctx);
+            //Can draw to HDMI only when fb_post is reached
             UIMirrorOverlay::draw(ctx);
+            //HDMI commit and primary commit (PAN) happening in parallel
             if(ctx->mExtDisplay->getExternalDisplay())
                 ctx->mExtDisplay->commit();
+            //Virtual barrier for threads to finish
+            wait4Pan(ctx);
         } else {
             ctx->mOverlay->setState(ovutils::OV_CLOSED);
             ctx->qbuf->unlockAll();
diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp
index 5f20875..c5f22af 100644
--- a/libhwcomposer/hwc_uimirror.cpp
+++ b/libhwcomposer/hwc_uimirror.cpp
@@ -154,12 +154,6 @@
     if(fbDev) {
         private_module_t* m = reinterpret_cast<private_module_t*>(
                               fbDev->common.module);
-        //wait for the fb_post to be called
-        pthread_mutex_lock(&m->fbPostLock);
-        while(m->fbPostDone == false) {
-            pthread_cond_wait(&(m->fbPostCond), &(m->fbPostLock));
-        }
-        pthread_mutex_unlock(&m->fbPostLock);
         switch (state) {
             case ovutils::OV_UI_MIRROR:
                 if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset,
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 669cf17..37eb8ea 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -17,6 +17,9 @@
 
 #include <EGL/egl.h>
 #include <overlay.h>
+#include <cutils/properties.h>
+#include <gralloc_priv.h>
+#include <fb_priv.h>
 #include "hwc_utils.h"
 #include "mdp_version.h"
 #include "hwc_video.h"
@@ -205,4 +208,33 @@
     }
 }
 
+void wait4fbPost(hwc_context_t* ctx) {
+    framebuffer_device_t *fbDev = ctx->mFbDev;
+    if(fbDev) {
+        private_module_t* m = reinterpret_cast<private_module_t*>(
+                              fbDev->common.module);
+        //wait for the fb_post to be called
+        pthread_mutex_lock(&m->fbPostLock);
+        while(m->fbPostDone == false) {
+            pthread_cond_wait(&(m->fbPostCond), &(m->fbPostLock));
+        }
+        m->fbPostDone = false;
+        pthread_mutex_unlock(&m->fbPostLock);
+    }
+}
+
+void wait4Pan(hwc_context_t* ctx) {
+    framebuffer_device_t *fbDev = ctx->mFbDev;
+    if(fbDev) {
+        private_module_t* m = reinterpret_cast<private_module_t*>(
+                              fbDev->common.module);
+        //wait for the fb_post's PAN to finish
+        pthread_mutex_lock(&m->fbPanLock);
+        while(m->fbPanDone == false) {
+            pthread_cond_wait(&(m->fbPanCond), &(m->fbPanLock));
+        }
+        m->fbPanDone = false;
+        pthread_mutex_unlock(&m->fbPanLock);
+    }
+}
 };//namespace
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index b586fa8..33446b9 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -77,6 +77,12 @@
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
         const int fbWidth, const int fbHeight);
 
+// Waits for the fb_post to be called
+void wait4fbPost(hwc_context_t* ctx);
+
+// Waits for the fb_post to finish PAN (primary commit)
+void wait4Pan(hwc_context_t* ctx);
+
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index c795b99..d161f4a 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -131,15 +131,17 @@
 bool MdpCtrl::set() {
     //deferred calcs, so APIs could be called in any order.
     doTransform();
-    if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
-        ALOGE("MdpCtrl failed to setOverlay, restoring last known "
-                "good ov info");
-        mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo);
-        mdp_wrapper::dump("== Last good known OVInfo is: ", mLkgo);
-        this->restore();
-        return false;
+    if(this->ovChanged()) {
+        if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
+            ALOGE("MdpCtrl failed to setOverlay, restoring last known "
+                  "good ov info");
+            mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo);
+            mdp_wrapper::dump("== Last good known OVInfo is: ", mLkgo);
+            this->restore();
+            return false;
+        }
+        this->save();
     }
-    this->save();
     return true;
 }