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

Commit 28471596 authored by Valerie Hau's avatar Valerie Hau Committed by Android (Google) Code Review
Browse files

Merge "Adding triple buffering without wait"

parents 0a37a2c5 d3b90d22
Loading
Loading
Loading
Loading
+41 −15
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@
 * limitations under the License.
 */

#undef LOG_TAG
#define LOG_TAG "BLASTBufferQueue"

#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>

@@ -24,8 +27,14 @@ using namespace std::chrono_literals;
namespace android {

BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
      : mSurfaceControl(surface), mWidth(width), mHeight(height) {
      : mSurfaceControl(surface),
        mPendingCallbacks(0),
        mWidth(width),
        mHeight(height),
        mNextTransaction(nullptr) {
    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
    mConsumer->setMaxBufferCount(MAX_BUFFERS);
    mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1);
    mBufferItemConsumer =
            new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
    mBufferItemConsumer->setName(String8("BLAST Consumer"));
@@ -34,6 +43,8 @@ BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width,
    mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
    mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
    mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint());

    mAcquired = false;
}

void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
@@ -59,20 +70,32 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
                                           const std::vector<SurfaceControlStats>& stats) {
    std::unique_lock _lock{mMutex};

    if (stats.size() > 0 && mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
    if (stats.size() > 0 && !mShadowQueue.empty()) {
        mBufferItemConsumer->releaseBuffer(mNextCallbackBufferItem,
                                           stats[0].previousReleaseFence
                                                   ? stats[0].previousReleaseFence
                                                   : Fence::NO_FENCE);
        mAcquired = false;
        mNextCallbackBufferItem = BufferItem();
        mBufferItemConsumer->setTransformHint(stats[0].transformHint);
    }
    mDequeueWaitCV.notify_all();
    mPendingCallbacks--;
    processNextBufferLocked();
    mCallbackCV.notify_all();
    decStrong((void*)transactionCallbackThunk);
}

void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    std::unique_lock _lock{mMutex};
void BLASTBufferQueue::processNextBufferLocked() {
    if (mShadowQueue.empty()) {
        return;
    }

    if (mAcquired) {
        return;
    }

    BufferItem item = std::move(mShadowQueue.front());
    mShadowQueue.pop();

    SurfaceComposerClient::Transaction localTransaction;
    bool applyTransaction = true;
@@ -83,11 +106,11 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
        applyTransaction = false;
    }

    int status = OK;
    mNextCallbackBufferItem = mLastSubmittedBufferItem;

    mLastSubmittedBufferItem = BufferItem();
    status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);

    status_t status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);
    mAcquired = true;
    if (status != OK) {
        ALOGE("Failed to acquire?");
    }
@@ -99,7 +122,6 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
        return;
    }


    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
    incStrong((void*)transactionCallbackThunk);

@@ -112,17 +134,21 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    t->setCrop(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});

    if (applyTransaction) {
        ALOGE("Apply transaction");
        t->apply();

        if (mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
            mDequeueWaitCV.wait_for(_lock, 5000ms);
    }
}

void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
    std::lock_guard _lock{mMutex};

    // add to shadow queue
    mShadowQueue.push(item);
    processNextBufferLocked();
    mPendingCallbacks++;
}

void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
    std::unique_lock _lock{mMutex};
    std::lock_guard _lock{mMutex};
    mNextTransaction = t;
}

+28 −27
Original line number Diff line number Diff line
@@ -189,48 +189,49 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(
}

