BufferQueueProducer: add detachNextBuffer

Adds a new method, IGBP::detachNextBuffer, that effectively does
dequeue + request + detach in a single call, but does not need to
know anything about the dequeued buffer, and will not block on
dequeue. This is mostly for the upcoming StreamSplitter to use in
its onBufferReleased callback.

Change-Id: Ie88a69de109003acebaa486a5b44c8a455726550
This commit is contained in:
Dan Stoza 2014-03-28 15:25:31 -07:00
parent 7f605bd4c0
commit d9822a3843
10 changed files with 143 additions and 0 deletions

View File

@ -199,6 +199,10 @@ public:
// See IGraphicBufferProducer::detachBuffer
virtual status_t detachProducerBuffer(int slot);
// See IGraphicBufferProducer::detachNextBuffer
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
// See IGraphicBufferProducer::attachBuffer
virtual status_t attachProducerBuffer(int* slot,
const sp<GraphicBuffer>& buffer);

View File

@ -99,6 +99,10 @@ public:
// See IGraphicBufferProducer::detachBuffer
virtual status_t detachBuffer(int slot);
// See IGraphicBufferProducer::detachNextBuffer
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
// See IGraphicBufferProducer::attachBuffer
virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer);

View File

@ -185,6 +185,27 @@ public:
// it refers to is not currently dequeued and requested.
virtual status_t detachBuffer(int slot) = 0;
// detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer,
// and detachBuffer in sequence, except for two things:
//
// 1) It is unnecessary to know the dimensions, format, or usage of the
// next buffer.
// 2) It will not block, since if it cannot find an appropriate buffer to
// return, it will return an error instead.
//
// Only slots that are free but still contain a GraphicBuffer will be
// considered, and the oldest of those will be returned. outBuffer is
// equivalent to outBuffer from the requestBuffer call, and outFence is
// equivalent to fence from the dequeueBuffer call.
//
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the buffer queue has been abandoned.
// * BAD_VALUE - either outBuffer or outFence were NULL.
// * NO_MEMORY - no slots were found that were both free and contained a
// GraphicBuffer.
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) = 0;
// attachBuffer attempts to transfer ownership of a buffer to the buffer
// queue. If this call succeeds, it will be as if this buffer was dequeued
// from the returned slot number. As such, this call will fail if attaching

View File

@ -103,6 +103,11 @@ status_t BufferQueue::detachProducerBuffer(int slot) {
return mProducer->detachBuffer(slot);
}
status_t BufferQueue::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
return mProducer->detachNextBuffer(outBuffer, outFence);
}
status_t BufferQueue::attachProducerBuffer(int* slot,
const sp<GraphicBuffer>& buffer) {
return mProducer->attachBuffer(slot, buffer);

View File

@ -393,6 +393,50 @@ status_t BufferQueueProducer::detachBuffer(int slot) {
return NO_ERROR;
}
status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
ATRACE_CALL();
if (outBuffer == NULL) {
BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
return BAD_VALUE;
} else if (outFence == NULL) {
BQ_LOGE("detachNextBuffer: outFence must not be NULL");
return BAD_VALUE;
}
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
// Find the oldest valid slot
int found = BufferQueueCore::INVALID_BUFFER_SLOT;
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
if (mSlots[s].mBufferState == BufferSlot::FREE &&
mSlots[s].mGraphicBuffer != NULL) {
if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
found = s;
}
}
}
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
return NO_MEMORY;
}
BQ_LOGV("detachNextBuffer detached slot %d", found);
*outBuffer = mSlots[found].mGraphicBuffer;
*outFence = mSlots[found].mFence;
mCore->freeBufferLocked(found);
return NO_ERROR;
}
status_t BufferQueueProducer::attachBuffer(int* outSlot,
const sp<android::GraphicBuffer>& buffer) {
ATRACE_CALL();

View File

@ -37,6 +37,7 @@ enum {
SET_BUFFER_COUNT,
DEQUEUE_BUFFER,
DETACH_BUFFER,
DETACH_NEXT_BUFFER,
ATTACH_BUFFER,
QUEUE_BUFFER,
CANCEL_BUFFER,
@ -123,6 +124,37 @@ public:
return result;
}
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
if (outBuffer == NULL) {
ALOGE("detachNextBuffer: outBuffer must not be NULL");
return BAD_VALUE;
} else if (outFence == NULL) {
ALOGE("detachNextBuffer: outFence must not be NULL");
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
status_t result = remote()->transact(DETACH_NEXT_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
}
result = reply.readInt32();
if (result == NO_ERROR) {
bool nonNull = reply.readInt32();
if (nonNull) {
*outBuffer = new GraphicBuffer;
reply.read(**outBuffer);
}
nonNull = reply.readInt32();
if (nonNull) {
*outFence = new Fence;
reply.read(**outFence);
}
}
return result;
}
virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
@ -274,6 +306,24 @@ status_t BnGraphicBufferProducer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
} break;
case DETACH_NEXT_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
sp<GraphicBuffer> buffer;
sp<Fence> fence;
int32_t result = detachNextBuffer(&buffer, &fence);
reply->writeInt32(result);
if (result == NO_ERROR) {
reply->writeInt32(buffer != NULL);
if (buffer != NULL) {
reply->write(*buffer);
}
reply->writeInt32(fence != NULL);
if (fence != NULL) {
reply->write(*fence);
}
}
return NO_ERROR;
} break;
case ATTACH_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
sp<GraphicBuffer> buffer = new GraphicBuffer();

View File

@ -380,6 +380,12 @@ status_t VirtualDisplaySurface::detachBuffer(int /* slot */) {
return INVALID_OPERATION;
}
status_t VirtualDisplaySurface::detachNextBuffer(
sp<GraphicBuffer>* /* outBuffer */, sp<Fence>* /* outFence */) {
VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface");
return INVALID_OPERATION;
}
status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */,
const sp<GraphicBuffer>& /* buffer */) {
VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface");

View File

@ -101,6 +101,8 @@ private:
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
virtual status_t queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output);

View File

@ -69,6 +69,11 @@ status_t MonitoredProducer::detachBuffer(int slot) {
return mProducer->detachBuffer(slot);
}
status_t MonitoredProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
return mProducer->detachNextBuffer(outBuffer, outFence);
}
status_t MonitoredProducer::attachBuffer(int* outSlot,
const sp<GraphicBuffer>& buffer) {
return mProducer->attachBuffer(outSlot, buffer);

View File

@ -39,6 +39,8 @@ public:
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
virtual status_t attachBuffer(int* outSlot,
const sp<GraphicBuffer>& buffer);
virtual status_t queueBuffer(int slot, const QueueBufferInput& input,