Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb6d43ff authored by Dan Stoza's avatar Dan Stoza Committed by Gerrit Code Review
Browse files

Merge "libgui: Change BufferQueue to use free lists"

parents 56f1f16c 0de7ea75
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,9 @@
#include <utils/Trace.h>
#include <utils/Trace.h>
#include <utils/Vector.h>
#include <utils/Vector.h>


#include <list>
#include <set>

#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -123,6 +126,10 @@ private:
    // waitWhileAllocatingLocked blocks until mIsAllocating is false.
    // waitWhileAllocatingLocked blocks until mIsAllocating is false.
    void waitWhileAllocatingLocked() const;
    void waitWhileAllocatingLocked() const;


    // validateConsistencyLocked ensures that the free lists are in sync with
    // the information stored in mSlots
    void validateConsistencyLocked() const;

    // mAllocator is the connection to SurfaceFlinger that is used to allocate
    // mAllocator is the connection to SurfaceFlinger that is used to allocate
    // new GraphicBuffer objects.
    // new GraphicBuffer objects.
    sp<IGraphicBufferAlloc> mAllocator;
    sp<IGraphicBufferAlloc> mAllocator;
@@ -177,6 +184,14 @@ private:
    // mQueue is a FIFO of queued buffers used in synchronous mode.
    // mQueue is a FIFO of queued buffers used in synchronous mode.
    Fifo mQueue;
    Fifo mQueue;


    // mFreeSlots contains all of the slots which are FREE and do not currently
    // have a buffer attached
    std::set<int> mFreeSlots;

    // mFreeBuffers contains all of the slots which are FREE and currently have
    // a buffer attached
    std::list<int> mFreeBuffers;

    // mOverrideMaxBufferCount is the limit on the number of buffers that will
    // mOverrideMaxBufferCount is the limit on the number of buffers that will
    // be allocated at one time. This value is set by the producer by calling
    // be allocated at one time. This value is set by the producer by calling
    // setBufferCount. The default is 0, which means that the producer doesn't
    // setBufferCount. The default is 0, which means that the producer doesn't
+20 −8
Original line number Original line Diff line number Diff line
@@ -120,6 +120,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
            if (mCore->stillTracking(front)) {
            if (mCore->stillTracking(front)) {
                // Front buffer is still in mSlots, so mark the slot as free
                // Front buffer is still in mSlots, so mark the slot as free
                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
                mCore->mFreeBuffers.push_back(front->mSlot);
            }
            }
            mCore->mQueue.erase(front);
            mCore->mQueue.erase(front);
            front = mCore->mQueue.begin();
            front = mCore->mQueue.begin();
@@ -173,6 +174,8 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,


    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());


    mCore->validateConsistencyLocked();

    return NO_ERROR;
    return NO_ERROR;
}
}


@@ -199,6 +202,7 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {


    mCore->freeBufferLocked(slot);
    mCore->freeBufferLocked(slot);
    mCore->mDequeueCondition.broadcast();
    mCore->mDequeueCondition.broadcast();
    mCore->validateConsistencyLocked();


    return NO_ERROR;
    return NO_ERROR;
}
}
@@ -217,18 +221,11 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,


    Mutex::Autolock lock(mCore->mMutex);
    Mutex::Autolock lock(mCore->mMutex);


    // Make sure we don't have too many acquired buffers and find a free slot
    // Make sure we don't have too many acquired buffers
    // to put the buffer into (the oldest if there are multiple).
    int numAcquiredBuffers = 0;
    int numAcquiredBuffers = 0;
    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
            ++numAcquiredBuffers;
            ++numAcquiredBuffers;
        } else if (mSlots[s].mBufferState == BufferSlot::FREE) {
            if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
                    mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
                found = s;
            }
        }
        }
    }
    }


@@ -238,6 +235,17 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
                mCore->mMaxAcquiredBufferCount);
                mCore->mMaxAcquiredBufferCount);
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }

    // Find a free slot to put the buffer into
    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
    if (!mCore->mFreeSlots.empty()) {
        auto slot = mCore->mFreeSlots.begin();
        found = *slot;
        mCore->mFreeSlots.erase(slot);
    } else if (!mCore->mFreeBuffers.empty()) {
        found = mCore->mFreeBuffers.front();
        mCore->mFreeBuffers.remove(found);
    }
    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
        BQ_LOGE("attachBuffer(P): could not find free buffer slot");
        BQ_LOGE("attachBuffer(P): could not find free buffer slot");
        return NO_MEMORY;
        return NO_MEMORY;
