Loading services/surfaceflinger/RefreshRateOverlay.cpp +70 −28 Original line number Diff line number Diff line Loading @@ -106,14 +106,17 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, cons drawSegment(Segment::Buttom, left, color, buffer, pixels); } sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, const half4& color) { if (number < 0 || number > 1000) return nullptr; std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber( int number, const half4& color, bool showSpinner) { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; const auto tens = (number / 10) % 10; const auto ones = number % 10; std::vector<sp<GraphicBuffer>> buffers; const auto loopCount = showSpinner ? 6 : 1; for (int i = 0; i < loopCount; i++) { sp<GraphicBuffer> buffer = new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | Loading @@ -126,21 +129,48 @@ sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, int left = 0; if (hundreds != 0) { drawDigit(hundreds, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; } left += DIGIT_WIDTH + DIGIT_SPACE; if (tens != 0) { drawDigit(tens, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; } left += DIGIT_WIDTH + DIGIT_SPACE; drawDigit(ones, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; if (showSpinner) { switch (i) { case 0: drawSegment(Segment::Upper, left, color, buffer, pixels); break; case 1: drawSegment(Segment::UpperRight, left, color, buffer, pixels); break; case 2: drawSegment(Segment::LowerRight, left, color, buffer, pixels); break; case 3: drawSegment(Segment::Buttom, left, color, buffer, pixels); break; case 4: drawSegment(Segment::LowerLeft, left, color, buffer, pixels); break; case 5: drawSegment(Segment::UpperLeft, left, color, buffer, pixels); break; } } buffer->unlock(); return buffer; buffers.emplace_back(buffer); } return buffers; } RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger) : mFlinger(flinger), mClient(new Client(&mFlinger)) { RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner) : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) { createLayer(); primeCache(); } Loading Loading @@ -176,7 +206,7 @@ void RefreshRateOverlay::primeCache() { if (allRefreshRates.size() == 1) { auto fps = allRefreshRates.begin()->second->getFps(); half4 color = {LOW_FPS_COLOR, ALPHA}; mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color)); mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); return; } Loading @@ -196,12 +226,12 @@ void RefreshRateOverlay::primeCache() { color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color)); mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); } } void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame(viewport.width >> 3, viewport.height >> 5); Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); mLayer->setFrame(frame); Loading @@ -209,7 +239,19 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { } void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { auto buffer = mBufferCache[refreshRate.getFps()]; mCurrentFps = refreshRate.getFps(); auto buffer = mBufferCache[*mCurrentFps][mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } void RefreshRateOverlay::onInvalidate() { if (!mCurrentFps.has_value()) return; const auto& buffers = mBufferCache[*mCurrentFps]; mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); Loading services/surfaceflinger/RefreshRateOverlay.h +10 −5 Original line number Diff line number Diff line Loading @@ -38,15 +38,17 @@ using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; class RefreshRateOverlay { public: explicit RefreshRateOverlay(SurfaceFlinger&); RefreshRateOverlay(SurfaceFlinger&, bool showSpinner); void setViewport(ui::Size); void changeRefreshRate(const RefreshRate&); void onInvalidate(); private: class SevenSegmentDrawer { public: static sp<GraphicBuffer> drawNumber(int number, const half4& color); static std::vector<sp<GraphicBuffer>> drawNumber(int number, const half4& color, bool showSpinner); static uint32_t getHeight() { return BUFFER_HEIGHT; } static uint32_t getWidth() { return BUFFER_WIDTH; } Loading @@ -65,7 +67,7 @@ private: static constexpr uint32_t DIGIT_SPACE = 16; static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT; static constexpr uint32_t BUFFER_WIDTH = 3 * DIGIT_WIDTH + 2 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit 4 * DIGIT_WIDTH + 3 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit|Space|Spinner }; bool createLayer(); Loading @@ -77,11 +79,14 @@ private: sp<IBinder> mIBinder; sp<IGraphicBufferProducer> mGbp; std::unordered_map<int, sp<GraphicBuffer>> mBufferCache; std::unordered_map<int, std::vector<sp<GraphicBuffer>>> mBufferCache; std::optional<int> mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f); const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f); const bool mShowSpinner; }; } // namespace android services/surfaceflinger/SurfaceFlinger.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -470,6 +470,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false); base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); } SurfaceFlinger::~SurfaceFlinger() = default; Loading Loading @@ -1965,6 +1967,12 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { mTracingEnabledChanged = false; } if (mRefreshRateOverlaySpinner) { if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { mRefreshRateOverlay->onInvalidate(); } } bool refreshNeeded; { ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled); Loading Loading @@ -6259,7 +6267,7 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { static_cast<void>(schedule([=] { std::unique_ptr<RefreshRateOverlay> overlay; if (enable) { overlay = std::make_unique<RefreshRateOverlay>(*this); overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner); } { Loading services/surfaceflinger/SurfaceFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -547,6 +547,8 @@ private: bool mKernelIdleTimerEnabled = false; // Keeps track of whether the kernel timer is supported on the SF side. bool mSupportKernelIdleTimer = false; // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; /* ------------------------------------------------------------------------ * Message handling */ Loading Loading
services/surfaceflinger/RefreshRateOverlay.cpp +70 −28 Original line number Diff line number Diff line Loading @@ -106,14 +106,17 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, cons drawSegment(Segment::Buttom, left, color, buffer, pixels); } sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, const half4& color) { if (number < 0 || number > 1000) return nullptr; std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber( int number, const half4& color, bool showSpinner) { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; const auto tens = (number / 10) % 10; const auto ones = number % 10; std::vector<sp<GraphicBuffer>> buffers; const auto loopCount = showSpinner ? 6 : 1; for (int i = 0; i < loopCount; i++) { sp<GraphicBuffer> buffer = new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | Loading @@ -126,21 +129,48 @@ sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, int left = 0; if (hundreds != 0) { drawDigit(hundreds, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; } left += DIGIT_WIDTH + DIGIT_SPACE; if (tens != 0) { drawDigit(tens, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; } left += DIGIT_WIDTH + DIGIT_SPACE; drawDigit(ones, left, color, buffer, pixels); left += DIGIT_WIDTH + DIGIT_SPACE; if (showSpinner) { switch (i) { case 0: drawSegment(Segment::Upper, left, color, buffer, pixels); break; case 1: drawSegment(Segment::UpperRight, left, color, buffer, pixels); break; case 2: drawSegment(Segment::LowerRight, left, color, buffer, pixels); break; case 3: drawSegment(Segment::Buttom, left, color, buffer, pixels); break; case 4: drawSegment(Segment::LowerLeft, left, color, buffer, pixels); break; case 5: drawSegment(Segment::UpperLeft, left, color, buffer, pixels); break; } } buffer->unlock(); return buffer; buffers.emplace_back(buffer); } return buffers; } RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger) : mFlinger(flinger), mClient(new Client(&mFlinger)) { RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner) : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) { createLayer(); primeCache(); } Loading Loading @@ -176,7 +206,7 @@ void RefreshRateOverlay::primeCache() { if (allRefreshRates.size() == 1) { auto fps = allRefreshRates.begin()->second->getFps(); half4 color = {LOW_FPS_COLOR, ALPHA}; mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color)); mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); return; } Loading @@ -196,12 +226,12 @@ void RefreshRateOverlay::primeCache() { color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color)); mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); } } void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame(viewport.width >> 3, viewport.height >> 5); Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); mLayer->setFrame(frame); Loading @@ -209,7 +239,19 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { } void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { auto buffer = mBufferCache[refreshRate.getFps()]; mCurrentFps = refreshRate.getFps(); auto buffer = mBufferCache[*mCurrentFps][mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } void RefreshRateOverlay::onInvalidate() { if (!mCurrentFps.has_value()) return; const auto& buffers = mBufferCache[*mCurrentFps]; mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); Loading
services/surfaceflinger/RefreshRateOverlay.h +10 −5 Original line number Diff line number Diff line Loading @@ -38,15 +38,17 @@ using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; class RefreshRateOverlay { public: explicit RefreshRateOverlay(SurfaceFlinger&); RefreshRateOverlay(SurfaceFlinger&, bool showSpinner); void setViewport(ui::Size); void changeRefreshRate(const RefreshRate&); void onInvalidate(); private: class SevenSegmentDrawer { public: static sp<GraphicBuffer> drawNumber(int number, const half4& color); static std::vector<sp<GraphicBuffer>> drawNumber(int number, const half4& color, bool showSpinner); static uint32_t getHeight() { return BUFFER_HEIGHT; } static uint32_t getWidth() { return BUFFER_WIDTH; } Loading @@ -65,7 +67,7 @@ private: static constexpr uint32_t DIGIT_SPACE = 16; static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT; static constexpr uint32_t BUFFER_WIDTH = 3 * DIGIT_WIDTH + 2 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit 4 * DIGIT_WIDTH + 3 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit|Space|Spinner }; bool createLayer(); Loading @@ -77,11 +79,14 @@ private: sp<IBinder> mIBinder; sp<IGraphicBufferProducer> mGbp; std::unordered_map<int, sp<GraphicBuffer>> mBufferCache; std::unordered_map<int, std::vector<sp<GraphicBuffer>>> mBufferCache; std::optional<int> mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f); const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f); const bool mShowSpinner; }; } // namespace android
services/surfaceflinger/SurfaceFlinger.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -470,6 +470,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false); base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); } SurfaceFlinger::~SurfaceFlinger() = default; Loading Loading @@ -1965,6 +1967,12 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { mTracingEnabledChanged = false; } if (mRefreshRateOverlaySpinner) { if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { mRefreshRateOverlay->onInvalidate(); } } bool refreshNeeded; { ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled); Loading Loading @@ -6259,7 +6267,7 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { static_cast<void>(schedule([=] { std::unique_ptr<RefreshRateOverlay> overlay; if (enable) { overlay = std::make_unique<RefreshRateOverlay>(*this); overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner); } { Loading
services/surfaceflinger/SurfaceFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -547,6 +547,8 @@ private: bool mKernelIdleTimerEnabled = false; // Keeps track of whether the kernel timer is supported on the SF side. bool mSupportKernelIdleTimer = false; // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; /* ------------------------------------------------------------------------ * Message handling */ Loading