From 14fab7dd794cd6bf29e6425340683c6221062b3c Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 1 Aug 2013 13:37:42 -0700 Subject: [PATCH] Drop frames based on presentation timestamp If there are two or more buffers pending that are ready for immediate presentation, drop all but the last one. Any code that didn't explicitly specify timestamps for buffers was using the default value (auto-generated "now"). As a result, surfaceflinger would drop frames whenever more than one buffer was queued. We now use zero as the auto-generated timestamp, and we don't set the timestamp in eglBeginFrame(). Change-Id: I187f42d33de227cd3411ff0dcd3b9ce1961457eb --- libs/gui/BufferQueue.cpp | 96 +++++++++++++++++++++++++++----------- libs/gui/Surface.cpp | 4 +- opengl/libs/EGL/eglApi.cpp | 5 -- 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 45488ff8d..e22679e49 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -807,7 +807,7 @@ void BufferQueue::freeAllBuffersLocked() { } } -status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { +status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) { ATRACE_CALL(); Mutex::Autolock _l(mMutex); @@ -835,37 +835,77 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { } Fifo::iterator front(mQueue.begin()); - int buf = front->mBuf; - // Compare the buffer's desired presentation time to the predicted - // actual display time. - // - // The "presentWhen" argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired-present time - // is earlier (less) than presentWhen, meaning it'll be displayed - // on time or possibly late, we acquire and return it. If we don't want - // to display it until after the presentWhen time, we return PRESENT_LATER - // without acquiring it. - // - // To be safe, we don't refuse to acquire the buffer if presentWhen is - // more than one second in the future beyond the desired present time - // (i.e. we'd be holding the buffer for a really long time). - const int MAX_FUTURE_NSEC = 1000000000ULL; - nsecs_t desiredPresent = front->mTimestamp; - if (presentWhen != 0 && desiredPresent > presentWhen && - desiredPresent - presentWhen < MAX_FUTURE_NSEC) - { - ST_LOGV("pts defer: des=%lld when=%lld (%lld) now=%lld", - desiredPresent, presentWhen, desiredPresent - presentWhen, + // If expectedPresent is specified, we may not want to return a buffer yet. + // If it's specified and there's more than one buffer queued, we may + // want to drop a buffer. + if (expectedPresent != 0) { + const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second + + // The "expectedPresent" argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired-present time + // is earlier (less) than expectedPresent, meaning it'll be displayed + // on time or possibly late if we show it ASAP, we acquire and return + // it. If we don't want to display it until after the expectedPresent + // time, we return PRESENT_LATER without acquiring it. + // + // To be safe, we don't defer acquisition if expectedPresent is + // more than one second in the future beyond the desired present time + // (i.e. we'd be holding the buffer for a long time). + // + // NOTE: code assumes monotonic time values from the system clock are + // positive. + while (mQueue.size() > 1) { + // If entry[1] is timely, drop entry[0] (and repeat). We apply + // an additional criteria here: we only drop the earlier buffer if + // our desiredPresent falls within +/- 1 second of the expected + // present. Otherwise, bogus desiredPresent times (e.g. 0 or + // a small relative timestamp), which normally mean "ignore the + // timestamp and acquire immediately", would cause us to drop + // frames. + // + // We may want to add an additional criteria: don't drop the + // earlier buffer if entry[1]'s fence hasn't signaled yet. + // + // (Vector front is [0], back is [size()-1]) + const BufferItem& bi(mQueue[1]); + nsecs_t desiredPresent = bi.mTimestamp; + if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || + desiredPresent > expectedPresent) { + // This buffer is set to display in the near future, or + // desiredPresent is garbage. Either way we don't want to + // drop the previous buffer just to get this on screen sooner. + ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + break; + } + ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d", + desiredPresent, expectedPresent, mQueue.size()); + if (stillTracking(front)) { + // front buffer is still in mSlots, so mark the slot as free + mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + } + mQueue.erase(front); + front = mQueue.begin(); + } + + // See if the front buffer is due. + nsecs_t desiredPresent = front->mTimestamp; + if (desiredPresent > expectedPresent && + desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { + ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + return PRESENT_LATER; + } + + ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - if (presentWhen != 0) { - ST_LOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)", - mSlots, buf, mSlots[buf].mFence->getSignalTime(), - desiredPresent, presentWhen, desiredPresent - presentWhen); } + int buf = front->mBuf; *buffer = *front; ATRACE_BUFFER_INDEX(buf); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 998ea8ac8..e2ec6434c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -261,9 +261,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { Mutex::Autolock lock(mMutex); int64_t timestamp; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); + timestamp = 0; } else { timestamp = mTimestamp; } diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 6c285d37b..6dfd30604 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -499,11 +499,6 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { setError(EGL_BAD_SURFACE, EGL_FALSE); return; } - - int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - - egl_surface_t const * const s = get_surface(surface); - native_window_set_buffers_timestamp(s->win.get(), timestamp); } // ----------------------------------------------------------------------------