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

Commit 31a353da authored by Jamie Gennis's avatar Jamie Gennis
Browse files

BufferQueue: clean up buffer counting

This change is a clean up of some of the handling of the maximum number of
buffers that are allowed at once.  It mostly renames a few member variables and
methods, but it includes a couple small refactorings.

Change-Id: I9959310f563d09583548d4291e1050a7bbc7d87d
parent c1396dd1
Loading
Loading
Loading
Loading
+26 −23
Original line number Diff line number Diff line
@@ -252,10 +252,10 @@ public:
    // requestBuffers when a with and height of zero is requested.
    status_t setDefaultBufferSize(uint32_t w, uint32_t h);

    // setBufferCountServer set the buffer count. If the client has requested
    // setDefaultBufferCount set the buffer count. If the client has requested
    // a buffer count using setBufferCount, the server-buffer count will
    // take effect once the client sets the count back to zero.
    status_t setBufferCountServer(int bufferCount);
    status_t setDefaultMaxBufferCount(int bufferCount);

    // isSynchronousMode returns whether the SurfaceTexture is currently in
    // synchronous mode.
@@ -298,7 +298,14 @@ private:
    // are freed except the current buffer.
    status_t drainQueueAndFreeBuffersLocked();

    status_t setBufferCountServerLocked(int bufferCount);
    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
    // that will be used if the producer does not override the buffer slot
    // count.
    status_t setDefaultMaxBufferCountLocked(int count);

    // getMinBufferCountLocked returns the minimum number of buffers allowed
    // given the current BufferQueue state.
    int getMinMaxBufferCountLocked() const;

    struct BufferSlot {

@@ -426,26 +433,22 @@ private:
    // not dequeued at any time
    int mMinUndequeuedBuffers;

    // mMinAsyncBufferSlots is a constraint on the minimum mBufferCount
    // when this BufferQueue is in asynchronous mode
    int mMinAsyncBufferSlots;

    // mMinSyncBufferSlots is a constraint on the minimum mBufferCount
    // when this BufferQueue is in synchronous mode
    int mMinSyncBufferSlots;

    // mBufferCount is the number of buffer slots that the client and server
    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
    // by calling setBufferCount or setBufferCountServer
    int mBufferCount;

    // mClientBufferCount is the number of buffer slots requested by the client.
    // The default is zero, which means the client doesn't care how many buffers
    // there is.
    int mClientBufferCount;

    // mServerBufferCount buffer count requested by the server-side
    int mServerBufferCount;
    // mMaxBufferCount is the maximum number of buffers that will be allocated
    // at once.
    int mMaxBufferCount;

    // mDefaultMaxBufferCount is the default limit on the number of buffers
    // that will be allocated at one time.  This default limit is set by the
    // consumer.  The limit (as opposed to the default limit) may be
    // overridden by the producer.
    int mDefaultMaxBufferCount;

    // mOverrideMaxBufferCount is the limit on the number of buffers that will
    // be allocated at one time. This value is set by the image producer by
    // calling setBufferCount. The default is zero, which means the producer
    // doesn't care about the number of buffers in the pool. In that case
    // mDefaultMaxBufferCount is used as the limit.
    int mOverrideMaxBufferCount;

    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
    // allocate new GraphicBuffer objects.
+4 −4
Original line number Diff line number Diff line
@@ -87,10 +87,10 @@ public:
    // when finished with it.
    void setReleaseFence(int fenceFd);

    // setBufferCountServer set the buffer count. If the client has requested
    // a buffer count using setBufferCount, the server-buffer count will
    // take effect once the client sets the count back to zero.
    status_t setBufferCountServer(int bufferCount);
    // setDefaultMaxBufferCount sets the default limit on the maximum number
    // of buffers that will be allocated at one time. The image producer may
    // override the limit.
    status_t setDefaultMaxBufferCount(int bufferCount);

    // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
    // associated with the texture image set by the most recent call to
+52 −51
Original line number Diff line number Diff line
@@ -86,11 +86,9 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
    mDefaultWidth(1),
    mDefaultHeight(1),
    mMinUndequeuedBuffers(bufferCount),
    mMinAsyncBufferSlots(bufferCount + 1),
    mMinSyncBufferSlots(bufferCount),
    mBufferCount(mMinAsyncBufferSlots),
    mClientBufferCount(0),
    mServerBufferCount(mMinAsyncBufferSlots),
    mMaxBufferCount(bufferCount + 1),
    mDefaultMaxBufferCount(bufferCount + 1),
    mOverrideMaxBufferCount(0),
    mSynchronousMode(false),
    mAllowSynchronousMode(allowSynchronousMode),
    mConnectedApi(NO_CONNECTED_API),
@@ -120,19 +118,19 @@ BufferQueue::~BufferQueue() {
    ST_LOGV("~BufferQueue");
}

status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
    if (bufferCount > NUM_BUFFER_SLOTS)
status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
    if (count > NUM_BUFFER_SLOTS)
        return BAD_VALUE;

    mServerBufferCount = bufferCount;
    mDefaultMaxBufferCount = count;

    if (bufferCount == mBufferCount)
    if (count == mMaxBufferCount)
        return OK;

    if (!mClientBufferCount &&
        bufferCount >= mBufferCount) {
    if (!mOverrideMaxBufferCount &&
        count >= mMaxBufferCount) {
        // easy, we just have more buffers
        mBufferCount = bufferCount;
        mMaxBufferCount = count;
        mDequeueCondition.broadcast();
    } else {
        // we're here because we're either
@@ -140,15 +138,16 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
        // - or there is a client-buffer-count in effect

        // less than 2 buffers is never allowed
        if (bufferCount < 2)
        if (count < 2)
            return BAD_VALUE;

        // when there is non client-buffer-count in effect, the client is not
        // allowed to dequeue more than one buffer at a time,
        // so the next time they dequeue a buffer, we know that they don't
        // own one. the actual resizing will happen during the next
        // dequeueBuffer.
        // When there is no client-buffer-count in effect, the client is not
        // allowed to dequeue more than one buffer at a time, so the next time
        // they dequeue a buffer, we know that they don't own one. the actual
        // resizing will happen during the next dequeueBuffer.

        // We signal this condition in case there is already a blocked
        // dequeueBuffer call.
        mDequeueCondition.broadcast();
    }
    return OK;
@@ -199,20 +198,19 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
        }

        // Error out if the user has dequeued buffers
        for (int i=0 ; i<mBufferCount ; i++) {
        for (int i=0 ; i<mMaxBufferCount ; i++) {
            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
                ST_LOGE("setBufferCount: client owns some buffers");
                return -EINVAL;
            }
        }

        const int minBufferSlots = mSynchronousMode ?
            mMinSyncBufferSlots : mMinAsyncBufferSlots;
        const int minBufferSlots = getMinMaxBufferCountLocked();
        if (bufferCount == 0) {
            mClientBufferCount = 0;
            bufferCount = (mServerBufferCount >= minBufferSlots) ?
                    mServerBufferCount : minBufferSlots;
            return setBufferCountServerLocked(bufferCount);
            mOverrideMaxBufferCount = 0;
            bufferCount = (mDefaultMaxBufferCount >= minBufferSlots) ?
                    mDefaultMaxBufferCount : minBufferSlots;
            return setDefaultMaxBufferCountLocked(bufferCount);
        }

        if (bufferCount < minBufferSlots) {
@@ -224,8 +222,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
        // here we're guaranteed that the client doesn't have dequeued buffers
        // and will release all of its buffer references.
        freeAllBuffersLocked();
        mBufferCount = bufferCount;
        mClientBufferCount = bufferCount;
        mMaxBufferCount = bufferCount;
        mOverrideMaxBufferCount = bufferCount;
        mBufferHasBeenQueued = false;
        mQueue.clear();
        mDequeueCondition.broadcast();
@@ -282,9 +280,9 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
        ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }
    if (slot < 0 || mBufferCount <= slot) {
    if (slot < 0 || mMaxBufferCount <= slot) {
        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
                mBufferCount, slot);
                mMaxBufferCount, slot);
        return BAD_VALUE;
    }
    mSlots[slot].mRequestBufferCalled = true;
