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

Commit 63a3e592 authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: Layer::shouldPresentNow should consider early frames

Move the decision whether to latch a buffer or not based on
the expected present time (that is whether a frame is considered too
early or out of vsync phase) from Layer::latchBuffer to
Layer::shouldPresentNow as the code assumes that Layer::latchBuffer would
not fail based on the expected present.

Bug: 176755514
Bug: 176416352
Test: atest CtsViewTestCases:android.view.cts.ASurfaceControlTest
Test: atest FrameRateOverrideHostTest
Change-Id: Ib83bda41c824549011f12fa5414263c8b03032e4
parent ae9bf1e1
Loading
Loading
Loading
Loading
+37 −18
Original line number Original line Diff line number Diff line
@@ -389,33 +389,58 @@ void BufferLayer::gatherBufferInfo() {
    mBufferInfo.mFrameLatencyNeeded = true;
    mBufferInfo.mFrameLatencyNeeded = true;
}
}


bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
    // If this is not a valid vsync for the layer's uid, return and try again later
    const bool isVsyncValidForUid =
            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
    if (!isVsyncValidForUid) {
        ATRACE_NAME("!isVsyncValidForUid");
        return false;
    }

    // AutoRefresh layers and sideband streams should always be presented
    if (getSidebandStreamChanged() || getAutoRefresh()) {
        return true;
    }

    // If the next planned present time is not current, return and try again later
    if (frameIsEarly(expectedPresentTime)) {
        ATRACE_NAME("frameIsEarly()");
        return false;
    }

    // If this layer doesn't have a frame is shouldn't be presented
    if (!hasFrameUpdate()) {
        return false;
    }

    // Defer to the derived class to decide whether the next buffer is due for
    // presentation.
    return isBufferDue(expectedPresentTime);
}

bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const {
bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const {
    // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
    // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
    // vsync period. We can do this change as soon as ag/13100772 is merged.
    // vsync period. We can do this change as soon as ag/13100772 is merged.
    constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;
    constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;


    const auto presentTime = nextPredictedPresentTime();
    const auto presentTime = nextPredictedPresentTime();
    if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
    if (!presentTime.has_value()) {
        return false;
        return false;
    }
    }


    return presentTime >= expectedPresentTime &&
    if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
            presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
        return false;
    }

    return *presentTime >= expectedPresentTime &&
            *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
}
}


bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                              nsecs_t expectedPresentTime) {
                              nsecs_t expectedPresentTime) {
    ATRACE_CALL();
    ATRACE_CALL();


    // If this is not a valid vsync for the layer's uid, return and try again later
    const bool isVsyncValidForUid =
            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
    if (!isVsyncValidForUid) {
        ATRACE_NAME("!isVsyncValidForUid");
        mFlinger->setTransactionFlags(eTraversalNeeded);
        return false;
    }

    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);


    if (refreshRequired) {
    if (refreshRequired) {
@@ -435,12 +460,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
        return false;
        return false;
    }
    }


    if (frameIsEarly(expectedPresentTime)) {
        ATRACE_NAME("frameIsEarly()");
        mFlinger->signalLayerUpdate();
        return false;
    }

    // If the head buffer's acquire fence hasn't signaled yet, return and
    // If the head buffer's acquire fence hasn't signaled yet, return and
    // try again later
    // try again later
    if (!fenceHasSignaled()) {
    if (!fenceHasSignaled()) {
+15 −8
Original line number Original line Diff line number Diff line
@@ -175,12 +175,24 @@ protected:
    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;


    // Transform hint provided to the producer. This must be accessed holding
    // Transform hint provided to the producer. This must be accessed holding
    /// the mStateLock.
    // the mStateLock.
    ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
    ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;


    bool getAutoRefresh() const { return mAutoRefresh; }
    bool getAutoRefresh() const { return mAutoRefresh; }
    bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
    bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }


    // Returns true if the next buffer should be presented at the expected present time
    bool shouldPresentNow(nsecs_t expectedPresentTime) const final;

    // Returns true if the next buffer should be presented at the expected present time,
    // overridden by BufferStateLayer and BufferQueueLayer for implementation
    // specific logic
    virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;

    // Returns true if the next frame is considered too early to present
    // at the given expectedPresentTime
    bool frameIsEarly(nsecs_t expectedPresentTime) const;

    std::atomic<bool> mAutoRefresh{false};
    std::atomic<bool> mAutoRefresh{false};
    std::atomic<bool> mSidebandStreamChanged{false};
    std::atomic<bool> mSidebandStreamChanged{false};


@@ -225,13 +237,8 @@ private:


    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;


    // Returns true if the next frame is considered too early to present
    // Returns the predicted present time of the next frame if available
    // at the given expectedPresentTime
    virtual std::optional<nsecs_t> nextPredictedPresentTime() const = 0;
    bool frameIsEarly(nsecs_t expectedPresentTime) const;

    // Returns the predicted present time of the next frame if available or
    // 0 otherwise.
    virtual nsecs_t nextPredictedPresentTime() const = 0;


    // The amount of time SF can delay a frame if it is considered early based
    // The amount of time SF can delay a frame if it is considered early based
    // on the VsyncModulator::VsyncConfig::appWorkDuration
    // on the VsyncModulator::VsyncConfig::appWorkDuration
+4 −12
Original line number Original line Diff line number Diff line
@@ -100,15 +100,7 @@ int32_t BufferQueueLayer::getQueuedFrameCount() const {
    return mQueuedFrames;
    return mQueuedFrames;
}
}


bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const {
    if (getSidebandStreamChanged() || getAutoRefresh()) {
        return true;
    }

    if (!hasFrameUpdate()) {
        return false;
    }

    Mutex::Autolock lock(mQueueItemLock);
    Mutex::Autolock lock(mQueueItemLock);


    const int64_t addedTime = mQueueItems[0].item.mTimestamp;
    const int64_t addedTime = mQueueItems[0].item.mTimestamp;
@@ -223,16 +215,16 @@ bool BufferQueueLayer::hasFrameUpdate() const {
    return mQueuedFrames > 0;
    return mQueuedFrames > 0;
}
}


nsecs_t BufferQueueLayer::nextPredictedPresentTime() const {
std::optional<nsecs_t> BufferQueueLayer::nextPredictedPresentTime() const {
    Mutex::Autolock lock(mQueueItemLock);
    Mutex::Autolock lock(mQueueItemLock);
    if (mQueueItems.empty()) {
    if (mQueueItems.empty()) {
        return 0;
        return std::nullopt;
    }
    }


    const auto& bufferData = mQueueItems[0];
    const auto& bufferData = mQueueItems[0];


    if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
    if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
        return 0;
        return std::nullopt;
    }
    }


    return bufferData.surfaceFrame->getPredictions().presentTime;
    return bufferData.surfaceFrame->getPredictions().presentTime;
+3 −2
Original line number Original line Diff line number Diff line
@@ -53,7 +53,8 @@ public:


    int32_t getQueuedFrameCount() const override;
    int32_t getQueuedFrameCount() const override;


    bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
    // Returns true if the next buffer should be presented at the expected present time
    bool isBufferDue(nsecs_t expectedPresentTime) const override;


    // Implements BufferLayer.
    // Implements BufferLayer.
    bool fenceHasSignaled() const override;
    bool fenceHasSignaled() const override;
@@ -116,7 +117,7 @@ private:
    // Temporary - Used only for LEGACY camera mode.
    // Temporary - Used only for LEGACY camera mode.
    uint32_t getProducerStickyTransform() const;
    uint32_t getProducerStickyTransform() const;


    nsecs_t nextPredictedPresentTime() const override;
    std::optional<nsecs_t> nextPredictedPresentTime() const override;


    sp<BufferLayerConsumer> mConsumer;
    sp<BufferLayerConsumer> mConsumer;
    sp<IGraphicBufferProducer> mProducer;
    sp<IGraphicBufferProducer> mProducer;
+2 −10
Original line number Original line Diff line number Diff line
@@ -212,14 +212,6 @@ void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime
    }
    }
}
}


bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
    if (getSidebandStreamChanged() || getAutoRefresh()) {
        return true;
    }

    return hasFrameUpdate();
}

bool BufferStateLayer::willPresentCurrentTransaction() const {
bool BufferStateLayer::willPresentCurrentTransaction() const {
    // Returns true if the most recent Transaction applied to CurrentState will be presented.
    // Returns true if the most recent Transaction applied to CurrentState will be presented.
    return (getSidebandStreamChanged() || getAutoRefresh() ||
    return (getSidebandStreamChanged() || getAutoRefresh() ||
@@ -602,9 +594,9 @@ bool BufferStateLayer::hasFrameUpdate() const {
    return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
    return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
}


nsecs_t BufferStateLayer::nextPredictedPresentTime() const {
std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
    if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
    if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
        return 0;
        return std::nullopt;
    }
    }


    return mSurfaceFrame->getPredictions().presentTime;
    return mSurfaceFrame->getPredictions().presentTime;
Loading