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

Commit 162b5e90 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "SurfaceFlinger: Support out of order transactions"

parents 9d7313b9 277142c5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -371,7 +371,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
                               mPendingTransactions.end());

    if (applyTransaction) {
        t->apply();
        t->setApplyToken(mApplyToken).apply();
    }

    BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
+18 −3
Original line number Diff line number Diff line
@@ -396,7 +396,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
        mContainsBuffer(other.mContainsBuffer),
        mDesiredPresentTime(other.mDesiredPresentTime),
        mIsAutoTimestamp(other.mIsAutoTimestamp),
        mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) {
        mFrameTimelineVsyncId(other.mFrameTimelineVsyncId),
        mApplyToken(other.mApplyToken) {
    mDisplayStates = other.mDisplayStates;
    mComposerStates = other.mComposerStates;
    mInputWindowCommands = other.mInputWindowCommands;
@@ -427,7 +428,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
    const int64_t desiredPresentTime = parcel->readInt64();
    const bool isAutoTimestamp = parcel->readBool();
    const int64_t frameTimelineVsyncId = parcel->readInt64();

    sp<IBinder> applyToken;
    parcel->readNullableStrongBinder(&applyToken);
    size_t count = static_cast<size_t>(parcel->readUint32());
    if (count > parcel->dataSize()) {
        return BAD_VALUE;
@@ -505,6 +507,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
    mListenerCallbacks = listenerCallbacks;
    mComposerStates = composerStates;
    mInputWindowCommands = inputWindowCommands;
    mApplyToken = applyToken;
    return NO_ERROR;
}

@@ -532,6 +535,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const
    parcel->writeInt64(mDesiredPresentTime);
    parcel->writeBool(mIsAutoTimestamp);
    parcel->writeInt64(mFrameTimelineVsyncId);
    parcel->writeStrongBinder(mApplyToken);
    parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
    for (auto const& displayState : mDisplayStates) {
        displayState.write(*parcel);
@@ -607,6 +611,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr
    mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
    mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
    mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
    mApplyToken = other.mApplyToken;

    // When merging vsync Ids we take the oldest one
    if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
@@ -635,6 +640,7 @@ void SurfaceComposerClient::Transaction::clear() {
    mDesiredPresentTime = 0;
    mIsAutoTimestamp = true;
    mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
    mApplyToken = nullptr;
}

void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -763,7 +769,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
        flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
    }

    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
    sp<IBinder> applyToken = mApplyToken
            ? mApplyToken
            : IInterface::asBinder(TransactionCompletedListener::getIInstance());

    sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
                            mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1579,6 +1588,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoR
    return *this;
}

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
        const sp<IBinder>& applyToken) {
    mApplyToken = applyToken;
    return *this;
}

// ---------------------------------------------------------------------------

DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
+4 −0
Original line number Diff line number Diff line
@@ -165,6 +165,10 @@ private:

    std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
    uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};

    // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
    // transactions from other parts of the client from blocking this transaction.
    const sp<IBinder> mApplyToken = new BBinder();
};

} // namespace android
+9 −0
Original line number Diff line number Diff line
@@ -388,6 +388,10 @@ public:
        // The vsync Id provided by Choreographer.getVsyncId
        int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;

        // If not null, transactions will be queued up using this token otherwise a common token
        // per process will be used.
        sp<IBinder> mApplyToken = nullptr;

        InputWindowCommands mInputWindowCommands;
        int mStatus = NO_ERROR;

@@ -555,6 +559,11 @@ public:
        // in shared buffer mode.
        Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);

        // Queues up transactions using this token in SurfaceFlinger.  By default, all transactions
        // from a client are placed on the same queue. This can be used to prevent multiple
        // transactions from blocking each other.
        Transaction& setApplyToken(const sp<IBinder>& token);

        status_t setDisplaySurface(const sp<IBinder>& token,
                const sp<IGraphicBufferProducer>& bufferProducer);

+61 −0
Original line number Diff line number Diff line
@@ -221,6 +221,32 @@ protected:
        return captureResults.result;
    }

    void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
                     nsecs_t presentTimeDelay) {
        int slot;
        sp<Fence> fence;
        sp<GraphicBuffer> buf;
        auto ret = igbp->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, igbp->requestBuffer(slot, &buf));

        uint32_t* bufData;
        buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
                  reinterpret_cast<void**>(&bufData));
        fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b);
        buf->unlock();

        IGraphicBufferProducer::QueueBufferOutput qbOutput;
        nsecs_t timestampNanos = systemTime() + presentTimeDelay;
        IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN,
                                                       Rect(mDisplayWidth, mDisplayHeight / 2),
                                                       NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
                                                       Fence::NO_FENCE);
        igbp->queueBuffer(slot, input, &qbOutput);
    }

    sp<SurfaceComposerClient> mClient;
    sp<ISurfaceComposer> mComposer;

@@ -528,6 +554,41 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) {
    ASSERT_EQ(queuesToNativeWindow, 1);
}

TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
    sp<SurfaceControl> bgSurface =
            mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
                                   ISurfaceComposerClient::eFXSurfaceBufferState);
    ASSERT_NE(nullptr, bgSurface.get());
    Transaction t;
    t.setLayerStack(bgSurface, 0)
            .show(bgSurface)
            .setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
            .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight))
            .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
            .apply();

    BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
    sp<IGraphicBufferProducer> slowIgbProducer;
    setUpProducer(slowAdapter, slowIgbProducer);
    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
    queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay);

    BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight);
    sp<IGraphicBufferProducer> fastIgbProducer;
    setUpProducer(fastAdapter, fastIgbProducer);
    uint8_t r = 255;
    uint8_t g = 0;
    uint8_t b = 0;
    queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */);
    fastAdapter.waitForCallbacks();

    // capture screen and verify that it is red
    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));

    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}

class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
public:
    void test(uint32_t tr) {