diff options
| -rw-r--r-- | services/surfaceflinger/Scheduler/PhaseOffsets.cpp | 11 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/PhaseOffsets.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/VSyncModulator.h | 26 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 28 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/FakePhaseOffsets.h | 2 |
6 files changed, 53 insertions, 22 deletions
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 16f67298ad..276bce1f89 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -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 @@ -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( diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 08747a5615..dc71e6eb60 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -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; }; @@ -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; @@ -84,6 +87,7 @@ private: Offsets mDefaultRefreshRateOffsets; Offsets mHighRefreshRateOffsets; + nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 1a0de081c6..81a7864cdb 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -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(); @@ -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; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1d54cb275b..5e0ba13faa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -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 repaintEverythingForHWC(); return true; @@ -1591,12 +1590,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)); @@ -1986,9 +1996,11 @@ void SurfaceFlinger::postComposition() } getBE().mDisplayTimeline.updateSignalTimes(); - mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId()) - : Fence::NO_FENCE; - auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence); + mPreviousPresentFences[1] = mPreviousPresentFences[0]; + mPreviousPresentFences[0] = displayDevice + ? getHwComposer().getPresentFence(*displayDevice->getId()) + : Fence::NO_FENCE; + auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]); getBE().mDisplayTimeline.push(presentFenceTime); DisplayStatInfo stats; @@ -2079,7 +2091,7 @@ void SurfaceFlinger::postComposition() } } - mTransactionCompletedThread.addPresentFence(mPreviousPresentFence); + mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling && mRegionSamplingThread) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 72e2ff91f0..fc89f53d7e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -824,6 +824,8 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } + bool previousFrameMissed(); + /* * Debugging & dumpsys */ @@ -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. diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index cfa8337577..96121bb088 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -49,6 +49,8 @@ public: // refresh rates, to properly update the offsets. void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {} + nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } + // Returns current offsets in human friendly format. void dump(std::string& /*result*/) const override {} }; |