diff options
author | Dan Stoza | 2015-04-28 16:42:06 -0500 |
---|---|---|
committer | Dan Stoza | 2015-04-30 17:29:05 -0500 |
commit | 2e36f2283f48ab764b496490c73a132acf21df3a (patch) | |
tree | 9c6a951420250a966b71b12317927c4d1d49114d /libs | |
parent | 8de71a2408f632407c25942a39c31f78c7f64ffd (diff) | |
download | frameworks-native-2e36f2283f48ab764b496490c73a132acf21df3a.tar.gz frameworks-native-2e36f2283f48ab764b496490c73a132acf21df3a.tar.xz frameworks-native-2e36f2283f48ab764b496490c73a132acf21df3a.zip |
SurfaceFlinger: Fix PTS on stale buffers
SurfaceFlinger's (Layer's) shadow copy of the BufferQueue queue was
getting out of sync for a few reasons. This change fixes these by
doing the following:
- Adds a check to re-synchronize the shadow copy every time we
successfully acquire a buffer by first dropping stale buffers before
removing the current buffer.
- Avoids trying to perform updates for buffers which have been rejected
(for incorrect dimensions) by SurfaceFlinger.
- Adds IGraphicBufferConsumer::setShadowQueueSize, which allows the
consumer to notify the BufferQueue that it is maintaining a shadow
copy of the queue and prevents it from dropping so many buffers
during acquireBuffer that it ends up returning a buffer for which the
consumer has not yet received an onFrameAvailable call.
Bug: 20096136
Change-Id: I78d0738428005fc19b3be85cc8f1db498043612f
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/BufferQueueConsumer.cpp | 22 | ||||
-rw-r--r-- | libs/gui/BufferQueueCore.cpp | 4 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferConsumer.cpp | 18 |
3 files changed, 43 insertions, 1 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index c7d5e0032..2deef0e77 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp | |||
@@ -89,7 +89,20 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, | |||
89 | // the timestamps are being auto-generated by Surface. If the app isn't | 89 | // the timestamps are being auto-generated by Surface. If the app isn't |
90 | // generating timestamps explicitly, it probably doesn't want frames to | 90 | // generating timestamps explicitly, it probably doesn't want frames to |
91 | // be discarded based on them. | 91 | // be discarded based on them. |
92 | // | ||
93 | // If the consumer is shadowing our queue, we also make sure that we | ||
94 | // don't drop so many buffers that the consumer hasn't received the | ||
95 | // onFrameAvailable callback for the buffer it acquires. That is, we | ||
96 | // want the buffer we return to be in the consumer's shadow queue. | ||
97 | size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ? | ||
98 | mCore->mConsumerShadowQueueSize - 1 : 0; | ||
92 | while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { | 99 | while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { |
100 | if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) { | ||
101 | BQ_LOGV("acquireBuffer: no droppable buffers in consumer's" | ||
102 | " shadow queue, continuing"); | ||
103 | break; | ||
104 | } | ||
105 | |||
93 | // If entry[1] is timely, drop entry[0] (and repeat). We apply an | 106 | // If entry[1] is timely, drop entry[0] (and repeat). We apply an |
94 | // additional criterion here: we only drop the earlier buffer if our | 107 | // additional criterion here: we only drop the earlier buffer if our |
95 | // desiredPresent falls within +/- 1 second of the expected present. | 108 | // desiredPresent falls within +/- 1 second of the expected present. |
@@ -124,6 +137,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, | |||
124 | } | 137 | } |
125 | mCore->mQueue.erase(front); | 138 | mCore->mQueue.erase(front); |
126 | front = mCore->mQueue.begin(); | 139 | front = mCore->mQueue.begin(); |
140 | --droppableBuffers; | ||
127 | } | 141 | } |
128 | 142 | ||
129 | // See if the front buffer is due | 143 | // See if the front buffer is due |
@@ -537,6 +551,14 @@ sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const { | |||
537 | return mCore->mSidebandStream; | 551 | return mCore->mSidebandStream; |
538 | } | 552 | } |
539 | 553 | ||
554 | void BufferQueueConsumer::setShadowQueueSize(size_t size) { | ||
555 | ATRACE_CALL(); | ||
556 | BQ_LOGV("setShadowQueueSize: %zu", size); | ||
557 | Mutex::Autolock lock(mCore->mMutex); | ||
558 | mCore->mConsumerHasShadowQueue = true; | ||
559 | mCore->mConsumerShadowQueueSize = size; | ||
560 | } | ||
561 | |||
540 | void BufferQueueConsumer::dump(String8& result, const char* prefix) const { | 562 | void BufferQueueConsumer::dump(String8& result, const char* prefix) const { |
541 | mCore->dump(result, prefix); | 563 | mCore->dump(result, prefix); |
542 | } | 564 | } |
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 887f2cbf0..d0f7afad4 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp | |||
@@ -71,7 +71,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : | |||
71 | mIsAllocating(false), | 71 | mIsAllocating(false), |
72 | mIsAllocatingCondition(), | 72 | mIsAllocatingCondition(), |
73 | mAllowAllocation(true), | 73 | mAllowAllocation(true), |
74 | mBufferAge(0) | 74 | mBufferAge(0), |
75 | mConsumerHasShadowQueue(false), | ||
76 | mConsumerShadowQueueSize(0) | ||
75 | { | 77 | { |
76 | if (allocator == NULL) { | 78 | if (allocator == NULL) { |
77 | sp<ISurfaceComposer> composer(ComposerService::getComposerService()); | 79 | sp<ISurfaceComposer> composer(ComposerService::getComposerService()); |
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 6658ab11d..480dfb646 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp | |||
@@ -52,6 +52,7 @@ enum { | |||
52 | SET_CONSUMER_USAGE_BITS, | 52 | SET_CONSUMER_USAGE_BITS, |
53 | SET_TRANSFORM_HINT, | 53 | SET_TRANSFORM_HINT, |
54 | GET_SIDEBAND_STREAM, | 54 | GET_SIDEBAND_STREAM, |
55 | SET_SHADOW_QUEUE_SIZE, | ||
55 | DUMP, | 56 | DUMP, |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -269,6 +270,17 @@ public: | |||
269 | return stream; | 270 | return stream; |
270 | } | 271 | } |
271 | 272 | ||
273 | virtual void setShadowQueueSize(size_t size) { | ||
274 | Parcel data, reply; | ||
275 | data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); | ||
276 | data.writeInt64(static_cast<int64_t>(size)); | ||
277 | status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply); | ||
278 | if (result != NO_ERROR) { | ||
279 | ALOGE("setShadowQueueSize failed (%d)", result); | ||
280 | return; | ||
281 | } | ||
282 | } | ||
283 | |||
272 | virtual void dump(String8& result, const char* prefix) const { | 284 | virtual void dump(String8& result, const char* prefix) const { |
273 | Parcel data, reply; | 285 | Parcel data, reply; |
274 | data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); | 286 | data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); |
@@ -423,6 +435,12 @@ status_t BnGraphicBufferConsumer::onTransact( | |||
423 | } | 435 | } |
424 | return NO_ERROR; | 436 | return NO_ERROR; |
425 | } | 437 | } |
438 | case SET_SHADOW_QUEUE_SIZE: { | ||
439 | CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); | ||
440 | size_t size = static_cast<size_t>(data.readInt64()); | ||
441 | setShadowQueueSize(size); | ||
442 | return NO_ERROR; | ||
443 | } | ||
426 | case DUMP: { | 444 | case DUMP: { |
427 | CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); | 445 | CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); |
428 | String8 result = data.readString8(); | 446 | String8 result = data.readString8(); |