Loading services/surfaceflinger/DisplayDevice.cpp +16 −7 Original line number Diff line number Diff line Loading @@ -203,7 +203,7 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps displayFps, Fps rend mRefreshRateSelector->setActiveMode(modeId, renderFps); if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(displayFps); mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps); } } Loading Loading @@ -410,26 +410,35 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinner, bool showRenderRate) { if (!enable) { mRefreshRateOverlay.reset(); return; } ftl::Flags<RefreshRateOverlay::Features> features; if (showSpinner) { features |= RefreshRateOverlay::Features::Spinner; } if (showRenderRate) { features |= RefreshRateOverlay::Features::RenderRate; } const auto fpsRange = mRefreshRateSelector->getSupportedRefreshRateRange(); mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner); mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, features); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); mRefreshRateOverlay->changeRefreshRate(getActiveMode().modePtr->getFps()); mRefreshRateOverlay->changeRefreshRate(getActiveMode().modePtr->getFps(), getActiveMode().fps); } bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId, bool timerExpired) { if (mRefreshRateSelector && mRefreshRateOverlay) { const auto newRefreshRate = const auto newMode = mRefreshRateSelector->onKernelTimerChanged(desiredModeId, timerExpired); if (newRefreshRate) { mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); if (newMode) { mRefreshRateOverlay->changeRefreshRate(newMode->modePtr->getFps(), newMode->fps); return true; } } Loading services/surfaceflinger/DisplayDevice.h +2 −1 Original line number Diff line number Diff line Loading @@ -236,7 +236,8 @@ public: } // Enables an overlay to be displayed with the current refresh rate void enableRefreshRateOverlay(bool enable, bool showSpinner) REQUIRES(kMainThreadContext); void enableRefreshRateOverlay(bool enable, bool showSpinner, bool showRenderRate) REQUIRES(kMainThreadContext); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired); void animateRefreshRateOverlay(); Loading services/surfaceflinger/RefreshRateOverlay.cpp +60 −43 Original line number Diff line number Diff line Loading @@ -42,8 +42,8 @@ constexpr int kDigitWidth = 64; constexpr int kDigitHeight = 100; constexpr int kDigitSpace = 16; // Layout is digit, space, digit, space, digit, space, spinner. constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace; constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1; constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace; constexpr int kBufferHeight = kDigitHeight; SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) { Loading Loading @@ -121,16 +121,10 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkCo drawSegment(Segment::Bottom, left, color, canvas); } auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, SkColor color, ui::Transform::RotationFlags rotation, bool showSpinner) -> Buffers { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; const auto tens = (number / 10) % 10; const auto ones = number % 10; const size_t loopCount = showSpinner ? 6 : 1; ftl::Flags<Features> features) -> Buffers { const size_t loopCount = features.test(Features::Spinner) ? 6 : 1; Buffers buffers; buffers.reserve(loopCount); Loading Loading @@ -169,20 +163,9 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, canvas->setMatrix(canvasTransform); int left = 0; if (hundreds != 0) { drawDigit(hundreds, left, color, *canvas); } left += kDigitWidth + kDigitSpace; if (tens != 0) { drawDigit(tens, left, color, *canvas); } left += kDigitWidth + kDigitSpace; drawDigit(ones, left, color, *canvas); left += kDigitWidth + kDigitSpace; if (showSpinner) { drawNumber(displayFps, left, color, *canvas); left += 3 * (kDigitWidth + kDigitSpace); if (features.test(Features::Spinner)) { switch (i) { case 0: drawSegment(Segment::Upper, left, color, *canvas); Loading @@ -205,6 +188,13 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, } } left += kDigitWidth + kDigitSpace; if (features.test(Features::RenderRate)) { drawNumber(renderFps, left, color, *canvas); } left += 3 * (kDigitWidth + kDigitSpace); void* pixels = nullptr; buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels)); Loading @@ -219,6 +209,23 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, return buffers; } void RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) { if (number < 0 || number >= 1000) return; if (number >= 100) { drawDigit(number / 100, left, color, canvas); } left += kDigitWidth + kDigitSpace; if (number >= 10) { drawDigit((number / 10) % 10, left, color, canvas); } left += kDigitWidth + kDigitSpace; drawDigit(number % 10, left, color, canvas); } std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() { sp<SurfaceControl> surfaceControl = SurfaceComposerClient::getDefault() Loading @@ -228,10 +235,8 @@ std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() { return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl)); } RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) : mFpsRange(fpsRange), mShowSpinner(showSpinner), mSurfaceControl(createSurfaceControlHolder()) { RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags<Features> features) : mFpsRange(fpsRange), mFeatures(features), mSurfaceControl(createSurfaceControlHolder()) { if (!mSurfaceControl) { ALOGE("%s: Failed to create buffer state layer", __func__); return; Loading @@ -243,10 +248,15 @@ RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) .apply(); } auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { auto RefreshRateOverlay::getOrCreateBuffers(Fps displayFps, Fps renderFps) -> const Buffers& { static const Buffers kNoBuffers; if (!mSurfaceControl) return kNoBuffers; // avoid caching different render rates if RenderRate is anyway not visible if (!mFeatures.test(Features::RenderRate)) { renderFps = 0_Hz; } const auto transformHint = static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint()); Loading @@ -266,17 +276,20 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { .setTransform(mSurfaceControl->get(), transform) .apply(); BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint}); BufferCache::const_iterator it = mBufferCache.find({displayFps.getIntValue(), renderFps.getIntValue(), transformHint}); if (it == mBufferCache.end()) { const int minFps = mFpsRange.min.getIntValue(); const int maxFps = mFpsRange.max.getIntValue(); // Clamp to the range. The current fps may be outside of this range if the display has // changed its set of supported refresh rates. const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps); // Clamp to the range. The current displayFps may be outside of this range if the display // has changed its set of supported refresh rates. const int displayIntFps = std::clamp(displayFps.getIntValue(), minFps, maxFps); const int renderIntFps = renderFps.getIntValue(); // Ensure non-zero range to avoid division by zero. const float fpsScale = static_cast<float>(intFps - minFps) / std::max(1, maxFps - minFps); const float fpsScale = static_cast<float>(displayIntFps - minFps) / std::max(1, maxFps - minFps); constexpr SkColor kMinFpsColor = SK_ColorRED; constexpr SkColor kMaxFpsColor = SK_ColorGREEN; Loading @@ -292,8 +305,11 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { const SkColor color = colorBase.toSkColor(); auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner); it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first; auto buffers = SevenSegmentDrawer::draw(displayIntFps, renderIntFps, color, transformHint, mFeatures); it = mBufferCache .try_emplace({displayIntFps, renderIntFps, transformHint}, std::move(buffers)) .first; } return it->second; Loading @@ -303,7 +319,7 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { constexpr int32_t kMaxWidth = 1000; const auto width = std::min({kMaxWidth, viewport.width, viewport.height}); const auto height = 2 * width; Rect frame((3 * width) >> 4, height >> 5); Rect frame((5 * width) >> 4, height >> 5); frame.offsetBy(width >> 5, height >> 4); createTransaction(mSurfaceControl->get()) Loading @@ -317,16 +333,17 @@ void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { createTransaction(mSurfaceControl->get()).setLayerStack(mSurfaceControl->get(), stack).apply(); } void RefreshRateOverlay::changeRefreshRate(Fps fps) { mCurrentFps = fps; const auto buffer = getOrCreateBuffers(fps)[mFrame]; void RefreshRateOverlay::changeRefreshRate(Fps displayFps, Fps renderFps) { mDisplayFps = displayFps; mRenderFps = renderFps; const auto buffer = getOrCreateBuffers(displayFps, renderFps)[mFrame]; createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply(); } void RefreshRateOverlay::animate() { if (!mShowSpinner || !mCurrentFps) return; if (!mFeatures.test(Features::Spinner) || !mDisplayFps) return; const auto& buffers = getOrCreateBuffers(*mCurrentFps); const auto& buffers = getOrCreateBuffers(*mDisplayFps, *mRenderFps); mFrame = (mFrame + 1) % buffers.size(); const auto buffer = buffers[mFrame]; createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply(); Loading services/surfaceflinger/RefreshRateOverlay.h +21 −8 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <SkColor.h> #include <vector> #include <ftl/flags.h> #include <ftl/small_map.h> #include <ui/LayerStack.h> #include <ui/Size.h> Loading Loading @@ -50,11 +51,16 @@ private: class RefreshRateOverlay { public: RefreshRateOverlay(FpsRange, bool showSpinner); enum class Features { Spinner = 1 << 0, RenderRate = 1 << 1, }; RefreshRateOverlay(FpsRange, ftl::Flags<Features>); void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(Fps); void changeRefreshRate(Fps, Fps); void animate(); private: Loading @@ -62,32 +68,39 @@ private: class SevenSegmentDrawer { public: static Buffers draw(int number, SkColor, ui::Transform::RotationFlags, bool showSpinner); static Buffers draw(int displayFps, int renderFps, SkColor, ui::Transform::RotationFlags, ftl::Flags<Features>); private: enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom }; static void drawSegment(Segment, int left, SkColor, SkCanvas&); static void drawDigit(int digit, int left, SkColor, SkCanvas&); static void drawNumber(int number, int left, SkColor, SkCanvas&); }; const Buffers& getOrCreateBuffers(Fps); const Buffers& getOrCreateBuffers(Fps, Fps); struct Key { int fps; int displayFps; int renderFps; ui::Transform::RotationFlags flags; bool operator==(Key other) const { return fps == other.fps && flags == other.flags; } bool operator==(Key other) const { return displayFps == other.displayFps && renderFps == other.renderFps && flags == other.flags; } }; using BufferCache = ftl::SmallMap<Key, Buffers, 9>; BufferCache mBufferCache; std::optional<Fps> mCurrentFps; std::optional<Fps> mDisplayFps; std::optional<Fps> mRenderFps; size_t mFrame = 0; const FpsRange mFpsRange; // For color interpolation. const bool mShowSpinner; const ftl::Flags<Features> mFeatures; const std::unique_ptr<SurfaceControlHolder> mSurfaceControl; }; Loading services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +11 −7 Original line number Diff line number Diff line Loading @@ -837,21 +837,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme return frameRateOverrides; } std::optional<Fps> RefreshRateSelector::onKernelTimerChanged( ftl::Optional<FrameRateMode> RefreshRateSelector::onKernelTimerChanged( std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const { std::lock_guard lock(mLock); const DisplayModePtr& current = desiredActiveModeId ? mDisplayModes.get(*desiredActiveModeId)->get() : getActiveModeLocked().modePtr.get(); const auto current = [&]() REQUIRES(mLock) -> FrameRateMode { if (desiredActiveModeId) { const auto& modePtr = mDisplayModes.get(*desiredActiveModeId)->get(); return FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)}; } return getActiveModeLocked(); }(); const DisplayModePtr& min = mMinRefreshRateModeIt->second; if (current == min) { if (current.modePtr->getId() == min->getId()) { return {}; } const auto& mode = timerExpired ? min : current; return mode->getFps(); return timerExpired ? FrameRateMode{min->getFps(), ftl::as_non_null(min)} : current; } const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const { Loading Loading
services/surfaceflinger/DisplayDevice.cpp +16 −7 Original line number Diff line number Diff line Loading @@ -203,7 +203,7 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps displayFps, Fps rend mRefreshRateSelector->setActiveMode(modeId, renderFps); if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(displayFps); mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps); } } Loading Loading @@ -410,26 +410,35 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinner, bool showRenderRate) { if (!enable) { mRefreshRateOverlay.reset(); return; } ftl::Flags<RefreshRateOverlay::Features> features; if (showSpinner) { features |= RefreshRateOverlay::Features::Spinner; } if (showRenderRate) { features |= RefreshRateOverlay::Features::RenderRate; } const auto fpsRange = mRefreshRateSelector->getSupportedRefreshRateRange(); mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner); mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, features); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); mRefreshRateOverlay->changeRefreshRate(getActiveMode().modePtr->getFps()); mRefreshRateOverlay->changeRefreshRate(getActiveMode().modePtr->getFps(), getActiveMode().fps); } bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId, bool timerExpired) { if (mRefreshRateSelector && mRefreshRateOverlay) { const auto newRefreshRate = const auto newMode = mRefreshRateSelector->onKernelTimerChanged(desiredModeId, timerExpired); if (newRefreshRate) { mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); if (newMode) { mRefreshRateOverlay->changeRefreshRate(newMode->modePtr->getFps(), newMode->fps); return true; } } Loading
services/surfaceflinger/DisplayDevice.h +2 −1 Original line number Diff line number Diff line Loading @@ -236,7 +236,8 @@ public: } // Enables an overlay to be displayed with the current refresh rate void enableRefreshRateOverlay(bool enable, bool showSpinner) REQUIRES(kMainThreadContext); void enableRefreshRateOverlay(bool enable, bool showSpinner, bool showRenderRate) REQUIRES(kMainThreadContext); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired); void animateRefreshRateOverlay(); Loading
services/surfaceflinger/RefreshRateOverlay.cpp +60 −43 Original line number Diff line number Diff line Loading @@ -42,8 +42,8 @@ constexpr int kDigitWidth = 64; constexpr int kDigitHeight = 100; constexpr int kDigitSpace = 16; // Layout is digit, space, digit, space, digit, space, spinner. constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace; constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1; constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace; constexpr int kBufferHeight = kDigitHeight; SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) { Loading Loading @@ -121,16 +121,10 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkCo drawSegment(Segment::Bottom, left, color, canvas); } auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, SkColor color, ui::Transform::RotationFlags rotation, bool showSpinner) -> Buffers { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; const auto tens = (number / 10) % 10; const auto ones = number % 10; const size_t loopCount = showSpinner ? 6 : 1; ftl::Flags<Features> features) -> Buffers { const size_t loopCount = features.test(Features::Spinner) ? 6 : 1; Buffers buffers; buffers.reserve(loopCount); Loading Loading @@ -169,20 +163,9 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, canvas->setMatrix(canvasTransform); int left = 0; if (hundreds != 0) { drawDigit(hundreds, left, color, *canvas); } left += kDigitWidth + kDigitSpace; if (tens != 0) { drawDigit(tens, left, color, *canvas); } left += kDigitWidth + kDigitSpace; drawDigit(ones, left, color, *canvas); left += kDigitWidth + kDigitSpace; if (showSpinner) { drawNumber(displayFps, left, color, *canvas); left += 3 * (kDigitWidth + kDigitSpace); if (features.test(Features::Spinner)) { switch (i) { case 0: drawSegment(Segment::Upper, left, color, *canvas); Loading @@ -205,6 +188,13 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, } } left += kDigitWidth + kDigitSpace; if (features.test(Features::RenderRate)) { drawNumber(renderFps, left, color, *canvas); } left += 3 * (kDigitWidth + kDigitSpace); void* pixels = nullptr; buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels)); Loading @@ -219,6 +209,23 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, return buffers; } void RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) { if (number < 0 || number >= 1000) return; if (number >= 100) { drawDigit(number / 100, left, color, canvas); } left += kDigitWidth + kDigitSpace; if (number >= 10) { drawDigit((number / 10) % 10, left, color, canvas); } left += kDigitWidth + kDigitSpace; drawDigit(number % 10, left, color, canvas); } std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() { sp<SurfaceControl> surfaceControl = SurfaceComposerClient::getDefault() Loading @@ -228,10 +235,8 @@ std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() { return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl)); } RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) : mFpsRange(fpsRange), mShowSpinner(showSpinner), mSurfaceControl(createSurfaceControlHolder()) { RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags<Features> features) : mFpsRange(fpsRange), mFeatures(features), mSurfaceControl(createSurfaceControlHolder()) { if (!mSurfaceControl) { ALOGE("%s: Failed to create buffer state layer", __func__); return; Loading @@ -243,10 +248,15 @@ RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) .apply(); } auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { auto RefreshRateOverlay::getOrCreateBuffers(Fps displayFps, Fps renderFps) -> const Buffers& { static const Buffers kNoBuffers; if (!mSurfaceControl) return kNoBuffers; // avoid caching different render rates if RenderRate is anyway not visible if (!mFeatures.test(Features::RenderRate)) { renderFps = 0_Hz; } const auto transformHint = static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint()); Loading @@ -266,17 +276,20 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { .setTransform(mSurfaceControl->get(), transform) .apply(); BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint}); BufferCache::const_iterator it = mBufferCache.find({displayFps.getIntValue(), renderFps.getIntValue(), transformHint}); if (it == mBufferCache.end()) { const int minFps = mFpsRange.min.getIntValue(); const int maxFps = mFpsRange.max.getIntValue(); // Clamp to the range. The current fps may be outside of this range if the display has // changed its set of supported refresh rates. const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps); // Clamp to the range. The current displayFps may be outside of this range if the display // has changed its set of supported refresh rates. const int displayIntFps = std::clamp(displayFps.getIntValue(), minFps, maxFps); const int renderIntFps = renderFps.getIntValue(); // Ensure non-zero range to avoid division by zero. const float fpsScale = static_cast<float>(intFps - minFps) / std::max(1, maxFps - minFps); const float fpsScale = static_cast<float>(displayIntFps - minFps) / std::max(1, maxFps - minFps); constexpr SkColor kMinFpsColor = SK_ColorRED; constexpr SkColor kMaxFpsColor = SK_ColorGREEN; Loading @@ -292,8 +305,11 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { const SkColor color = colorBase.toSkColor(); auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner); it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first; auto buffers = SevenSegmentDrawer::draw(displayIntFps, renderIntFps, color, transformHint, mFeatures); it = mBufferCache .try_emplace({displayIntFps, renderIntFps, transformHint}, std::move(buffers)) .first; } return it->second; Loading @@ -303,7 +319,7 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { constexpr int32_t kMaxWidth = 1000; const auto width = std::min({kMaxWidth, viewport.width, viewport.height}); const auto height = 2 * width; Rect frame((3 * width) >> 4, height >> 5); Rect frame((5 * width) >> 4, height >> 5); frame.offsetBy(width >> 5, height >> 4); createTransaction(mSurfaceControl->get()) Loading @@ -317,16 +333,17 @@ void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { createTransaction(mSurfaceControl->get()).setLayerStack(mSurfaceControl->get(), stack).apply(); } void RefreshRateOverlay::changeRefreshRate(Fps fps) { mCurrentFps = fps; const auto buffer = getOrCreateBuffers(fps)[mFrame]; void RefreshRateOverlay::changeRefreshRate(Fps displayFps, Fps renderFps) { mDisplayFps = displayFps; mRenderFps = renderFps; const auto buffer = getOrCreateBuffers(displayFps, renderFps)[mFrame]; createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply(); } void RefreshRateOverlay::animate() { if (!mShowSpinner || !mCurrentFps) return; if (!mFeatures.test(Features::Spinner) || !mDisplayFps) return; const auto& buffers = getOrCreateBuffers(*mCurrentFps); const auto& buffers = getOrCreateBuffers(*mDisplayFps, *mRenderFps); mFrame = (mFrame + 1) % buffers.size(); const auto buffer = buffers[mFrame]; createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply(); Loading
services/surfaceflinger/RefreshRateOverlay.h +21 −8 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <SkColor.h> #include <vector> #include <ftl/flags.h> #include <ftl/small_map.h> #include <ui/LayerStack.h> #include <ui/Size.h> Loading Loading @@ -50,11 +51,16 @@ private: class RefreshRateOverlay { public: RefreshRateOverlay(FpsRange, bool showSpinner); enum class Features { Spinner = 1 << 0, RenderRate = 1 << 1, }; RefreshRateOverlay(FpsRange, ftl::Flags<Features>); void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(Fps); void changeRefreshRate(Fps, Fps); void animate(); private: Loading @@ -62,32 +68,39 @@ private: class SevenSegmentDrawer { public: static Buffers draw(int number, SkColor, ui::Transform::RotationFlags, bool showSpinner); static Buffers draw(int displayFps, int renderFps, SkColor, ui::Transform::RotationFlags, ftl::Flags<Features>); private: enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom }; static void drawSegment(Segment, int left, SkColor, SkCanvas&); static void drawDigit(int digit, int left, SkColor, SkCanvas&); static void drawNumber(int number, int left, SkColor, SkCanvas&); }; const Buffers& getOrCreateBuffers(Fps); const Buffers& getOrCreateBuffers(Fps, Fps); struct Key { int fps; int displayFps; int renderFps; ui::Transform::RotationFlags flags; bool operator==(Key other) const { return fps == other.fps && flags == other.flags; } bool operator==(Key other) const { return displayFps == other.displayFps && renderFps == other.renderFps && flags == other.flags; } }; using BufferCache = ftl::SmallMap<Key, Buffers, 9>; BufferCache mBufferCache; std::optional<Fps> mCurrentFps; std::optional<Fps> mDisplayFps; std::optional<Fps> mRenderFps; size_t mFrame = 0; const FpsRange mFpsRange; // For color interpolation. const bool mShowSpinner; const ftl::Flags<Features> mFeatures; const std::unique_ptr<SurfaceControlHolder> mSurfaceControl; }; Loading
services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +11 −7 Original line number Diff line number Diff line Loading @@ -837,21 +837,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme return frameRateOverrides; } std::optional<Fps> RefreshRateSelector::onKernelTimerChanged( ftl::Optional<FrameRateMode> RefreshRateSelector::onKernelTimerChanged( std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const { std::lock_guard lock(mLock); const DisplayModePtr& current = desiredActiveModeId ? mDisplayModes.get(*desiredActiveModeId)->get() : getActiveModeLocked().modePtr.get(); const auto current = [&]() REQUIRES(mLock) -> FrameRateMode { if (desiredActiveModeId) { const auto& modePtr = mDisplayModes.get(*desiredActiveModeId)->get(); return FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)}; } return getActiveModeLocked(); }(); const DisplayModePtr& min = mMinRefreshRateModeIt->second; if (current == min) { if (current.modePtr->getId() == min->getId()) { return {}; } const auto& mode = timerExpired ? min : current; return mode->getFps(); return timerExpired ? FrameRateMode{min->getFps(), ftl::as_non_null(min)} : current; } const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const { Loading