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

Commit 526c3389 authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

SF: Break dependency between VsyncConfiguration and RefreshRateConfigs

The VsyncConfiguration class doesn't need to know the list of
supported refresh rates, because the offsets can be calculated
and cached on the fly. This is better because the list of refresh
rates can change during runtime (for example for Android TV).

After fixing this the dependency on RefreshRateConfigs is only needed
for getting the current refresh rate at construction time. For
this it's sufficient to pass only the Fps instead of the whole
RefreshRateConfigs object.

Bug: 159590486
Test: presubmit
Change-Id: I1c0ceaf2524b517e85c8067577fc9f5146f1f632
parent a176f5f2
Loading
Loading
Loading
Loading
+36 −56
Original line number Diff line number Diff line
@@ -16,14 +16,19 @@

#include "VsyncConfiguration.h"

#include <cutils/properties.h>

#include <chrono>
#include <cinttypes>
#include <optional>

#include <cutils/properties.h>
#include <log/log.h>

#include "SurfaceFlingerProperties.h"

namespace {

using namespace std::chrono_literals;

std::optional<nsecs_t> getProperty(const char* name) {
    char value[PROPERTY_VALUE_MAX];
    property_get(name, value, "-1");
@@ -31,19 +36,6 @@ std::optional<nsecs_t> getProperty(const char* name) {
    return std::nullopt;
}

std::vector<android::Fps> getRefreshRatesFromConfigs(
        const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
    const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
    std::vector<android::Fps> refreshRates;
    refreshRates.reserve(allRefreshRates.size());

    for (const auto& [ignored, refreshRate] : allRefreshRates) {
        refreshRates.emplace_back(refreshRate->getFps());
    }

    return refreshRates;
}

} // namespace

namespace android::scheduler::impl {
@@ -51,25 +43,19 @@ namespace android::scheduler::impl {
VsyncConfiguration::VsyncConfiguration(Fps currentFps) : mRefreshRateFps(currentFps) {}

PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fps) const {
    const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
                                   [&fps](const std::pair<Fps, VsyncConfigSet>& candidateFps) {
                                       return fps.equalsWithMargin(candidateFps.first);
                                   });

    if (iter != mOffsets.end()) {
        return iter->second;
    std::lock_guard lock(mLock);
    return getConfigsForRefreshRateLocked(fps);
}

    // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
    // In this case just construct the offset.
    ALOGW("Can't find offset for %s", to_string(fps).c_str());
    return constructOffsets(fps.getPeriodNsecs());
PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const {
    const auto iter = mOffsetsCache.find(fps);
    if (iter != mOffsetsCache.end()) {
        return iter->second;
    }

void VsyncConfiguration::initializeOffsets(const std::vector<Fps>& refreshRates) {
    for (const auto fps : refreshRates) {
        mOffsets.emplace(fps, constructOffsets(fps.getPeriodNsecs()));
    }
    const auto offset = constructOffsets(fps.getPeriodNsecs());
    mOffsetsCache[fps] = offset;
    return offset;
}

void VsyncConfiguration::dump(std::string& result) const {
@@ -98,10 +84,8 @@ void VsyncConfiguration::dump(std::string& result) const {
                  earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
}

PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
      : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
                     refreshRateConfigs.getCurrentRefreshRate().getFps(),
                     sysprop::vsync_event_phase_offset_ns(1000000),
PhaseOffsets::PhaseOffsets(Fps currentRefreshRate)
      : PhaseOffsets(currentRefreshRate, sysprop::vsync_event_phase_offset_ns(1000000),
                     sysprop::vsync_sf_event_phase_offset_ns(1000000),
                     getProperty("debug.sf.early_phase_offset_ns"),
                     getProperty("debug.sf.early_gl_phase_offset_ns"),
@@ -121,15 +105,17 @@ PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfi
                     getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
                             .value_or(std::numeric_limits<nsecs_t>::max())) {}

PhaseOffsets::PhaseOffsets(
        const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t vsyncPhaseOffsetNs,
        nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
        std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
        std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
        nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
PhaseOffsets::PhaseOffsets(Fps currentFps, nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
                           std::optional<nsecs_t> earlySfOffsetNs,
                           std::optional<nsecs_t> earlyGpuSfOffsetNs,
                           std::optional<nsecs_t> earlyAppOffsetNs,
                           std::optional<nsecs_t> earlyGpuAppOffsetNs,
                           nsecs_t highFpsVsyncPhaseOffsetNs, nsecs_t highFpsSfVSyncPhaseOffsetNs,
                           std::optional<nsecs_t> highFpsEarlySfOffsetNs,
                           std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
                           std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
        std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync)
                           std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
                           nsecs_t thresholdForNextVsync)
      : VsyncConfiguration(currentFps),
        mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
        mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
@@ -143,9 +129,7 @@ PhaseOffsets::PhaseOffsets(
        mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
        mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
        mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
        mThresholdForNextVsync(thresholdForNextVsync) {
    initializeOffsets(refreshRates);
}
        mThresholdForNextVsync(thresholdForNextVsync) {}

PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
    if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
@@ -361,10 +345,8 @@ WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuratio
    };
}

WorkDuration::WorkDuration(const scheduler::RefreshRateConfigs& refreshRateConfigs)
      : WorkDuration(getRefreshRatesFromConfigs(refreshRateConfigs),
                     refreshRateConfigs.getCurrentRefreshRate().getFps(),
                     getProperty("debug.sf.late.sf.duration").value_or(-1),
WorkDuration::WorkDuration(Fps currentRefreshRate)
      : WorkDuration(currentRefreshRate, getProperty("debug.sf.late.sf.duration").value_or(-1),
                     getProperty("debug.sf.late.app.duration").value_or(-1),
                     getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
                     getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
@@ -373,17 +355,15 @@ WorkDuration::WorkDuration(const scheduler::RefreshRateConfigs& refreshRateConfi
    validateSysprops();
}

WorkDuration::WorkDuration(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t sfDuration,
                           nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration,
                           nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
                           nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration)
      : VsyncConfiguration(currentFps),
      : VsyncConfiguration(currentRefreshRate),
        mSfDuration(sfDuration),
        mAppDuration(appDuration),
        mSfEarlyDuration(sfEarlyDuration),
        mAppEarlyDuration(appEarlyDuration),
        mSfEarlyGpuDuration(sfEarlyGpuDuration),
        mAppEarlyGpuDuration(appEarlyGpuDuration) {
    initializeOffsets(refreshRates);
}
        mAppEarlyGpuDuration(appEarlyGpuDuration) {}

} // namespace android::scheduler::impl
+31 −17
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

#pragma once

#include <mutex>
#include <type_traits>
#include <unordered_map>
#include <vector>

#include <utils/Timers.h>

#include "Fps.h"
#include "RefreshRateConfigs.h"
#include "VsyncModulator.h"

namespace android::scheduler {
@@ -39,9 +41,9 @@ public:
    virtual ~VsyncConfiguration() = default;
    virtual VsyncConfigSet getCurrentConfigs() const = 0;
    virtual VsyncConfigSet getConfigsForRefreshRate(Fps fps) const = 0;
    virtual void reset() = 0;

    virtual void setRefreshRateFps(Fps fps) = 0;

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

@@ -57,26 +59,39 @@ public:
    explicit VsyncConfiguration(Fps currentFps);

    // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
    VsyncConfigSet getConfigsForRefreshRate(Fps fps) const override;
    VsyncConfigSet getConfigsForRefreshRate(Fps fps) const override EXCLUDES(mLock);

    // Returns early, early GL, and late offsets for Apps and SF.
    VsyncConfigSet getCurrentConfigs() const override {
        return getConfigsForRefreshRate(mRefreshRateFps);
    VsyncConfigSet getCurrentConfigs() const override EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
        return getConfigsForRefreshRateLocked(mRefreshRateFps);
    }

    // Cleans the internal cache.
    void reset() override EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
        mOffsetsCache.clear();
    }

    // This function should be called when the device is switching between different
    // refresh rates, to properly update the offsets.
    void setRefreshRateFps(Fps fps) override { mRefreshRateFps = fps; }
    void setRefreshRateFps(Fps fps) override EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
        mRefreshRateFps = fps;
    }

    // Returns current offsets in human friendly format.
    void dump(std::string& result) const override;

protected:
    void initializeOffsets(const std::vector<Fps>& refreshRates);
    virtual VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const = 0;

    std::unordered_map<Fps, VsyncConfigSet, std::hash<Fps>, Fps::EqualsInBuckets> mOffsets;
    std::atomic<Fps> mRefreshRateFps;
    VsyncConfigSet getConfigsForRefreshRateLocked(Fps fps) const REQUIRES(mLock);

    mutable std::unordered_map<Fps, VsyncConfigSet, std::hash<Fps>, Fps::EqualsInBuckets>
            mOffsetsCache GUARDED_BY(mLock);
    std::atomic<Fps> mRefreshRateFps GUARDED_BY(mLock);
    mutable std::mutex mLock;
};

/*
@@ -85,13 +100,13 @@ protected:
 */
class PhaseOffsets : public VsyncConfiguration {
public:
    explicit PhaseOffsets(const scheduler::RefreshRateConfigs&);
    explicit PhaseOffsets(Fps currentRefreshRate);

protected:
    // Used for unit tests
    PhaseOffsets(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t vsyncPhaseOffsetNs,
                 nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
                 std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
    PhaseOffsets(Fps currentRefreshRate, nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
                 std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGpuSfOffsetNs,
                 std::optional<nsecs_t> earlyAppOffsetNs,
                 std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
                 nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
                 std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
@@ -128,13 +143,12 @@ private:
 */
class WorkDuration : public VsyncConfiguration {
public:
    explicit WorkDuration(const scheduler::RefreshRateConfigs&);
    explicit WorkDuration(Fps currentRefrshRate);

protected:
    // Used for unit tests
    WorkDuration(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t sfDuration,
                 nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
                 nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration);
    WorkDuration(Fps currentFps, nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
                 nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration);

private:
    VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const override;
+9 −3
Original line number Diff line number Diff line
@@ -2620,10 +2620,16 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
            setPowerModeInternal(display, hal::PowerMode::ON);

            // TODO(b/175678251) Call a listener instead.
            if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
                const auto displayId = currentState.physical->id;
                const auto configs = getHwComposer().getConfigs(displayId);
                mVsyncConfiguration->reset();
                updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate());
                if (mRefreshRateOverlay) {
                    mRefreshRateOverlay->reset();
                }
            }
        }
        return;
    }

@@ -2908,7 +2914,7 @@ void SurfaceFlinger::initScheduler(PhysicalDisplayId primaryDisplayId) {
            std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate.getFps(),
                                                          hal::PowerMode::OFF);

    mVsyncConfiguration = getFactory().createVsyncConfiguration(*mRefreshRateConfigs);
    mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate.getFps());
    mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());

    // start the EventThread
+3 −3
Original line number Diff line number Diff line
@@ -56,11 +56,11 @@ std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
}

std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfiguration(
        const scheduler::RefreshRateConfigs& refreshRateConfigs) {
        Fps currentRefreshRate) {
    if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) {
        return std::make_unique<scheduler::impl::WorkDuration>(refreshRateConfigs);
        return std::make_unique<scheduler::impl::WorkDuration>(currentRefreshRate);
    } else {
        return std::make_unique<scheduler::impl::PhaseOffsets>(refreshRateConfigs);
        return std::make_unique<scheduler::impl::PhaseOffsets>(currentRefreshRate);
    }
}

+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ public:
    std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
    std::unique_ptr<MessageQueue> createMessageQueue() override;
    std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
            const scheduler::RefreshRateConfigs&) override;
            Fps currentRefreshRate) override;
    std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
                                               ISchedulerCallback&) override;
    sp<SurfaceInterceptor> createSurfaceInterceptor() override;
Loading