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

Commit 5f683cf6 authored by Adithya Srinivasan's avatar Adithya Srinivasan
Browse files

Enable SurfaceFlinger to use FrameTimeline

This change adds the necessary plumbing from SurfaceFlinger to use
FrameTimeline for the BufferQueueLayers.

Bug: 162890590
Test: libsurfaceflinger_unittest
Change-Id: Ibac00ccb6584e9eb8d06eb9682747400b3e92845
parent 74e17562
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "BufferLayerConsumer.h"
#include "Client.h"
#include "DisplayHardware/HWComposer.h"
#include "FrameTimeline.h"
#include "FrameTracker.h"
#include "Layer.h"
#include "LayerVector.h"
+52 −22
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include "TimeStats/TimeStats.h"

namespace android {
using PresentState = frametimeline::SurfaceFrame::PresentState;

BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}

@@ -109,7 +110,7 @@ bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {

    Mutex::Autolock lock(mQueueItemLock);

    const int64_t addedTime = mQueueItems[0].mTimestamp;
    const int64_t addedTime = mQueueItems[0].item.mTimestamp;

    // Ignore timestamps more than a second in the future
    const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
@@ -136,7 +137,7 @@ bool BufferQueueLayer::fenceHasSignaled() const {
    }

    Mutex::Autolock lock(mQueueItemLock);
    if (mQueueItems[0].mIsDroppable) {
    if (mQueueItems[0].item.mIsDroppable) {
        // Even though this buffer's fence may not have signaled yet, it could
        // be replaced by another buffer before it has a chance to, which means
        // that it's possible to get into a situation where a buffer is never
@@ -144,7 +145,7 @@ bool BufferQueueLayer::fenceHasSignaled() const {
        return true;
    }
    const bool fenceSignaled =
            mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
            mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
    if (!fenceSignaled) {
        mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
                                                    TimeStats::LatchSkipReason::LateAcquire);
@@ -159,12 +160,12 @@ bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co
    }

    Mutex::Autolock lock(mQueueItemLock);
    return mQueueItems[0].mTimestamp <= expectedPresentTime;
    return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
}

uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
    Mutex::Autolock lock(mQueueItemLock);
    uint64_t frameNumber = mQueueItems[0].mFrameNumber;
    uint64_t frameNumber = mQueueItems[0].item.mFrameNumber;

    // The head of the queue will be dropped if there are signaled and timely frames behind it
    if (isRemovedFromCurrentState()) {
@@ -173,23 +174,23 @@ uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {

    for (int i = 1; i < mQueueItems.size(); i++) {
        const bool fenceSignaled =
                mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
                mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
        if (!fenceSignaled) {
            break;
        }

        // We don't drop frames without explicit timestamps
        if (mQueueItems[i].mIsAutoTimestamp) {
        if (mQueueItems[i].item.mIsAutoTimestamp) {
            break;
        }

        const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
        const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp;
        if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
            desiredPresent > expectedPresentTime) {
            break;
        }

        frameNumber = mQueueItems[i].mFrameNumber;
        frameNumber = mQueueItems[i].item.mFrameNumber;
    }

    return frameNumber;
@@ -258,11 +259,11 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t
        Mutex::Autolock lock(mQueueItemLock);
        for (int i = 0; i < mQueueItems.size(); i++) {
            bool fenceSignaled =
                    mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
                    mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
            if (!fenceSignaled) {
                break;
            }
            lastSignaledFrameNumber = mQueueItems[i].mFrameNumber;
            lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber;
        }
    }
    const uint64_t maxFrameNumberToAcquire =
@@ -280,9 +281,13 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t
        // and return early
        if (queuedBuffer) {
            Mutex::Autolock lock(mQueueItemLock);
            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
            mQueueItems.removeAt(0);
            mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
            if (mQueueItems[0].surfaceFrame) {
                mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
                                                          PresentState::Dropped);
            }
            mQueueItems.erase(mQueueItems.begin());
            mQueuedFrames--;
        }
        return BAD_VALUE;
@@ -293,6 +298,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t
        // early.
        if (queuedBuffer) {
            Mutex::Autolock lock(mQueueItemLock);
            for (auto& [item, surfaceFrame] : mQueueItems) {
                if (surfaceFrame) {
                    mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
                                                              PresentState::Dropped);
                }
            }
            mQueueItems.clear();
            mQueuedFrames = 0;
            mFlinger->mTimeStats->onDestroy(layerId);
@@ -316,19 +327,29 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t

        // Remove any stale buffers that have been dropped during
        // updateTexImage
        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
            mQueueItems.removeAt(0);
        while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
            mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
            if (mQueueItems[0].surfaceFrame) {
                mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
                                                          PresentState::Dropped);
            }
            mQueueItems.erase(mQueueItems.begin());
            mQueuedFrames--;
        }

        uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
        uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId();
        mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime);
        mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime,
                                               FrameTracer::FrameEvent::LATCH);

        mQueueItems.removeAt(0);
        if (mQueueItems[0].surfaceFrame) {
            mQueueItems[0].surfaceFrame->setActualEndTime(
                    mQueueItems[0].item.mFenceTime->getSignalTime());
            mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
                                                      PresentState::Presented);
        }
        mQueueItems.erase(mQueueItems.begin());
    }

    // Decrement the queued-frames count.  Signal another event if we
