Add interface for controlling single buffer auto refresh
- Adds a boolean to BufferQueue that controls whether or not auto
refresh is enabled in SurfaceFlinger when in single buffer mode.
- Adds plumbing up to ANativeWindow.
- When enabled, it will cache the shared buffer slot in Surface in
order to prevent the Binder transaction with SurfaceFlinger.
Bug 24940410
Change-Id: I83142afdc00e203f198a32288f071d926f8fda95
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6fc55c3..42adf90 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,7 +44,11 @@
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
- mGenerationNumber(0)
+ mGenerationNumber(0),
+ mSingleBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
+ mSharedBufferHasBeenQueued(false)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
@@ -232,6 +236,16 @@
reqFormat = mReqFormat;
reqUsage = mReqUsage;
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot !=
+ BufferItem::INVALID_BUFFER_SLOT) {
+ sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
+ if (gbuf != NULL) {
+ *buffer = gbuf.get();
+ *fenceFd = -1;
+ return OK;
+ }
+ }
} // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
int buf = -1;
@@ -279,6 +293,15 @@
}
*buffer = gbuf.get();
+
+ if (mSingleBufferMode && mAutoRefresh) {
+ mSharedBufferSlot = buf;
+ mSharedBufferHasBeenQueued = false;
+ } else if (mSharedBufferSlot == buf) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
+ }
+
return OK;
}
@@ -294,8 +317,19 @@
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return OK;
}
@@ -323,6 +357,7 @@
Mutex::Autolock lock(mMutex);
int64_t timestamp;
bool isAutoTimestamp = false;
+
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
isAutoTimestamp = true;
@@ -338,6 +373,12 @@
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
// Make sure the crop rectangle is entirely inside the buffer.
@@ -417,6 +458,7 @@
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
+
uint32_t numPendingBuffers = 0;
uint32_t hint = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
@@ -434,6 +476,10 @@
mDirtyRegion = Region::INVALID_REGION;
}
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return err;
}
@@ -557,6 +603,9 @@
case NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE:
res = dispatchSetSingleBufferMode(args);
break;
+ case NATIVE_WINDOW_SET_AUTO_REFRESH:
+ res = dispatchSetAutoRefresh(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -669,8 +718,12 @@
int Surface::dispatchSetSingleBufferMode(va_list args) {
bool singleBufferMode = va_arg(args, int);
- setSingleBufferMode(singleBufferMode);
- return NO_ERROR;
+ return setSingleBufferMode(singleBufferMode);
+}
+
+int Surface::dispatchSetAutoRefresh(va_list args) {
+ bool autoRefresh = va_arg(args, int);
+ return setAutoRefresh(autoRefresh);
}
int Surface::connect(int api) {
@@ -714,6 +767,8 @@
ATRACE_CALL();
ALOGV("Surface::disconnect");
Mutex::Autolock lock(mMutex);
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
freeAllBuffers();
int err = mGraphicBufferProducer->disconnect(api);
if (!err) {
@@ -796,6 +851,9 @@
{
ALOGV("Surface::setUsage");
Mutex::Autolock lock(mMutex);
+ if (reqUsage != mReqUsage) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqUsage = reqUsage;
return OK;
}
@@ -888,12 +946,29 @@
status_t err = mGraphicBufferProducer->setSingleBufferMode(
singleBufferMode);
- ALOGE_IF(err, "IGraphicsBufferProducer::setSingleBufferMode(%d) returned"
+ if (err == NO_ERROR) {
+ mSingleBufferMode = singleBufferMode;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setSingleBufferMode(%d) returned"
"%s", singleBufferMode, strerror(-err));
return err;
}
+int Surface::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAutoRefresh (%d)", autoRefresh);
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setAutoRefresh(autoRefresh);
+ if (err == NO_ERROR) {
+ mAutoRefresh = autoRefresh;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setAutoRefresh(%d) returned %s",
+ autoRefresh, strerror(-err));
+ return err;
+}
+
int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
{
ATRACE_CALL();
@@ -903,6 +978,9 @@
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mReqWidth || height != mReqHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqWidth = width;
mReqHeight = height;
return NO_ERROR;
@@ -917,6 +995,9 @@
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mUserWidth || height != mUserHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mUserWidth = width;
mUserHeight = height;
return NO_ERROR;
@@ -927,6 +1008,9 @@
ALOGV("Surface::setBuffersFormat");
Mutex::Autolock lock(mMutex);
+ if (format != mReqFormat) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqFormat = format;
return NO_ERROR;
}