@@ -330,21 +328,20 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
            // The condition "number of buffers needs to change" is true if
            // - the client doesn't care about how many buffers there are
            // - AND the actual number of buffer is different from what was
            //   set in the last setBufferCountServer()
            //   set in the last setDefaultMaxBufferCount()
            //                         - OR -
            //   setBufferCountServer() was set to a value incompatible with
            //   setDefaultMaxBufferCount() was set to a value incompatible with
            //   the synchronization mode (for instance because the sync mode
            //   changed since)
            //
            // As long as this condition is true AND the FIFO is not empty, we
            // wait on mDequeueCondition.

            const int minBufferCountNeeded = mSynchronousMode ?
                    mMinSyncBufferSlots : mMinAsyncBufferSlots;
            const int minBufferCountNeeded = getMinMaxBufferCountLocked();

            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
                    ((mServerBufferCount != mBufferCount) ||
                            (mServerBufferCount < minBufferCountNeeded));
            const bool numberOfBuffersNeedsToChange = !mOverrideMaxBufferCount &&
                    ((mDefaultMaxBufferCount != mMaxBufferCount) ||
                            (mDefaultMaxBufferCount < minBufferCountNeeded));

            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
                // wait for the FIFO to drain
@@ -357,9 +354,9 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
            if (numberOfBuffersNeedsToChange) {
                // here we're guaranteed that mQueue is empty
                freeAllBuffersLocked();
                mBufferCount = mServerBufferCount;
                if (mBufferCount < minBufferCountNeeded)
                    mBufferCount = minBufferCountNeeded;
                mMaxBufferCount = mDefaultMaxBufferCount;
                if (mMaxBufferCount < minBufferCountNeeded)
                    mMaxBufferCount = minBufferCountNeeded;
                mBufferHasBeenQueued = false;
                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
            }
