Improve SurfaceFlinger PTS estimation
Get the next refresh time from DispSync instead of guessing based
on the current time.
Change-Id: I8dc72a3217bfd4e9b4c905034194d1a298cad69a
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index a412543..7de6ac4 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -29,7 +29,8 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
+ const DispSync& dispSync)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -51,7 +52,7 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item, computeExpectedPresent());
+ err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -128,35 +129,41 @@
// will be slightly later then the actual-present timing. If we get a
// desired-present time that is unintentionally a hair after the next
// vsync, we'll hold the frame when we really want to display it. We
-// want to use an expected-presentation time that is slightly late to
-// avoid this sort of edge case.
-nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss. We want to do it here, not in every app. A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
{
- // Don't yet have an easy way to get actual buffer flip time for
- // the specific display, so use the current time. This is typically
- // 1.3ms past the vsync event time.
- const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC);
-
- // Given a SurfaceFlinger reference, and information about what display
- // we're destined for, we could query the HWC for the refresh rate. This
- // could change over time, e.g. we could switch to 24fps for a movie.
- // For now, assume 60fps.
- //const nsecs_t vsyncPeriod =
- // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
- const nsecs_t vsyncPeriod = 16700000;
-
// The HWC doesn't currently have a way to report additional latency.
- // Assume that whatever we submit now will appear on the next flip,
- // i.e. 1 frame of latency w.r.t. the previous flip.
- const uint32_t hwcLatency = 1;
+ // Assume that whatever we submit now will appear right after the flip.
+ // For a smart panel this might be 1. This is expressed in frames,
+ // rather than time, because we expect to have a constant frame delay
+ // regardless of the refresh rate.
+ const uint32_t hwcLatency = 0;
- // A little extra padding to compensate for slack between actual vsync
- // time and vsync event receipt. Currently not needed since we're
- // using "now" instead of a vsync time.
- const nsecs_t extraPadding = 0;
+ // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+ const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
- // Total it up.
- return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
+ // The DispSync time is already adjusted for the difference between
+ // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
+ // we don't need to factor that in here. Pad a little to avoid
+ // weird effects if apps might be requesting times right on the edge.
+ nsecs_t extraPadding = 0;
+ if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
+ extraPadding = 1000000; // 1ms (6% of 60Hz)
+ }
+
+ return nextRefresh + extraPadding;
}
void SurfaceFlingerConsumer::setContentsChangedListener(