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 Original line Diff line number Diff line
@@ -14,6 +14,9 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


#undef LOG_TAG
#define LOG_TAG "BLASTBufferQueue"

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


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


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

    mAcquired = false;
}
}


void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
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) {
                                           const std::vector<SurfaceControlStats>& stats) {
    std::unique_lock _lock{mMutex};
    std::unique_lock _lock{mMutex};


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


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

    if (mAcquired) {
        return;
    }

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


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


    int status = OK;
    mNextCallbackBufferItem = mLastSubmittedBufferItem;
    mNextCallbackBufferItem = mLastSubmittedBufferItem;

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

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



    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
    incStrong((void*)transactionCallbackThunk);
    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()});
    t->setCrop(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});


    if (applyTransaction) {
    if (applyTransaction) {
        ALOGE("Apply transaction");
        t->apply();
        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) {
void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
    std::unique_lock _lock{mMutex};
    std::lock_guard _lock{mMutex};
    mNextTransaction = t;
    mNextTransaction = t;
}
}


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


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


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

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


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


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


namespace android {
namespace android {


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


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



    virtual ~BLASTBufferQueue() = default;
    virtual ~BLASTBufferQueue() = default;


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


    void processNextBufferLocked() REQUIRES(mMutex);

    sp<SurfaceControl> mSurfaceControl;
    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 {
    struct BufferInfo {
        sp<GraphicBuffer> buffer;
        sp<GraphicBuffer> buffer;
        int fence;
        int fence;
    };
    };


    int mDequeuedBuffers = 0;
    std::queue<const BufferItem> mShadowQueue GUARDED_BY(mMutex);

    bool mAcquired GUARDED_BY(mMutex);
    int mWidth;
    int mHeight;


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


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


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


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


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


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


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


private:
private:
@@ -116,6 +120,17 @@ protected:
                .apply();
                .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,
    void fillBuffer(uint32_t* bufData, uint32_t width, uint32_t height, uint32_t stride, uint8_t r,
                    uint8_t g, uint8_t b) {
                    uint8_t g, uint8_t b) {
        for (uint32_t row = 0; row < height; row++) {
        for (uint32_t row = 0; row < height; row++) {
@@ -195,14 +210,8 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
    uint8_t b = 0;
    uint8_t b = 0;


    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
    auto igbProducer = adapter.getIGraphicBufferProducer();
    sp<IGraphicBufferProducer> igbProducer;
    ASSERT_NE(nullptr, igbProducer.get());
    setUpProducer(adapter, igbProducer);
    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);


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


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


    adapter.waitForCallback();
    sleep(1);


    // capture screen and verify that it is red
    // capture screen and verify that it is red
    bool capturedSecureLayers;
    bool capturedSecureLayers;
@@ -237,4 +247,43 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
                                       /*useIdentityTransform*/ false));
                                       /*useIdentityTransform*/ false));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b));
    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
} // namespace android
+0 −1
Original line number Original line Diff line number Diff line
@@ -543,7 +543,6 @@ TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
    // Should now be able to dequeue up to minBuffers times
    // Should now be able to dequeue up to minBuffers times
    DequeueBufferResult result;
    DequeueBufferResult result;
    for (int i = 0; i < minBuffers; ++i) {
    for (int i = 0; i < minBuffers; ++i) {

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