@@ -271,6 +279,8 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
    // for attached buffers.
    // for attached buffers.
    mSlots[*outSlot].mAcquireCalled = false;
    mSlots[*outSlot].mAcquireCalled = false;


    mCore->validateConsistencyLocked();

    return NO_ERROR;
    return NO_ERROR;
}
}


@@ -311,6 +321,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
            mSlots[slot].mEglFence = eglFence;
            mSlots[slot].mEglFence = eglFence;
            mSlots[slot].mFence = releaseFence;
            mSlots[slot].mFence = releaseFence;
            mSlots[slot].mBufferState = BufferSlot::FREE;
            mSlots[slot].mBufferState = BufferSlot::FREE;
            mCore->mFreeBuffers.push_back(slot);
            listener = mCore->mConnectedProducerListener;
            listener = mCore->mConnectedProducerListener;
            BQ_LOGV("releaseBuffer: releasing slot %d", slot);
            BQ_LOGV("releaseBuffer: releasing slot %d", slot);
        } else if (mSlots[slot].mNeedsCleanupOnRelease) {
        } else if (mSlots[slot].mNeedsCleanupOnRelease) {
@@ -325,6 +336,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
        }
        }


        mCore->mDequeueCondition.broadcast();
        mCore->mDequeueCondition.broadcast();
        mCore->validateConsistencyLocked();
    } // Autolock scope
    } // Autolock scope


    // Call back without lock held
    // Call back without lock held
+59 −1
Original line number Original line Diff line number Diff line
@@ -53,6 +53,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
    mConnectedProducerListener(),
    mConnectedProducerListener(),
    mSlots(),
    mSlots(),
    mQueue(),
    mQueue(),
    mFreeSlots(),
    mFreeBuffers(),
    mOverrideMaxBufferCount(0),
    mOverrideMaxBufferCount(0),
    mDequeueCondition(),
    mDequeueCondition(),
    mUseAsyncBuffer(true),
    mUseAsyncBuffer(true),
@@ -76,6 +78,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
            BQ_LOGE("createGraphicBufferAlloc failed");
            BQ_LOGE("createGraphicBufferAlloc failed");
        }
        }
    }
    }
    for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
        mFreeSlots.insert(slot);
    }
}
}


BufferQueueCore::~BufferQueueCore() {}
BufferQueueCore::~BufferQueueCore() {}
@@ -190,12 +195,20 @@ status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) {


void BufferQueueCore::freeBufferLocked(int slot) {
void BufferQueueCore::freeBufferLocked(int slot) {
    BQ_LOGV("freeBufferLocked: slot %d", slot);
    BQ_LOGV("freeBufferLocked: slot %d", slot);
    bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL;
    mSlots[slot].mGraphicBuffer.clear();
    mSlots[slot].mGraphicBuffer.clear();
    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
        mSlots[slot].mNeedsCleanupOnRelease = true;
        mSlots[slot].mNeedsCleanupOnRelease = true;
    }
    }
    if (mSlots[slot].mBufferState != BufferSlot::FREE) {
        mFreeSlots.insert(slot);
    } else if (hadBuffer) {
        // If the slot was FREE, but we had a buffer, we need to move this slot
        // from the free buffers list to the the free slots list
        mFreeBuffers.remove(slot);
        mFreeSlots.insert(slot);
    }
    mSlots[slot].mBufferState = BufferSlot::FREE;
    mSlots[slot].mBufferState = BufferSlot::FREE;
    mSlots[slot].mFrameNumber = UINT32_MAX;
    mSlots[slot].mAcquireCalled = false;
    mSlots[slot].mAcquireCalled = false;


    // Destroy fence as BufferQueue now takes ownership
    // Destroy fence as BufferQueue now takes ownership
@@ -204,6 +217,7 @@ void BufferQueueCore::freeBufferLocked(int slot) {
        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
    }
    }
    mSlots[slot].mFence = Fence::NO_FENCE;
    mSlots[slot].mFence = Fence::NO_FENCE;
    validateConsistencyLocked();
}
}


void BufferQueueCore::freeAllBuffersLocked() {
void BufferQueueCore::freeAllBuffersLocked() {
@@ -236,4 +250,48 @@ void BufferQueueCore::waitWhileAllocatingLocked() const {
    }
    }
}
}


