SurfaceFlinger: Do less work when using PTS

Currently, SurfaceFlinger is very dumb about how it handles buffer
updates at less than 60fps. If there is a new frame pending, but its
timestamp says not to present it until later SurfaceFlinger will wake
up every vsync until it is time to present it. Even worse, if
SurfaceFlinger has woken up but nothing has changed, it still goes
through the entire composition process.

This change (mostly) fixes that inefficiency. SurfaceFlinger will
still wake up every refresh period while there is a new frame
pending, but if there is no work to do, it will almost immediately go
back to sleep.

Bug: 18111837
Change-Id: I7825bacd37f40bf26edcc6a5e0f051dce45291fb
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c469627..b8b6472 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -829,30 +829,39 @@
 void SurfaceFlinger::onMessageReceived(int32_t what) {
     ATRACE_CALL();
     switch (what) {
-    case MessageQueue::TRANSACTION:
-        handleMessageTransaction();
-        break;
-    case MessageQueue::INVALIDATE:
-        handleMessageTransaction();
-        handleMessageInvalidate();
-        signalRefresh();
-        break;
-    case MessageQueue::REFRESH:
-        handleMessageRefresh();
-        break;
+        case MessageQueue::TRANSACTION: {
+            handleMessageTransaction();
+            break;
+        }
+        case MessageQueue::INVALIDATE: {
+            bool refreshNeeded = handleMessageTransaction();
+            refreshNeeded |= handleMessageInvalidate();
+            if (refreshNeeded) {
+                // Signal a refresh if a transaction modified the window state or if
+                // a new buffer was latched
+                signalRefresh();
+            }
+            break;
+        }
+        case MessageQueue::REFRESH: {
+            handleMessageRefresh();
+            break;
+        }
     }
 }
 
-void SurfaceFlinger::handleMessageTransaction() {
+bool SurfaceFlinger::handleMessageTransaction() {
     uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
     if (transactionFlags) {
         handleTransaction(transactionFlags);
+        return true;
     }
+    return false;
 }
 
-void SurfaceFlinger::handleMessageInvalidate() {
+bool SurfaceFlinger::handleMessageInvalidate() {
     ATRACE_CALL();
-    handlePageFlip();
+    return handlePageFlip();
 }
 
 void SurfaceFlinger::handleMessageRefresh() {
@@ -1685,12 +1694,13 @@
     }
 }
 
-void SurfaceFlinger::handlePageFlip()
+bool SurfaceFlinger::handlePageFlip()
 {
     Region dirtyRegion;
 
     bool visibleRegions = false;
     const LayerVector& layers(mDrawingState.layersSortedByZ);
+    bool frameQueued = false;
 
     // Store the set of layers that need updates. This set must not change as
     // buffers are being latched, as this could result in a deadlock.
@@ -1704,8 +1714,12 @@
     Vector<Layer*> layersWithQueuedFrames;
     for (size_t i = 0, count = layers.size(); i<count ; i++) {
         const sp<Layer>& layer(layers[i]);
-        if (layer->hasQueuedFrame())
-            layersWithQueuedFrames.push_back(layer.get());
+        if (layer->hasQueuedFrame()) {
+            frameQueued = true;
+            if (layer->shouldPresentNow(mPrimaryDispSync)) {
+                layersWithQueuedFrames.push_back(layer.get());
+            }
+        }
     }
     for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
         Layer* layer = layersWithQueuedFrames[i];
@@ -1715,6 +1729,16 @@
     }
 
     mVisibleRegionsDirty |= visibleRegions;
+
+    // If we will need to wake up at some time in the future to deal with a
+    // queued frame that shouldn't be displayed during this vsync period, wake
+    // up during the next vsync period to check again.
+    if (frameQueued && layersWithQueuedFrames.empty()) {
+        signalLayerUpdate();
+    }
+
+    // Only continue with the refresh if there is actually new work to do
+    return !layersWithQueuedFrames.empty();
 }
 
 void SurfaceFlinger::invalidateHwcGeometry()