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
This commit is contained in:
Mathias Agopian 2013-07-18 22:10:56 -07:00
parent a3fbda3cef
commit 7cdd786fa8
10 changed files with 113 additions and 75 deletions

View File

@ -167,7 +167,7 @@ public:
// //
// In both cases, the producer will need to call requestBuffer to get a // In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot. // GraphicBuffer handle for the returned slot.
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage); uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the BufferQueue. // queueBuffer returns a filled buffer to the BufferQueue.
@ -229,7 +229,7 @@ public:
mTimestamp(0), mTimestamp(0),
mFrameNumber(0), mFrameNumber(0),
mBuf(INVALID_BUFFER_SLOT), mBuf(INVALID_BUFFER_SLOT),
mDequeueBufferCannotBlock(false), mIsDroppable(false),
mAcquireCalled(false) { mAcquireCalled(false) {
mCrop.makeInvalid(); mCrop.makeInvalid();
} }
@ -260,12 +260,12 @@ public:
// mFence is a fence that will signal when the buffer is idle. // mFence is a fence that will signal when the buffer is idle.
sp<Fence> mFence; sp<Fence> mFence;
// mDequeueBufferCannotBlock whether this buffer was queued with the // mIsDroppable whether this buffer was queued with the
// property that it can be replaced by a new buffer for the purpose of // property that it can be replaced by a new buffer for the purpose of
// making sure dequeueBuffer() won't block. // making sure dequeueBuffer() won't block.
// i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
// was queued. // was queued.
bool mDequeueBufferCannotBlock; bool mIsDroppable;
// Indicates whether this buffer has been seen by a consumer yet // Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled; bool mAcquireCalled;
@ -379,9 +379,15 @@ private:
// The initial default is 2. // The initial default is 2.
status_t setDefaultMaxBufferCountLocked(int count); status_t setDefaultMaxBufferCountLocked(int count);
// getMinUndequeuedBufferCount returns the minimum number of buffers
// that must remain in a state other than DEQUEUED.
// The async parameter tells whether we're in asynchronous mode.
int getMinUndequeuedBufferCount(bool async) const;
// getMinBufferCountLocked returns the minimum number of buffers allowed // getMinBufferCountLocked returns the minimum number of buffers allowed
// given the current BufferQueue state. // given the current BufferQueue state.
int getMinMaxBufferCountLocked() const; // The async parameter tells whether we're in asynchronous mode.
int getMinMaxBufferCountLocked(bool async) const;
// getMaxBufferCountLocked returns the maximum number of buffers that can // getMaxBufferCountLocked returns the maximum number of buffers that can
// be allocated at once. This value depends upon the following member // be allocated at once. This value depends upon the following member
@ -391,10 +397,11 @@ private:
// mMaxAcquiredBufferCount // mMaxAcquiredBufferCount
// mDefaultMaxBufferCount // mDefaultMaxBufferCount
// mOverrideMaxBufferCount // mOverrideMaxBufferCount
// async parameter
// //
// Any time one of these member variables is changed while a producer is // Any time one of these member variables is changed while a producer is
// connected, mDequeueCondition must be broadcast. // connected, mDequeueCondition must be broadcast.
int getMaxBufferCountLocked() const; int getMaxBufferCountLocked(bool async) const;
// stillTracking returns true iff the buffer item is still being tracked // stillTracking returns true iff the buffer item is still being tracked
// in one of the slots. // in one of the slots.
@ -516,11 +523,6 @@ private:
// in dequeueBuffer() if a width and height of zero is specified. // in dequeueBuffer() if a width and height of zero is specified.
uint32_t mDefaultHeight; uint32_t mDefaultHeight;
// mMinUndequeuedBufferCount holds the minimum number of buffers
// that must remain in a state other than DEQUEUED.
// This value cannot change while connected.
int mMinUndequeuedBufferCount;
// mMaxAcquiredBufferCount is the number of buffers that the consumer may // mMaxAcquiredBufferCount is the number of buffers that the consumer may
// acquire at one time. It defaults to 1 and can be changed by the // acquire at one time. It defaults to 1 and can be changed by the
// consumer via the setMaxAcquiredBufferCount method, but this may only be // consumer via the setMaxAcquiredBufferCount method, but this may only be

View File

