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
(cherry picked from commit 2e36f2283f48ab764b496490c73a132acf21df3a)
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..9fb94dd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -127,6 +127,10 @@
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
+ // Set the shadow queue size to 0 to notify the BufferQueue that we are
+ // shadowing it
+ mSurfaceFlingerConsumer->setShadowQueueSize(0);
+
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
@@ -164,9 +168,10 @@
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.push_back(item);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+ android_atomic_inc(&mQueuedFrames);
}
- android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
@@ -1259,14 +1264,39 @@
// layer update so we check again at the next opportunity.
mFlinger->signalLayerUpdate();
return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Update the BufferQueue with the new shadow queue size after
+ // dropping this item
+ mQueueItems.removeAt(0);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+
+ android_atomic_dec(&mQueuedFrames);
+ return outDirtyRegion;
}
- // Remove this buffer from our internal queue tracker
{ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ // Update the BufferQueue with our new shadow queue size, since we
+ // have removed at least one item
mQueueItems.removeAt(0);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
}
+
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if (android_atomic_dec(&mQueuedFrames) > 1) {