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

Commit a3fbda3c authored by Mathias Agopian's avatar Mathias Agopian
Browse files

BuffferQueue disconnect is now always asynchrnous

we tag queued buffers with the "bufferqueue cannot block" flag
and use that bit to discard a buffer in the queue by new ones
comming in. this allows us to remove the buffer queue drain in
disconnect while maintaining the right behaviour if it gets
connected again (since each buffer remembers how it was enqueued).

Change-Id: I1e703d363a687b70b19ba49cef32213116e8bd3f
parent 595264f1
Loading
Loading
Loading
Loading
+15 −21
Original line number Diff line number Diff line
@@ -223,13 +223,13 @@ public:
    // public facing structure for BufferSlot
    struct BufferItem {

        BufferItem()
         :
        BufferItem() :
           mTransform(0),
           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
           mTimestamp(0),
           mFrameNumber(0),
           mBuf(INVALID_BUFFER_SLOT),
           mDequeueBufferCannotBlock(false),
           mAcquireCalled(false) {
             mCrop.makeInvalid();
        }
@@ -260,6 +260,13 @@ public:
        // mFence is a fence that will signal when the buffer is idle.
        sp<Fence> mFence;

        // mDequeueBufferCannotBlock whether this buffer was queued with the
        // property that it can be replaced by a new buffer for the purpose of
        // making sure dequeueBuffer() won't block.
        // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
        // was queued.
        bool mDequeueBufferCannotBlock;

        // Indicates whether this buffer has been seen by a consumer yet
        bool mAcquireCalled;
    };
@@ -366,17 +373,6 @@ private:
    // all slots.
    void freeAllBuffersLocked();

    // drainQueueLocked waits for the buffer queue to empty if we're in
    // synchronous mode, or returns immediately otherwise. It returns NO_INIT
    // if the BufferQueue is abandoned (consumer disconnected) or disconnected
    // (producer disconnected) during the call.
    status_t drainQueueLocked();

    // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
    // synchronous mode and free all buffers. In asynchronous mode, all buffers
    // are freed except the currently queued buffer (if it exists).
    status_t drainQueueAndFreeBuffersLocked();

    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
    // that will be used if the producer does not override the buffer slot
    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
@@ -387,15 +383,11 @@ private:
    // given the current BufferQueue state.
    int getMinMaxBufferCountLocked() const;

    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
    // that must remain in a state other than DEQUEUED.
    int getMinUndequeuedBufferCountLocked() const;

    // getMaxBufferCountLocked returns the maximum number of buffers that can
    // be allocated at once.  This value depends upon the following member
    // variables:
    //
    //      mSynchronousMode
    //      mDequeueBufferCannotBlock
    //      mMaxAcquiredBufferCount
    //      mDefaultMaxBufferCount
    //      mOverrideMaxBufferCount
@@ -524,6 +516,11 @@ private:
    // in dequeueBuffer() if a width and height of zero is specified.
    uint32_t mDefaultHeight;

    // mMinUndequeuedBufferCount holds the minimum number of buffers
    // that must remain in a state other than DEQUEUED.
    // This value cannot change while connected.
    int mMinUndequeuedBufferCount;

    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
    // acquire at one time.  It defaults to 1 and can be changed by the
    // consumer via the setMaxAcquiredBufferCount method, but this may only be
@@ -564,9 +561,6 @@ private:
    // by the application.
    bool mDequeueBufferCannotBlock;

    // mSynchronousMode whether we're in synchronous mode or not
    bool mSynchronousMode;

    // mConnectedApi indicates the producer API that is currently connected
    // to this BufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets
    // updated by the connect and disconnect methods.
+20 −54
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
    mOverrideMaxBufferCount(0),
    mConsumerControlledByApp(false),
    mDequeueBufferCannotBlock(false),
    mSynchronousMode(true),
    mConnectedApi(NO_CONNECTED_API),
    mAbandoned(false),
    mFrameCounter(0),
@@ -210,7 +209,7 @@ int BufferQueue::query(int what, int* outValue)
        value = mDefaultBufferFormat;
        break;
    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
        value = getMinUndequeuedBufferCountLocked();
        value = mMinUndequeuedBufferCount;
        break;
    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
        value = (mQueue.size() >= 2);