@@ -367,7 +364,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
            // look for a free buffer to give to the client
            found = INVALID_BUFFER_SLOT;
            dequeuedCount = 0;
            for (int i = 0; i < mBufferCount; i++) {
            for (int i = 0; i < mMaxBufferCount; i++) {
                const int state = mSlots[i].mBufferState;
                if (state == BufferSlot::DEQUEUED) {
                    dequeuedCount++;
@@ -397,7 +394,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,

            // clients are not allowed to dequeue more than one buffer
            // if they didn't set a buffer count.
            if (!mClientBufferCount && dequeuedCount) {
            if (!mOverrideMaxBufferCount && dequeuedCount) {
                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
                        "setting the buffer count");
                return -EINVAL;
@@ -409,7 +406,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
            if (mBufferHasBeenQueued) {
                // make sure the client is not trying to dequeue more buffers
                // than allowed.
                const int avail = mBufferCount - (dequeuedCount+1);
                const int avail = mMaxBufferCount - (dequeuedCount+1);
                if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {
                    ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded "
                            "(dequeued=%d)",
@@ -560,9 +557,9 @@ status_t BufferQueue::queueBuffer(int buf,
            ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
            return NO_INIT;
        }
        if (buf < 0 || buf >= mBufferCount) {
        if (buf < 0 || buf >= mMaxBufferCount) {
            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                    mBufferCount, buf);
                    mMaxBufferCount, buf);
            return -EINVAL;
        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
            ST_LOGE("queueBuffer: slot %d is not owned by the client "
@@ -656,9 +653,9 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
        return;
    }

    if (buf < 0 || buf >= mBufferCount) {
    if (buf < 0 || buf >= mMaxBufferCount) {
        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
                mBufferCount, buf);
                mMaxBufferCount, buf);
        return;
    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@@ -779,9 +776,9 @@ void BufferQueue::dump(String8& result, const char* prefix,
    }

    snprintf(buffer, SIZE,
            "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
            "%s-BufferQueue mMaxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
            "default-format=%d, FIFO(%d)={%s}\n",
            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
            prefix, mMaxBufferCount, mSynchronousMode, mDefaultWidth,
            mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
    result.append(buffer);

@@ -798,7 +795,7 @@ void BufferQueue::dump(String8& result, const char* prefix,
        }
    } stateName;

    for (int i=0 ; i<mBufferCount ; i++) {
    for (int i=0 ; i<mMaxBufferCount ; i++) {
        const BufferSlot& slot(mSlots[i]);
        snprintf(buffer, SIZE,
                "%s%s[%02d] "
@@ -991,10 +988,10 @@ status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
    return OK;
}

status_t BufferQueue::setBufferCountServer(int bufferCount) {
status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
    ATRACE_CALL();
    Mutex::Autolock lock(mMutex);
    return setBufferCountServerLocked(bufferCount);
    return setDefaultMaxBufferCountLocked(bufferCount);
}

void BufferQueue::freeAllBuffersExceptHeadLocked() {
@@ -1038,6 +1035,10 @@ status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
    return err;
}

int BufferQueue::getMinMaxBufferCountLocked() const {
    return mSynchronousMode ? mMinUndequeuedBuffers : mMinUndequeuedBuffers + 1;
}

BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
        const wp<BufferQueue::ConsumerListener>& consumerListener):
        mConsumerListener(consumerListener) {}
+2 −2
Original line number Diff line number Diff line
@@ -125,9 +125,9 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
    mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}

status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setBufferCountServer(bufferCount);
    return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
}


+6 −6
Original line number Diff line number Diff line
@@ -848,7 +848,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
    enum { numFrames = 1024 };

    ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
            texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
@@ -1321,7 +1321,7 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
    };

    ASSERT_EQ(OK, mST->setSynchronousMode(true));
    ASSERT_EQ(OK, mST->setBufferCountServer(2));
    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));

    sp<Thread> pt(new ProducerThread(mANW));
    pt->run();
@@ -1584,7 +1584,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {

TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
    // This test requires 3 buffers to run on a single thread.
    mST->setBufferCountServer(3);
    mST->setDefaultMaxBufferCount(3);

    ASSERT_TRUE(mST->isSynchronousMode());

@@ -2045,7 +2045,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
    };

    ASSERT_EQ(OK, mST->setSynchronousMode(true));
    ASSERT_EQ(OK, mST->setBufferCountServer(2));
    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));

    runProducerThread(new PT());

@@ -2059,7 +2059,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
    // We must call updateTexImage to consume the first frame so that the
    // SurfaceTexture is able to reduce the buffer count to 2.  This is because
    // the GL driver may dequeue a buffer when the EGLSurface is created, and
    // that happens before we call setBufferCountServer.  It's possible that the
    // that happens before we call setDefaultMaxBufferCount.  It's possible that the
    // driver does not dequeue a buffer at EGLSurface creation time, so we
    // cannot rely on this to cause the second dequeueBuffer call to block.
    mST->updateTexImage();
@@ -2586,7 +2586,7 @@ TEST_F(SurfaceTextureMultiContextGLTest,
TEST_F(SurfaceTextureMultiContextGLTest,
        UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
    ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));

    // produce two frames and consume them both on the primary context
    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
Loading