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/include/gui/BufferItem.h b/include/gui/BufferItem.h
index a515f39..6f45181 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -119,8 +119,10 @@
// previous frame
Region mSurfaceDamage;
- // Indicates that the BufferQueue is in single buffer mode
- bool mSingleBufferMode;
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in single buffer mode.
+ bool mAutoRefresh;
// 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.
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index e2e73a0..d10ba2f 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -292,6 +292,11 @@
// consumer and producer to access the same buffer simultaneously.
bool mSingleBufferMode;
+ // When single buffer mode is enabled, this indicates whether the consumer
+ // should acquire buffers even if BufferQueue doesn't indicate that they are
+ // available.
+ bool mAutoRefresh;
+
// When single buffer mode is enabled, this tracks which slot contains the
// shared buffer.
int mSingleBufferSlot;
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index dc05e98..312f323 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -176,6 +176,9 @@
// See IGraphicBufferProducer::setSingleBufferMode
virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ // See IGraphicBufferProducer::setAutoRefresh
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
+
// See IGraphicBufferProducer::setDequeueTimeout
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 265728f..f6b4230 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -531,6 +531,14 @@
// the producer and consumer to simultaneously access the same buffer.
virtual status_t setSingleBufferMode(bool singleBufferMode) = 0;
+ // Used to enable/disable auto-refresh.
+ //
+ // Auto refresh has no effect outside of single buffer mode. In single
+ // buffer mode, when enabled, it indicates to the consumer that it should
+ // attempt to acquire buffers even if it is not aware of any being
+ // available.
+ virtual status_t setAutoRefresh(bool autoRefresh) = 0;
+
// Sets how long dequeueBuffer will wait for a buffer to become available
// before returning an error (TIMED_OUT).
//
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index f79210b..3afdaae 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -168,6 +168,7 @@
int dispatchSetBuffersDataSpace(va_list args);
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSingleBufferMode(va_list args);
+ int dispatchSetAutoRefresh(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -197,6 +198,7 @@
virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual int setAsyncMode(bool async);
virtual int setSingleBufferMode(bool singleBufferMode);
+ virtual int setAutoRefresh(bool autoRefresh);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
@@ -331,6 +333,19 @@
// Stores the current generation number. See setGenerationNumber and
// IGraphicBufferProducer::setGenerationNumber for more information.
uint32_t mGenerationNumber;
+
+ // Caches the values that have been passed to the producer.
+ bool mSingleBufferMode;
+ bool mAutoRefresh;
+
+ // If in single buffer mode and auto refresh is enabled, store the shared
+ // buffer slot and return it for all calls to queue/dequeue without going
+ // over Binder.
+ int mSharedBufferSlot;
+
+ // This is true if the shared buffer has already been queued/canceled. It's
+ // used to prevent a mismatch between the number of queue/dequeue calls.
+ bool mSharedBufferHasBeenQueued;
};
}; // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 036ef1e..5e3924a 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -38,7 +38,7 @@
mAcquireCalled(false),
mTransformToDisplayInverse(false),
mSurfaceDamage(),
- mSingleBufferMode(false),
+ mAutoRefresh(false),
mQueuedBuffer(true),
mIsStale(false) {
}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 92285e5..f8b50cc 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -67,7 +67,7 @@
}
bool sharedBufferAvailable = mCore->mSingleBufferMode &&
- mCore->mSingleBufferSlot !=
+ mCore->mAutoRefresh && mCore->mSingleBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// In asynchronous mode the list is guaranteed to be one buffer deep,
@@ -214,16 +214,15 @@
(mCore->mSingleBufferCache.transform &
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
- outBuffer->mSingleBufferMode = true;
outBuffer->mQueuedBuffer = false;
outBuffer->mIsStale = false;
+ outBuffer->mAutoRefresh = mCore->mSingleBufferMode &&
+ mCore->mAutoRefresh;
} 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/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index f785db0..ba07362 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -79,6 +79,7 @@
mGenerationNumber(0),
mAsyncMode(false),
mSingleBufferMode(false),
+ mAutoRefresh(false),
mSingleBufferSlot(INVALID_BUFFER_SLOT),
mSingleBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN)
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9d42464..e065e61 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -806,8 +806,8 @@
mCore->mDequeueBufferCannotBlock ||
(mCore->mSingleBufferMode && mCore->mSingleBufferSlot == slot);
item.mSurfaceDamage = surfaceDamage;
- item.mSingleBufferMode = mCore->mSingleBufferMode;
item.mQueuedBuffer = true;
+ item.mAutoRefresh = mCore->mSingleBufferMode && mCore->mAutoRefresh;
mStickyTransform = stickyTransform;
@@ -1309,6 +1309,16 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ BQ_LOGV("setAutoRefresh: %d", autoRefresh);
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ mCore->mAutoRefresh = autoRefresh;
+ return NO_ERROR;
+}
+
status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) {
ATRACE_CALL();
BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index e1abd45..55059dd 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -407,7 +407,7 @@
}
// Do whatever sync ops we need to do before releasing the old slot.
- if (!item.mSingleBufferMode || slot != mCurrentTexture) {
+ if (slot != mCurrentTexture) {
err = syncForReleaseLocked(mEglDisplay);
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 2478601..c66694d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -52,6 +52,7 @@
SET_ASYNC_MODE,
GET_NEXT_FRAME_NUMBER,
SET_SINGLE_BUFFER_MODE,
+ SET_AUTO_REFRESH,
SET_DEQUEUE_TIMEOUT,
};
@@ -355,6 +356,18 @@
return result;
}
+ virtual status_t setAutoRefresh(bool autoRefresh) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(autoRefresh);
+ status_t result = remote()->transact(SET_AUTO_REFRESH, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
+
virtual status_t setDequeueTimeout(nsecs_t timeout) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
@@ -562,6 +575,13 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_AUTO_REFRESH: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ bool autoRefresh = data.readInt32();
+ status_t result = setAutoRefresh(autoRefresh);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
case SET_DEQUEUE_TIMEOUT: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
nsecs_t timeout = data.readInt64();
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;
}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index f4c47ed..b6af166 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -65,6 +65,27 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
}
+ void testBufferItem(const IGraphicBufferProducer::QueueBufferInput& input,
+ const BufferItem& item) {
+ int64_t timestamp;
+ bool isAutoTimestamp;
+ android_dataspace dataSpace;
+ Rect crop;
+ int scalingMode;
+ uint32_t transform;
+ sp<Fence> fence;
+
+ input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop,
+ &scalingMode, &transform, &fence, NULL);
+ ASSERT_EQ(timestamp, item.mTimestamp);
+ ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp);
+ ASSERT_EQ(dataSpace, item.mDataSpace);
+ ASSERT_EQ(crop, item.mCrop);
+ ASSERT_EQ(static_cast<uint32_t>(scalingMode), item.mScalingMode);
+ ASSERT_EQ(transform, item.mTransform);
+ ASSERT_EQ(fence, item.mFence);
+ }
+
sp<IGraphicBufferProducer> mProducer;
sp<IGraphicBufferConsumer> mConsumer;
};
@@ -521,7 +542,7 @@
ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer));
}
-TEST_F(BufferQueueTest, TestSingleBufferMode) {
+TEST_F(BufferQueueTest, TestSingleBufferModeWithoutAutoRefresh) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
@@ -545,19 +566,66 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+ // Repeatedly queue and dequeue a buffer from the producer side, it should
+ // always return the same one. And we won't run out of buffers because it's
+ // always the same one and because async mode gets enabled.
+ int slot;
+ for (int i = 0; i < 5; i++) {
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(singleSlot, slot);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+ }
+
+ // acquire the buffer
+ BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ ASSERT_EQ(singleSlot, item.mSlot);
+ testBufferItem(input, item);
+ ASSERT_EQ(true, item.mQueuedBuffer);
+ ASSERT_EQ(false, item.mAutoRefresh);
+
+ ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+ // attempt to acquire a second time should return no buffer available
+ ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
+ mConsumer->acquireBuffer(&item, 0));
+}
+
+TEST_F(BufferQueueTest, TestSingleBufferModeWithAutoRefresh) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, true, &output));
+
+ ASSERT_EQ(OK, mProducer->setSingleBufferMode(true));
+ ASSERT_EQ(OK, mProducer->setAutoRefresh(true));
+
+ // Get a buffer
+ int singleSlot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&singleSlot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(OK, mProducer->requestBuffer(singleSlot, &buffer));
+
+ // Queue the buffer
+ IGraphicBufferProducer::QueueBufferInput input(0, false,
+ HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+
// Repeatedly acquire and release a buffer from the consumer side, it should
// always return the same one.
BufferItem item;
for (int i = 0; i < 5; i++) {
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(singleSlot, item.mSlot);
- ASSERT_EQ(0, item.mTimestamp);
- ASSERT_EQ(false, item.mIsAutoTimestamp);
- ASSERT_EQ(HAL_DATASPACE_UNKNOWN, item.mDataSpace);
- ASSERT_EQ(Rect(0, 0, 1, 1), item.mCrop);
- ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode);
- ASSERT_EQ(0u, item.mTransform);
- ASSERT_EQ(Fence::NO_FENCE, item.mFence);
+ testBufferItem(input, item);
+ ASSERT_EQ(i == 0, item.mQueuedBuffer);
+ ASSERT_EQ(true, item.mAutoRefresh);
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
@@ -585,6 +653,8 @@
ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode);
ASSERT_EQ(0u, item.mTransform);
ASSERT_EQ(Fence::NO_FENCE, item.mFence);
+ ASSERT_EQ(i == 0, item.mQueuedBuffer);
+ ASSERT_EQ(true, item.mAutoRefresh);
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c7e2afb..05700f8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1197,6 +1197,7 @@
//XXX: temporary hack for the EGL hook-up for single buffer mode
if (attribute == EGL_RENDER_BUFFER && (value == EGL_BACK_BUFFER ||
value == EGL_SINGLE_BUFFER)) {
+ native_window_set_auto_refresh(s->win.get(), true);
return (native_window_set_single_buffer_mode(s->win.get(),
value == EGL_SINGLE_BUFFER)) ? EGL_TRUE : EGL_FALSE;
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 64c1dd9..1a0d689 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -547,8 +547,14 @@
return 0;
}
-status_t VirtualDisplaySurface::setSingleBufferMode(bool singleBufferMode) {
- return mSource[SOURCE_SINK]->setSingleBufferMode(singleBufferMode);
+status_t VirtualDisplaySurface::setSingleBufferMode(bool /*singleBufferMode*/) {
+ ALOGE("setSingleBufferMode not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
+}
+
+status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) {
+ ALOGE("setAutoRefresh not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
}
status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 7f451a9..ede204c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -121,6 +121,7 @@
virtual String8 getConsumerName() const override;
virtual uint64_t getNextFrameNumber() const override;
virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
//
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d39075f..6574898 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -88,7 +88,7 @@
mQueueItems(),
mLastFrameNumberReceived(0),
mUpdateTexImageFailed(false),
- mSingleBufferMode(false)
+ mAutoRefresh(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -1260,7 +1260,7 @@
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
- if (mSidebandStreamChanged || mSingleBufferMode) {
+ if (mSidebandStreamChanged || mAutoRefresh) {
return true;
}
@@ -1284,7 +1284,7 @@
bool Layer::onPreComposition() {
mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged || mSingleBufferMode;
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
}
void Layer::onPostComposition() {
@@ -1341,7 +1341,7 @@
}
Region outDirtyRegion;
- if (mQueuedFrames > 0 || mSingleBufferMode) {
+ if (mQueuedFrames > 0 || mAutoRefresh) {
// if we've already called updateTexImage() without going through
// a composition step, we have to skip this layer at this point
@@ -1507,7 +1507,7 @@
// buffer mode.
bool queuedBuffer = false;
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, &mSingleBufferMode, &queuedBuffer,
+ mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
@@ -1563,7 +1563,7 @@
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
- || mSingleBufferMode) {
+ || mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d91e94e..1773daf 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -307,7 +307,7 @@
* Returns if a frame is queued.
*/
bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
- mSidebandStreamChanged || mSingleBufferMode; }
+ mSidebandStreamChanged || mAutoRefresh; }
// -----------------------------------------------------------------------
@@ -493,7 +493,7 @@
std::atomic<uint64_t> mLastFrameNumberReceived;
bool mUpdateTexImageFailed; // This is only modified from the main thread
- bool mSingleBufferMode;
+ bool mAutoRefresh;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index efc44ab..e161d9f 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -135,6 +135,10 @@
return mProducer->setSingleBufferMode(singleBufferMode);
}
+status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) {
+ return mProducer->setAutoRefresh(autoRefresh);
+}
+
status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) {
return mProducer->setDequeueTimeout(timeout);
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index aea2e39..35ce558 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -60,7 +60,8 @@
virtual uint64_t getNextFrameNumber() const override;
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
virtual IBinder* onAsBinder();
- virtual status_t setSingleBufferMode(bool singleBufferMode);
+ virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
private:
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 5722fb4..d3b66e6 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync, bool* singleBufferMode, bool* queuedBuffer,
+ const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber)
{
ATRACE_CALL();
@@ -78,8 +78,8 @@
return BUFFER_REJECTED;
}
- if (singleBufferMode) {
- *singleBufferMode = item.mSingleBufferMode;
+ if (autoRefresh) {
+ *autoRefresh = item.mAutoRefresh;
}
if (queuedBuffer) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 207c243..f3942ab 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -57,7 +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,
+ bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().