BQ: Add support for single buffer mode
- Adds a single buffer mode to BufferQueue. In this mode designate the
first dequeued buffer as the shared buffer. All calls to dequeue()
and acquire() will then return the shared buffer, allowing the
producer and consumer to share it.
- Modify the buffer slot state tracking. Add a new SHARED state for
the shared buffer in single buffer mode. Also track how many times
a buffer has been dequeued/queued/acquired as it's possible for a
shared buffer to be both dequeued and acquired at the same time, or
dequeued/acquired multiple times. This tracking is needed to know
when to drop the buffer out of the SHARED state after single buffer
mode has been disabled.
- Add plumbing for enabling/disabling single buffer mode from Surface.
Bug 24940410
Change-Id: I3fc550c74bacb5523c049a227111356257386853
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 36cd238..fbd5114 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -107,10 +107,10 @@
// freeBufferLocked frees the GraphicBuffer and sync resources for the
// given slot.
- void freeBufferLocked(int slot);
+ void freeBufferLocked(int slot, bool validate = true);
// freeAllBuffersLocked frees the GraphicBuffer and sync resources for
- // all slots.
+ // all slots, even if they're currently dequeued, queued, or acquired.
void freeAllBuffersLocked();
// stillTracking returns true iff the buffer item is still being tracked
@@ -271,6 +271,32 @@
// enqueue buffers without blocking.
bool mAsyncMode;
+ // mSingleBufferMode indicates whether or not single buffer mode is enabled.
+ // In single buffer mode, the last buffer that was dequeued is cached and
+ // returned to all calls to dequeueBuffer and acquireBuffer. This allows the
+ // consumer and producer to access the same buffer simultaneously.
+ bool mSingleBufferMode;
+
+ // When single buffer mode is enabled, this tracks which slot contains the
+ // shared buffer.
+ int mSingleBufferSlot;
+
+ // Cached data about the shared buffer in single buffer mode
+ struct SingleBufferCache {
+ SingleBufferCache(Rect _crop, uint32_t _transform, int _scalingMode,
+ android_dataspace _dataspace)
+ : crop(_crop),
+ transform(_transform),
+ scalingMode(_scalingMode),
+ dataspace(_dataspace) {
+ };
+
+ Rect crop;
+ uint32_t transform;
+ uint32_t scalingMode;
+ android_dataspace dataspace;
+ } mSingleBufferCache;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 322f2ec..5fe5ce0 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -173,6 +173,9 @@
// See IGraphicBufferProducer::getNextFrameNumber
virtual uint64_t getNextFrameNumber() const override;
+ // See IGraphicBufferProducer::setSingleBufferMode
+ virtual status_t setSingleBufferMode(bool singleBufferMode);
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/BufferSlot.h b/include/gui/BufferSlot.h
index 6085e11..17a654a 100644
--- a/include/gui/BufferSlot.h
+++ b/include/gui/BufferSlot.h
@@ -29,11 +29,153 @@
class Fence;
+// BufferState tracks the states in which a buffer slot can be.
+struct BufferState {
+
+ // All slots are initially FREE (not dequeued, queued, acquired, or shared).
+ BufferState()
+ : mDequeueCount(0),
+ mQueueCount(0),
+ mAcquireCount(0),
+ mShared(false) {
+ }
+
+ uint32_t mDequeueCount;
+ uint32_t mQueueCount;
+ uint32_t mAcquireCount;
+ bool mShared;
+
+ // A buffer can be in one of five states, represented as below:
+ //
+ // | mShared | mDequeueCount | mQueueCount | mAcquireCount |
+ // --------|---------|---------------|-------------|---------------|
+ // FREE | false | 0 | 0 | 0 |
+ // DEQUEUED| false | 1 | 0 | 0 |
+ // QUEUED | false | 0 | 1 | 0 |
+ // ACQUIRED| false | 0 | 0 | 1 |
+ // SHARED | true | any | any | any |
+ //
+ // FREE indicates that the buffer is available to be dequeued by the
+ // producer. The slot is "owned" by BufferQueue. It transitions to DEQUEUED
+ // when dequeueBuffer is called.
+ //
+ // DEQUEUED indicates that the buffer has been dequeued by the producer, but
+ // has not yet been queued or canceled. The producer may modify the
+ // buffer's contents as soon as the associated release fence is signaled.
+ // The slot is "owned" by the producer. It can transition to QUEUED (via
+ // queueBuffer or attachBuffer) or back to FREE (via cancelBuffer or
+ // detachBuffer).
+ //
+ // QUEUED indicates that the buffer has been filled by the producer and
+ // queued for use by the consumer. The buffer contents may continue to be
+ // modified for a finite time, so the contents must not be accessed until
+ // the associated fence is signaled. The slot is "owned" by BufferQueue. It
+ // can transition to ACQUIRED (via acquireBuffer) or to FREE (if another
+ // buffer is queued in asynchronous mode).
+ //
+ // ACQUIRED indicates that the buffer has been acquired by the consumer. As
+ // with QUEUED, the contents must not be accessed by the consumer until the
+ // acquire fence is signaled. The slot is "owned" by the consumer. It
+ // transitions to FREE when releaseBuffer (or detachBuffer) is called. A
+ // detached buffer can also enter the ACQUIRED state via attachBuffer.
+ //
+ // SHARED indicates that this buffer is being used in single-buffer
+ // mode. It can be in any combination of the other states at the same time,
+ // except for FREE (since that excludes being in any other state). It can
+ // also be dequeued, queued, or acquired multiple times.
+
+ inline bool isFree() const {
+ return !isAcquired() && !isDequeued() && !isQueued();
+ }
+
+ inline bool isDequeued() const {
+ return mDequeueCount > 0;
+ }
+
+ inline bool isQueued() const {
+ return mQueueCount > 0;
+ }
+
+ inline bool isAcquired() const {
+ return mAcquireCount > 0;
+ }
+
+ inline bool isShared() const {
+ return mShared;
+ }
+
+ inline void reset() {
+ *this = BufferState();
+ }
+
+ const char* string() const;
+
+ inline void dequeue() {
+ mDequeueCount++;
+ }
+
+ inline void detachProducer() {
+ if (mDequeueCount > 0) {
+ mDequeueCount--;
+ }
+ }
+
+ inline void attachProducer() {
+ mDequeueCount++;
+ }
+
+ inline void queue() {
+ if (mDequeueCount > 0) {
+ mDequeueCount--;
+ }
+ mQueueCount++;
+ }
+
+ inline void cancel() {
+ if (mDequeueCount > 0) {
+ mDequeueCount--;
+ }
+ }
+
+ inline void freeQueued() {
+ if (mQueueCount > 0) {
+ mQueueCount--;
+ }
+ }
+
+ inline void acquire() {
+ if (mQueueCount > 0) {
+ mQueueCount--;
+ }
+ mAcquireCount++;
+ }
+
+ inline void acquireNotInQueue() {
+ mAcquireCount++;
+ }
+
+ inline void release() {
+ if (mAcquireCount > 0) {
+ mAcquireCount--;
+ }
+ }
+
+ inline void detachConsumer() {
+ if (mAcquireCount > 0) {
+ mAcquireCount--;
+ }
+ }
+
+ inline void attachConsumer() {
+ mAcquireCount++;
+ }
+};
+
struct BufferSlot {
BufferSlot()
: mEglDisplay(EGL_NO_DISPLAY),
- mBufferState(BufferSlot::FREE),
+ mBufferState(),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
@@ -49,47 +191,6 @@
// mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
EGLDisplay mEglDisplay;
- // BufferState represents the different states in which a buffer slot
- // can be. All slots are initially FREE.
- enum BufferState {
- // FREE indicates that the buffer is available to be dequeued
- // by the producer. The buffer may be in use by the consumer for
- // a finite time, so the buffer must not be modified until the
- // associated fence is signaled.
- //
- // The slot is "owned" by BufferQueue. It transitions to DEQUEUED
- // when dequeueBuffer is called.
- FREE = 0,
-
- // DEQUEUED indicates that the buffer has been dequeued by the
- // producer, but has not yet been queued or canceled. The
- // producer may modify the buffer's contents as soon as the
- // associated ready fence is signaled.
- //
- // The slot is "owned" by the producer. It can transition to
- // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
- DEQUEUED = 1,
-
- // QUEUED indicates that the buffer has been filled by the
- // producer and queued for use by the consumer. The buffer
- // contents may continue to be modified for a finite time, so
- // the contents must not be accessed until the associated fence
- // is signaled.
- //
- // The slot is "owned" by BufferQueue. It can transition to
- // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
- // queued in asynchronous mode).
- QUEUED = 2,
-
- // ACQUIRED indicates that the buffer has been acquired by the
- // consumer. As with QUEUED, the contents must not be accessed
- // by the consumer until the fence is signaled.
- //
- // The slot is "owned" by the consumer. It transitions to FREE
- // when releaseBuffer is called.
- ACQUIRED = 3
- };
-
static const char* bufferStateName(BufferState state);
// mBufferState is the current state of this buffer slot.
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 4586839..d6daca7 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -511,6 +511,13 @@
// Returns the number of the next frame which will be dequeued.
virtual uint64_t getNextFrameNumber() const = 0;
+
+ // Used to enable/disable single buffer mode.
+ //
+ // In single buffer mode the last buffer that was dequeued will be cached
+ // and returned to all calls to dequeueBuffer and acquireBuffer. This allows
+ // the producer and consumer to simultaneously access the same buffer.
+ virtual status_t setSingleBufferMode(bool singleBufferMode) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 3f46460..f9fc6df 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -159,6 +159,7 @@
int dispatchSetSidebandStream(va_list args);
int dispatchSetBuffersDataSpace(va_list args);
int dispatchSetSurfaceDamage(va_list args);
+ int dispatchSetSingleBufferMode(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -188,6 +189,7 @@
public:
virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual int setAsyncMode(bool async);
+ virtual int setSingleBufferMode(bool singleBufferMode);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 1711071..5cf316f 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -59,7 +59,7 @@
: what(0),
x(0), y(0), z(0), w(0), h(0), layerStack(0),
alpha(0), flags(0), mask(0),
- reserved(0), crop(Rect::INVALID_RECT)
+ reserved(0), crop(Rect::INVALID_RECT), frameNumber(0)
{
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;