void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
    std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
    {
        std::lock_guard<std::mutex> lock(mMutex);

        /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
         * callbackIds, except for when Transactions are merged together. This probably cannot be
     * solved before this point because the Transactions could be merged together and applied in a
     * different process.
         * solved before this point because the Transactions could be merged together and applied in
         * a different process.
         *
     * Fortunately, we get all the callbacks for this listener for the same frame together at the
     * same time. This means if any Transactions were merged together, we will get their callbacks
     * at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps for all the
     * callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
     * that could possibly exist for the callbacks.
         * Fortunately, we get all the callbacks for this listener for the same frame together at
         * the same time. This means if any Transactions were merged together, we will get their
         * callbacks at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps
         * for all the callbackIds to generate one super map that contains all the sp<IBinder> to
         * sp<SurfaceControl> that could possibly exist for the callbacks.
         */
    std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
            surfaceControls;
        callbacksMap = mCallbacks;
        for (const auto& transactionStats : listenerStats.transactionStats) {
        for (auto callbackId : transactionStats.callbackIds) {
            auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
            surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end());
            for (auto& callbackId : transactionStats.callbackIds) {
                mCallbacks.erase(callbackId);
            }
        }
    }

    for (const auto& transactionStats : listenerStats.transactionStats) {
        for (auto callbackId : transactionStats.callbackIds) {
            auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
            auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
            if (!callbackFunction) {
                ALOGE("cannot call null callback function, skipping");
                continue;
            }
            std::vector<SurfaceControlStats> surfaceControlStats;
            for (const auto& surfaceStats : transactionStats.surfaceStats) {
                surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
                                                 surfaceStats.acquireTime,
                                                 surfaceStats.previousReleaseFence,
                                                 surfaceStats.transformHint);
                surfaceControls[surfaceStats.surfaceControl]->setTransformHint(
                surfaceControlStats
                        .emplace_back(callbacksMap[callbackId]
                                              .surfaceControls[surfaceStats.surfaceControl],
                                      surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
                                      surfaceStats.transformHint);
                callbacksMap[callbackId]
                        .surfaceControls[surfaceStats.surfaceControl]
                        ->setTransformHint(surfaceStats.transformHint);
            }

            callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                             surfaceControlStats);
            mCallbacks.erase(callbackId);
        }
    }
}
+16 −13
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <utils/RefBase.h>

#include <system/window.h>
#include <thread>

namespace android {

@@ -51,7 +52,6 @@ public:

    void update(const sp<SurfaceControl>& surface, int width, int height);


    virtual ~BLASTBufferQueue() = default;

private:
@@ -61,32 +61,35 @@ private:
    BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
    BLASTBufferQueue(const BLASTBufferQueue& rhs);

    void processNextBufferLocked() REQUIRES(mMutex);

    sp<SurfaceControl> mSurfaceControl;

    mutable std::mutex mMutex;
    std::mutex mMutex;
    std::condition_variable mCallbackCV;
    uint64_t mPendingCallbacks GUARDED_BY(mMutex);

    static const int MAX_BUFFERS = 2;
    static const int MAX_BUFFERS = 3;
    struct BufferInfo {
        sp<GraphicBuffer> buffer;
        int fence;
    };

    int mDequeuedBuffers = 0;

    int mWidth;
    int mHeight;
    std::queue<const BufferItem> mShadowQueue GUARDED_BY(mMutex);
    bool mAcquired GUARDED_BY(mMutex);

    BufferItem mLastSubmittedBufferItem;
    BufferItem mNextCallbackBufferItem;
    sp<Fence> mLastFence;
    int mWidth GUARDED_BY(mMutex);
    int mHeight GUARDED_BY(mMutex);

    std::condition_variable mDequeueWaitCV;
    BufferItem mLastSubmittedBufferItem GUARDED_BY(mMutex);
    BufferItem mNextCallbackBufferItem GUARDED_BY(mMutex);
    sp<Fence> mLastFence GUARDED_BY(mMutex);

    sp<IGraphicBufferConsumer> mConsumer;
    sp<IGraphicBufferProducer> mProducer;
    sp<BufferItemConsumer> mBufferItemConsumer;

    SurfaceComposerClient::Transaction* mNextTransaction = nullptr;
    SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
};

} // namespace android
+60 −11
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <gui/BLASTBufferQueue.h>

