diff options
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/RefreshRateOverlay.cpp | 50 | ||||
-rw-r--r-- | services/surfaceflinger/RefreshRateOverlay.h | 12 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/ISchedulerCallback.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateSelector.cpp | 3 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateSelector.h | 6 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 16 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h | 2 |
11 files changed, 82 insertions, 21 deletions
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 8288b99864..75b07a8854 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -468,6 +468,12 @@ bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredMod return false; } +void DisplayDevice::onVrrIdle(bool idle) { + if (mRefreshRateOverlay) { + mRefreshRateOverlay->onVrrIdle(idle); + } +} + void DisplayDevice::animateOverlay() { if (mRefreshRateOverlay) { mRefreshRateOverlay->animate(); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3cc8cf5d63..1b8a3a8f54 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -196,6 +196,7 @@ public: bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } void animateOverlay(); bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired); + void onVrrIdle(bool idle); // Enables an overlay to be display with the hdr/sdr ratio void enableHdrSdrRatioOverlay(bool enable) REQUIRES(kMainThreadContext); diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 9527a997df..35f12a0484 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -28,10 +28,11 @@ namespace android { -auto RefreshRateOverlay::draw(int refreshRate, int renderFps, SkColor color, +auto RefreshRateOverlay::draw(int refreshRate, int renderFps, bool idle, SkColor color, ui::Transform::RotationFlags rotation, ftl::Flags<Features> features) -> Buffers { const size_t loopCount = features.test(Features::Spinner) ? 6 : 1; + const bool isSetByHwc = features.test(Features::SetByHwc); Buffers buffers; buffers.reserve(loopCount); @@ -71,7 +72,11 @@ auto RefreshRateOverlay::draw(int refreshRate, int renderFps, SkColor color, canvas->setMatrix(canvasTransform); int left = 0; - drawNumber(refreshRate, left, color, *canvas); + if (idle && !isSetByHwc) { + drawDash(left, *canvas); + } else { + drawNumber(refreshRate, left, color, *canvas); + } left += 3 * (kDigitWidth + kDigitSpace); if (features.test(Features::Spinner)) { switch (i) { @@ -104,7 +109,11 @@ auto RefreshRateOverlay::draw(int refreshRate, int renderFps, SkColor color, left += kDigitWidth + kDigitSpace; if (features.test(Features::RenderRate)) { - drawNumber(renderFps, left, color, *canvas); + if (idle) { + drawDash(left, *canvas); + } else { + drawNumber(renderFps, left, color, *canvas); + } } left += 3 * (kDigitWidth + kDigitSpace); @@ -138,6 +147,14 @@ void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanva SegmentDrawer::drawDigit(number % 10, left, color, canvas); } +void RefreshRateOverlay::drawDash(int left, SkCanvas& canvas) { + left += kDigitWidth + kDigitSpace; + SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas); + + left += kDigitWidth + kDigitSpace; + SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas); +} + std::unique_ptr<RefreshRateOverlay> RefreshRateOverlay::create(FpsRange range, ftl::Flags<Features> features) { std::unique_ptr<RefreshRateOverlay> overlay = @@ -171,7 +188,8 @@ bool RefreshRateOverlay::initCheck() const { return mSurfaceControl != nullptr; } -auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps) -> const Buffers& { +auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps, bool idle) + -> const Buffers& { static const Buffers kNoBuffers; if (!mSurfaceControl) return kNoBuffers; @@ -197,8 +215,8 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps) -> c createTransaction().setTransform(mSurfaceControl->get(), transform).apply(); - BufferCache::const_iterator it = - mBufferCache.find({refreshRate.getIntValue(), renderFps.getIntValue(), transformHint}); + BufferCache::const_iterator it = mBufferCache.find( + {refreshRate.getIntValue(), renderFps.getIntValue(), transformHint, idle}); if (it == mBufferCache.end()) { const int maxFps = mFpsRange.max.getIntValue(); @@ -222,10 +240,10 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps) -> c const SkColor color = colorBase.toSkColor(); - auto buffers = draw(refreshIntFps, renderIntFps, color, transformHint, mFeatures); + auto buffers = draw(refreshIntFps, renderIntFps, idle, color, transformHint, mFeatures); it = mBufferCache - .try_emplace({refreshIntFps, renderIntFps, transformHint}, std::move(buffers)) - .first; + .try_emplace({refreshIntFps, renderIntFps, transformHint, idle}, + std::move(buffers)).first; } return it->second; @@ -257,7 +275,15 @@ void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { void RefreshRateOverlay::changeRefreshRate(Fps refreshRate, Fps renderFps) { mRefreshRate = refreshRate; mRenderFps = renderFps; - const auto buffer = getOrCreateBuffers(refreshRate, renderFps)[mFrame]; + const auto buffer = getOrCreateBuffers(refreshRate, renderFps, mIsVrrIdle)[mFrame]; + createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); +} + +void RefreshRateOverlay::onVrrIdle(bool idle) { + mIsVrrIdle = idle; + if (!mRefreshRate || !mRenderFps) return; + + const auto buffer = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle)[mFrame]; createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); } @@ -265,7 +291,7 @@ void RefreshRateOverlay::changeRenderRate(Fps renderFps) { if (mFeatures.test(Features::RenderRate) && mRefreshRate && FlagManager::getInstance().misc1()) { mRenderFps = renderFps; - const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps)[mFrame]; + const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps, mIsVrrIdle)[mFrame]; createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); } } @@ -273,7 +299,7 @@ void RefreshRateOverlay::changeRenderRate(Fps renderFps) { void RefreshRateOverlay::animate() { if (!mFeatures.test(Features::Spinner) || !mRefreshRate) return; - const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps); + const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle); mFrame = (mFrame + 1) % buffers.size(); const auto buffer = buffers[mFrame]; createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index b2896f07dd..d8aa048747 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -57,6 +57,7 @@ public: void changeRenderRate(Fps); void animate(); bool isSetByHwc() const { return mFeatures.test(RefreshRateOverlay::Features::SetByHwc); } + void onVrrIdle(bool idle); RefreshRateOverlay(ConstructorTag, FpsRange, ftl::Flags<Features>); @@ -65,11 +66,12 @@ private: using Buffers = std::vector<sp<GraphicBuffer>>; - static Buffers draw(int refreshRate, int renderFps, SkColor, ui::Transform::RotationFlags, - ftl::Flags<Features>); + static Buffers draw(int refreshRate, int renderFps, bool idle, SkColor, + ui::Transform::RotationFlags, ftl::Flags<Features>); static void drawNumber(int number, int left, SkColor, SkCanvas&); + static void drawDash(int left, SkCanvas&); - const Buffers& getOrCreateBuffers(Fps, Fps); + const Buffers& getOrCreateBuffers(Fps, Fps, bool); SurfaceComposerClient::Transaction createTransaction() const; @@ -77,10 +79,11 @@ private: int refreshRate; int renderFps; ui::Transform::RotationFlags flags; + bool idle; bool operator==(Key other) const { return refreshRate == other.refreshRate && renderFps == other.renderFps && - flags == other.flags; + flags == other.flags && idle == other.idle; } }; @@ -89,6 +92,7 @@ private: std::optional<Fps> mRefreshRate; std::optional<Fps> mRenderFps; + bool mIsVrrIdle = false; size_t mFrame = 0; const FpsRange mFpsRange; // For color interpolation. diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h index 43cdb5ec41..f430526b76 100644 --- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h +++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h @@ -33,6 +33,7 @@ struct ISchedulerCallback { virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps renderRate) = 0; virtual void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) = 0; + virtual void vrrDisplayIdle(bool idle) = 0; protected: ~ISchedulerCallback() = default; diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 47c8fd70ca..9f6eab288b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -1501,7 +1501,7 @@ void RefreshRateSelector::constructAvailableRefreshRates() { return str; }; ALOGV("%s render rates: %s, isVrrDevice? %d", rangeName, stringifyModes().c_str(), - mIsVrrDevice); + mIsVrrDevice.load()); return frameRateModes; }; @@ -1511,7 +1511,6 @@ void RefreshRateSelector::constructAvailableRefreshRates() { } bool RefreshRateSelector::isVrrDevice() const { - std::lock_guard lock(mLock); return mIsVrrDevice; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 4f491d9986..6f9c146dea 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -383,6 +383,7 @@ public: Callbacks platform; Callbacks kernel; + Callbacks vrr; }; void setIdleTimerCallbacks(IdleTimerCallbacks callbacks) EXCLUDES(mIdleTimerCallbacksMutex) { @@ -501,6 +502,9 @@ private: std::optional<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const REQUIRES(mIdleTimerCallbacksMutex) { if (!mIdleTimerCallbacks) return {}; + + if (mIsVrrDevice) return mIdleTimerCallbacks->vrr; + return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel : mIdleTimerCallbacks->platform; } @@ -536,7 +540,7 @@ private: std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock); // Caches whether the device is VRR-compatible based on the active display mode. - bool mIsVrrDevice GUARDED_BY(mLock) = false; + std::atomic_bool mIsVrrDevice = false; Policy mDisplayManagerPolicy GUARDED_BY(mLock); std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index c43e942723..fbd788b987 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -942,8 +942,9 @@ std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); }, .onExpired = [this] { idleTimerCallback(TimerState::Expired); }}, .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); }, - .onExpired = - [this] { kernelIdleTimerCallback(TimerState::Expired); }}}); + .onExpired = [this] { kernelIdleTimerCallback(TimerState::Expired); }}, + .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); }, + .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}}); pacesetter.selectorPtr->startIdleTimer(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c75c9f5001..c90b3d83fe 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7691,6 +7691,22 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { })); } +void SurfaceFlinger::vrrDisplayIdle(bool idle) { + // Update the overlay on the main thread to avoid race conditions with + // RefreshRateSelector::getActiveMode + static_cast<void>(mScheduler->schedule([=, this] { + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); + if (!display) { + ALOGW("%s: default display is null", __func__); + return; + } + if (!display->isRefreshRateOverlayEnabled()) return; + + display->onVrrIdle(idle); + mScheduler->scheduleFrame(); + })); +} + std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) { const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported( diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 65bfce2c55..e3e583bdaa 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -704,6 +704,7 @@ private: Fps renderRate) override; void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) override REQUIRES(kMainThreadContext); + void vrrDisplayIdle(bool idle) override; // ICEPowerCallback overrides: void notifyCpuLoadUp() override; diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index dec5fa56ea..8f21cdbaa6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -31,6 +31,7 @@ struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps), (override)); MOCK_METHOD(void, onCommitNotComposited, (PhysicalDisplayId), (override)); + MOCK_METHOD(void, vrrDisplayIdle, (bool), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { @@ -41,6 +42,7 @@ struct NoOpSchedulerCallback final : ISchedulerCallback { void onChoreographerAttached() override {} void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {} void onCommitNotComposited(PhysicalDisplayId) override {} + void vrrDisplayIdle(bool) override {} }; } // namespace android::scheduler::mock |