Merge changes I09a74538,I08d96b38,Ic1d3344b

* changes:
  SurfaceTexture: disable a failing test.
  SurfaceTexture: fix an error check in dequeueBuffer.
  SurfaceTexture: clean up some comments, tests, etc.
This commit is contained in:
Jamie Gennis
2011-05-25 15:54:35 -07:00
committed by Android (Google) Code Review
4 changed files with 116 additions and 77 deletions

View File

@@ -197,8 +197,9 @@ private:
mEglDisplay(EGL_NO_DISPLAY),
mBufferState(BufferSlot::FREE),
mRequestBufferCalled(false),
mLastQueuedTransform(0),
mLastQueuedTimestamp(0) {
mTransform(0),
mTimestamp(0) {
mCrop.makeInvalid();
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
@@ -211,32 +212,56 @@ private:
// mEglDisplay is the EGLDisplay used to create mEglImage.
EGLDisplay mEglDisplay;
// mBufferState indicates whether the slot is currently accessible to a
// client and should not be used by the SurfaceTexture object. It gets
// set to true when dequeueBuffer returns the slot and is reset to false
// when the client calls either queueBuffer or cancelBuffer on the slot.
enum { DEQUEUED=-2, FREE=-1, QUEUED=0 };
int8_t mBufferState;
// BufferState represents the different states in which a buffer slot
// can be.
enum BufferState {
// FREE indicates that the buffer is not currently being used and
// will not be used in the future until it gets dequeued and
// subseqently queued by the client.
FREE = 0,
// DEQUEUED indicates that the buffer has been dequeued by the
// client, but has not yet been queued or canceled. The buffer is
// considered 'owned' by the client, and the server should not use
// it for anything.
//
// Note that when in synchronous-mode (mSynchronousMode == true),
// the buffer that's currently attached to the texture may be
// dequeued by the client. That means that the current buffer can
// be in either the DEQUEUED or QUEUED state. In asynchronous mode,
// however, the current buffer is always in the QUEUED state.
DEQUEUED = 1,
// QUEUED indicates that the buffer has been queued by the client,
// and has not since been made available for the client to dequeue.
// Attaching the buffer to the texture does NOT transition the
// buffer away from the QUEUED state. However, in Synchronous mode
// the current buffer may be dequeued by the client under some
// circumstances. See the note about the current buffer in the
// documentation for DEQUEUED.
QUEUED = 2,
};
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
// mRequestBufferCalled is used for validating that the client did
// call requestBuffer() when told to do so. Technically this is not
// needed but useful for debugging and catching client bugs.
bool mRequestBufferCalled;
// mLastQueuedCrop is the crop rectangle for the buffer that was most
// recently queued. This gets set to mNextCrop each time queueBuffer gets
// called.
Rect mLastQueuedCrop;
// mCrop is the current crop rectangle for this buffer slot. This gets
// set to mNextCrop each time queueBuffer gets called for this buffer.
Rect mCrop;
// mLastQueuedTransform is the transform identifier for the buffer that was
// most recently queued. This gets set to mNextTransform each time
// queueBuffer gets called.
uint32_t mLastQueuedTransform;
// mTransform is the current transform flags for this buffer slot. This
// gets set to mNextTransform each time queueBuffer gets called for this
// slot.
uint32_t mTransform;
// mLastQueuedTimestamp is the timestamp for the buffer that was most
// recently queued. This gets set by queueBuffer.
int64_t mLastQueuedTimestamp;
// mTimestamp is the current timestamp for this buffer slot. This gets
// to set by queueBuffer each time this slot is queued.
int64_t mTimestamp;
};
// mSlots is the array of buffer slots that must be mirrored on the client

View File

@@ -285,15 +285,19 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
return -EINVAL;
}
// make sure the client is not trying to dequeue more buffers
// than allowed.
const int avail = mBufferCount - (dequeuedCount+1);
if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
dequeuedCount);
// TODO: Enable this error report after we fix issue 4435022
// return -EBUSY;
// See whether a buffer has been queued since the last setBufferCount so
// we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
if (bufferHasBeenQueued) {
// make sure the client is not trying to dequeue more buffers
// than allowed.
const int avail = mBufferCount - (dequeuedCount+1);
if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
dequeuedCount);
return -EBUSY;
}
}
// we're in synchronous mode and didn't find a buffer, we need to wait
@@ -390,49 +394,49 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
if (buf < 0 || buf >= mBufferCount) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
LOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
buf, mSlots[buf].mBufferState);
return -EINVAL;
} else if (buf == mCurrentTexture) {
LOGE("queueBuffer: slot %d is current!", buf);
return -EINVAL;
} else if (!mSlots[buf].mRequestBufferCalled) {
LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
buf);
return -EINVAL;
}
Mutex::Autolock lock(mMutex);
if (buf < 0 || buf >= mBufferCount) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
LOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
buf, mSlots[buf].mBufferState);
return -EINVAL;
} else if (buf == mCurrentTexture) {
LOGE("queueBuffer: slot %d is current!", buf);
return -EINVAL;
} else if (!mSlots[buf].mRequestBufferCalled) {
LOGE("queueBuffer: slot %d was enqueued without requesting a "
"buffer", buf);
return -EINVAL;
}
if (mQueue.empty()) {
listener = mFrameAvailableListener;
}
if (mSynchronousMode) {
// in synchronous mode we queue all buffers in a FIFO
mQueue.push_back(buf);
} else {
// in asynchronous mode we only keep the most recent buffer
if (mQueue.empty()) {
listener = mFrameAvailableListener;
}
if (mSynchronousMode) {
// in synchronous mode we queue all buffers in a FIFO
mQueue.push_back(buf);
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
mSlots[*front].mBufferState = BufferSlot::FREE;
// and we record the new buffer index in the queued list
*front = buf;
// in asynchronous mode we only keep the most recent buffer
if (mQueue.empty()) {
mQueue.push_back(buf);
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
mSlots[*front].mBufferState = BufferSlot::FREE;
// and we record the new buffer index in the queued list
*front = buf;
}
}
}
mSlots[buf].mBufferState = BufferSlot::QUEUED;
mSlots[buf].mLastQueuedCrop = mNextCrop;
mSlots[buf].mLastQueuedTransform = mNextTransform;
mSlots[buf].mLastQueuedTimestamp = timestamp;
mDequeueCondition.signal();
mSlots[buf].mBufferState = BufferSlot::QUEUED;
mSlots[buf].mCrop = mNextCrop;
mSlots[buf].mTransform = mNextTransform;
mSlots[buf].mTimestamp = timestamp;
mDequeueCondition.signal();
} // scope for the lock
// call back without lock held
@@ -540,9 +544,9 @@ status_t SurfaceTexture::updateTexImage() {
mCurrentTexture = buf;
mCurrentTextureTarget = target;
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = mSlots[buf].mLastQueuedCrop;
mCurrentTransform = mSlots[buf].mLastQueuedTransform;
mCurrentTimestamp = mSlots[buf].mLastQueuedTimestamp;
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentTimestamp = mSlots[buf].mTimestamp;
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
@@ -826,12 +830,10 @@ void SurfaceTexture::dump(String8& result, const char* prefix,
const BufferSlot& slot(mSlots[i]);
snprintf(buffer, SIZE,
"%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, "
"timestamp=%lld\n"
,
"timestamp=%lld\n",
prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState),
slot.mLastQueuedCrop.left, slot.mLastQueuedCrop.top,
slot.mLastQueuedCrop.right, slot.mLastQueuedCrop.bottom,
slot.mLastQueuedTransform, slot.mLastQueuedTimestamp
slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
slot.mTransform, slot.mTimestamp
);
result.append(buffer);
}

View File

@@ -117,7 +117,8 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
mReqFormat, mReqUsage);
if (result < 0) {
LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
"failed: %d", result, mReqWidth, mReqHeight, mReqFormat, mReqUsage);
"failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
result);
return result;
}
sp<GraphicBuffer>& gbuf(mSlots[buf]);

View File

@@ -400,7 +400,9 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]);
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDequeueCurrent) {
// XXX: We currently have no hardware that properly handles dequeuing the
// buffer that is currently bound to the texture.
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
android_native_buffer_t* buf[3];
@@ -429,10 +431,13 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
android_native_buffer_t* buf[3];
ASSERT_EQ(OK, st->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
// We should be able to dequeue all the buffers before we've queued any.
EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
EXPECT_EQ(-EBUSY, anw->dequeueBuffer(anw.get(), &buf[2]));
EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2]));
ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
EXPECT_EQ(OK, st->updateTexImage());
@@ -440,11 +445,17 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
// Once we've queued a buffer, however we should not be able to dequeue more
// than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case.
EXPECT_EQ(-EBUSY, anw->dequeueBuffer(anw.get(), &buf[1]));
ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2]));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeWaitRetire) {
// XXX: This is not expected to pass until the synchronization hacks are removed
// from the SurfaceTexture class.
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);