@ -84,7 +84,10 @@ public:
// the buffer. The contents of the buffer must not be overwritten until the // the buffer. The contents of the buffer must not be overwritten until the
// fence signals. If the fence is NULL, the buffer may be written // fence signals. If the fence is NULL, the buffer may be written
// immediately. // immediately.
virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence, //
// The async parameter sets whether we're in asynchrnous mode for this
// deququeBuffer() call.
virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
// queueBuffer indicates that the client has finished filling in the // queueBuffer indicates that the client has finished filling in the
@ -96,6 +99,8 @@ public:
// must be monotonically increasing. Its other properties (zero point, etc) // must be monotonically increasing. Its other properties (zero point, etc)
// are client-dependent, and should be documented by the client. // are client-dependent, and should be documented by the client.
// //
// The async parameter sets whether we're queuing a buffer in asynchronous mode.
//
// outWidth, outHeight and outTransform are filled with the default width // outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers, // and height of the window and current transform applied to buffers,
// respectively. // respectively.
@ -103,17 +108,18 @@ public:
struct QueueBufferInput : public Flattenable { struct QueueBufferInput : public Flattenable {
inline QueueBufferInput(const Parcel& parcel); inline QueueBufferInput(const Parcel& parcel);
inline QueueBufferInput(int64_t timestamp, inline QueueBufferInput(int64_t timestamp,
const Rect& crop, int scalingMode, uint32_t transform, const Rect& crop, int scalingMode, uint32_t transform, bool async,
sp<Fence> fence) const sp<Fence>& fence)
: timestamp(timestamp), crop(crop), scalingMode(scalingMode), : timestamp(timestamp), crop(crop), scalingMode(scalingMode),
transform(transform), fence(fence) { } transform(transform), async(async), fence(fence) { }
inline void deflate(int64_t* outTimestamp, Rect* outCrop, inline void deflate(int64_t* outTimestamp, Rect* outCrop,
int* outScalingMode, uint32_t* outTransform, int* outScalingMode, uint32_t* outTransform, bool* outAsync,
sp<Fence>* outFence) const { sp<Fence>* outFence) const {
*outTimestamp = timestamp; *outTimestamp = timestamp;
*outCrop = crop; *outCrop = crop;
*outScalingMode = scalingMode; *outScalingMode = scalingMode;
*outTransform = transform; *outTransform = transform;
*outAsync = bool(async);
*outFence = fence; *outFence = fence;
} }
@ -130,6 +136,7 @@ public:
Rect crop; Rect crop;
int scalingMode; int scalingMode;
uint32_t transform; uint32_t transform;
int async;
sp<Fence> fence; sp<Fence> fence;
}; };

View File

@ -235,6 +235,10 @@ private:
// by the application // by the application
bool mProducerControlledByApp; bool mProducerControlledByApp;
// mSwapIntervalZero set if we should drop buffers at queue() time to
// achieve an asynchronous swap interval
bool mSwapIntervalZero;
// mConsumerRunningBehind whether the consumer is running more than // mConsumerRunningBehind whether the consumer is running more than
// one buffer behind the producer. // one buffer behind the producer.
mutable bool mConsumerRunningBehind; mutable bool mConsumerRunningBehind;

View File

