make sure to disable VSYNC while screen is off

Change-Id: If1894c43b0a39a2851e1280a35ae77bccd6d9abd
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6ae03c9..b87e191 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -205,6 +205,9 @@
 
 status_t HWComposer::release() const {
     if (mHwc) {
+        if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+            mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);
+        }
         int err = mHwc->set(mHwc, NULL, NULL, NULL);
         return (status_t)err;
     }
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 5813eefb..d86c280 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -41,6 +41,7 @@
       mHw(flinger->graphicPlane(0).editDisplayHardware()),
       mLastVSyncTimestamp(0),
       mVSyncTimestamp(0),
+      mUseSoftwareVSync(false),
       mDeliveredEvents(0),
       mDebugVsyncEnabled(false)
 {
@@ -55,16 +56,6 @@
     return new Connection(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<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
@@ -108,6 +99,24 @@
     }
 }
 
+void EventThread::onScreenReleased() {
+    Mutex::Autolock _l(mLock);
+    // wait for an eventual pending vsync to be serviced
+    if (!mUseSoftwareVSync) {
+        while (mVSyncTimestamp) {
+            mCondition.wait(mLock);
+        }
+    }
+    // disable reliance on h/w vsync
+    mUseSoftwareVSync = true;
+}
+
+void EventThread::onScreenAcquired() {
+    Mutex::Autolock _l(mLock);
+    mUseSoftwareVSync = false;
+}
+
+
 void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
     Mutex::Autolock _l(mLock);
     mVSyncTimestamp = timestamp;
@@ -121,7 +130,6 @@
     Vector< wp<EventThread::Connection> > displayEventConnections;
 
     do {
-
         Mutex::Autolock _l(mLock);
         do {
             // latch VSYNC event if any
@@ -145,7 +153,7 @@
                 if (!waitForNextVsync) {
                     // we received a VSYNC but we have no clients
                     // don't report it, and disable VSYNC events
-                    disableVSync();
+                    disableVSyncLocked();
                 } else {
                     // report VSYNC event
                     break;
@@ -157,12 +165,21 @@
                 // disable VSYNC events then.
                 if (waitForNextVsync) {
                     // enable
-                    enableVSync();
+                    enableVSyncLocked();
                 }
             }
 
             // wait for something to happen
-            mCondition.wait(mLock);
+            if (mUseSoftwareVSync == true) {
+                // h/w vsync cannot be used (screen is off), so we use
+                // a  timeout instead. it doesn't matter how imprecise this
+                // is, we just need to make sure to serve the clients
+                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+                    mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+                }
+            } else {
+                mCondition.wait(mLock);
+            }
         } while(true);
 
         // process vsync event
@@ -233,12 +250,15 @@
     return true;
 }
 
-void EventThread::enableVSync() {
-    mHw.getHwComposer().eventControl(HWComposer::EVENT_VSYNC, true);
+void EventThread::enableVSyncLocked() {
+    if (!mUseSoftwareVSync) {
+        // never enable h/w VSYNC when screen is off
+        mHw.getHwComposer().eventControl(HWComposer::EVENT_VSYNC, true);
+    }
     mDebugVsyncEnabled = true;
 }
 
-void EventThread::disableVSync() {
+void EventThread::disableVSyncLocked() {
     mHw.getHwComposer().eventControl(HWComposer::EVENT_VSYNC, false);
     mDebugVsyncEnabled = false;
 }
@@ -252,6 +272,8 @@
     Mutex::Autolock _l(mLock);
     result.appendFormat("VSYNC state: %s\n",
             mDebugVsyncEnabled?"enabled":"disabled");
+    result.appendFormat("  soft-vsync: %s\n",
+            mUseSoftwareVSync?"enabled":"disabled");
     result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
             mDisplayEventConnections.size(), mDeliveredEvents);
     for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 2e237dd..b42cab6 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -72,8 +72,11 @@
     void setVsyncRate(uint32_t count, const sp<Connection>& connection);
     void requestNextVsync(const sp<Connection>& connection);
 
-    nsecs_t getLastVSyncTimestamp() const;
-    nsecs_t getVSyncPeriod() const;
+    // called before the screen is turned off from main thread
+    void onScreenReleased();
+
+    // called after the screen is turned on from main thread
+    void onScreenAcquired();
 
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
@@ -84,8 +87,8 @@
     virtual void        onVSyncReceived(int, nsecs_t timestamp);
 
     void removeDisplayEventConnection(const wp<Connection>& connection);
-    void enableVSync();
-    void disableVSync();
+    void enableVSyncLocked();
+    void disableVSyncLocked();
 
     // constants
     sp<SurfaceFlinger> mFlinger;
@@ -98,6 +101,7 @@
     SortedVector< wp<Connection> > mDisplayEventConnections;
     nsecs_t mLastVSyncTimestamp;
     nsecs_t mVSyncTimestamp;
+    bool mUseSoftwareVSync;
 
     // main thread only
     size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f891b29..ce6c4a0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1467,16 +1467,18 @@
 void SurfaceFlinger::onScreenAcquired() {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     hw.acquireScreen();
+    mEventThread->onScreenAcquired();
     // this is a temporary work-around, eventually this should be called
     // by the power-manager
     SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
     mDirtyRegion.set(hw.bounds());
-    // from this point on, SF will priocess updates again
+    // from this point on, SF will process updates again
 }
 
 void SurfaceFlinger::onScreenReleased() {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (hw.isScreenAcquired()) {
+        mEventThread->onScreenReleased();
         mDirtyRegion.set(hw.bounds());
         hw.releaseScreen();
         // from this point on, SF will stop drawing
@@ -1883,6 +1885,8 @@
 status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
         GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
 {
+    ATRACE_CALL();
+
     if (!GLExtensions::getInstance().haveFramebufferObject())
         return INVALID_OPERATION;
 
@@ -2263,6 +2267,8 @@
 
 status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode)
 {
+    ATRACE_CALL();
+
     DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
     if (!hw.canDraw()) {
         // we're already off