void BufferQueueCore::validateConsistencyLocked() const {
    static const useconds_t PAUSE_TIME = 0;
    for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
        bool isInFreeSlots = mFreeSlots.count(slot) != 0;
        bool isInFreeBuffers =
                std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
                mFreeBuffers.cend();
        if (mSlots[slot].mBufferState == BufferSlot::FREE) {
            if (mSlots[slot].mGraphicBuffer == NULL) {
                if (!isInFreeSlots) {
                    BQ_LOGE("Slot %d is FREE but is not in mFreeSlots", slot);
                    usleep(PAUSE_TIME);
                }
                if (isInFreeBuffers) {
                    BQ_LOGE("Slot %d is in mFreeSlots "
                            "but is also in mFreeBuffers", slot);
                    usleep(PAUSE_TIME);
                }
            } else {
                if (!isInFreeBuffers) {
                    BQ_LOGE("Slot %d is FREE but is not in mFreeBuffers", slot);
                    usleep(PAUSE_TIME);
                }
                if (isInFreeSlots) {
                    BQ_LOGE("Slot %d is in mFreeBuffers "
                            "but is also in mFreeSlots", slot);
                    usleep(PAUSE_TIME);
                }
            }
        } else {
            if (isInFreeSlots) {
                BQ_LOGE("Slot %d is in mFreeSlots but is not FREE (%d)",
                        slot, mSlots[slot].mBufferState);
                usleep(PAUSE_TIME);
            }
            if (isInFreeBuffers) {
                BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE (%d)",
                        slot, mSlots[slot].mBufferState);
                usleep(PAUSE_TIME);
            }
        }
    }
}

} // namespace android
} // namespace android
+37 −30
Original line number Original line Diff line number Diff line
@@ -161,8 +161,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
            }
            }
        }
        }


        // Look for a free buffer to give to the client
        *found = BufferQueueCore::INVALID_BUFFER_SLOT;
        int dequeuedCount = 0;
        int dequeuedCount = 0;
        int acquiredCount = 0;
        int acquiredCount = 0;
        for (int s = 0; s < maxBufferCount; ++s) {
        for (int s = 0; s < maxBufferCount; ++s) {
@@ -173,15 +171,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
                case BufferSlot::ACQUIRED:
                case BufferSlot::ACQUIRED:
                    ++acquiredCount;
                    ++acquiredCount;
                    break;
                    break;
                case BufferSlot::FREE:
                    // We return the oldest of the free buffers to avoid
                    // stalling the producer if possible, since the consumer
                    // may still have pending reads of in-flight buffers
                    if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||
                            mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
                        *found = s;
                    }
                    break;
                default:
                default:
                    break;
                    break;
            }
            }
@@ -214,6 +203,8 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
            }
            }
        }
        }


        *found = BufferQueueCore::INVALID_BUFFER_SLOT;

        // If we disconnect and reconnect quickly, we can be in a state where
        // If we disconnect and reconnect quickly, we can be in a state where
        // our slots are empty but we have many buffers in the queue. This can
        // our slots are empty but we have many buffers in the queue. This can
        // cause us to run out of memory if we outrun the consumer. Wait here if
        // cause us to run out of memory if we outrun the consumer. Wait here if
@@ -223,6 +214,19 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
        if (tooManyBuffers) {
        if (tooManyBuffers) {
            BQ_LOGV("%s: queue size is %zu, waiting", caller,
            BQ_LOGV("%s: queue size is %zu, waiting", caller,
                    mCore->mQueue.size());
                    mCore->mQueue.size());
        } else {
            if (!mCore->mFreeBuffers.empty()) {
                auto slot = mCore->mFreeBuffers.begin();
                *found = *slot;
                mCore->mFreeBuffers.erase(slot);
            } else if (!mCore->mFreeSlots.empty()) {
                auto slot = mCore->mFreeSlots.begin();
                // Only return free slots up to the max buffer count
                if (*slot < maxBufferCount) {
                    *found = *slot;
                    mCore->mFreeSlots.erase(slot);
                }
            }
        }
        }


        // If no buffer is found, or if the queue has too many buffers
        // If no buffer is found, or if the queue has too many buffers
@@ -335,6 +339,8 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
        *outFence = mSlots[found].mFence;
        *outFence = mSlots[found].mFence;
        mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
        mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
        mSlots[found].mFence = Fence::NO_FENCE;
        mSlots[found].mFence = Fence::NO_FENCE;

        mCore->validateConsistencyLocked();
    } // Autolock scope
    } // Autolock scope


    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
@@ -355,7 +361,6 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
                return NO_INIT;
                return NO_INIT;
            }
            }


            mSlots[*outSlot].mFrameNumber = UINT32_MAX;
            mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
            mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
        } // Autolock scope
        } // Autolock scope
    }
    }
