SF now synchronizes to VSYNC

Change-Id: Ic5e4f2ea9927ce133eef9499c03161325e9d02c5
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95d651a..732af53 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -23,18 +23,22 @@
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+ifeq ($(TARGET_HAS_WAITFORVSYNC), true)
+	LOCAL_CFLAGS += -DHAS_WAITFORVSYNC
+endif
+
 ifeq ($(TARGET_BOARD_PLATFORM), omap3)
 	LOCAL_CFLAGS += -DNO_RGBX_8888
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), omap4)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+	LOCAL_CFLAGS += -DUSE_TRIPLE_BUFFERING=1
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
 	LOCAL_CFLAGS += -DREFRESH_RATE=56
 endif
 
-
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libhardware \
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 6796d7d..92d4266 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -36,6 +36,7 @@
 EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger),
       mHw(flinger->graphicPlane(0).displayHardware()),
+      mLastVSyncTimestamp(0),
       mDeliveredEvents(0)
 {
 }
@@ -44,6 +45,20 @@
     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 }
 
+sp<DisplayEventConnection> EventThread::createEventConnection() const {
+    return new DisplayEventConnection(const_cast<EventThread*>(this));
+}
+
+nsecs_t EventThread::getLastVSyncTimestamp() const {
+    Mutex::Autolock _l(mLock);
+    return mLastVSyncTimestamp;
+}
+
+nsecs_t EventThread::getVSyncPeriod() const {
+    return mHw.getRefreshPeriod();
+
+}
+
 status_t EventThread::registerDisplayEventConnection(
         const sp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
@@ -80,8 +95,11 @@
         Mutex::Autolock _l(mLock);
         ConnectionInfo* info = getConnectionInfoLocked(connection);
         if (info) {
-            info->count = (count == 0) ? -1 : count;
-            mCondition.signal();
+            const int32_t new_count = (count == 0) ? -1 : count;
+            if (info->count != new_count) {
+                info->count = new_count;
+                mCondition.signal();
+            }
         }
     }
 }
@@ -90,10 +108,8 @@
         const wp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
     ConnectionInfo* info = getConnectionInfoLocked(connection);
-    if (info) {
-        if (info->count < 0) {
-            info->count = 0;
-        }
+    if (info && info->count < 0) {
+        info->count = 0;
         mCondition.signal();
     }
 }
@@ -132,6 +148,7 @@
             timestamp = mHw.waitForRefresh();
             mLock.lock();
             mDeliveredEvents++;
+            mLastVSyncTimestamp = timestamp;
 
             // now see if we still need to report this VSYNC event
             bool reportVsync = false;
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 35bd299..3a3071e 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -36,6 +36,7 @@
 
 class SurfaceFlinger;
 class DisplayHardware;
+class DisplayEventConnection;
 
 // ---------------------------------------------------------------------------
 
@@ -45,6 +46,8 @@
 public:
     EventThread(const sp<SurfaceFlinger>& flinger);
 
+    sp<DisplayEventConnection> createEventConnection() const;
+
     status_t registerDisplayEventConnection(
             const sp<DisplayEventConnection>& connection);
 
@@ -56,6 +59,10 @@
 
     void requestNextVsync(const wp<DisplayEventConnection>& connection);
 
+    nsecs_t getLastVSyncTimestamp() const;
+
+    nsecs_t getVSyncPeriod() const;
+
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
 private:
@@ -88,6 +95,7 @@
 
     // protected by mLock
     KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+    nsecs_t mLastVSyncTimestamp;
 
     // main thread only
     size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8e87b88..9c04d59 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -97,7 +97,12 @@
     mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
     mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
     mSurfaceTexture->setSynchronousMode(true);
+#ifdef USE_TRIPLE_BUFFERING
+#warning "using triple buffering"
+    mSurfaceTexture->setBufferCountServer(3);
+#else
     mSurfaceTexture->setBufferCountServer(2);
+#endif
 }
 
 Layer::~Layer()
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index cbd530c..70711e7 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -18,12 +18,17 @@
 #include <errno.h>
 #include <sys/types.h>
 
+#include <binder/IPCThreadState.h>
+
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/Log.h>
-#include <binder/IPCThreadState.h>
+
+#include <gui/IDisplayEventConnection.h>
+#include <gui/BitTube.h>
 
 #include "MessageQueue.h"
