SF: Force refresh when in single buffer mode
- Add a boolean to BufferItem to track whether single buffer mode is
enabled. When it is, force SurfaceFlinger to acquire a new buffer
and refresh on every vsync.
Bug 24940410
Change-Id: Iea67330c416b6fb14500865f98c67f1c12f23197
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 504ac64..370f5d5 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -118,6 +118,13 @@
// Describes the portion of the surface that has been modified since the
// previous frame
Region mSurfaceDamage;
+
+ // Indicates that the BufferQueue is in single buffer mode
+ bool mSingleBufferMode;
+
+ // Indicates that this buffer was queued by the producer. When in single
+ // buffer mode acquire() can return a BufferItem that wasn't in the queue.
+ bool mQueuedBuffer;
};
} // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 7305861..de8ff70 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -37,7 +37,9 @@
mIsDroppable(false),
mAcquireCalled(false),
mTransformToDisplayInverse(false),
- mSurfaceDamage() {
+ mSurfaceDamage(),
+ mSingleBufferMode(false),
+ mQueuedBuffer(true) {
}
BufferItem::~BufferItem() {}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 8e2afd0..6f9f21f 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -203,11 +203,15 @@
(mCore->mSingleBufferCache.transform &
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
+ outBuffer->mSingleBufferMode = true;
+ outBuffer->mQueuedBuffer = false;
} else {
slot = front->mSlot;
*outBuffer = *front;
}
+ outBuffer->mSingleBufferMode = mCore->mSingleBufferMode;
+
ATRACE_BUFFER_INDEX(slot);
BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 268c9da..ef01745 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -744,6 +744,8 @@
mCore->mDequeueBufferCannotBlock ||
(mCore->mSingleBufferMode && mCore->mSingleBufferSlot == slot);
item.mSurfaceDamage = surfaceDamage;
+ item.mSingleBufferMode = mCore->mSingleBufferMode;
+ item.mQueuedBuffer = true;
mStickyTransform = stickyTransform;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a7b167f..ad53226 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1254,7 +1254,7 @@
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
- if (mSidebandStreamChanged) {
+ if (mSidebandStreamChanged || mSingleBufferMode) {
return true;
}
@@ -1278,7 +1278,7 @@
bool Layer::onPreComposition() {
mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged;
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mSingleBufferMode;
}
void Layer::onPostComposition() {
@@ -1335,7 +1335,7 @@
}
Region outDirtyRegion;
- if (mQueuedFrames > 0) {
+ if (mQueuedFrames > 0 || mSingleBufferMode) {
// if we've already called updateTexImage() without going through
// a composition step, we have to skip this layer at this point
@@ -1492,8 +1492,14 @@
}
}
+ // This boolean is used to make sure that SurfaceFlinger's shadow copy
+ // of the buffer queue isn't modified when the buffer queue is returning
+ // BufferItem's that weren't actually queued. This can happen in single
+ // buffer mode.
+ bool queuedBuffer = false;
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, maxFrameNumber);
+ mFlinger->mPrimaryDispSync, &mSingleBufferMode, &queuedBuffer,
+ maxFrameNumber);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
@@ -1502,16 +1508,18 @@
} 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);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
return outDirtyRegion;
} else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
// This can occur if something goes wrong when trying to create the
// EGLImage for this buffer. If this happens, the buffer has already
// been released, so we need to clean up the queue and bug out
// early.
- {
+ if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
android_atomic_and(0, &mQueuedFrames);
@@ -1526,7 +1534,8 @@
return outDirtyRegion;
}
- { // Autolock scope
+ if (queuedBuffer) {
+ // Autolock scope
auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
Mutex::Autolock lock(mQueueItemLock);
@@ -1544,7 +1553,8 @@
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
- if (android_atomic_dec(&mQueuedFrames) > 1) {
+ if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
+ || mSingleBufferMode) {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4ff9006..9e3c4db 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -306,7 +306,8 @@
/*
* Returns if a frame is queued.
*/
- bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged; }
+ bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
+ mSidebandStreamChanged || mSingleBufferMode; }
// -----------------------------------------------------------------------
@@ -489,6 +490,8 @@
Vector<BufferItem> mQueueItems;
uint64_t mLastFrameNumberReceived;
bool mUpdateTexImageFailed; // This is only modified from the main thread
+
+ bool mSingleBufferMode;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 930e7c7..5722fb4 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,8 @@
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync, uint64_t maxFrameNumber)
+ const DispSync& dispSync, bool* singleBufferMode, bool* queuedBuffer,
+ uint64_t maxFrameNumber)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -68,7 +69,6 @@
return err;
}
-
// We call the rejecter here, in case the caller has a reason to
// not accept this buffer. This is used by SurfaceFlinger to
// reject buffers which have the wrong size
@@ -78,6 +78,14 @@
return BUFFER_REJECTED;
}
+ if (singleBufferMode) {
+ *singleBufferMode = item.mSingleBufferMode;
+ }
+
+ if (queuedBuffer) {
+ *queuedBuffer = item.mQueuedBuffer;
+ }
+
// Release the previous buffer.
err = updateAndReleaseLocked(item);
if (err != NO_ERROR) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 779e5b7..207c243 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -57,6 +57,7 @@
// this does not guarantee that the buffer has been bound to the GL
// texture.
status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+ bool* singleBufferMode, bool* queuedBuffer,
uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().