BufferQueue: Allow detaching/reattaching buffers
Adds detachBuffer and attachBuffer calls to both the producer and
consumer sides of BufferQueue. Buffers may be detached while dequeued
by the producer or acquired by the consumer, and when attached, enter
the dequeued and acquired states, respectively.
Bug: 13173343
Change-Id: Ic152692b0a94d99e0135b9bfa62747dab2a54220
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 7eaf842..f230e55 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -28,10 +28,43 @@
#include <binder/IBinder.h>
namespace android {
-// ----------------------------------------------------------------------------
-class BufferQueue : public BnGraphicBufferProducer,
- public BnGraphicBufferConsumer,
+// BQProducer and BQConsumer are thin shim classes to allow methods with the
+// same signature in both IGraphicBufferProducer and IGraphicBufferConsumer.
+// This will stop being an issue when we deprecate creating BufferQueues
+// directly (as opposed to using the *Producer and *Consumer interfaces).
+class BQProducer : public BnGraphicBufferProducer {
+public:
+ virtual status_t detachProducerBuffer(int slot) = 0;
+ virtual status_t attachProducerBuffer(int* slot,
+ const sp<GraphicBuffer>& buffer) = 0;
+
+ virtual status_t detachBuffer(int slot) {
+ return detachProducerBuffer(slot);
+ }
+
+ virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+ return attachProducerBuffer(slot, buffer);
+ }
+};
+
+class BQConsumer : public BnGraphicBufferConsumer {
+public:
+ virtual status_t detachConsumerBuffer(int slot) = 0;
+ virtual status_t attachConsumerBuffer(int* slot,
+ const sp<GraphicBuffer>& buffer) = 0;
+
+ virtual status_t detachBuffer(int slot) {
+ return detachConsumerBuffer(slot);
+ }
+
+ virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+ return attachConsumerBuffer(slot, buffer);
+ }
+};
+
+class BufferQueue : public BQProducer,
+ public BQConsumer,
private IBinder::DeathRecipient {
public:
// BufferQueue will keep track of at most this value of buffers.
@@ -73,6 +106,10 @@
wp<ConsumerListener> mConsumerListener;
};
+ static void createBufferQueue(sp<BnGraphicBufferProducer>* outProducer,
+ sp<BnGraphicBufferConsumer>* outConsumer,
+ const sp<IGraphicBufferAlloc>& allocator = NULL);
+
// BufferQueue manages a pool of gralloc memory slots to be used by
// producers and consumers. allocator is used to allocate all the
// needed gralloc buffers.
@@ -157,6 +194,13 @@
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+ // See IGraphicBufferProducer::detachBuffer
+ virtual status_t detachProducerBuffer(int slot);
+
+ // See IGraphicBufferProducer::attachBuffer
+ virtual status_t attachProducerBuffer(int* slot,
+ const sp<GraphicBuffer>& buffer);
+
// queueBuffer returns a filled buffer to the BufferQueue.
//
// Additional data is provided in the QueueBufferInput struct. Notably,
@@ -223,6 +267,13 @@
// is CLOCK_MONOTONIC.
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen);
+ // See IGraphicBufferConsumer::detachBuffer
+ virtual status_t detachConsumerBuffer(int slot);
+
+ // See IGraphicBufferConsumer::attachBuffer
+ virtual status_t attachConsumerBuffer(int* slot,
+ const sp<GraphicBuffer>& buffer);
+
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue. This may be done while the buffer's contents are still
// being accessed. The fence will signal when the buffer is no longer
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 20db98c..71105df 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -49,6 +49,12 @@
virtual status_t acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent);
+ // See IGraphicBufferConsumer::detachBuffer
+ virtual status_t detachBuffer(int slot);
+
+ // See IGraphicBufferConsumer::attachBuffer
+ virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
+
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue. This may be done while the buffer's contents are still
// being accessed. The fence will signal when the buffer is no longer
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 8912097..2eeb979 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -96,6 +96,12 @@
virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+ // See IGraphicBufferProducer::detachBuffer
+ virtual status_t detachBuffer(int slot);
+
+ // See IGraphicBufferProducer::attachBuffer
+ virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer);
+
// queueBuffer returns a filled buffer to the BufferQueue.
//
// Additional data is provided in the QueueBufferInput struct. Notably,
@@ -151,6 +157,14 @@
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
+ // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
+ // block if there are no available slots and we are not in non-blocking
+ // mode (producer and consumer controlled by the application). If it blocks,
+ // it will release mCore->mMutex while blocked so that other operations on
+ // the BufferQueue may succeed.
+ status_t waitForFreeSlotThenRelock(const char* caller, bool async,
+ int* found, status_t* returnFlags) const;
+
sp<BufferQueueCore> mCore;
// This references mCore->mSlots. Lock mCore->mMutex while accessing.
diff --git a/include/gui/BufferSlot.h b/include/gui/BufferSlot.h
index 2c4b43f..6085e11 100644
--- a/include/gui/BufferSlot.h
+++ b/include/gui/BufferSlot.h
@@ -38,7 +38,8 @@
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
mAcquireCalled(false),
- mNeedsCleanupOnRelease(false) {
+ mNeedsCleanupOnRelease(false),
+ mAttachedByConsumer(false) {
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
@@ -129,6 +130,11 @@
// consumer. This is set when a buffer in ACQUIRED state is freed.
// It causes releaseBuffer to return STALE_BUFFER_SLOT.
bool mNeedsCleanupOnRelease;
+
+ // Indicates whether the buffer was attached on the consumer side.
+ // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued
+ // to prevent the producer from using a stale cached buffer.
+ bool mAttachedByConsumer;
};
} // namespace android
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 9a6645c..5e97854 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -139,6 +139,36 @@
// * INVALID_OPERATION - too many buffers have been acquired
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
+ // detachBuffer attempts to remove all ownership of the buffer in the given
+ // slot from the buffer queue. If this call succeeds, the slot will be
+ // freed, and there will be no way to obtain the buffer from this interface.
+ // The freed slot will remain unallocated until either it is selected to
+ // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+ // to the slot. The buffer must have already been acquired.
+ //
+ // Return of a value other than NO_ERROR means an error has occurred:
+ // * BAD_VALUE - the given slot number is invalid, either because it is
+ // out of the range [0, NUM_BUFFER_SLOTS) or because the slot
+ // it refers to is not currently acquired.
+ virtual status_t detachBuffer(int slot) = 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 acquired
+ // from the returned slot number. As such, this call will fail if attaching
+ // this buffer would cause too many buffers to be simultaneously acquired.
+ //
+ // If the buffer is successfully attached, its frameNumber is initialized
+ // to 0. This must be passed into the releaseBuffer call or else the buffer
+ // will be deallocated as stale.
+ //
+ // Return of a value other than NO_ERROR means an error has occurred:
+ // * BAD_VALUE - outSlot or buffer were NULL
+ // * INVALID_OPERATION - cannot attach the buffer because it would cause too
+ // many buffers to be acquired.
+ // * NO_MEMORY - no free slots available
+ virtual status_t attachBuffer(int *outSlot,
+ const sp<GraphicBuffer>& buffer) = 0;
+
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue. This may be done while the buffer's contents are still
// being accessed. The fence will signal when the buffer is no longer
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 7002530..25a86a5 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -150,12 +150,14 @@
//
// Return of a negative means an error has occurred:
// * NO_INIT - the buffer queue has been abandoned.
- // * BAD_VALUE - one of the below conditions occurred:
- // * both in async mode and buffer count was less than the
- // max numbers of buffers that can be allocated at once
- // * attempting dequeue more than one buffer at a time
- // without setting the buffer count with setBufferCount()
- // * -EBUSY - attempting to dequeue too many buffers at a time
+ // * BAD_VALUE - both in async mode and buffer count was less than the
+ // max numbers of buffers that can be allocated at once.
+ // * INVALID_OPERATION - cannot attach the buffer because it would cause
+ // too many buffers to be dequeued, either because
+ // the producer already has a single buffer dequeued
+ // and did not set a buffer count, or because a
+ // buffer count was set and this call would cause
+ // it to be exceeded.
// * WOULD_BLOCK - no buffer is currently available, and blocking is disabled
// since both the producer/consumer are controlled by app
// * NO_MEMORY - out of memory, cannot allocate the graphics buffer.
@@ -165,6 +167,49 @@
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
+ // detachBuffer attempts to remove all ownership of the buffer in the given
+ // slot from the buffer queue. If this call succeeds, the slot will be
+ // freed, and there will be no way to obtain the buffer from this interface.
+ // The freed slot will remain unallocated until either it is selected to
+ // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+ // to the slot. The buffer must have already been dequeued, and the caller
+ // must already possesses the sp<GraphicBuffer> (i.e., must have called
+ // requestBuffer).
+ //
+ // Return of a value other than NO_ERROR means an error has occurred:
+ // * NO_INIT - the buffer queue has been abandoned.
+ // * BAD_VALUE - the given slot number is invalid, either because it is
+ // out of the range [0, NUM_BUFFER_SLOTS), or because the slot
+ // it refers to is not currently dequeued and requested.
+ virtual status_t detachBuffer(int slot) = 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
+ // this buffer would cause too many buffers to be simultaneously dequeued.
+ //
+ // If attachBuffer returns the RELEASE_ALL_BUFFERS flag, the caller is
+ // expected to release all of the mirrored slot->buffer mappings.
+ //
+ // A non-negative value with flags set (see above) will be returned upon
+ // success.
+ //
+ // Return of a negative value means an error has occurred:
+ // * NO_INIT - the buffer queue has been abandoned.
+ // * BAD_VALUE - outSlot or buffer were NULL or invalid combination of
+ // async mode and buffer count override.
+ // * INVALID_OPERATION - cannot attach the buffer because it would cause
+ // too many buffers to be dequeued, either because
+ // the producer already has a single buffer dequeued
+ // and did not set a buffer count, or because a
+ // buffer count was set and this call would cause
+ // it to be exceeded.
+ // * WOULD_BLOCK - no buffer slot is currently available, and blocking is
+ // disabled since both the producer/consumer are
+ // controlled by the app.
+ virtual status_t attachBuffer(int* outSlot,
+ const sp<GraphicBuffer>& buffer) = 0;
+
// queueBuffer indicates that the client has finished filling in the
// contents of the buffer associated with slot and transfers ownership of
// that slot back to the server.