@@ -329,7 +328,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
                // make sure the client is not trying to dequeue more buffers
                // than allowed.
                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
                const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
                const int minUndequeuedCount = mMinUndequeuedBufferCount;
                if (newUndequeuedCount < minUndequeuedCount) {
                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
                            "exceeded (dequeued=%d undequeudCount=%d)",
@@ -524,31 +523,27 @@ status_t BufferQueue::queueBuffer(int buf,
        item.mFrameNumber = mFrameCounter;
        item.mBuf = buf;
        item.mFence = fence;
        item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock;

        if (mSynchronousMode) {
            // In synchronous mode we queue all buffers in a FIFO.
            mQueue.push_back(item);

            // Synchronous mode always signals that an additional frame should
            // be consumed.
            listener = mConsumerListener;
        } else {
            // In asynchronous mode we only keep the most recent buffer.
        if (mQueue.empty()) {
            // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
            // simply queue this buffer.
            mQueue.push_back(item);

                // Asynchronous mode only signals that a frame should be
                // consumed if no previous frame was pending. If a frame were
                // pending then the consumer would have already been notified.
            listener = mConsumerListener;
        } else {
            // when the queue is not empty, we need to look at the front buffer
            // state and see if we need to replace it.
            Fifo::iterator front(mQueue.begin());
            if (front->mDequeueBufferCannotBlock) {
                // 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
                // and we record the new buffer in the queued list
                *front = item;
            } else {
                mQueue.push_back(item);
                listener = mConsumerListener;
            }
        }

@@ -635,7 +630,8 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer

    mBufferHasBeenQueued = false;
    mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
    mSynchronousMode = !mDequeueBufferCannotBlock;
    mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ?
            mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;

    return err;
}
@@ -662,7 +658,7 @@ status_t BufferQueue::disconnect(int api) {
            case NATIVE_WINDOW_API_MEDIA:
            case NATIVE_WINDOW_API_CAMERA:
                if (mConnectedApi == api) {
                    drainQueueAndFreeBuffersLocked();
                    freeAllBuffersLocked();
                    mConnectedApi = NO_CONNECTED_API;
                    mDequeueCondition.broadcast();
                    listener = mConsumerListener;
@@ -711,9 +707,9 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
    int maxBufferCount = getMaxBufferCountLocked();

    result.appendFormat(
            "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
            "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
            "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
            prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
            prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
            mDefaultHeight, mDefaultBufferFormat, mTransformHint,
            fifoSize, fifo.string());

@@ -768,8 +764,6 @@ void BufferQueue::freeBufferLocked(int slot) {
}

void BufferQueue::freeAllBuffersLocked() {
    ALOGD_IF(!mQueue.isEmpty(),
            "freeAllBuffersLocked called with non-empty mQueue");
    mBufferHasBeenQueued = false;
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
        freeBufferLocked(i);
@@ -1024,36 +1018,8 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
    return NO_ERROR;
}

status_t BufferQueue::drainQueueLocked() {
    while (mSynchronousMode && mQueue.size() > 1) {
        mDequeueCondition.wait(mMutex);
        if (mAbandoned) {
            ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
            return NO_INIT;
        }
        if (mConnectedApi == NO_CONNECTED_API) {
            ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
            return NO_INIT;
        }
    }
    return NO_ERROR;
}

status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
    status_t err = drainQueueLocked();
    if (err == NO_ERROR) {
        freeAllBuffersLocked();
    }
    return err;
}

int BufferQueue::getMinMaxBufferCountLocked() const {
    return getMinUndequeuedBufferCountLocked() + 1;
}

int BufferQueue::getMinUndequeuedBufferCountLocked() const {
    return mSynchronousMode ? mMaxAcquiredBufferCount :
            mMaxAcquiredBufferCount + 1;
    return mMinUndequeuedBufferCount + 1;
}

int BufferQueue::getMaxBufferCountLocked() const {
+1 −3
Original line number Diff line number Diff line
@@ -83,9 +83,7 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
}

// This test probably doesn't belong here.
// DISABLED because it hangs when disconnecting because of draining the queue.
// will be fixed in a subsequent BQ change
TEST_F(SurfaceTest, DISABLED_ScreenshotsOfProtectedBuffersSucceed) {
TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
    sp<ANativeWindow> anw(mSurface);

    // Verify the screenshot works with no protected buffers.