#include <android/hardware/graphics/common/1.2/types.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
@@ -65,9 +67,11 @@ public:
        return mBlastBufferQueueAdapter->mSurfaceControl;
    }

    void waitForCallback() {
    void waitForCallbacks() {
        std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
        mBlastBufferQueueAdapter->mDequeueWaitCV.wait_for(lock, 1s);
        while (mBlastBufferQueueAdapter->mPendingCallbacks > 0) {
            mBlastBufferQueueAdapter->mCallbackCV.wait(lock);
        }
    }

private:
@@ -116,6 +120,17 @@ protected:
                .apply();
    }

    void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
        auto igbProducer = adapter.getIGraphicBufferProducer();
        ASSERT_NE(nullptr, igbProducer.get());
        IGraphicBufferProducer::QueueBufferOutput qbOutput;
        ASSERT_EQ(NO_ERROR,
                  igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
                                       &qbOutput));
        ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
        producer = igbProducer;
    }

    void fillBuffer(uint32_t* bufData, uint32_t width, uint32_t height, uint32_t stride, uint8_t r,
                    uint8_t g, uint8_t b) {
        for (uint32_t row = 0; row < height; row++) {
@@ -195,14 +210,8 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
    uint8_t b = 0;

    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
    auto igbProducer = adapter.getIGraphicBufferProducer();
    ASSERT_NE(nullptr, igbProducer.get());
    IGraphicBufferProducer::QueueBufferOutput qbOutput;
    ASSERT_EQ(NO_ERROR,
              igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
                                   &qbOutput));
    ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(3));
    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
    sp<IGraphicBufferProducer> igbProducer;
    setUpProducer(adapter, igbProducer);

    int slot;
    sp<Fence> fence;
@@ -219,6 +228,7 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
    fillBuffer(bufData, buf->getWidth(), buf->getHeight(), buf->getStride(), r, g, b);
    buf->unlock();

    IGraphicBufferProducer::QueueBufferOutput qbOutput;
    IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
                                                   Rect(mDisplayWidth, mDisplayHeight),
                                                   NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
@@ -226,7 +236,7 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
    igbProducer->queueBuffer(slot, input, &qbOutput);
    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);

    adapter.waitForCallback();
    sleep(1);

    // capture screen and verify that it is red
    bool capturedSecureLayers;
@@ -237,4 +247,43 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
                                       /*useIdentityTransform*/ false));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b));
}

TEST_F(BLASTBufferQueueTest, TripleBuffering) {
    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
    sp<IGraphicBufferProducer> igbProducer;
    setUpProducer(adapter, igbProducer);

    std::vector<std::pair<int, sp<Fence>>> allocated;
    for (int i = 0; i < 3; i++) {
        int slot;
        sp<Fence> fence;
        sp<GraphicBuffer> buf;
        auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
                                              PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
                                              nullptr, nullptr);
        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
        ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
        allocated.push_back({slot, fence});
    }
    for (int i = 0; i < allocated.size(); i++) {
        igbProducer->cancelBuffer(allocated[i].first, allocated[i].second);
    }

    for (int i = 0; i < 10; i++) {
        int slot;
        sp<Fence> fence;
        sp<GraphicBuffer> buf;
        auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
                                              PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
                                              nullptr, nullptr);
        ASSERT_EQ(NO_ERROR, ret);
        IGraphicBufferProducer::QueueBufferOutput qbOutput;
        IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
                                                       Rect(mDisplayWidth, mDisplayHeight),
                                                       NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
                                                       Fence::NO_FENCE);
        igbProducer->queueBuffer(slot, input, &qbOutput);
    }
    adapter.waitForCallbacks();
}
} // namespace android
+0 −1
Original line number Diff line number Diff line
@@ -543,7 +543,6 @@ TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
    // Should now be able to dequeue up to minBuffers times
    DequeueBufferResult result;
    for (int i = 0; i < minBuffers; ++i) {

        EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
                              TEST_PRODUCER_USAGE_BITS, &result)))