HWC2: Backpressure missed vsyncs into apps
Adds a mechanism to detect whether the prior frame SurfaceFlinger
presented to hardware composer was actually picked up or not. We then
use this mechanism to avoid pushing two frames in the same vsync.
This backpressure is passed back to applications by not latching any
buffers, which will manifest as dequeueBuffer stalling until
SurfaceFlinger releases a buffer on the following vsync.
Also makes the former INVALIDATE_ON_VSYNC behavior the only behavior
so that this functionality works correctly.
Bug: 29413700
Change-Id: Ibde358e45423ee6fea7b5e09ff65e49c4ad67baa
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9a2747d..c541668 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -167,9 +167,6 @@
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
mGpuToCpuSupported = !atoi(value);
- property_get("debug.sf.drop_missed_frames", value, "0");
- mDropMissedFrames = atoi(value);
-
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
@@ -933,6 +930,14 @@
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
+ bool frameMissed = !mHadClientComposition &&
+ mPreviousPresentFence != Fence::NO_FENCE &&
+ mPreviousPresentFence->getSignalTime() == INT64_MAX;
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ if (frameMissed) {
+ signalLayerUpdate();
+ return false;
+ }
return handlePageFlip();
}
@@ -940,36 +945,22 @@
ATRACE_CALL();
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
- static nsecs_t previousExpectedPresent = 0;
- nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
- static bool previousFrameMissed = false;
- bool frameMissed = (expectedPresent == previousExpectedPresent);
- if (frameMissed != previousFrameMissed) {
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- }
- previousFrameMissed = frameMissed;
- if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
- // Latch buffers, but don't send anything to HWC, then signal another
- // wakeup for the next vsync
- preComposition();
- repaintEverything();
- } else {
- preComposition();
- rebuildLayerStacks();
- setUpHWComposer();
- doDebugFlashRegions();
- doComposition();
- postComposition(refreshStartTime);
- }
+ preComposition();
+ rebuildLayerStacks();
+ setUpHWComposer();
+ doDebugFlashRegions();
+ doComposition();
+ postComposition(refreshStartTime);
+
+ mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
+ mHadClientComposition = mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY);
// Release any buffers which were replaced this frame
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer();
}
mLayersWithQueuedFrames.clear();
-
- previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
}
void SurfaceFlinger::doDebugFlashRegions()