Make ANW.setSwapInterval(0) work again
we can now queue/dequeue a buffer in asynchrnous mode by using the
async parameter to these calls. async mode is only specified
with those calls (it is not modal anymore).
as a consequence it can only be specified when the buffer count
is not overidden, as error is returned otherwise.
Change-Id: Ic63f4f96f671cb9d65c4cecbcc192615e09a8b6b
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index f99bd29..cf81431 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -30,6 +30,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <utils/CallStack.h>
// Macros for including the BufferQueue name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@@ -150,21 +151,21 @@
}
// Error out if the user has dequeued buffers
- int maxBufferCount = getMaxBufferCountLocked();
- for (int i=0 ; i<maxBufferCount; i++) {
+ for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL;
}
}
- const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) {
mOverrideMaxBufferCount = 0;
mDequeueCondition.broadcast();
return NO_ERROR;
}
+ // fine to assume async to false before we're setting the buffer count
+ const int minBufferSlots = getMinMaxBufferCountLocked(false);
if (bufferCount < minBufferSlots) {
ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
"minimum (%d)", bufferCount, minBufferSlots);
@@ -209,7 +210,7 @@
value = mDefaultBufferFormat;
break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = mMinUndequeuedBufferCount;
+ value = getMinUndequeuedBufferCount(false);
break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2);
@@ -229,15 +230,11 @@
ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
- int maxBufferCount = getMaxBufferCountLocked();
- if (slot < 0 || maxBufferCount <= slot) {
+ if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- maxBufferCount, slot);
+ NUM_BUFFER_SLOTS, slot);
return BAD_VALUE;
} else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
- // XXX: I vaguely recall there was some reason this can be valid, but
- // for the life of me I can't recall under what circumstances that's
- // the case.
ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
slot, mSlots[slot].mBufferState);
return BAD_VALUE;
@@ -247,7 +244,7 @@
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@@ -279,7 +276,16 @@
return NO_INIT;
}
- const int maxBufferCount = getMaxBufferCountLocked();
+ const int maxBufferCount = getMaxBufferCountLocked(async);
+ if (async && mOverrideMaxBufferCount) {
+ // FIXME: some drivers are manually setting the buffer-count (which they
+ // shouldn't), so we do this extra test here to handle that case.
+ // This is TEMPORARY, until we get this fixed.
+ if (mOverrideMaxBufferCount < maxBufferCount) {
+ ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
+ return BAD_VALUE;
+ }
+ }
// Free up any buffers that are in slots beyond the max buffer
// count.
@@ -328,7 +334,7 @@
// make sure the client is not trying to dequeue more buffers
// than allowed.
const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
- const int minUndequeuedCount = mMinUndequeuedBufferCount;
+ const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
if (newUndequeuedCount < minUndequeuedCount) {
ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
"exceeded (dequeued=%d undequeudCount=%d)",
@@ -448,9 +454,10 @@
uint32_t transform;
int scalingMode;
int64_t timestamp;
+ bool async;
sp<Fence> fence;
- input.deflate(×tamp, &crop, &scalingMode, &transform, &fence);
+ input.deflate(×tamp, &crop, &scalingMode, &transform, &async, &fence);
if (fence == NULL) {
ST_LOGE("queueBuffer: fence is NULL");
@@ -477,7 +484,17 @@
ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
- int maxBufferCount = getMaxBufferCountLocked();
+
+ const int maxBufferCount = getMaxBufferCountLocked(async);
+ if (async && mOverrideMaxBufferCount) {
+ // FIXME: some drivers are manually setting the buffer-count (which they
+ // shouldn't), so we do this extra test here to handle that case.
+ // This is TEMPORARY, until we get this fixed.
+ if (mOverrideMaxBufferCount < maxBufferCount) {
+ ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
+ return BAD_VALUE;
+ }
+ }
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf);
@@ -523,7 +540,7 @@
item.mFrameNumber = mFrameCounter;
item.mBuf = buf;
item.mFence = fence;
- item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock;
+ item.mIsDroppable = mDequeueBufferCannotBlock || async;
if (mQueue.empty()) {
// when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
@@ -534,7 +551,7 @@
// when the queue is not empty, we need to look at the front buffer
// state and see if we need to replace it.
Fifo::iterator front(mQueue.begin());
- if (front->mDequeueBufferCannotBlock) {
+ if (front->mIsDroppable) {
// buffer slot currently queued is marked free if still tracked
if (stillTracking(front)) {
mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
@@ -573,10 +590,9 @@
return;
}
- int maxBufferCount = getMaxBufferCountLocked();
- if (buf < 0 || buf >= maxBufferCount) {
+ if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
- maxBufferCount, buf);
+ NUM_BUFFER_SLOTS, buf);
return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@@ -630,8 +646,6 @@
mBufferHasBeenQueued = false;
mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
- mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ?
- mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
return err;
}
@@ -704,12 +718,11 @@
fifoSize++;
}
- int maxBufferCount = getMaxBufferCountLocked();
result.appendFormat(
- "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
+ "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
"default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
- prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
+ prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, mTransformHint,
fifoSize, fifo.string());
@@ -725,16 +738,25 @@
}
} stateName;
+ // just trim the free buffers to not spam the dump
+ int maxBufferCount = 0;
+ for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
+ const BufferSlot& slot(mSlots[i]);
+ if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
+ maxBufferCount = i+1;
+ break;
+ }
+ }
+
for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]);
+ const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
result.appendFormat(
"%s%s[%02d:%p] state=%-8s",
- prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
- slot.mGraphicBuffer.get(),
+ prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
stateName(slot.mBufferState)
);
- const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
if (buf != NULL) {
result.appendFormat(
", %p [%4ux%4u:%4u,%3X]",
@@ -1018,12 +1040,17 @@
return NO_ERROR;
}
-int BufferQueue::getMinMaxBufferCountLocked() const {
- return mMinUndequeuedBufferCount + 1;
+int BufferQueue::getMinUndequeuedBufferCount(bool async) const {
+ return (mDequeueBufferCannotBlock || async) ?
+ mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
}
-int BufferQueue::getMaxBufferCountLocked() const {
- int minMaxBufferCount = getMinMaxBufferCountLocked();
+int BufferQueue::getMinMaxBufferCountLocked(bool async) const {
+ return getMinUndequeuedBufferCount(async) + 1;
+}
+
+int BufferQueue::getMaxBufferCountLocked(bool async) const {
+ int minMaxBufferCount = getMinMaxBufferCountLocked(async);
int maxBufferCount = mDefaultMaxBufferCount;
if (maxBufferCount < minMaxBufferCount) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 9f65fc3..2e561df 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -80,10 +80,11 @@
return result;
}
- virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(async);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -197,13 +198,14 @@
} break;
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ bool async = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
sp<Fence> fence;
- int result = dequeueBuffer(&buf, &fence, w, h, format, usage);
+ int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
@@ -274,6 +276,7 @@
+ sizeof(crop)
+ sizeof(scalingMode)
+ sizeof(transform)
+ + sizeof(async)
+ fence->getFlattenedSize();
}
@@ -291,6 +294,7 @@
memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
+ memcpy(p, &async, sizeof(async)); p += sizeof(async);
err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
return err;
}
@@ -304,6 +308,7 @@
memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
+ memcpy(&async, p, sizeof(async)); p += sizeof(async);
fence = new Fence();
err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
return err;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0d4449a..998ea8a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -73,6 +73,7 @@
mConsumerRunningBehind = false;
mConnectedToCpu = false;
mProducerControlledByApp = true;
+ mSwapIntervalZero = false;
}
Surface::~Surface() {
@@ -162,7 +163,6 @@
// EGL specification states:
// interval is silently clamped to minimum and maximum implementation
// dependent values before being stored.
- // Although we don't have to, we apply the same logic here.
if (interval < minSwapInterval)
interval = minSwapInterval;
@@ -170,11 +170,9 @@
if (interval > maxSwapInterval)
interval = maxSwapInterval;
- // FIXME: re-implement swap-interval
- //status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
- status_t res = NO_ERROR;
+ mSwapIntervalZero = (interval == 0);
- return res;
+ return NO_ERROR;
}
int Surface::dequeueBuffer(android_native_buffer_t** buffer,
@@ -186,7 +184,7 @@
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence;
- status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
@@ -282,7 +280,7 @@
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
- mTransform, fence);
+ mTransform, mSwapIntervalZero, fence);
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1f8e7fa..b691fc1 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -71,12 +71,12 @@
sp<Fence> fence;
sp<GraphicBuffer> buf;
IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
- NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
BufferQueue::BufferItem item;
for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@@ -84,7 +84,7 @@
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 9908cc9..158c94b 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -361,7 +361,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -382,7 +381,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -403,7 +401,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -429,7 +426,6 @@
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
android_native_buffer_t* buf[3];
android_native_buffer_t* firstBuf;
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
@@ -449,7 +445,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy.
@@ -528,7 +523,6 @@
};
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));