summaryrefslogtreecommitdiff
path: root/libs/gui/BufferQueue.cpp
diff options
context:
space:
mode:
author Andy McFadden <fadden@android.com> 2013-06-28 13:52:40 -0700
committer Andy McFadden <fadden@android.com> 2013-07-10 15:38:40 -0700
commit1585c4d9fbbba3ba70ae625923b85cd02cb8a0fd (patch)
tree42299de67a0088fb4416dba825e40f5b6a22312a /libs/gui/BufferQueue.cpp
parent06b6aed2f158d48ae04c4854d2a8832777ac942e (diff)
Pay attention to buffer timestamps
When acquiring a buffer, SurfaceFlinger now computes the expected presentation time and passes it to the BufferQueue acquireBuffer() method. If it's not yet time to display the buffer, acquireBuffer() returns PRESENT_LATER instead of a buffer. The current implementation of the expected-present-time computation uses approximations and guesswork. Bug 7900302 Change-Id: If9345611c5983a11a811935aaf27d6388a5036f1
Diffstat (limited to 'libs/gui/BufferQueue.cpp')
-rw-r--r--libs/gui/BufferQueue.cpp84
1 files changed, 57 insertions, 27 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 0dab86427d..8d4b174450 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -807,7 +807,7 @@ void BufferQueue::freeAllBuffersLocked() {
}
}
-status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
+status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
@@ -830,38 +830,68 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
// check if queue is empty
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- if (!mQueue.empty()) {
- Fifo::iterator front(mQueue.begin());
- int buf = front->mBuf;
- *buffer = *front;
- ATRACE_BUFFER_INDEX(buf);
+ if (mQueue.empty()) {
+ return NO_BUFFER_AVAILABLE;
+ }
- ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
- front->mBuf, front->mFrameNumber,
- front->mGraphicBuffer->handle);
- // if front buffer still being tracked update slot state
- if (stillTracking(front)) {
- mSlots[buf].mAcquireCalled = true;
- mSlots[buf].mNeedsCleanupOnRelease = false;
- mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
- mSlots[buf].mFence = Fence::NO_FENCE;
- }
+ 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)
+ {
+ ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
+ desiredPresent, presentWhen, desiredPresent - presentWhen,
+ systemTime(CLOCK_MONOTONIC));
+ return PRESENT_LATER;
+ }
+ if (presentWhen != 0) {
+ ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
+ mSlots, buf, mSlots[buf].mFence->getSignalTime(),
+ desiredPresent, presentWhen, desiredPresent - presentWhen);
+ }
- // If the buffer has previously been acquired by the consumer, set
- // mGraphicBuffer to NULL to avoid unnecessarily remapping this
- // buffer on the consumer side.
- if (buffer->mAcquireCalled) {
- buffer->mGraphicBuffer = NULL;
- }
+ *buffer = *front;
+ ATRACE_BUFFER_INDEX(buf);
- mQueue.erase(front);
- mDequeueCondition.broadcast();
+ ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+ front->mBuf, front->mFrameNumber,
+ front->mGraphicBuffer->handle);
+ // if front buffer still being tracked update slot state
+ if (stillTracking(front)) {
+ mSlots[buf].mAcquireCalled = true;
+ mSlots[buf].mNeedsCleanupOnRelease = false;
+ mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[buf].mFence = Fence::NO_FENCE;
+ }
- ATRACE_INT(mConsumerName.string(), mQueue.size());
- } else {
- return NO_BUFFER_AVAILABLE;
+ // If the buffer has previously been acquired by the consumer, set
+ // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+ // buffer on the consumer side.
+ if (buffer->mAcquireCalled) {
+ buffer->mGraphicBuffer = NULL;
}
+ mQueue.erase(front);
+ mDequeueCondition.broadcast();
+
+ ATRACE_INT(mConsumerName.string(), mQueue.size());
+
return NO_ERROR;
}