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

Commit c183eed0 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Encapsulate frame targeting

Introduce FrameTargeter to isolate a display's per-frame metrics around
past/upcoming deadline targets. The Scheduler updates the FrameTargeter
on frame begin/end, whereas ICompositor (concretely SurfaceFlinger) has
read-only access via the FrameTarget interface.

For now, only instantiate the pacesetter's FrameTargeter.

The only functional change is that `earliestPresentTime` now takes into
account the case of targeting two VSYNCs ahead.

Bug: 241285475
Bug: 241285191
Test: Perfetto
Test: dumpsys SurfaceFlinger --scheduler
Test: atest libscheduler_test:FrameTargeterTest
Change-Id: Idf9f43b37f3479c94a478d154eaa46f43e0c6c9d
parent 16a345b0
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -142,6 +142,8 @@ private:
    std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID};
};

using FenceTimePtr = std::shared_ptr<FenceTime>;

// A queue of FenceTimes that are expected to signal in FIFO order.
// Only maintains a queue of weak pointers so it doesn't keep references
// to Fences on its own.
@@ -190,8 +192,15 @@ private:
// before the new one is added.
class FenceToFenceTimeMap {
public:
    // Create a new FenceTime with that wraps the provided Fence.
    std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);
    using FencePair = std::pair<sp<Fence>, FenceTimePtr>;

    FencePair makePendingFenceForTest() {
        const auto fence = sp<Fence>::make();
        return {fence, createFenceTimeForTest(fence)};
    }

    // Create a new FenceTime that wraps the provided Fence.
    FenceTimePtr createFenceTimeForTest(const sp<Fence>&);

    // Signals all FenceTimes created through this class that are wrappers
    // around |fence|.
@@ -205,7 +214,6 @@ private:
    std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
};


}; // namespace android
} // namespace android

#endif // ANDROID_FENCE_TIME_H
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library_static {
    name: "libscheduler",
    defaults: ["libscheduler_defaults"],
    srcs: [
        "src/FrameTargeter.cpp",
        "src/PresentLatencyTracker.cpp",
        "src/Timer.cpp",
    ],
@@ -52,6 +53,7 @@ cc_test {
    test_suites: ["device-tests"],
    defaults: ["libscheduler_defaults"],
    srcs: [
        "tests/FrameTargeterTest.cpp",
        "tests/PresentLatencyTrackerTest.cpp",
        "tests/TimerTest.cpp",
    ],
+19 −10
Original line number Diff line number Diff line
@@ -159,14 +159,21 @@ void Scheduler::run() {

void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
                              TimePoint expectedVsyncTime) {
    const TimePoint frameTime = SchedulerClock::now();

    if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
    mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(),
                                         .vsyncId = vsyncId,
                                         .expectedVsyncTime = expectedVsyncTime,
                                         .sfWorkDuration =
                                                 mVsyncModulator->getVsyncConfig().sfWorkDuration},
                                        *getVsyncSchedule());

    if (!compositor.commit(mPacesetterFrameTargeter.target())) {
        return;
    }

    compositor.composite(frameTime, vsyncId);
    const auto compositeResult = compositor.composite(mPacesetterFrameTargeter);
    compositor.sample();

    mPacesetterFrameTargeter.endFrame(compositeResult);
}

std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
@@ -176,23 +183,23 @@ std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
            .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
}

bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const {
bool Scheduler::isVsyncValid(TimePoint expectedVsyncTime, uid_t uid) const {
    const auto frameRate = getFrameRateOverride(uid);
    if (!frameRate.has_value()) {
        return true;
    }

    ATRACE_FORMAT("%s uid: %d frameRate: %s", __func__, uid, to_string(*frameRate).c_str());
    return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate);
    return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), *frameRate);
}

bool Scheduler::isVsyncInPhase(TimePoint timePoint, const Fps frameRate) const {
    return getVsyncSchedule()->getTracker().isVSyncInPhase(timePoint.ns(), frameRate);
bool Scheduler::isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const {
    return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), frameRate);
}

impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
    return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
        return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
    return [this](nsecs_t expectedVsyncTime, uid_t uid) {
        return !isVsyncValid(TimePoint::fromNs(expectedVsyncTime), uid);
    };
}

@@ -681,6 +688,8 @@ void Scheduler::dump(utils::Dumper& dumper) const {

    mFrameRateOverrideMappings.dump(dumper);
    dumper.eol();

    mPacesetterFrameTargeter.dump(dumper);
}

void Scheduler::dumpVsync(std::string& out) const {
+6 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <ftl/fake_guard.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
#include <scheduler/FrameTargeter.h>
#include <scheduler/Time.h>
#include <scheduler/VsyncConfig.h>
#include <ui/DisplayId.h>
@@ -249,9 +250,11 @@ public:
        return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
    }

    const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); }

    // Returns true if a given vsync timestamp is considered valid vsync
    // for a given uid
    bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
    bool isVsyncValid(TimePoint expectedVsyncTime, uid_t uid) const;

    bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const;

@@ -441,6 +444,8 @@ private:
    ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock)
            GUARDED_BY(kMainThreadContext);

    FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)};

    ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) {
        return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform(
                [](const Display& display) { return std::ref(const_cast<Display&>(display)); });
+9 −5
Original line number Diff line number Diff line
@@ -19,13 +19,16 @@
#include <memory>
#include <string>

#include <ThreadContext.h>
#include <android-base/thread_annotations.h>
#include <ftl/enum.h>
#include <ftl/optional.h>
#include <ui/DisplayId.h>

#include <scheduler/Features.h>
#include <scheduler/IVsyncSource.h>
#include <scheduler/Time.h>
#include <ui/DisplayId.h>

#include "ThreadContext.h"

namespace android {
class EventThreadTest;
@@ -49,13 +52,14 @@ using VsyncDispatch = VSyncDispatch;
using VsyncTracker = VSyncTracker;

// Schedule that synchronizes to hardware VSYNC of a physical display.
class VsyncSchedule {
class VsyncSchedule final : public IVsyncSource {
public:
    VsyncSchedule(PhysicalDisplayId, FeatureFlags);
    ~VsyncSchedule();

    Period period() const;
    TimePoint vsyncDeadlineAfter(TimePoint) const;
    // IVsyncSource overrides:
    Period period() const override;
    TimePoint vsyncDeadlineAfter(TimePoint) const override;

    // Inform the schedule that the period is changing and the schedule needs to recalibrate
    // itself. The schedule will end the period transition internally. This will
Loading