@ -30,6 +30,7 @@
#include <utils/Log.h> #include <utils/Log.h>
#include <utils/Trace.h> #include <utils/Trace.h>
#include <utils/CallStack.h>
// Macros for including the BufferQueue name in log messages // Macros for including the BufferQueue name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) #define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@ -150,21 +151,21 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
} }
// Error out if the user has dequeued buffers // Error out if the user has dequeued buffers
int maxBufferCount = getMaxBufferCountLocked(); for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
for (int i=0 ; i<maxBufferCount; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers"); ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL; return -EINVAL;
} }
} }
const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) { if (bufferCount == 0) {
mOverrideMaxBufferCount = 0; mOverrideMaxBufferCount = 0;
mDequeueCondition.broadcast(); mDequeueCondition.broadcast();
return NO_ERROR; return NO_ERROR;
} }
// fine to assume async to false before we're setting the buffer count
const int minBufferSlots = getMinMaxBufferCountLocked(false);
if (bufferCount < minBufferSlots) { if (bufferCount < minBufferSlots) {
ST_LOGE("setBufferCount: requested buffer count (%d) is less than " ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
"minimum (%d)", bufferCount, minBufferSlots); "minimum (%d)", bufferCount, minBufferSlots);
@ -209,7 +210,7 @@ int BufferQueue::query(int what, int* outValue)
value = mDefaultBufferFormat; value = mDefaultBufferFormat;
break; break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
value = mMinUndequeuedBufferCount; value = getMinUndequeuedBufferCount(false);
break; break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2); value = (mQueue.size() >= 2);
@ -229,15 +230,11 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGE("requestBuffer: BufferQueue has been abandoned!"); ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
return NO_INIT; return NO_INIT;
} }
int maxBufferCount = getMaxBufferCountLocked(); if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
if (slot < 0 || maxBufferCount <= slot) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, slot); NUM_BUFFER_SLOTS, slot);
return BAD_VALUE; return BAD_VALUE;
} else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { } 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)", ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
slot, mSlots[slot].mBufferState); slot, mSlots[slot].mBufferState);
return BAD_VALUE; return BAD_VALUE;
@ -247,7 +244,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
return NO_ERROR; 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) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL(); ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@ -279,7 +276,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
return NO_INIT; 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 // Free up any buffers that are in slots beyond the max buffer
// count. // count.
@ -328,7 +334,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
// make sure the client is not trying to dequeue more buffers // make sure the client is not trying to dequeue more buffers
// than allowed. // than allowed.
const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
const int minUndequeuedCount = mMinUndequeuedBufferCount; const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
if (newUndequeuedCount < minUndequeuedCount) { if (newUndequeuedCount < minUndequeuedCount) {
ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
"exceeded (dequeued=%d undequeudCount=%d)", "exceeded (dequeued=%d undequeudCount=%d)",
@ -448,9 +454,10 @@ status_t BufferQueue::queueBuffer(int buf,
uint32_t transform; uint32_t transform;
int scalingMode; int scalingMode;
int64_t timestamp; int64_t timestamp;
bool async;
sp<Fence> fence; sp<Fence> fence;
input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence); input.deflate(&timestamp, &crop, &scalingMode, &transform, &async, &fence);
if (fence == NULL) { if (fence == NULL) {
ST_LOGE("queueBuffer: fence is NULL"); ST_LOGE("queueBuffer: fence is NULL");
@ -477,7 +484,17 @@ status_t BufferQueue::queueBuffer(int buf,
ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
return NO_INIT; 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) { if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf); maxBufferCount, buf);
@ -523,7 +540,7 @@ status_t BufferQueue::queueBuffer(int buf,
item.mFrameNumber = mFrameCounter; item.mFrameNumber = mFrameCounter;
item.mBuf = buf; item.mBuf = buf;
item.mFence = fence; item.mFence = fence;
item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock; item.mIsDroppable = mDequeueBufferCannotBlock || async;
if (mQueue.empty()) { if (mQueue.empty()) {
// when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
@ -534,7 +551,7 @@ status_t BufferQueue::queueBuffer(int buf,
// when the queue is not empty, we need to look at the front buffer // when the queue is not empty, we need to look at the front buffer
// state and see if we need to replace it. // state and see if we need to replace it.
Fifo::iterator front(mQueue.begin()); Fifo::iterator front(mQueue.begin());
if (front->mDequeueBufferCannotBlock) { if (front->mIsDroppable) {
// buffer slot currently queued is marked free if still tracked // buffer slot currently queued is marked free if still tracked
if (stillTracking(front)) { if (stillTracking(front)) {
mSlots[front->mBuf].mBufferState = BufferSlot::FREE; mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
@ -573,10 +590,9 @@ void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
return; return;
} }
int maxBufferCount = getMaxBufferCountLocked(); if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf); NUM_BUFFER_SLOTS, buf);
return; return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@ -630,8 +646,6 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer
mBufferHasBeenQueued = false; mBufferHasBeenQueued = false;
mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ?
mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
return err; return err;
} }
@ -704,12 +718,11 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
fifoSize++; fifoSize++;
} }
int maxBufferCount = getMaxBufferCountLocked();
result.appendFormat( 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", "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, mTransformHint, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
fifoSize, fifo.string()); fifoSize, fifo.string());
@ -725,16 +738,25 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
} }
} stateName; } 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++) { for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]); const BufferSlot& slot(mSlots[i]);
const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
result.appendFormat( result.appendFormat(
"%s%s[%02d:%p] state=%-8s", "%s%s[%02d:%p] state=%-8s",
prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
slot.mGraphicBuffer.get(),
stateName(slot.mBufferState) stateName(slot.mBufferState)
); );
const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
if (buf != NULL) { if (buf != NULL) {
result.appendFormat( result.appendFormat(
", %p [%4ux%4u:%4u,%3X]", ", %p [%4ux%4u:%4u,%3X]",
@ -1018,12 +1040,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
return NO_ERROR; return NO_ERROR;
} }
int BufferQueue::getMinMaxBufferCountLocked() const { int BufferQueue::getMinUndequeuedBufferCount(bool async) const {
return mMinUndequeuedBufferCount + 1; return (mDequeueBufferCannotBlock || async) ?
mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
} }
int BufferQueue::getMaxBufferCountLocked() const { int BufferQueue::getMinMaxBufferCountLocked(bool async) const {
int minMaxBufferCount = getMinMaxBufferCountLocked(); return getMinUndequeuedBufferCount(async) + 1;
}
int BufferQueue::getMaxBufferCountLocked(bool async) const {
int minMaxBufferCount = getMinMaxBufferCountLocked(async);
int maxBufferCount = mDefaultMaxBufferCount; int maxBufferCount = mDefaultMaxBufferCount;
if (maxBufferCount < minMaxBufferCount) { if (maxBufferCount < minMaxBufferCount) {

View File

@ -80,10 +80,11 @@ public:
return result; 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) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(async);
data.writeInt32(w); data.writeInt32(w);
data.writeInt32(h); data.writeInt32(h);
data.writeInt32(format); data.writeInt32(format);
@ -197,13 +198,14 @@ status_t BnGraphicBufferProducer::onTransact(
} break; } break;
case DEQUEUE_BUFFER: { case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply); CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = data.readInt32();
uint32_t w = data.readInt32(); uint32_t w = data.readInt32();
uint32_t h = data.readInt32(); uint32_t h = data.readInt32();
uint32_t format = data.readInt32(); uint32_t format = data.readInt32();
uint32_t usage = data.readInt32(); uint32_t usage = data.readInt32();
int buf; int buf;
sp<Fence> fence; 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(buf);
reply->writeInt32(fence != NULL); reply->writeInt32(fence != NULL);
if (fence != NULL) { if (fence != NULL) {
@ -274,6 +276,7 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const
+ sizeof(crop) + sizeof(crop)
+ sizeof(scalingMode) + sizeof(scalingMode)
+ sizeof(transform) + sizeof(transform)
+ sizeof(async)
+ fence->getFlattenedSize(); + fence->getFlattenedSize();
} }
@ -291,6 +294,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t
memcpy(p, &crop, sizeof(crop)); p += sizeof(crop); memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(p, &transform, sizeof(transform)); p += sizeof(transform); 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); err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
return err; return err;
} }
@ -304,6 +308,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer,
memcpy(&crop, p, sizeof(crop)); p += sizeof(crop); memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(&transform, p, sizeof(transform)); p += sizeof(transform); memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
memcpy(&async, p, sizeof(async)); p += sizeof(async);
fence = new Fence(); fence = new Fence();
err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
return err; return err;

View File

@ -73,6 +73,7 @@ Surface::Surface(
mConsumerRunningBehind = false; mConsumerRunningBehind = false;
mConnectedToCpu = false; mConnectedToCpu = false;
mProducerControlledByApp = true; mProducerControlledByApp = true;
mSwapIntervalZero = false;
} }
Surface::~Surface() { Surface::~Surface() {
@ -162,7 +163,6 @@ int Surface::setSwapInterval(int interval) {
// EGL specification states: // EGL specification states:
// interval is silently clamped to minimum and maximum implementation // interval is silently clamped to minimum and maximum implementation
// dependent values before being stored. // dependent values before being stored.
// Although we don't have to, we apply the same logic here.
if (interval < minSwapInterval) if (interval < minSwapInterval)
interval = minSwapInterval; interval = minSwapInterval;
@ -170,11 +170,9 @@ int Surface::setSwapInterval(int interval) {
if (interval > maxSwapInterval) if (interval > maxSwapInterval)
interval = maxSwapInterval; interval = maxSwapInterval;
// FIXME: re-implement swap-interval mSwapIntervalZero = (interval == 0);
//status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
status_t res = NO_ERROR;
return res; return NO_ERROR;
} }
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int Surface::dequeueBuffer(android_native_buffer_t** buffer,
@ -186,7 +184,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer,
int reqW = mReqWidth ? mReqWidth : mUserWidth; int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight; int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence; sp<Fence> fence;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage); reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) { if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
@ -282,7 +280,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
mTransform, fence); mTransform, mSwapIntervalZero, fence);
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) { if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);