@@ -420,7 +441,11 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
            }
        }

        mQueueItems.push_back(item);
        auto surfaceFrame =
                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
        surfaceFrame->setActualQueueTime(systemTime());

        mQueueItems.push_back({item, std::move(surfaceFrame)});
        mQueuedFrames++;

        // Wake up any pending callbacks
@@ -453,7 +478,12 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
            ALOGE("Can't replace a frame on an empty queue");
            return;
        }
        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;

        auto surfaceFrame =
                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
        surfaceFrame->setActualQueueTime(systemTime());
        mQueueItems[mQueueItems.size() - 1].item = item;
        mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);

        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
+12 −1
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@

namespace android {

namespace frametimeline {
class SurfaceFrame;
}

/*
 * A new BufferQueue and a new BufferLayerConsumer are created when the
 * BufferLayer is first referenced.
@@ -126,7 +130,14 @@ private:
    // Local copy of the queued contents of the incoming BufferQueue
    mutable Mutex mQueueItemLock;
    Condition mQueueItemCondition;
    Vector<BufferItem> mQueueItems;

    struct BufferData {
        BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
              : item(item), surfaceFrame(std::move(surfaceFrame)) {}
        BufferItem item;
        std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
    };
    std::vector<BufferData> mQueueItems;
    std::atomic<uint64_t> mLastFrameNumberReceived{0};

    bool mAutoRefresh{false};
+29 −4
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "FrameTimeline.h"
#include <android-base/stringprintf.h>
#include <utils/Trace.h>
#include <cinttypes>

namespace android::frametimeline::impl {
@@ -27,6 +28,7 @@ namespace android::frametimeline::impl {
using base::StringAppendF;

int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
    ATRACE_CALL();
    std::lock_guard<std::mutex> lock(mMutex);
    const int64_t assignedToken = mCurrentToken++;
    mPredictions[assignedToken] = predictions;
@@ -88,18 +90,34 @@ TimelineItem SurfaceFrame::getActuals() {
    return mActuals;
}

void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) {
nsecs_t SurfaceFrame::getActualQueueTime() {
    std::lock_guard<std::mutex> lock(mMutex);
    mActuals = actuals;
    return mActualQueueTime;
}

void SurfaceFrame::setPresentTime(nsecs_t presentTime) {
void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
    std::lock_guard<std::mutex> lock(mMutex);
    mActuals.startTime = actualStartTime;
}

void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
    std::lock_guard<std::mutex> lock(mMutex);
    mActualQueueTime = actualQueueTime;
}
void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) {
    std::lock_guard<std::mutex> lock(mMutex);
    mActuals.endTime = actualEndTime;
}

void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
    std::lock_guard<std::mutex> lock(mMutex);
    mActuals.presentTime = presentTime;
}

void SurfaceFrame::dump(std::string& result) {
    std::lock_guard<std::mutex> lock(mMutex);
    StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState));
    StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState));
    StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime);
    StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime);
    StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime);
@@ -120,6 +138,7 @@ FrameTimeline::DisplayFrame::DisplayFrame()

std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
        const std::string& layerName, std::optional<int64_t> token) {
    ATRACE_CALL();
    if (!token) {
        return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
                                                    TimelineItem());
@@ -136,6 +155,7 @@ std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfa
void FrameTimeline::addSurfaceFrame(
        std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
        SurfaceFrame::PresentState state) {
    ATRACE_CALL();
    surfaceFrame->setPresentState(state);
    std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
            static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
@@ -144,18 +164,21 @@ void FrameTimeline::addSurfaceFrame(
}

void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
    ATRACE_CALL();
    const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
    std::lock_guard<std::mutex> lock(mMutex);
    if (!prediction) {
        mCurrentDisplayFrame->predictionState = PredictionState::Expired;
    } else {
        mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
        mCurrentDisplayFrame->predictionState = PredictionState::Valid;
    }
    mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
}

void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
                                 const std::shared_ptr<FenceTime>& presentFence) {
    ATRACE_CALL();
    std::lock_guard<std::mutex> lock(mMutex);
    mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
    mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
@@ -179,7 +202,7 @@ void FrameTimeline::flushPendingPresentFences() {
            for (auto& surfaceFrame : displayFrame->surfaceFrames) {
                if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
                    // Only presented SurfaceFrames need to be updated
                    surfaceFrame->setPresentTime(signalTime);
                    surfaceFrame->setActualPresentTime(signalTime);
                }
            }
        }
@@ -204,6 +227,8 @@ void FrameTimeline::dump(std::string& result) {
    StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
    for (const auto& displayFrame : mDisplayFrames) {
        StringAppendF(&result, "---Display Frame---\n");
        StringAppendF(&result, "Prediction State : %d\n",
                      static_cast<int>(displayFrame->predictionState));
        StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n",
                      displayFrame->surfaceFlingerPredictions.startTime);
        StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n",
+18 −12
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ public:

    // Generates a token for the given set of predictions. Stores the predictions for 120ms and
    // destroys it later.
    virtual int64_t generateTokenForPredictions(TimelineItem&& prediction);
    virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0;
};

enum class PredictionState {
@@ -76,15 +76,18 @@ public:

    virtual TimelineItem getPredictions() = 0;
    virtual TimelineItem getActuals() = 0;
    virtual nsecs_t getActualQueueTime() = 0;
    virtual PresentState getPresentState() = 0;
    virtual PredictionState getPredictionState() = 0;

    virtual void setPresentState(PresentState state) = 0;
    virtual void setActuals(TimelineItem&& actuals) = 0;

    // There is no prediction for Queue time and it is not a part of TimelineItem. Set it
    // separately.
    // Actual timestamps of the app are set individually at different functions.
    // Start time (if the app provides) and Queue time are accessible after queueing the frame,
    // whereas End time is available only during latch.
    virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
    virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
    virtual void setActualEndTime(nsecs_t actualEndTime) = 0;
};

/*
@@ -94,7 +97,7 @@ public:
class FrameTimeline {
public:
    virtual ~FrameTimeline() = default;
    virtual TokenManager& getTokenManager() = 0;
    virtual TokenManager* getTokenManager() = 0;

    // Create a new surface frame, set the predictions based on a token and return it to the caller.
    // Sets the PredictionState of SurfaceFrame.
@@ -115,6 +118,8 @@ public:
    // that vsync.
    virtual void setSfPresent(nsecs_t sfPresentTime,
                              const std::shared_ptr<FenceTime>& presentFence) = 0;

    virtual void dump(std::string& result) = 0;
};

namespace impl {
@@ -151,14 +156,15 @@ public:

    TimelineItem getPredictions() override { return mPredictions; };
    TimelineItem getActuals() override;
    nsecs_t getActualQueueTime() override;
    PresentState getPresentState() override;
    PredictionState getPredictionState() override;
    void setActuals(TimelineItem&& actuals) override;
    void setActualQueueTime(nsecs_t actualQueueTime) override {
        mActualQueueTime = actualQueueTime;
    };

    void setActualStartTime(nsecs_t actualStartTime) override;
    void setActualQueueTime(nsecs_t actualQueueTime) override;
    void setActualEndTime(nsecs_t actualEndTime) override;
    void setPresentState(PresentState state) override;
    void setPresentTime(nsecs_t presentTime);
    void setActualPresentTime(nsecs_t presentTime);
    void dump(std::string& result);

private:
@@ -176,7 +182,7 @@ public:
    FrameTimeline();
    ~FrameTimeline() = default;

    frametimeline::TokenManager& getTokenManager() override { return mTokenManager; }
    frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
    std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
            const std::string& layerName, std::optional<int64_t> token) override;
    void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
@@ -184,7 +190,7 @@ public:
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
    void setSfPresent(nsecs_t sfPresentTime,
                      const std::shared_ptr<FenceTime>& presentFence) override;
    void dump(std::string& result);
    void dump(std::string& result) override;

private:
    // Friend class for testing
Loading