+#include "EventThread.h"
 
 namespace android {
 
@@ -51,6 +56,15 @@
 MessageQueue::~MessageQueue() {
 }
 
+void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
+{
+    mEventThread = eventThread;
+    mEvents = eventThread->createEventConnection();
+    mEventTube = mEvents->getDataChannel();
+    mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
+            MessageQueue::cb_eventReceiver, this);
+}
+
 void MessageQueue::waitMessage() {
     do {
         IPCThreadState::self()->flushCommands();
@@ -93,13 +107,54 @@
     return NO_ERROR;
 }
 
-status_t MessageQueue::invalidate() {
+void MessageQueue::scheduleWorkASAP() {
     if (android_atomic_or(1, &mWorkPending) == 0) {
         mLooper->wake();
-    }
+   }
+}
+
+status_t MessageQueue::invalidate() {
+    mEvents->requestNextVsync();
     return NO_ERROR;
 }
 
+int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
+    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+    return queue->eventReceiver(fd, events);
+}
+
+int MessageQueue::eventReceiver(int fd, int events) {
+    ssize_t n;
+    DisplayEventReceiver::Event buffer[8];
+    while ((n = getEvents(buffer, 8)) > 0) {
+        for (int i=0 ; i<n ; i++) {
+            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                scheduleWorkASAP();
+                break;
+            }
+        }
+    }
+    return 1;
+}
+
+ssize_t MessageQueue::getEvents(
+        DisplayEventReceiver::Event* events, size_t count)
+{
+    ssize_t size = mEventTube->read(events, sizeof(events[0])*count);
+    ALOGE_IF(size<0, "MessageQueue::getEvents error (%s)", strerror(-size));
+    if (size >= 0) {
+        // Note: if (size % sizeof(events[0])) != 0, we've got a
+        // partial read. This can happen if the queue filed up (ie: if we
+        // didn't pull from it fast enough).
+        // We discard the partial event and rely on the sender to
+        // re-send the event if appropriate (some events, like VSYNC
+        // can be lost forever).
+        // returns number of events read
+        size /= sizeof(events[0]);
+    }
+    return size;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 2317d81..5ea197d 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,10 +25,15 @@
 #include <utils/Timers.h>
 #include <utils/Looper.h>
 
+#include <gui/DisplayEventReceiver.h>
+
 #include "Barrier.h"
 
 namespace android {
 
+class IDisplayEventConnection;
+class EventThread;
+
 // ---------------------------------------------------------------------------
 
 class MessageBase : public MessageHandler
@@ -55,11 +60,20 @@
 
 class MessageQueue {
     sp<Looper> mLooper;
-    volatile int32_t mWorkPending;
+    sp<EventThread> mEventThread;
+    sp<IDisplayEventConnection> mEvents;
+    sp<BitTube> mEventTube;
+    int32_t mWorkPending;
+
+    static int cb_eventReceiver(int fd, int events, void* data);
+    int eventReceiver(int fd, int events);
+    ssize_t getEvents(DisplayEventReceiver::Event* events, size_t count);
+    void scheduleWorkASAP();
 
 public:
     MessageQueue();
     ~MessageQueue();
+    void setEventThread(const sp<EventThread>& events);
 
     void waitMessage();
     status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 887aee7..ff70ec3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -296,6 +296,7 @@
 
     // start the EventThread
     mEventThread = new EventThread(this);
+    mEventQueue.setEventThread(mEventThread);
 
     /*
      *  We're now ready to accept clients...
@@ -383,8 +384,7 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
-    return result;
+    return mEventThread->createEventConnection();
 }
 
 // ----------------------------------------------------------------------------
@@ -432,7 +432,6 @@
     } else {
         // pretend we did the post
         hw.compositionComplete();
-        hw.waitForRefresh();
     }
     return true;
 }
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 259b937..49e8e63 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -94,6 +94,10 @@
             *outTransform = orientation;
         }
         switch(api) {
+            case NATIVE_WINDOW_API_CPU:
+                // SurfaceTextureClient supports only 2 buffers for CPU connections
+                this->setBufferCountServer(2);
+                break;
             case NATIVE_WINDOW_API_MEDIA:
             case NATIVE_WINDOW_API_CAMERA:
                 // Camera preview and videos are rate-limited on the producer