View File

@ -71,12 +71,12 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
sp<Fence> fence; sp<Fence> fence;
sp<GraphicBuffer> buf; sp<GraphicBuffer> buf;
IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), 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; BufferQueue::BufferItem item;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, 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)); GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@ -84,7 +84,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
} }
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, 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)); GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));

View File

@ -361,7 +361,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3]; 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_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[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@ -382,7 +381,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3]; 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_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[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@ -403,7 +401,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
android_native_buffer_t* buf[3]; 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_set_buffer_count(mANW.get(), 3));
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[0]));
@ -429,7 +426,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
android_native_buffer_t* firstBuf; 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_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
@ -449,7 +445,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent)
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
android_native_buffer_t* buf[3]; 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_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy. // We should be able to dequeue all the buffers before we've queued mANWy.
@ -528,7 +523,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
}; };
android_native_buffer_t* buf[3]; 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_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer // dequeue/queue/update so we have a current buffer
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[0]));

View File

@ -126,7 +126,7 @@ status_t VirtualDisplaySurface::advanceFrame() {
mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight, mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
&transformHint, &numPendingBuffers); &transformHint, &numPendingBuffers);
int sslot; int sslot;
result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence); result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false);
if (result < 0) if (result < 0)
return result; return result;
mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
@ -196,7 +196,7 @@ void VirtualDisplaySurface::onFrameCommitted() {
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
QueueBufferInput(systemTime(), QueueBufferInput(systemTime(),
Rect(mSinkBufferWidth, mSinkBufferHeight), Rect(mSinkBufferWidth, mSinkBufferHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence),
&qbo); &qbo);
if (result == NO_ERROR) { if (result == NO_ERROR) {
updateQueueBufferOutput(qbo); updateQueueBufferOutput(qbo);
@ -224,8 +224,8 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
} }
status_t VirtualDisplaySurface::dequeueBuffer(Source source, status_t VirtualDisplaySurface::dequeueBuffer(Source source,
uint32_t format, int* sslot, sp<Fence>* fence) { uint32_t format, int* sslot, sp<Fence>* fence, bool async) {
status_t result = mSource[source]->dequeueBuffer(sslot, fence, status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
if (result < 0) if (result < 0)
return result; return result;
@ -257,7 +257,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source,
return result; return result;
} }
status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
"Unexpected dequeueBuffer() in %s state", dbgStateStr()); "Unexpected dequeueBuffer() in %s state", dbgStateStr());
@ -273,7 +273,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
} }
int sslot; int sslot;
status_t result = dequeueBuffer(source, format, &sslot, fence); status_t result = dequeueBuffer(source, format, &sslot, fence, async);
if (result >= 0) { if (result >= 0) {
*pslot = mapSource2ProducerSlot(source, sslot); *pslot = mapSource2ProducerSlot(source, sslot);
} }
@ -321,8 +321,9 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot,
Rect crop; Rect crop;
int scalingMode; int scalingMode;
uint32_t transform; uint32_t transform;
bool async;
input.deflate(&timestamp, &crop, &scalingMode, &transform, input.deflate(&timestamp, &crop, &scalingMode, &transform,
&mFbFence); &async, &mFbFence);
mFbProducerSlot = pslot; mFbProducerSlot = pslot;
} }

View File

@ -95,7 +95,7 @@ private:
// //
virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
virtual status_t setBufferCount(int bufferCount); virtual status_t setBufferCount(int bufferCount);
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage); uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t queueBuffer(int pslot, virtual status_t queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output); const QueueBufferInput& input, QueueBufferOutput* output);
@ -109,7 +109,7 @@ private:
// //
static Source fbSourceForCompositionType(CompositionType type); static Source fbSourceForCompositionType(CompositionType type);
status_t dequeueBuffer(Source source, uint32_t format, status_t dequeueBuffer(Source source, uint32_t format,
int* sslot, sp<Fence>* fence); int* sslot, sp<Fence>* fence, bool async);
void updateQueueBufferOutput(const QueueBufferOutput& qbo); void updateQueueBufferOutput(const QueueBufferOutput& qbo);
void resetPerFrameState(); void resetPerFrameState();