Loading services/surfaceflinger/Scheduler/PhaseOffsets.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,13 @@ PhaseOffsets::PhaseOffsets() { property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); const int highFpsLateSfOffsetNs = atoi(value); // 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); mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, earlyAppOffsetNs != -1 ? earlyAppOffsetNs Loading @@ -84,6 +91,10 @@ PhaseOffsets::PhaseOffsets() { highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs : highFpsLateAppOffsetNs}; mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs : std::numeric_limits<nsecs_t>::max(); } PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( Loading services/surfaceflinger/Scheduler/PhaseOffsets.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ public: RefreshRateConfigs::RefreshRateType refreshRateType) const = 0; virtual Offsets getCurrentOffsets() const = 0; virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0; virtual nsecs_t getOffsetThresholdForNextVsync() const = 0; virtual void dump(std::string& result) const = 0; }; Loading @@ -72,6 +73,8 @@ public: mRefreshRateType = refreshRateType; } nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; Loading @@ -84,6 +87,7 @@ private: Offsets mDefaultRefreshRateOffsets; Offsets mHighRefreshRateOffsets; nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl Loading services/surfaceflinger/Scheduler/VSyncModulator.h +13 −13 Original line number Diff line number Diff line Loading @@ -139,6 +139,19 @@ public: } } Offsets getOffsets() { // 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 mEarlyOffsets; } else if (mLastFrameUsedRenderEngine) { return mEarlyGlOffsets; } else { return mLateOffsets; } } private: void updateOffsets() { const Offsets desired = getOffsets(); Loading Loading @@ -167,19 +180,6 @@ private: } } Offsets getOffsets() { // 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 mEarlyOffsets; } else if (mLastFrameUsedRenderEngine) { return mEarlyGlOffsets; } else { return mLateOffsets; } } Offsets mLateOffsets; Offsets mEarlyOffsets; Offsets mEarlyGlOffsets; Loading services/surfaceflinger/SurfaceFlinger.cpp +20 −8 Original line number Diff line number Diff line Loading @@ -977,8 +977,7 @@ void SurfaceFlinger::setActiveConfigInternal() { bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { if (mPreviousPresentFence != Fence::NO_FENCE && (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) { if (previousFrameMissed()) { // fence has not signaled yet. wait for the next invalidate mEventQueue->invalidateForHWC(); return true; Loading Loading @@ -1587,12 +1586,23 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 const sp<Fence>& fence = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? mPreviousPresentFences[0] : mPreviousPresentFences[1]; return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE && (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled); bool frameMissed = previousFrameMissed(); bool hwcFrameMissed = mHadDeviceComposition && frameMissed; bool gpuFrameMissed = mHadClientComposition && frameMissed; ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); Loading Loading @@ -1982,9 +1992,11 @@ void SurfaceFlinger::postComposition() } getBE().mDisplayTimeline.updateSignalTimes(); mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId()) mPreviousPresentFences[1] = mPreviousPresentFences[0]; mPreviousPresentFences[0] = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId()) : Fence::NO_FENCE; auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence); auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]); getBE().mDisplayTimeline.push(presentFenceTime); DisplayStatInfo stats; Loading Loading @@ -2075,7 +2087,7 @@ void SurfaceFlinger::postComposition() } } mTransactionCompletedThread.addPresentFence(mPreviousPresentFence); mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling && mRegionSamplingThread) { Loading services/surfaceflinger/SurfaceFlinger.h +3 −1 Original line number Diff line number Diff line Loading @@ -824,6 +824,8 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } bool previousFrameMissed(); /* * Debugging & dumpsys */ Loading Loading @@ -956,7 +958,7 @@ private: std::vector<sp<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; sp<Fence> mPreviousPresentFence = Fence::NO_FENCE; std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE}; // True if in the previous frame at least one layer was composed via the GPU. bool mHadClientComposition = false; // True if in the previous frame at least one layer was composed via HW Composer. Loading Loading
services/surfaceflinger/Scheduler/PhaseOffsets.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,13 @@ PhaseOffsets::PhaseOffsets() { property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); const int highFpsLateSfOffsetNs = atoi(value); // 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); mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, earlyAppOffsetNs != -1 ? earlyAppOffsetNs Loading @@ -84,6 +91,10 @@ PhaseOffsets::PhaseOffsets() { highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs : highFpsLateAppOffsetNs}; mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs : std::numeric_limits<nsecs_t>::max(); } PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( Loading
services/surfaceflinger/Scheduler/PhaseOffsets.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ public: RefreshRateConfigs::RefreshRateType refreshRateType) const = 0; virtual Offsets getCurrentOffsets() const = 0; virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0; virtual nsecs_t getOffsetThresholdForNextVsync() const = 0; virtual void dump(std::string& result) const = 0; }; Loading @@ -72,6 +73,8 @@ public: mRefreshRateType = refreshRateType; } nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; Loading @@ -84,6 +87,7 @@ private: Offsets mDefaultRefreshRateOffsets; Offsets mHighRefreshRateOffsets; nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl Loading
services/surfaceflinger/Scheduler/VSyncModulator.h +13 −13 Original line number Diff line number Diff line Loading @@ -139,6 +139,19 @@ public: } } Offsets getOffsets() { // 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 mEarlyOffsets; } else if (mLastFrameUsedRenderEngine) { return mEarlyGlOffsets; } else { return mLateOffsets; } } private: void updateOffsets() { const Offsets desired = getOffsets(); Loading Loading @@ -167,19 +180,6 @@ private: } } Offsets getOffsets() { // 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 mEarlyOffsets; } else if (mLastFrameUsedRenderEngine) { return mEarlyGlOffsets; } else { return mLateOffsets; } } Offsets mLateOffsets; Offsets mEarlyOffsets; Offsets mEarlyGlOffsets; Loading
services/surfaceflinger/SurfaceFlinger.cpp +20 −8 Original line number Diff line number Diff line Loading @@ -977,8 +977,7 @@ void SurfaceFlinger::setActiveConfigInternal() { bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { if (mPreviousPresentFence != Fence::NO_FENCE && (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) { if (previousFrameMissed()) { // fence has not signaled yet. wait for the next invalidate mEventQueue->invalidateForHWC(); return true; Loading Loading @@ -1587,12 +1586,23 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 const sp<Fence>& fence = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? mPreviousPresentFences[0] : mPreviousPresentFences[1]; return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE && (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled); bool frameMissed = previousFrameMissed(); bool hwcFrameMissed = mHadDeviceComposition && frameMissed; bool gpuFrameMissed = mHadClientComposition && frameMissed; ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); Loading Loading @@ -1982,9 +1992,11 @@ void SurfaceFlinger::postComposition() } getBE().mDisplayTimeline.updateSignalTimes(); mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId()) mPreviousPresentFences[1] = mPreviousPresentFences[0]; mPreviousPresentFences[0] = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId()) : Fence::NO_FENCE; auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence); auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]); getBE().mDisplayTimeline.push(presentFenceTime); DisplayStatInfo stats; Loading Loading @@ -2075,7 +2087,7 @@ void SurfaceFlinger::postComposition() } } mTransactionCompletedThread.addPresentFence(mPreviousPresentFence); mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling && mRegionSamplingThread) { Loading
services/surfaceflinger/SurfaceFlinger.h +3 −1 Original line number Diff line number Diff line Loading @@ -824,6 +824,8 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } bool previousFrameMissed(); /* * Debugging & dumpsys */ Loading Loading @@ -956,7 +958,7 @@ private: std::vector<sp<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; sp<Fence> mPreviousPresentFence = Fence::NO_FENCE; std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE}; // True if in the previous frame at least one layer was composed via the GPU. bool mHadClientComposition = false; // True if in the previous frame at least one layer was composed via HW Composer. Loading