Loading services/surfaceflinger/Scheduler/PhaseOffsets.cpp +65 −78 Original line number Diff line number Diff line Loading @@ -18,115 +18,102 @@ #include <cutils/properties.h> #include "SurfaceFlingerProperties.h" namespace android { using namespace android::sysprop; namespace scheduler { using RefreshRateType = RefreshRateConfigs::RefreshRateType; PhaseOffsets::~PhaseOffsets() = default; #include <optional> namespace impl { PhaseOffsets::PhaseOffsets() { int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000); #include "SurfaceFlingerProperties.h" int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000); namespace { std::optional<int> getProperty(const char* name) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.early_phase_offset_ns", value, "-1"); const int earlySfOffsetNs = atoi(value); property_get("debug.sf.early_gl_phase_offset_ns", value, "-1"); const int earlyGlSfOffsetNs = atoi(value); property_get("debug.sf.early_app_phase_offset_ns", value, "-1"); const int earlyAppOffsetNs = atoi(value); property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1"); const int earlyGlAppOffsetNs = atoi(value); property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1"); const int highFpsEarlySfOffsetNs = atoi(value); property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1"); const int highFpsEarlyGlSfOffsetNs = atoi(value); property_get(name, value, "-1"); if (const int i = atoi(value); i != -1) return i; return std::nullopt; } property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1"); const int highFpsEarlyAppOffsetNs = atoi(value); } // namespace property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1"); const int highFpsEarlyGlAppOffsetNs = atoi(value); namespace android::scheduler { // TODO(b/122905996): Define these in device.mk. property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000"); const int highFpsLateAppOffsetNs = atoi(value); PhaseOffsets::~PhaseOffsets() = default; property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); const int highFpsLateSfOffsetNs = atoi(value); namespace impl { PhaseOffsets::PhaseOffsets() { // Below defines the threshold when an offset is considered to be negative, i.e. targeting // for the N+2 vsync instead of N+1. This means that: // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); const int phaseOffsetThresholdForNextVsyncNs = atoi(value); Offsets defaultOffsets; Offsets highFpsOffsets; defaultOffsets.early = {RefreshRateType::DEFAULT, earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; highFpsOffsets.early = {RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs : highFpsLateSfOffsetNs, highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs : highFpsLateAppOffsetNs}; highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs : highFpsLateSfOffsetNs, highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs : highFpsLateAppOffsetNs}; highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; const nsecs_t thresholdForNextVsync = getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") .value_or(std::numeric_limits<nsecs_t>::max()); const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs : std::numeric_limits<nsecs_t>::max(); } PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { RefreshRateType refreshRateType) const { return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { const auto [early, earlyGl, late] = getCurrentOffsets(); const auto [early, earlyGl, late, threshold] = getCurrentOffsets(); base::StringAppendF(&result, " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n", late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf); "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" "threshold for next VSYNC: %" PRId64 " ns\n", late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); } nsecs_t PhaseOffsets::getCurrentAppOffset() { return getCurrentOffsets().late.app; PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) { const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000); const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000); const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns"); const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns"); const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, thresholdForNextVsync}; } nsecs_t PhaseOffsets::getCurrentSfOffset() { return getCurrentOffsets().late.sf; PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) { // TODO(b/122905996): Define these in device.mk. const int highFpsLateAppOffsetNs = getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000); const int highFpsLateSfOffsetNs = getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000); const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns"); const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns"); const auto highFpsEarlyGlAppOffsetNs = getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, thresholdForNextVsync}; } } // namespace impl } // namespace scheduler } // namespace android } // namespace android::scheduler services/surfaceflinger/Scheduler/PhaseOffsets.h +23 −29 Original line number Diff line number Diff line Loading @@ -16,14 +16,12 @@ #pragma once #include <cinttypes> #include <unordered_map> #include "RefreshRateConfigs.h" #include "VSyncModulator.h" namespace android { namespace scheduler { namespace android::scheduler { /* * This class encapsulates offsets for different refresh rates. Depending Loading @@ -33,35 +31,33 @@ namespace scheduler { */ class PhaseOffsets { public: struct Offsets { VSyncModulator::Offsets early; VSyncModulator::Offsets earlyGl; VSyncModulator::Offsets late; }; using Offsets = VSyncModulator::OffsetsConfig; using RefreshRateType = RefreshRateConfigs::RefreshRateType; virtual ~PhaseOffsets(); virtual nsecs_t getCurrentAppOffset() = 0; virtual nsecs_t getCurrentSfOffset() = 0; virtual Offsets getOffsetsForRefreshRate( RefreshRateConfigs::RefreshRateType refreshRateType) const = 0; nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; } nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; } nsecs_t getOffsetThresholdForNextVsync() const { return getCurrentOffsets().thresholdForNextVsync; } virtual Offsets getCurrentOffsets() const = 0; virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0; virtual nsecs_t getOffsetThresholdForNextVsync() const = 0; virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0; virtual void setRefreshRateType(RefreshRateType) = 0; virtual void dump(std::string& result) const = 0; }; namespace impl { class PhaseOffsets : public scheduler::PhaseOffsets { public: PhaseOffsets(); nsecs_t getCurrentAppOffset() override; nsecs_t getCurrentSfOffset() override; // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. Offsets getOffsetsForRefreshRate( RefreshRateConfigs::RefreshRateType refreshRateType) const override; Offsets getOffsetsForRefreshRate(RefreshRateType) const override; // Returns early, early GL, and late offsets for Apps and SF. Offsets getCurrentOffsets() const override { Loading @@ -70,23 +66,21 @@ public: // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override { void setRefreshRateType(RefreshRateType refreshRateType) override { mRefreshRateType = refreshRateType; } nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; private: std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT; std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets; nsecs_t mOffsetThresholdForNextVsync; std::unordered_map<RefreshRateType, Offsets> mOffsets; }; } // namespace impl } // namespace scheduler } // namespace android } // namespace impl } // namespace android::scheduler services/surfaceflinger/Scheduler/VSyncModulator.cpp +35 −48 Original line number Diff line number Diff line Loading @@ -24,25 +24,24 @@ #include <cinttypes> #include <mutex> namespace android { using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; VSyncModulator::VSyncModulator() { namespace android::scheduler { VSyncModulator::VSyncModulator(Scheduler& scheduler, const sp<Scheduler::ConnectionHandle>& appConnectionHandle, const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig& config) : mScheduler(scheduler), mAppConnectionHandle(appConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mOffsetsConfig(config) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.vsync_trace_detailed_info", value, "0"); mTraceDetailedInfo = atoi(value); // Populate the offset map with some default offsets. const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); } void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) { void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { std::lock_guard<std::mutex> lock(mMutex); mOffsetMap.insert_or_assign(OffsetType::Early, early); mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); mOffsetMap.insert_or_assign(OffsetType::Late, late); mThresholdForNextVsync = thresholdForNextVsync; mOffsetsConfig = config; updateOffsetsLocked(); } Loading Loading @@ -100,25 +99,21 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) { } } VSyncModulator::Offsets VSyncModulator::getOffsets() { VSyncModulator::Offsets VSyncModulator::getOffsets() const { std::lock_guard<std::mutex> lock(mMutex); return mOffsets; } VSyncModulator::Offsets VSyncModulator::getNextOffsets() { return mOffsetMap.at(getNextOffsetType()); } VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return OffsetType::Early; return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { return OffsetType::EarlyGl; return mOffsetsConfig.earlyGl; } else { return OffsetType::Late; return mOffsetsConfig.late; } } Loading @@ -128,37 +123,29 @@ void VSyncModulator::updateOffsets() { } void VSyncModulator::updateOffsetsLocked() { const Offsets desired = getNextOffsets(); const Offsets& offsets = getNextOffsets(); if (mSfConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); } mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); if (mAppConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); } mOffsets = offsets; flushOffsets(); } void VSyncModulator::flushOffsets() { OffsetType type = getNextOffsetType(); mOffsets = mOffsetMap.at(type); if (!mTraceDetailedInfo) { return; } ATRACE_INT("Vsync-EarlyOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); ATRACE_INT("Vsync-EarlyGLOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-LateOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-HighFpsLateOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); } } // namespace android const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT; const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE; const bool isEarly = &offsets == &mOffsetsConfig.early; const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl; const bool isLate = &offsets == &mOffsetsConfig.late; ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly); ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl); ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate); ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly); ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl); ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate); } } // namespace android::scheduler services/surfaceflinger/Scheduler/VSyncModulator.h +26 −47 Original line number Diff line number Diff line Loading @@ -16,12 +16,11 @@ #pragma once #include <cinttypes> #include <mutex> #include "Scheduler.h" namespace android { namespace android::scheduler { /* * Modulates the vsync-offsets depending on current SurfaceFlinger state. Loading @@ -31,51 +30,36 @@ private: // Number of frames we'll keep the early phase offsets once they are activated for a // transaction. This acts as a low-pass filter in case the client isn't quick enough in // sending new transactions. const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; // Number of frames we'll keep the early gl phase offsets once they are activated. // This acts as a low-pass filter to avoid scenarios where we rapidly // switch in and out of gl composition. const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: VSyncModulator(); using RefreshRateType = RefreshRateConfigs::RefreshRateType; public: // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration. struct Offsets { scheduler::RefreshRateConfigs::RefreshRateType fpsMode; RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; enum class OffsetType { Early, EarlyGl, Late, struct OffsetsConfig { Offsets early; // For transactions with the eEarlyWakeup flag. Offsets earlyGl; // As above but while compositing with GL. Offsets late; // Default. nsecs_t thresholdForNextVsync; }; // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction // as early. May be the same as late, in which case we don't shift offsets. // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition // and the transaction was marked as early, we'll use sfEarly. // sfLate: The regular SF vsync phase offset. // appEarly: Like sfEarly, but for the app-vsync // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, Scheduler::ConnectionHandle* sfConnectionHandle) { mScheduler = scheduler; mAppConnectionHandle = appConnectionHandle; mSfConnectionHandle = sfConnectionHandle; } VSyncModulator(Scheduler&, const sp<Scheduler::ConnectionHandle>& appConnectionHandle, const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig&); void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex); // Signals that a transaction has started, and changes offsets accordingly. void setTransactionStart(Scheduler::TransactionStart transactionStart); Loading @@ -98,28 +82,23 @@ public: void onRefreshed(bool usedRenderEngine); // Returns the offsets that we are currently using Offsets getOffsets() EXCLUDES(mMutex); Offsets getOffsets() const EXCLUDES(mMutex); private: // Returns the next offsets that we should be using Offsets getNextOffsets() REQUIRES(mMutex); // Returns the next offset type that we should use. OffsetType getNextOffsetType(); const Offsets& getNextOffsets() const REQUIRES(mMutex); // Updates offsets and persists them into the scheduler framework. void updateOffsets() EXCLUDES(mMutex); void updateOffsetsLocked() REQUIRES(mMutex); // Updates the internal offsets and offset type. void flushOffsets() REQUIRES(mMutex); mutable std::mutex mMutex; std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex); nsecs_t mThresholdForNextVsync; Scheduler& mScheduler; const sp<Scheduler::ConnectionHandle> mAppConnectionHandle; const sp<Scheduler::ConnectionHandle> mSfConnectionHandle; Scheduler* mScheduler = nullptr; Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; mutable std::mutex mMutex; OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex); Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late}; std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; Loading @@ -130,4 +109,4 @@ private: bool mTraceDetailedInfo = false; }; } // namespace android } // namespace android::scheduler services/surfaceflinger/SurfaceFlinger.cpp +18 −27 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/Scheduler/PhaseOffsets.cpp +65 −78 Original line number Diff line number Diff line Loading @@ -18,115 +18,102 @@ #include <cutils/properties.h> #include "SurfaceFlingerProperties.h" namespace android { using namespace android::sysprop; namespace scheduler { using RefreshRateType = RefreshRateConfigs::RefreshRateType; PhaseOffsets::~PhaseOffsets() = default; #include <optional> namespace impl { PhaseOffsets::PhaseOffsets() { int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000); #include "SurfaceFlingerProperties.h" int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000); namespace { std::optional<int> getProperty(const char* name) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.early_phase_offset_ns", value, "-1"); const int earlySfOffsetNs = atoi(value); property_get("debug.sf.early_gl_phase_offset_ns", value, "-1"); const int earlyGlSfOffsetNs = atoi(value); property_get("debug.sf.early_app_phase_offset_ns", value, "-1"); const int earlyAppOffsetNs = atoi(value); property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1"); const int earlyGlAppOffsetNs = atoi(value); property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1"); const int highFpsEarlySfOffsetNs = atoi(value); property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1"); const int highFpsEarlyGlSfOffsetNs = atoi(value); property_get(name, value, "-1"); if (const int i = atoi(value); i != -1) return i; return std::nullopt; } property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1"); const int highFpsEarlyAppOffsetNs = atoi(value); } // namespace property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1"); const int highFpsEarlyGlAppOffsetNs = atoi(value); namespace android::scheduler { // TODO(b/122905996): Define these in device.mk. property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000"); const int highFpsLateAppOffsetNs = atoi(value); PhaseOffsets::~PhaseOffsets() = default; property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); const int highFpsLateSfOffsetNs = atoi(value); namespace impl { PhaseOffsets::PhaseOffsets() { // Below defines the threshold when an offset is considered to be negative, i.e. targeting // for the N+2 vsync instead of N+1. This means that: // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); const int phaseOffsetThresholdForNextVsyncNs = atoi(value); Offsets defaultOffsets; Offsets highFpsOffsets; defaultOffsets.early = {RefreshRateType::DEFAULT, earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; highFpsOffsets.early = {RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs : highFpsLateSfOffsetNs, highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs : highFpsLateAppOffsetNs}; highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs : highFpsLateSfOffsetNs, highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs : highFpsLateAppOffsetNs}; highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; const nsecs_t thresholdForNextVsync = getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") .value_or(std::numeric_limits<nsecs_t>::max()); const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs : std::numeric_limits<nsecs_t>::max(); } PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { RefreshRateType refreshRateType) const { return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { const auto [early, earlyGl, late] = getCurrentOffsets(); const auto [early, earlyGl, late, threshold] = getCurrentOffsets(); base::StringAppendF(&result, " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n", late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf); "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" "threshold for next VSYNC: %" PRId64 " ns\n", late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); } nsecs_t PhaseOffsets::getCurrentAppOffset() { return getCurrentOffsets().late.app; PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) { const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000); const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000); const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns"); const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns"); const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, thresholdForNextVsync}; } nsecs_t PhaseOffsets::getCurrentSfOffset() { return getCurrentOffsets().late.sf; PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) { // TODO(b/122905996): Define these in device.mk. const int highFpsLateAppOffsetNs = getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000); const int highFpsLateSfOffsetNs = getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000); const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns"); const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns"); const auto highFpsEarlyGlAppOffsetNs = getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, thresholdForNextVsync}; } } // namespace impl } // namespace scheduler } // namespace android } // namespace android::scheduler
services/surfaceflinger/Scheduler/PhaseOffsets.h +23 −29 Original line number Diff line number Diff line Loading @@ -16,14 +16,12 @@ #pragma once #include <cinttypes> #include <unordered_map> #include "RefreshRateConfigs.h" #include "VSyncModulator.h" namespace android { namespace scheduler { namespace android::scheduler { /* * This class encapsulates offsets for different refresh rates. Depending Loading @@ -33,35 +31,33 @@ namespace scheduler { */ class PhaseOffsets { public: struct Offsets { VSyncModulator::Offsets early; VSyncModulator::Offsets earlyGl; VSyncModulator::Offsets late; }; using Offsets = VSyncModulator::OffsetsConfig; using RefreshRateType = RefreshRateConfigs::RefreshRateType; virtual ~PhaseOffsets(); virtual nsecs_t getCurrentAppOffset() = 0; virtual nsecs_t getCurrentSfOffset() = 0; virtual Offsets getOffsetsForRefreshRate( RefreshRateConfigs::RefreshRateType refreshRateType) const = 0; nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; } nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; } nsecs_t getOffsetThresholdForNextVsync() const { return getCurrentOffsets().thresholdForNextVsync; } virtual Offsets getCurrentOffsets() const = 0; virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0; virtual nsecs_t getOffsetThresholdForNextVsync() const = 0; virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0; virtual void setRefreshRateType(RefreshRateType) = 0; virtual void dump(std::string& result) const = 0; }; namespace impl { class PhaseOffsets : public scheduler::PhaseOffsets { public: PhaseOffsets(); nsecs_t getCurrentAppOffset() override; nsecs_t getCurrentSfOffset() override; // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. Offsets getOffsetsForRefreshRate( RefreshRateConfigs::RefreshRateType refreshRateType) const override; Offsets getOffsetsForRefreshRate(RefreshRateType) const override; // Returns early, early GL, and late offsets for Apps and SF. Offsets getCurrentOffsets() const override { Loading @@ -70,23 +66,21 @@ public: // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override { void setRefreshRateType(RefreshRateType refreshRateType) override { mRefreshRateType = refreshRateType; } nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; private: std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT; std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets; nsecs_t mOffsetThresholdForNextVsync; std::unordered_map<RefreshRateType, Offsets> mOffsets; }; } // namespace impl } // namespace scheduler } // namespace android } // namespace impl } // namespace android::scheduler
services/surfaceflinger/Scheduler/VSyncModulator.cpp +35 −48 Original line number Diff line number Diff line Loading @@ -24,25 +24,24 @@ #include <cinttypes> #include <mutex> namespace android { using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; VSyncModulator::VSyncModulator() { namespace android::scheduler { VSyncModulator::VSyncModulator(Scheduler& scheduler, const sp<Scheduler::ConnectionHandle>& appConnectionHandle, const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig& config) : mScheduler(scheduler), mAppConnectionHandle(appConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mOffsetsConfig(config) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.vsync_trace_detailed_info", value, "0"); mTraceDetailedInfo = atoi(value); // Populate the offset map with some default offsets. const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); } void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) { void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { std::lock_guard<std::mutex> lock(mMutex); mOffsetMap.insert_or_assign(OffsetType::Early, early); mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); mOffsetMap.insert_or_assign(OffsetType::Late, late); mThresholdForNextVsync = thresholdForNextVsync; mOffsetsConfig = config; updateOffsetsLocked(); } Loading Loading @@ -100,25 +99,21 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) { } } VSyncModulator::Offsets VSyncModulator::getOffsets() { VSyncModulator::Offsets VSyncModulator::getOffsets() const { std::lock_guard<std::mutex> lock(mMutex); return mOffsets; } VSyncModulator::Offsets VSyncModulator::getNextOffsets() { return mOffsetMap.at(getNextOffsetType()); } VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return OffsetType::Early; return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { return OffsetType::EarlyGl; return mOffsetsConfig.earlyGl; } else { return OffsetType::Late; return mOffsetsConfig.late; } } Loading @@ -128,37 +123,29 @@ void VSyncModulator::updateOffsets() { } void VSyncModulator::updateOffsetsLocked() { const Offsets desired = getNextOffsets(); const Offsets& offsets = getNextOffsets(); if (mSfConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); } mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); if (mAppConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); } mOffsets = offsets; flushOffsets(); } void VSyncModulator::flushOffsets() { OffsetType type = getNextOffsetType(); mOffsets = mOffsetMap.at(type); if (!mTraceDetailedInfo) { return; } ATRACE_INT("Vsync-EarlyOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); ATRACE_INT("Vsync-EarlyGLOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-LateOffsetsOn", mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-HighFpsLateOffsetsOn", mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); } } // namespace android const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT; const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE; const bool isEarly = &offsets == &mOffsetsConfig.early; const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl; const bool isLate = &offsets == &mOffsetsConfig.late; ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly); ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl); ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate); ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly); ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl); ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate); } } // namespace android::scheduler
services/surfaceflinger/Scheduler/VSyncModulator.h +26 −47 Original line number Diff line number Diff line Loading @@ -16,12 +16,11 @@ #pragma once #include <cinttypes> #include <mutex> #include "Scheduler.h" namespace android { namespace android::scheduler { /* * Modulates the vsync-offsets depending on current SurfaceFlinger state. Loading @@ -31,51 +30,36 @@ private: // Number of frames we'll keep the early phase offsets once they are activated for a // transaction. This acts as a low-pass filter in case the client isn't quick enough in // sending new transactions. const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; // Number of frames we'll keep the early gl phase offsets once they are activated. // This acts as a low-pass filter to avoid scenarios where we rapidly // switch in and out of gl composition. const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: VSyncModulator(); using RefreshRateType = RefreshRateConfigs::RefreshRateType; public: // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration. struct Offsets { scheduler::RefreshRateConfigs::RefreshRateType fpsMode; RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; enum class OffsetType { Early, EarlyGl, Late, struct OffsetsConfig { Offsets early; // For transactions with the eEarlyWakeup flag. Offsets earlyGl; // As above but while compositing with GL. Offsets late; // Default. nsecs_t thresholdForNextVsync; }; // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction // as early. May be the same as late, in which case we don't shift offsets. // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition // and the transaction was marked as early, we'll use sfEarly. // sfLate: The regular SF vsync phase offset. // appEarly: Like sfEarly, but for the app-vsync // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, Scheduler::ConnectionHandle* sfConnectionHandle) { mScheduler = scheduler; mAppConnectionHandle = appConnectionHandle; mSfConnectionHandle = sfConnectionHandle; } VSyncModulator(Scheduler&, const sp<Scheduler::ConnectionHandle>& appConnectionHandle, const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig&); void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex); // Signals that a transaction has started, and changes offsets accordingly. void setTransactionStart(Scheduler::TransactionStart transactionStart); Loading @@ -98,28 +82,23 @@ public: void onRefreshed(bool usedRenderEngine); // Returns the offsets that we are currently using Offsets getOffsets() EXCLUDES(mMutex); Offsets getOffsets() const EXCLUDES(mMutex); private: // Returns the next offsets that we should be using Offsets getNextOffsets() REQUIRES(mMutex); // Returns the next offset type that we should use. OffsetType getNextOffsetType(); const Offsets& getNextOffsets() const REQUIRES(mMutex); // Updates offsets and persists them into the scheduler framework. void updateOffsets() EXCLUDES(mMutex); void updateOffsetsLocked() REQUIRES(mMutex); // Updates the internal offsets and offset type. void flushOffsets() REQUIRES(mMutex); mutable std::mutex mMutex; std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex); nsecs_t mThresholdForNextVsync; Scheduler& mScheduler; const sp<Scheduler::ConnectionHandle> mAppConnectionHandle; const sp<Scheduler::ConnectionHandle> mSfConnectionHandle; Scheduler* mScheduler = nullptr; Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; mutable std::mutex mMutex; OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex); Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late}; std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; Loading @@ -130,4 +109,4 @@ private: bool mTraceDetailedInfo = false; }; } // namespace android } // namespace android::scheduler
services/surfaceflinger/SurfaceFlinger.cpp +18 −27 File changed.Preview size limit exceeded, changes collapsed. Show changes