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

Commit 22f842ba authored by Shuzhen Wang's avatar Shuzhen Wang
Browse files

BufferQueue: Add bufferReplaced flag in QueueBufferOutput

For async buffer queue, when queueBuffer overwrites a previously queued
buffer, because consumer won't be able to acquire the overwritten
buffer, onBufferReleased isn't triggered either.

This makes it difficult to track which buffer in the buffer queue
becomes free other than calling dequeueBuffer(). Adding a flag in
QueueBufferOutput addresses this issue.

Test: TestBufferReplacedInQueueBuffer in BufferQueue_tests
Bug: 34481539
Change-Id: Ic7f4be2d3f9691dd6b007a450240614c0c420f0d
parent 90b25ed5
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -385,6 +385,7 @@ public:
        uint32_t numPendingBuffers{0};
        uint32_t numPendingBuffers{0};
        uint64_t nextFrameNumber{0};
        uint64_t nextFrameNumber{0};
        FrameEventHistoryDelta frameTimestamps;
        FrameEventHistoryDelta frameTimestamps;
        bool bufferReplaced{false};
    };
    };


    virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
    virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
+3 −0
Original line number Original line Diff line number Diff line
@@ -879,6 +879,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
            mCore->mSharedBufferCache.dataspace = dataSpace;
            mCore->mSharedBufferCache.dataspace = dataSpace;
        }
        }


        output->bufferReplaced = false;
        if (mCore->mQueue.empty()) {
        if (mCore->mQueue.empty()) {
            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
            // and simply queue this buffer
            // and simply queue this buffer
@@ -905,6 +906,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
                    if (!mSlots[last.mSlot].mBufferState.isShared()) {
                    if (!mSlots[last.mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(last.mSlot);
                        mCore->mActiveBuffers.erase(last.mSlot);
                        mCore->mFreeBuffers.push_back(last.mSlot);
                        mCore->mFreeBuffers.push_back(last.mSlot);
                        output->bufferReplaced = true;
                    }
                    }
                }
                }


@@ -1158,6 +1160,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
            output->numPendingBuffers =
            output->numPendingBuffers =
                    static_cast<uint32_t>(mCore->mQueue.size());
                    static_cast<uint32_t>(mCore->mQueue.size());
            output->nextFrameNumber = mCore->mFrameCounter + 1;
            output->nextFrameNumber = mCore->mFrameCounter + 1;
            output->bufferReplaced = false;


            if (listener != NULL) {
            if (listener != NULL) {
                // Set up a death notification so that we can disconnect
                // Set up a death notification so that we can disconnect
+4 −1
Original line number Original line Diff line number Diff line
@@ -830,7 +830,8 @@ constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
            sizeof(height) +
            sizeof(height) +
            sizeof(transformHint) +
            sizeof(transformHint) +
            sizeof(numPendingBuffers) +
            sizeof(numPendingBuffers) +
            sizeof(nextFrameNumber);
            sizeof(nextFrameNumber) +
            sizeof(bufferReplaced);
}
}


size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
@@ -853,6 +854,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
    FlattenableUtils::write(buffer, size, transformHint);
    FlattenableUtils::write(buffer, size, transformHint);
    FlattenableUtils::write(buffer, size, numPendingBuffers);
    FlattenableUtils::write(buffer, size, numPendingBuffers);
    FlattenableUtils::write(buffer, size, nextFrameNumber);
    FlattenableUtils::write(buffer, size, nextFrameNumber);
    FlattenableUtils::write(buffer, size, bufferReplaced);


    return frameTimestamps.flatten(buffer, size, fds, count);
    return frameTimestamps.flatten(buffer, size, fds, count);
}
}
@@ -869,6 +871,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
    FlattenableUtils::read(buffer, size, transformHint);
    FlattenableUtils::read(buffer, size, transformHint);
    FlattenableUtils::read(buffer, size, numPendingBuffers);
    FlattenableUtils::read(buffer, size, numPendingBuffers);
    FlattenableUtils::read(buffer, size, nextFrameNumber);
    FlattenableUtils::read(buffer, size, nextFrameNumber);
    FlattenableUtils::read(buffer, size, bufferReplaced);


    return frameTimestamps.unflatten(buffer, size, fds, count);
    return frameTimestamps.unflatten(buffer, size, fds, count);
}
}
+41 −0
Original line number Original line Diff line number Diff line
@@ -1076,4 +1076,45 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) {
    }
    }
}
}


TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) {
    createBufferQueue();
    sp<DummyConsumer> dc(new DummyConsumer);
    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
    IGraphicBufferProducer::QueueBufferOutput output;
    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
            NATIVE_WINDOW_API_CPU, true, &output));
    ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));

    int slot = BufferQueue::INVALID_BUFFER_SLOT;
    sp<Fence> fence = Fence::NO_FENCE;
    sp<GraphicBuffer> buffer = nullptr;
    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
        HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
        NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
    BufferItem item{};

    // Preallocate, dequeue, request, and cancel 2 buffers so we don't get
    // BUFFER_NEEDS_REALLOCATION below
    int slots[2] = {};
    ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
    for (size_t i = 0; i < 2; ++i) {
        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
                0, 0, 0, 0, nullptr);
        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
        ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
    }
    for (size_t i = 0; i < 2; ++i) {
        ASSERT_EQ(OK, mProducer->cancelBuffer(slots[i], Fence::NO_FENCE));
    }

    // Fill 2 buffers without consumer consuming them. Verify that all
    // queued buffer returns proper bufferReplaced flag
    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
    ASSERT_EQ(false, output.bufferReplaced);
    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
    ASSERT_EQ(true, output.bufferReplaced);
}

} // namespace android
} // namespace android