@@ -414,6 +419,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) {


    mCore->freeBufferLocked(slot);
    mCore->freeBufferLocked(slot);
    mCore->mDequeueCondition.broadcast();
    mCore->mDequeueCondition.broadcast();
    mCore->validateConsistencyLocked();


    return NO_ERROR;
    return NO_ERROR;
}
}
@@ -438,27 +444,19 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
        return NO_INIT;
        return NO_INIT;
    }
    }


    // Find the oldest valid slot
    if (mCore->mFreeBuffers.empty()) {
    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;
        return NO_MEMORY;
    }
    }


    int found = mCore->mFreeBuffers.front();
    mCore->mFreeBuffers.remove(found);

    BQ_LOGV("detachNextBuffer detached slot %d", found);
    BQ_LOGV("detachNextBuffer detached slot %d", found);


    *outBuffer = mSlots[found].mGraphicBuffer;
    *outBuffer = mSlots[found].mGraphicBuffer;
    *outFence = mSlots[found].mFence;
    *outFence = mSlots[found].mFence;
    mCore->freeBufferLocked(found);
    mCore->freeBufferLocked(found);
    mCore->validateConsistencyLocked();


    return NO_ERROR;
    return NO_ERROR;
}
}
@@ -506,6 +504,8 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
    mSlots[*outSlot].mFence = Fence::NO_FENCE;
    mSlots[*outSlot].mFence = Fence::NO_FENCE;
    mSlots[*outSlot].mRequestBufferCalled = true;
    mSlots[*outSlot].mRequestBufferCalled = true;


    mCore->validateConsistencyLocked();

    return returnFlags;
    return returnFlags;
}
}


@@ -640,9 +640,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
                // mark it as freed
                // mark it as freed
                if (mCore->stillTracking(front)) {
                if (mCore->stillTracking(front)) {
                    mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
                    mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
                    // Reset the frame number of the freed buffer so that it is
                    mCore->mFreeBuffers.push_front(front->mSlot);
                    // the first in line to be dequeued again
                    mSlots[front->mSlot].mFrameNumber = 0;
                }
                }
                // Overwrite the droppable buffer with the incoming one
                // Overwrite the droppable buffer with the incoming one
                *front = item;
                *front = item;
@@ -664,6 +662,8 @@ status_t BufferQueueProducer::queueBuffer(int slot,


        // Take a ticket for the callback functions
        // Take a ticket for the callback functions
        callbackTicket = mNextCallbackTicket++;
        callbackTicket = mNextCallbackTicket++;

        mCore->validateConsistencyLocked();
    } // Autolock scope
    } // Autolock scope


    // Wait without lock held
    // Wait without lock held
@@ -724,10 +724,11 @@ void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
        return;
        return;
    }
    }


    mCore->mFreeBuffers.push_front(slot);
    mSlots[slot].mBufferState = BufferSlot::FREE;
    mSlots[slot].mBufferState = BufferSlot::FREE;
    mSlots[slot].mFrameNumber = 0;
    mSlots[slot].mFence = fence;
    mSlots[slot].mFence = fence;
    mCore->mDequeueCondition.broadcast();
    mCore->mDequeueCondition.broadcast();
    mCore->validateConsistencyLocked();
}
}


int BufferQueueProducer::query(int what, int *outValue) {
int BufferQueueProducer::query(int what, int *outValue) {
@@ -1009,13 +1010,19 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
                }
                }
                mCore->freeBufferLocked(slot); // Clean up the slot first
                mCore->freeBufferLocked(slot); // Clean up the slot first
                mSlots[slot].mGraphicBuffer = buffers[i];
                mSlots[slot].mGraphicBuffer = buffers[i];
                mSlots[slot].mFrameNumber = 0;
                mSlots[slot].mFence = Fence::NO_FENCE;
                mSlots[slot].mFence = Fence::NO_FENCE;

                // freeBufferLocked puts this slot on the free slots list. Since
                // we then attached a buffer, move the slot to free buffer list.
                mCore->mFreeSlots.erase(slot);
                mCore->mFreeBuffers.push_front(slot);

                BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
                BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
            }
            }


            mCore->mIsAllocating = false;
            mCore->mIsAllocating = false;
            mCore->mIsAllocatingCondition.broadcast();
            mCore->mIsAllocatingCondition.broadcast();
            mCore->validateConsistencyLocked();
        } // Autolock scope
        } // Autolock scope
    }
    }
}
}