summaryrefslogtreecommitdiff
path: root/libs/gui/BufferQueueConsumer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/BufferQueueConsumer.cpp')
-rw-r--r--libs/gui/BufferQueueConsumer.cpp163
1 files changed, 117 insertions, 46 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d52b47f3b0..8e2afd0012 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -50,7 +50,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
// buffer before releasing the old one.
int numAcquiredBuffers = 0;
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+ if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
@@ -60,10 +60,13 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
return INVALID_OPERATION;
}
- // Check if the queue is empty.
+ bool sharedBufferAvailable = mCore->mSingleBufferMode &&
+ mCore->mSingleBufferSlot !=
+ BufferQueueCore::INVALID_BUFFER_SLOT;
+
// In asynchronous mode the list is guaranteed to be one buffer deep,
// while in synchronous mode we use the oldest buffer.
- if (mCore->mQueue.empty()) {
+ if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
@@ -72,7 +75,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
// If expectedPresent is specified, we may not want to return a buffer yet.
// If it's specified and there's more than one buffer queued, we may want
// to drop a buffer.
- if (expectedPresent != 0) {
+ // Skip this if we're in single buffer mode and the queue is empty,
+ // since in that case we'll just return the shared buffer.
+ if (expectedPresent != 0 && !mCore->mQueue.empty()) {
const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
// The 'expectedPresent' argument indicates when the buffer is expected
@@ -130,8 +135,19 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
desiredPresent, expectedPresent, mCore->mQueue.size());
if (mCore->stillTracking(front)) {
// Front buffer is still in mSlots, so mark the slot as free
- mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
- mCore->mFreeBuffers.push_back(front->mSlot);
+ mSlots[front->mSlot].mBufferState.freeQueued();
+
+ // After leaving single buffer mode, the shared buffer will
+ // still be around. Mark it as no longer shared if this
+ // operation causes it to be free.
+ if (!mCore->mSingleBufferMode &&
+ mSlots[front->mSlot].mBufferState.isFree()) {
+ mSlots[front->mSlot].mBufferState.mShared = false;
+ }
+ // Don't put the shared buffer on the free list.
+ if (!mSlots[front->mSlot].mBufferState.isShared()) {
+ mCore->mFreeBuffers.push_back(front->mSlot);
+ }
listener = mCore->mConnectedProducerListener;
++numDroppedBuffers;
}
@@ -162,17 +178,52 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
systemTime(CLOCK_MONOTONIC));
}
- int slot = front->mSlot;
- *outBuffer = *front;
+ int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
+
+ if (sharedBufferAvailable && mCore->mQueue.empty()) {
+ // make sure the buffer has finished allocating before acquiring it
+ mCore->waitWhileAllocatingLocked();
+
+ slot = mCore->mSingleBufferSlot;
+
+ // Recreate the BufferItem for the shared buffer from the data that
+ // was cached when it was last queued.
+ outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
+ outBuffer->mFence = Fence::NO_FENCE;
+ outBuffer->mCrop = mCore->mSingleBufferCache.crop;
+ outBuffer->mTransform = mCore->mSingleBufferCache.transform &
+ ~static_cast<uint32_t>(
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+ outBuffer->mScalingMode = mCore->mSingleBufferCache.scalingMode;
+ outBuffer->mDataSpace = mCore->mSingleBufferCache.dataspace;
+ outBuffer->mFrameNumber = mCore->mFrameCounter;
+ outBuffer->mSlot = slot;
+ outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
+ outBuffer->mTransformToDisplayInverse =
+ (mCore->mSingleBufferCache.transform &
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
+ outBuffer->mSurfaceDamage = Region::INVALID_REGION;
+ } else {
+ slot = front->mSlot;
+ *outBuffer = *front;
+ }
+
ATRACE_BUFFER_INDEX(slot);
BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
- slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+ slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle);
// If the front buffer is still being tracked, update its slot state
- if (mCore->stillTracking(front)) {
+ if (mCore->stillTracking(outBuffer)) {
mSlots[slot].mAcquireCalled = true;
mSlots[slot].mNeedsCleanupOnRelease = false;
- mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+ // Don't decrease the queue count if the BufferItem wasn't
+ // previously in the queue. This happens in single buffer mode when
+ // the queue is empty and the BufferItem is created above.
+ if (mCore->mQueue.empty()) {
+ mSlots[slot].mBufferState.acquireNotInQueue();
+ } else {
+ mSlots[slot].mBufferState.acquire();
+ }
mSlots[slot].mFence = Fence::NO_FENCE;
}
@@ -207,24 +258,31 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
status_t BufferQueueConsumer::detachBuffer(int slot) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(slot);
- BQ_LOGV("detachBuffer(C): slot %d", slot);
+ BQ_LOGV("detachBuffer: slot %d", slot);
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
- BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned");
+ BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
+ if (mCore->mSingleBufferMode) {
+ BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
+ "mode");
+ return BAD_VALUE;
+ }
+
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
- BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)",
+ BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
- } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) {
- BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer "
- "(state = %d)", slot, mSlots[slot].mBufferState);
+ } else if (!mSlots[slot].mBufferState.isAcquired()) {
+ BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
+ "(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
+ mSlots[slot].mBufferState.detachConsumer();
mCore->freeBufferLocked(slot);
mCore->mDequeueCondition.broadcast();
mCore->validateConsistencyLocked();
@@ -237,25 +295,31 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
ATRACE_CALL();
if (outSlot == NULL) {
- BQ_LOGE("attachBuffer(P): outSlot must not be NULL");
+ BQ_LOGE("attachBuffer: outSlot must not be NULL");
return BAD_VALUE;
} else if (buffer == NULL) {
- BQ_LOGE("attachBuffer(P): cannot attach NULL buffer");
+ BQ_LOGE("attachBuffer: cannot attach NULL buffer");
return BAD_VALUE;
}
Mutex::Autolock lock(mCore->mMutex);
+ if (mCore->mSingleBufferMode) {
+ BQ_LOGE("attachBuffer: cannot attach a buffer in single buffer"
+ "mode");
+ return BAD_VALUE;
+ }
+
// Make sure we don't have too many acquired buffers
int numAcquiredBuffers = 0;
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+ if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
- BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d "
+ BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
"(max %d)", numAcquiredBuffers,
mCore->mMaxAcquiredBufferCount);
return INVALID_OPERATION;
@@ -279,16 +343,16 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
mCore->mFreeBuffers.remove(found);
}
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
- BQ_LOGE("attachBuffer(P): could not find free buffer slot");
+ BQ_LOGE("attachBuffer: could not find free buffer slot");
return NO_MEMORY;
}
*outSlot = found;
ATRACE_BUFFER_INDEX(*outSlot);
- BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot);
+ BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
mSlots[*outSlot].mGraphicBuffer = buffer;
- mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[*outSlot].mBufferState.attachConsumer();
mSlots[*outSlot].mAttachedByConsumer = true;
mSlots[*outSlot].mNeedsCleanupOnRelease = false;
mSlots[*outSlot].mFence = Fence::NO_FENCE;
@@ -334,38 +398,45 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
Mutex::Autolock lock(mCore->mMutex);
// If the frame number has changed because the buffer has been reallocated,
- // we can ignore this releaseBuffer for the old buffer
- if (frameNumber != mSlots[slot].mFrameNumber) {
+ // we can ignore this releaseBuffer for the old buffer.
+ // Ignore this for the shared buffer where the frame number can easily
+ // get out of sync due to the buffer being queued and acquired at the
+ // same time.
+ if (frameNumber != mSlots[slot].mFrameNumber &&
+ !mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
- // Make sure this buffer hasn't been queued while acquired by the consumer
- BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
- while (current != mCore->mQueue.end()) {
- if (current->mSlot == slot) {
- BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
- "currently queued", slot);
- return BAD_VALUE;
- }
- ++current;
- }
- if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+ if (mSlots[slot].mBufferState.isAcquired()) {
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
- mSlots[slot].mBufferState = BufferSlot::FREE;
- mCore->mFreeBuffers.push_back(slot);
+ mSlots[slot].mBufferState.release();
+
+ // After leaving single buffer mode, the shared buffer will
+ // still be around. Mark it as no longer shared if this
+ // operation causes it to be free.
+ if (!mCore->mSingleBufferMode &&
+ mSlots[slot].mBufferState.isFree()) {
+ mSlots[slot].mBufferState.mShared = false;
+ }
+ // Don't put the shared buffer on the free list.
+ if (!mSlots[slot].mBufferState.isShared()) {
+ mCore->mFreeBuffers.push_back(slot);
+ }
+
listener = mCore->mConnectedProducerListener;
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
} else if (mSlots[slot].mNeedsCleanupOnRelease) {
BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
- "(state = %d)", slot, mSlots[slot].mBufferState);
+ "(state = %s)", slot, mSlots[slot].mBufferState.string());
mSlots[slot].mNeedsCleanupOnRelease = false;
return STALE_BUFFER_SLOT;
} else {
BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
- "but its state was %d", slot, mSlots[slot].mBufferState);
+ "but its state was %s", slot,
+ mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
@@ -386,17 +457,17 @@ status_t BufferQueueConsumer::connect(
ATRACE_CALL();
if (consumerListener == NULL) {
- BQ_LOGE("connect(C): consumerListener may not be NULL");
+ BQ_LOGE("connect: consumerListener may not be NULL");
return BAD_VALUE;
}
- BQ_LOGV("connect(C): controlledByApp=%s",
+ BQ_LOGV("connect: controlledByApp=%s",
controlledByApp ? "true" : "false");
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
- BQ_LOGE("connect(C): BufferQueue has been abandoned");
+ BQ_LOGE("connect: BufferQueue has been abandoned");
return NO_INIT;
}
@@ -409,12 +480,12 @@ status_t BufferQueueConsumer::connect(
status_t BufferQueueConsumer::disconnect() {
ATRACE_CALL();
- BQ_LOGV("disconnect(C)");
+ BQ_LOGV("disconnect");
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mConsumerListener == NULL) {
- BQ_LOGE("disconnect(C): no consumer is connected");
+ BQ_LOGE("disconnect: no consumer is connected");
return BAD_VALUE;
}