BufferQueue: track buffer-queue by instance vs. by reference
Instead of representing the buffer-queue as a vector of buffer indices, represent them as a vector of BufferItems (copies). This allows modifying the buffer slots independent of the queued buffers. As part of this change, BufferSlot properties that are only been relevant in the buffer-queue have been removed. Also, invalid scalingMode in queueBuffer now returns an error. ConsumerBase has also changed to allow reuse of the same buffer slots by different buffers. Change-Id: If2a698fa142b67c69ad41b8eaca6e127eb3ef75b Signed-off-by: Lajos Molnar <lajos@google.com> Related-to-bug: 7093648
This commit is contained in:
parent
d837969640
commit
c5d7b7d323
@ -240,7 +240,8 @@ public:
|
||||
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
|
||||
mTimestamp(0),
|
||||
mFrameNumber(0),
|
||||
mBuf(INVALID_BUFFER_SLOT) {
|
||||
mBuf(INVALID_BUFFER_SLOT),
|
||||
mAcquireCalled(false) {
|
||||
mCrop.makeInvalid();
|
||||
}
|
||||
// mGraphicBuffer points to the buffer allocated for this slot, or is NULL
|
||||
@ -269,6 +270,9 @@ public:
|
||||
|
||||
// mFence is a fence that will signal when the buffer is idle.
|
||||
sp<Fence> mFence;
|
||||
|
||||
// Indicates whether this buffer has been seen by a consumer yet
|
||||
bool mAcquireCalled;
|
||||
};
|
||||
|
||||
// The following public functions are the consumer-facing interface
|
||||
@ -285,7 +289,7 @@ public:
|
||||
// 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
|
||||
// in use.
|
||||
// in use. frameNumber is used to indentify the exact buffer returned.
|
||||
//
|
||||
// If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
|
||||
// any references to the just-released buffer that it might have, as if it
|
||||
@ -294,7 +298,8 @@ public:
|
||||
//
|
||||
// Note that the dependencies on EGL will be removed once we switch to using
|
||||
// the Android HW Sync HAL.
|
||||
status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence,
|
||||
status_t releaseBuffer(int buf, uint64_t frameNumber,
|
||||
EGLDisplay display, EGLSyncKHR fence,
|
||||
const sp<Fence>& releaseFence);
|
||||
|
||||
// consumerConnect connects a consumer to the BufferQueue. Only one
|
||||
@ -410,20 +415,20 @@ private:
|
||||
// connected, mDequeueCondition must be broadcast.
|
||||
int getMaxBufferCountLocked() const;
|
||||
|
||||
// stillTracking returns true iff the buffer item is still being tracked
|
||||
// in one of the slots.
|
||||
bool stillTracking(const BufferItem *item) const;
|
||||
|
||||
struct BufferSlot {
|
||||
|
||||
BufferSlot()
|
||||
: mEglDisplay(EGL_NO_DISPLAY),
|
||||
mBufferState(BufferSlot::FREE),
|
||||
mRequestBufferCalled(false),
|
||||
mTransform(0),
|
||||
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
|
||||
mTimestamp(0),
|
||||
mFrameNumber(0),
|
||||
mEglFence(EGL_NO_SYNC_KHR),
|
||||
mAcquireCalled(false),
|
||||
mNeedsCleanupOnRelease(false) {
|
||||
mCrop.makeInvalid();
|
||||
}
|
||||
|
||||
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
|
||||
@ -482,21 +487,6 @@ private:
|
||||
// needed but useful for debugging and catching producer bugs.
|
||||
bool mRequestBufferCalled;
|
||||
|
||||
// mCrop is the current crop rectangle for this buffer slot.
|
||||
Rect mCrop;
|
||||
|
||||
// mTransform is the current transform flags for this buffer slot.
|
||||
// (example: NATIVE_WINDOW_TRANSFORM_ROT_90)
|
||||
uint32_t mTransform;
|
||||
|
||||
// mScalingMode is the current scaling mode for this buffer slot.
|
||||
// (example: NATIVE_WINDOW_SCALING_MODE_FREEZE)
|
||||
uint32_t mScalingMode;
|
||||
|
||||
// mTimestamp is the current timestamp for this buffer slot. This gets
|
||||
// to set by queueBuffer each time this slot is queued.
|
||||
int64_t mTimestamp;
|
||||
|
||||
// mFrameNumber is the number of the queued frame for this slot. This
|
||||
// is used to dequeue buffers in LRU order (useful because buffers
|
||||
// may be released before their release fence is signaled).
|
||||
@ -592,7 +582,7 @@ private:
|
||||
mutable Condition mDequeueCondition;
|
||||
|
||||
// mQueue is a FIFO of queued buffers used in synchronous mode
|
||||
typedef Vector<int> Fifo;
|
||||
typedef Vector<BufferItem> Fifo;
|
||||
Fifo mQueue;
|
||||
|
||||
// mAbandoned indicates that the BufferQueue will no longer be used to
|
||||
@ -613,7 +603,7 @@ private:
|
||||
mutable Mutex mMutex;
|
||||
|
||||
// mFrameCounter is the free running counter, incremented on every
|
||||
// successful queueBuffer call.
|
||||
// successful queueBuffer call, and buffer allocation.
|
||||
uint64_t mFrameCounter;
|
||||
|
||||
// mBufferHasBeenQueued is true once a buffer has been queued. It is
|
||||
|
@ -160,17 +160,23 @@ protected:
|
||||
// Derived classes should override this method to perform any cleanup that
|
||||
// must take place when a buffer is released back to the BufferQueue. If
|
||||
// it is overridden the derived class's implementation must call
|
||||
// ConsumerBase::releaseBufferLocked.
|
||||
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
|
||||
EGLSyncKHR eglFence);
|
||||
// ConsumerBase::releaseBufferLocked.e
|
||||
virtual status_t releaseBufferLocked(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer,
|
||||
EGLDisplay display, EGLSyncKHR eglFence);
|
||||
|
||||
// returns true iff the slot still has the graphicBuffer in it.
|
||||
bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
|
||||
|
||||
// addReleaseFence* adds the sync points associated with a fence to the set
|
||||
// of sync points that must be reached before the buffer in the given slot
|
||||
// may be used after the slot has been released. This should be called by
|
||||
// derived classes each time some asynchronous work is kicked off that
|
||||
// references the buffer.
|
||||
status_t addReleaseFence(int slot, const sp<Fence>& fence);
|
||||
status_t addReleaseFenceLocked(int slot, const sp<Fence>& fence);
|
||||
status_t addReleaseFence(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
|
||||
status_t addReleaseFenceLocked(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
|
||||
|
||||
// Slot contains the information and object references that
|
||||
// ConsumerBase maintains about a BufferQueue buffer slot.
|
||||
@ -184,6 +190,9 @@ protected:
|
||||
// overwritten. The buffer can be dequeued before the fence signals;
|
||||
// the producer is responsible for delaying writes until it signals.
|
||||
sp<Fence> mFence;
|
||||
|
||||
// the frame number of the last acquired frame for this slot
|
||||
uint64_t mFrameNumber;
|
||||
};
|
||||
|
||||
// mSlots stores the buffers that have been allocated by the BufferQueue
|
||||
|
@ -241,11 +241,13 @@ protected:
|
||||
|
||||
// releaseBufferLocked overrides the ConsumerBase method to update the
|
||||
// mEglSlots array in addition to the ConsumerBase.
|
||||
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
|
||||
EGLSyncKHR eglFence);
|
||||
virtual status_t releaseBufferLocked(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer,
|
||||
EGLDisplay display, EGLSyncKHR eglFence);
|
||||
|
||||
status_t releaseBufferLocked(int buf, EGLSyncKHR eglFence) {
|
||||
return releaseBufferLocked(buf, mEglDisplay, eglFence);
|
||||
status_t releaseBufferLocked(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer, EGLSyncKHR eglFence) {
|
||||
return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence);
|
||||
}
|
||||
|
||||
static bool isExternalFormat(uint32_t format);
|
||||
|
@ -82,9 +82,9 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
|
||||
|
||||
Mutex::Autolock _l(mMutex);
|
||||
|
||||
err = addReleaseFenceLocked(item.mBuf, releaseFence);
|
||||
err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence);
|
||||
|
||||
err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
|
||||
err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY,
|
||||
EGL_NO_SYNC_KHR);
|
||||
if (err != OK) {
|
||||
BI_LOGE("Failed to release buffer: %s (%d)",
|
||||
|
@ -418,6 +418,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
|
||||
return NO_INIT;
|
||||
}
|
||||
|
||||
mSlots[*outBuf].mFrameNumber = ~0;
|
||||
mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
|
||||
}
|
||||
}
|
||||
@ -435,7 +436,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
|
||||
eglDestroySyncKHR(dpy, eglFence);
|
||||
}
|
||||
|
||||
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
|
||||
ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
|
||||
mSlots[*outBuf].mFrameNumber,
|
||||
mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
|
||||
|
||||
return returnFlags;
|
||||
@ -491,15 +493,22 @@ status_t BufferQueue::queueBuffer(int buf,
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
|
||||
"scale=%s",
|
||||
buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
|
||||
transform, scalingModeName(scalingMode));
|
||||
switch (scalingMode) {
|
||||
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
|
||||
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
|
||||
case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
|
||||
case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
|
||||
break;
|
||||
default:
|
||||
ST_LOGE("unknown scaling mode: %d", scalingMode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sp<ConsumerListener> listener;
|
||||
|
||||
{ // scope for the lock
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
if (mAbandoned) {
|
||||
ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
|
||||
return NO_INIT;
|
||||
@ -519,6 +528,12 @@ status_t BufferQueue::queueBuffer(int buf,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] "
|
||||
"tr=%#x scale=%s",
|
||||
buf, mFrameCounter + 1, timestamp,
|
||||
crop.left, crop.top, crop.right, crop.bottom,
|
||||
transform, scalingModeName(scalingMode));
|
||||
|
||||
const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
|
||||
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
|
||||
Rect croppedCrop;
|
||||
@ -529,9 +544,25 @@ status_t BufferQueue::queueBuffer(int buf,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mSlots[buf].mFence = fence;
|
||||
mSlots[buf].mBufferState = BufferSlot::QUEUED;
|
||||
mFrameCounter++;
|
||||
mSlots[buf].mFrameNumber = mFrameCounter;
|
||||
|
||||
BufferItem item;
|
||||
item.mAcquireCalled = mSlots[buf].mAcquireCalled;
|
||||
item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
|
||||
item.mCrop = crop;
|
||||
item.mTransform = transform;
|
||||
item.mScalingMode = scalingMode;
|
||||
item.mTimestamp = timestamp;
|
||||
item.mFrameNumber = mFrameCounter;
|
||||
item.mBuf = buf;
|
||||
item.mFence = fence;
|
||||
|
||||
if (mSynchronousMode) {
|
||||
// In synchronous mode we queue all buffers in a FIFO.
|
||||
mQueue.push_back(buf);
|
||||
mQueue.push_back(item);
|
||||
|
||||
// Synchronous mode always signals that an additional frame should
|
||||
// be consumed.
|
||||
@ -539,7 +570,7 @@ status_t BufferQueue::queueBuffer(int buf,
|
||||
} else {
|
||||
// In asynchronous mode we only keep the most recent buffer.
|
||||
if (mQueue.empty()) {
|
||||
mQueue.push_back(buf);
|
||||
mQueue.push_back(item);
|
||||
|
||||
// Asynchronous mode only signals that a frame should be
|
||||
// consumed if no previous frame was pending. If a frame were
|
||||
@ -547,34 +578,15 @@ status_t BufferQueue::queueBuffer(int buf,
|
||||
listener = mConsumerListener;
|
||||
} else {
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
// buffer currently queued is freed
|
||||
mSlots[*front].mBufferState = BufferSlot::FREE;
|
||||
// buffer slot currently queued is marked free if still tracked
|
||||
if (stillTracking(front)) {
|
||||
mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
|
||||
}
|
||||
// and we record the new buffer index in the queued list
|
||||
*front = buf;
|
||||
*front = item;
|
||||
}
|
||||
}
|
||||
|
||||
mSlots[buf].mTimestamp = timestamp;
|
||||
mSlots[buf].mCrop = crop;
|
||||
mSlots[buf].mTransform = transform;
|
||||
mSlots[buf].mFence = fence;
|
||||
|
||||
switch (scalingMode) {
|
||||
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
|
||||
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
|
||||
case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
|
||||
break;
|
||||
default:
|
||||
ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);
|
||||
scalingMode = mSlots[buf].mScalingMode;
|
||||
break;
|
||||
}
|
||||
|
||||
mSlots[buf].mBufferState = BufferSlot::QUEUED;
|
||||
mSlots[buf].mScalingMode = scalingMode;
|
||||
mFrameCounter++;
|
||||
mSlots[buf].mFrameNumber = mFrameCounter;
|
||||
|
||||
mBufferHasBeenQueued = true;
|
||||
mDequeueCondition.broadcast();
|
||||
|
||||
@ -718,7 +730,14 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
|
||||
int fifoSize = 0;
|
||||
Fifo::const_iterator i(mQueue.begin());
|
||||
while (i != mQueue.end()) {
|
||||
fifo.appendFormat("%02d ", *i++);
|
||||
fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
|
||||
"xform=0x%02x, time=%#llx, scale=%s\n",
|
||||
i->mBuf, i->mGraphicBuffer.get(),
|
||||
i->mCrop.left, i->mCrop.top, i->mCrop.right,
|
||||
i->mCrop.bottom, i->mTransform, i->mTimestamp,
|
||||
scalingModeName(i->mScalingMode)
|
||||
);
|
||||
i++;
|
||||
fifoSize++;
|
||||
}
|
||||
|
||||
@ -746,14 +765,10 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
|
||||
for (int i=0 ; i<maxBufferCount ; i++) {
|
||||
const BufferSlot& slot(mSlots[i]);
|
||||
result.appendFormat(
|
||||
"%s%s[%02d] "
|
||||
"state=%-8s, crop=[%d,%d,%d,%d], "
|
||||
"xform=0x%02x, time=%#llx, scale=%s",
|
||||
"%s%s[%02d:%p] state=%-8s",
|
||||
prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
|
||||
stateName(slot.mBufferState),
|
||||
slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
|
||||
slot.mCrop.bottom, slot.mTransform, slot.mTimestamp,
|
||||
scalingModeName(slot.mScalingMode)
|
||||
slot.mGraphicBuffer.get(),
|
||||
stateName(slot.mBufferState)
|
||||
);
|
||||
|
||||
const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
|
||||
@ -820,27 +835,27 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
|
||||
// deep, while in synchronous mode we use the oldest buffer.
|
||||
if (!mQueue.empty()) {
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
int buf = *front;
|
||||
|
||||
int buf = front->mBuf;
|
||||
*buffer = *front;
|
||||
ATRACE_BUFFER_INDEX(buf);
|
||||
|
||||
if (mSlots[buf].mAcquireCalled) {
|
||||
buffer->mGraphicBuffer = NULL;
|
||||
} else {
|
||||
buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
|
||||
ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
|
||||
front->mBuf, front->mFrameNumber,
|
||||
front->mGraphicBuffer->handle);
|
||||
// if front buffer still being tracked update slot state
|
||||
if (stillTracking(front)) {
|
||||
mSlots[buf].mAcquireCalled = true;
|
||||
mSlots[buf].mNeedsCleanupOnRelease = false;
|
||||
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
|
||||
mSlots[buf].mFence = Fence::NO_FENCE;
|
||||
}
|
||||
buffer->mCrop = mSlots[buf].mCrop;
|
||||
buffer->mTransform = mSlots[buf].mTransform;
|
||||
buffer->mScalingMode = mSlots[buf].mScalingMode;
|
||||
buffer->mFrameNumber = mSlots[buf].mFrameNumber;
|
||||
buffer->mTimestamp = mSlots[buf].mTimestamp;
|
||||
buffer->mBuf = buf;
|
||||
buffer->mFence = mSlots[buf].mFence;
|
||||
|
||||
mSlots[buf].mAcquireCalled = true;
|
||||
mSlots[buf].mNeedsCleanupOnRelease = false;
|
||||
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
|
||||
mSlots[buf].mFence = Fence::NO_FENCE;
|
||||
// If the buffer has previously been acquired by the consumer, set
|
||||
// mGraphicBuffer to NULL to avoid unnecessarily remapping this
|
||||
// buffer on the consumer side.
|
||||
if (buffer->mAcquireCalled) {
|
||||
buffer->mGraphicBuffer = NULL;
|
||||
}
|
||||
|
||||
mQueue.erase(front);
|
||||
mDequeueCondition.broadcast();
|
||||
@ -853,7 +868,8 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
|
||||
status_t BufferQueue::releaseBuffer(
|
||||
int buf, uint64_t frameNumber, EGLDisplay display,
|
||||
EGLSyncKHR eglFence, const sp<Fence>& fence) {
|
||||
ATRACE_CALL();
|
||||
ATRACE_BUFFER_INDEX(buf);
|
||||
@ -864,12 +880,35 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mSlots[buf].mEglDisplay = display;
|
||||
mSlots[buf].mEglFence = eglFence;
|
||||
mSlots[buf].mFence = fence;
|
||||
// Check if this buffer slot is on the queue
|
||||
bool slotQueued = false;
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
while (front != mQueue.end() && !slotQueued) {
|
||||
if (front->mBuf == buf)
|
||||
slotQueued = true;
|
||||
front++;
|
||||
}
|
||||
|
||||
// If the frame number has changed because buffer has been reallocated,
|
||||
// we can ignore this releaseBuffer for the old buffer.
|
||||
if (frameNumber != mSlots[buf].mFrameNumber) {
|
||||
// This should only occur if new buffer is still in the queue
|
||||
ALOGE_IF(!slotQueued,
|
||||
"received old buffer(#%lld) after new buffer(#%lld) on same "
|
||||
"slot #%d already acquired", frameNumber,
|
||||
mSlots[buf].mFrameNumber, buf);
|
||||
return STALE_BUFFER_SLOT;
|
||||
}
|
||||
// this should never happen
|
||||
ALOGE_IF(slotQueued,
|
||||
"received new buffer(#%lld) on slot #%d that has not yet been "
|
||||
"acquired", frameNumber, buf);
|
||||
|
||||
// The buffer can now only be released if its in the acquired state
|
||||
if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
|
||||
mSlots[buf].mEglDisplay = display;
|
||||
mSlots[buf].mEglFence = eglFence;
|
||||
mSlots[buf].mFence = fence;
|
||||
mSlots[buf].mBufferState = BufferSlot::FREE;
|
||||
} else if (mSlots[buf].mNeedsCleanupOnRelease) {
|
||||
ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
|
||||
@ -934,6 +973,17 @@ status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
|
||||
mask |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove buffers in flight (on the queue) from the mask where acquire has
|
||||
// been called, as the consumer will not receive the buffer address, so
|
||||
// it should not free these slots.
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
while (front != mQueue.end()) {
|
||||
if (front->mAcquireCalled)
|
||||
mask &= ~(1 << front->mBuf);
|
||||
front++;
|
||||
}
|
||||
|
||||
*slotMask = mask;
|
||||
|
||||
ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
|
||||
@ -977,16 +1027,14 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
|
||||
}
|
||||
|
||||
void BufferQueue::freeAllBuffersExceptHeadLocked() {
|
||||
int head = -1;
|
||||
if (!mQueue.empty()) {
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
head = *front;
|
||||
}
|
||||
// only called if mQueue is not empty
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
mBufferHasBeenQueued = false;
|
||||
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
||||
if (i != head) {
|
||||
const BufferSlot &slot = mSlots[i];
|
||||
if (slot.mGraphicBuffer == NULL ||
|
||||
slot.mGraphicBuffer->handle != front->mGraphicBuffer->handle)
|
||||
freeBufferLocked(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1052,6 +1100,22 @@ int BufferQueue::getMaxBufferCountLocked() const {
|
||||
return maxBufferCount;
|
||||
}
|
||||
|
||||
bool BufferQueue::stillTracking(const BufferItem *item) const {
|
||||
const BufferSlot &slot = mSlots[item->mBuf];
|
||||
|
||||
ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, "
|
||||
"slot: { slot=%d/%llu, buffer=%p }",
|
||||
item->mBuf, item->mFrameNumber,
|
||||
(item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
|
||||
item->mBuf, slot.mFrameNumber,
|
||||
(slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
|
||||
|
||||
// Compare item with its original buffer slot. We can check the slot
|
||||
// as the buffer would not be moved to a different slot by the producer.
|
||||
return (slot.mGraphicBuffer != NULL &&
|
||||
item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
|
||||
}
|
||||
|
||||
BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
|
||||
const wp<BufferQueue::ConsumerListener>& consumerListener):
|
||||
mConsumerListener(consumerListener) {}
|
||||
|
@ -95,6 +95,7 @@ void ConsumerBase::freeBufferLocked(int slotIndex) {
|
||||
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
|
||||
mSlots[slotIndex].mGraphicBuffer = 0;
|
||||
mSlots[slotIndex].mFence = Fence::NO_FENCE;
|
||||
mSlots[slotIndex].mFrameNumber = 0;
|
||||
}
|
||||
|
||||
// Used for refactoring, should not be in final interface
|
||||
@ -191,21 +192,31 @@ status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
|
||||
mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
|
||||
}
|
||||
|
||||
mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
|
||||
mSlots[item->mBuf].mFence = item->mFence;
|
||||
|
||||
CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
|
||||
CB_LOGV("acquireBufferLocked: -> slot=%d/%llu",
|
||||
item->mBuf, item->mFrameNumber);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
|
||||
status_t ConsumerBase::addReleaseFence(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
|
||||
Mutex::Autolock lock(mMutex);
|
||||
return addReleaseFenceLocked(slot, fence);
|
||||
return addReleaseFenceLocked(slot, graphicBuffer, fence);
|
||||
}
|
||||
|
||||
status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) {
|
||||
status_t ConsumerBase::addReleaseFenceLocked(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
|
||||
CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
|
||||
|
||||
// If consumer no longer tracks this graphicBuffer, we can safely
|
||||
// drop this fence, as it will never be received by the producer.
|
||||
if (!stillTracking(slot, graphicBuffer)) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (!mSlots[slot].mFence.get()) {
|
||||
mSlots[slot].mFence = fence;
|
||||
} else {
|
||||
@ -225,11 +236,20 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
|
||||
EGLSyncKHR eglFence) {
|
||||
CB_LOGV("releaseBufferLocked: slot=%d", slot);
|
||||
status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence,
|
||||
mSlots[slot].mFence);
|
||||
status_t ConsumerBase::releaseBufferLocked(
|
||||
int slot, const sp<GraphicBuffer> graphicBuffer,
|
||||
EGLDisplay display, EGLSyncKHR eglFence) {
|
||||
// If consumer no longer tracks this graphicBuffer (we received a new
|
||||
// buffer on the same slot), the buffer producer is definitely no longer
|
||||
// tracking it.
|
||||
if (!stillTracking(slot, graphicBuffer)) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
CB_LOGV("releaseBufferLocked: slot=%d/%llu",
|
||||
slot, mSlots[slot].mFrameNumber);
|
||||
status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFrameNumber,
|
||||
display, eglFence, mSlots[slot].mFence);
|
||||
if (err == BufferQueue::STALE_BUFFER_SLOT) {
|
||||
freeBufferLocked(slot);
|
||||
}
|
||||
@ -239,4 +259,13 @@ status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
|
||||
return err;
|
||||
}
|
||||
|
||||
bool ConsumerBase::stillTracking(int slot,
|
||||
const sp<GraphicBuffer> graphicBuffer) {
|
||||
if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
|
||||
return false;
|
||||
}
|
||||
return (mSlots[slot].mGraphicBuffer != NULL &&
|
||||
mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
@ -189,7 +189,9 @@ status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) {
|
||||
// disconnected after this buffer was acquired.
|
||||
if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
|
||||
mSlots[buf].mGraphicBuffer)) {
|
||||
releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
releaseBufferLocked(
|
||||
buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer,
|
||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
}
|
||||
|
||||
AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
|
||||
|
@ -188,12 +188,16 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t GLConsumer::releaseBufferLocked(int buf, EGLDisplay display,
|
||||
EGLSyncKHR eglFence) {
|
||||
status_t err = ConsumerBase::releaseBufferLocked(buf, display, eglFence);
|
||||
|
||||
status_t GLConsumer::releaseBufferLocked(int buf,
|
||||
sp<GraphicBuffer> graphicBuffer,
|
||||
EGLDisplay display, EGLSyncKHR eglFence) {
|
||||
// release the buffer if it hasn't already been discarded by the
|
||||
// BufferQueue. This can happen, for example, when the producer of this
|
||||
// buffer has reallocated the original buffer slot after this buffer
|
||||
// was acquired.
|
||||
status_t err = ConsumerBase::releaseBufferLocked(
|
||||
buf, graphicBuffer, display, eglFence);
|
||||
mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -237,7 +241,10 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
|
||||
if (err != NO_ERROR) {
|
||||
// Release the buffer we just acquired. It's not safe to
|
||||
// release the old buffer, so instead we just drop the new frame.
|
||||
releaseBufferLocked(buf, mEglDisplay, EGL_NO_SYNC_KHR);
|
||||
// As we are still under lock since acquireBuffer, it is safe to
|
||||
// release by slot.
|
||||
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
|
||||
mEglDisplay, EGL_NO_SYNC_KHR);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -248,7 +255,8 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
|
||||
|
||||
// release old buffer
|
||||
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
|
||||
status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay,
|
||||
status_t status = releaseBufferLocked(
|
||||
mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
|
||||
mEglSlots[mCurrentTexture].mEglFence);
|
||||
if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
|
||||
ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)",
|
||||
@ -334,7 +342,8 @@ status_t GLConsumer::checkAndUpdateEglStateLocked() {
|
||||
void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
|
||||
if (fence->isValid() &&
|
||||
mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
|
||||
status_t err = addReleaseFence(mCurrentTexture, fence);
|
||||
status_t err = addReleaseFence(mCurrentTexture,
|
||||
mCurrentTextureBuf, fence);
|
||||
if (err != OK) {
|
||||
ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
|
||||
strerror(-err), err);
|
||||
@ -503,7 +512,8 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
sp<Fence> fence(new Fence(fenceFd));
|
||||
status_t err = addReleaseFenceLocked(mCurrentTexture, fence);
|
||||
status_t err = addReleaseFenceLocked(mCurrentTexture,
|
||||
mCurrentTextureBuf, fence);
|
||||
if (err != OK) {
|
||||
ST_LOGE("syncForReleaseLocked: error adding release fence: "
|
||||
"%s (%d)", strerror(-err), err);
|
||||
|
@ -103,8 +103,8 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>&
|
||||
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
|
||||
item.mBuf != mCurrentBufferSlot) {
|
||||
// Release the previous buffer.
|
||||
err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
|
||||
EGL_NO_SYNC_KHR);
|
||||
err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
|
||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
|
||||
if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
|
||||
ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
|
||||
return err;
|
||||
@ -144,7 +144,8 @@ void FramebufferSurface::onFrameCommitted() {
|
||||
sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
|
||||
if (fence->isValid() &&
|
||||
mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
|
||||
status_t err = addReleaseFence(mCurrentBufferSlot, fence);
|
||||
status_t err = addReleaseFence(mCurrentBufferSlot,
|
||||
mCurrentBuffer, fence);
|
||||
ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
|
||||
strerror(-err), err);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
|
||||
// reject buffers which have the wrong size
|
||||
int buf = item.mBuf;
|
||||
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
|
||||
releaseBufferLocked(buf, EGL_NO_SYNC_KHR);
|
||||
releaseBufferLocked(buf, item.mGraphicBuffer, EGL_NO_SYNC_KHR);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user