Skip to content

feat: add real-time FPS display#550

Merged
zccrs merged 1 commit intolinuxdeepin:masterfrom
Dami-star:FPS
Sep 26, 2025
Merged

feat: add real-time FPS display#550
zccrs merged 1 commit intolinuxdeepin:masterfrom
Dami-star:FPS

Conversation

@Dami-star
Copy link
Collaborator

@Dami-star Dami-star commented Sep 9, 2025

Introduces an on-screen FPS overlay with timer-based sampling aligned to the active screen’s refresh rate. automatic refresh-rate handling on screen changes.

Summary by Sourcery

Add a real-time, on-screen FPS display feature with a manager that samples vsync timings, a QML overlay for rendering FPS metrics, and a keyboard shortcut to toggle visibility while handling dynamic refresh rates

New Features:

  • Add FpsDisplayManager for sampling vsync events and computing real-time FPS metrics
  • Introduce a QML FpsDisplay overlay to show current and maximum FPS, toggleable with Meta+F11
  • Automatically detect and adapt to the active screen’s refresh rate when computing FPS

Build:

  • Include fpsdisplaymanager sources and FpsDisplay.qml in the project’s CMakeLists

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Dami-star

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai
Copy link

sourcery-ai bot commented Sep 9, 2025

Reviewer's Guide

This PR implements a new FPS overlay subsystem that samples frame timing via v-sync and timers, automatically adapts to display refresh rates, and integrates a toggleable QML overlay using a Meta+F11 shortcut.

Sequence diagram for toggling the FPS overlay with Meta+F11

sequenceDiagram
    actor User
    participant Helper
    participant FpsDisplayManager
    participant QmlEngine
    participant FpsDisplay (QML)
    User->>Helper: Press Meta+F11
    Helper->>Helper: toggleFpsDisplay()
    alt FPS overlay is visible
        Helper->>FpsDisplayManager: hide()
        FpsDisplayManager-->>Helper: visibilityChanged()
        Helper->>FpsDisplay: setProperty("fpsVisible", false)
        Helper->>FpsDisplay: deleteLater()
    else FPS overlay is hidden
        Helper->>QmlEngine: createFpsDisplay(parent)
        QmlEngine-->>Helper: FpsDisplay (QML)
        Helper->>FpsDisplayManager: show()
        FpsDisplayManager-->>Helper: visibilityChanged()
        Helper->>FpsDisplay: setProperty("fpsVisible", true)
        FpsDisplayManager-->>Helper: fpsDataChanged(currentFpsText, maximumFpsText)
        Helper->>FpsDisplay: setProperty("currentFpsText", ...)
        Helper->>FpsDisplay: setProperty("maximumFpsText", ...)
    end
Loading

Class diagram for FpsDisplayManager and Helper integration

classDiagram
    class Helper {
        +void toggleFpsDisplay()
        -QQuickItem *m_fpsDisplay
        -FpsDisplayManager *m_fpsDisplayManager
    }
    class FpsDisplayManager {
        +void setTargetWindow(QQuickWindow *window)
        +void show()
        +void hide()
        +void toggle()
        +void reset()
        +bool isVisible()
        +int currentFps()
        +int averageFps()
        +int maximumFps()
        +QString currentFpsText()
        +QString maximumFpsText()
        +signal fpsDataChanged(QString, QString)
        +signal visibilityChanged()
    }
    Helper --> FpsDisplayManager : manages
    FpsDisplayManager --> QQuickWindow : uses
    FpsDisplayManager --> QTimer : uses
    FpsDisplayManager --> QElapsedTimer : uses
    FpsDisplayManager --> WOutput : queries
    FpsDisplayManager --> QQuickItem : for overlay
Loading

Class diagram for QmlEngine FPS display integration

classDiagram
    class QmlEngine {
        +QQuickItem *createFpsDisplay(QQuickItem *parent)
        -QQmlComponent fpsDisplayComponent
    }
    QmlEngine --> QQuickItem : creates FPS overlay
    QmlEngine --> QQmlComponent : uses fpsDisplayComponent
Loading

File-Level Changes

Change Details Files
Introduce FPS display manager subsystem
  • Implement FpsDisplayManager class with v-sync and timer based sampling
  • Detect and adapt to display refresh rate and handle screen changes
  • Maintain sample queue and apply smoothing, emit data and visibility signals
src/utils/fpsdisplaymanager.h
src/utils/fpsdisplaymanager.cpp
Integrate FPS toggling in Helper
  • Initialize FpsDisplayManager and set target window in constructor
  • Bind Meta+F11 to toggle slot and implement show/hide logic
  • Connect fpsDataChanged and visibilityChanged to QML item properties
src/seat/helper.h
src/seat/helper.cpp
Expose FPS display to QML engine
  • Add fpsDisplayComponent member and register QML type
  • Implement createFpsDisplay factory method
src/core/qmlengine.h
src/core/qmlengine.cpp
Update build and logging configuration
  • Include fpsdisplaymanager sources and QML file in CMakeLists
  • Add treeland.fpsdisplay logging category
src/CMakeLists.txt
src/common/treelandlogging.h
src/common/treelandlogging.cpp
Add QML UI for FPS overlay
  • Create FpsDisplay.qml with current and maximum FPS labels
  • Implement show/hide animations, styling and layout
src/core/qml/FpsDisplay.qml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/utils/fpsdisplaymanager.cpp:131` </location>
<code_context>
+
+void FpsDisplayManager::updateFps()
+{
+    if (!m_visible || m_vSyncTimes.isEmpty())
+        return;
+
</code_context>

<issue_to_address>
updateFps does not update if m_vSyncTimes is empty.

When no vsync events have occurred, the display may show outdated FPS values. Consider clearing or resetting the display when m_vSyncTimes is empty.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
void FpsDisplayManager::updateFps()
{
    if (!m_visible || m_vSyncTimes.isEmpty())
        return;
=======
void FpsDisplayManager::updateFps()
{
    if (!m_visible)
        return;

    if (m_vSyncTimes.isEmpty()) {
        if (m_displayItem) {
            // Clear or reset the FPS display when no vsync events have occurred
            m_displayItem->setProperty("text", QStringLiteral("N/A"));
        }
        return;
    }
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `src/utils/fpsdisplaymanager.cpp:186` </location>
<code_context>
+{
+    m_displayRefreshRate = 60;
+    if (m_targetWindow) {
+        if (auto screen = m_targetWindow->screen()) {
+            qreal refreshRate = screen->refreshRate();
+            if (refreshRate > 0) {
</code_context>

<issue_to_address>
No handling for screens with refreshRate() returning zero.

Recommend adding a warning log when the refresh rate is zero to aid in diagnosing display issues.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
            qreal refreshRate = screen->refreshRate();
            if (refreshRate > 0) {
                m_displayRefreshRate = qRound(refreshRate);
                qCDebug(treelandFpsDisplay) << "Detected display refresh rate:" << m_displayRefreshRate << "Hz";
                return;
            }
=======
            qreal refreshRate = screen->refreshRate();
            if (refreshRate > 0) {
                m_displayRefreshRate = qRound(refreshRate);
                qCDebug(treelandFpsDisplay) << "Detected display refresh rate:" << m_displayRefreshRate << "Hz";
                return;
            } else {
                qCWarning(treelandFpsDisplay) << "Screen refresh rate is zero or negative; using default value (" << m_displayRefreshRate << "Hz).";
            }
>>>>>>> REPLACE

</suggested_fix>

### Comment 3
<location> `src/utils/fpsdisplaymanager.cpp:207` </location>
<code_context>
+    }
+}
+
+class FpsDisplayItem : public QQuickPaintedItem
+{
+    Q_OBJECT
</code_context>

<issue_to_address>
Consider moving the FpsDisplayItem class to its own files and removing manual event handling, relying on Qt's built-in input disabling instead.

```suggestion
Split out the UI class and drop the huge `event()` + per‐event overrides – you can rely on Qt’s built-in “disabled” behavior and input flags instead of manually ignoring every QEvent. For example:

// In FpsDisplayItem.h
#pragma once
#include <QQuickPaintedItem>

class FpsDisplayItem : public QQuickPaintedItem {
public:
    explicit FpsDisplayItem(QQuickItem *parent = nullptr)
      : QQuickPaintedItem(parent)
    {
        // disable all input
        setEnabled(false);
        setAcceptedMouseButtons(Qt::NoButton);
        setAcceptHoverEvents(false);
        setAcceptTouchEvents(false);
        setFlag(ItemAcceptsInputMethod,   false);
        setFlag(ItemAcceptsDrops,         false);
        setFlag(ItemIsFocusScope,         false);
        setFlag(ItemHasContents,          true);

        // initial geometry
        setVisible(false);
        setWidth(130);
        setHeight(45);
    }

    void paint(QPainter *p) override {
        // ... your existing rendering code ...
    }

    // no Q_OBJECT, no event()/mouse/key/focus overrides
};

---> move the above into its own FpsDisplayItem.{h,cpp}, remove
the embedded class in fpsdisplaymanager.cpp and delete
all event()/mouse*/key*/focus*/hover*/touch*/moc-related lines.
This cuts the boilerplate and makes fpsdisplaymanager.cpp much sharper
and focused purely on FPS logic.
</issue_to_address>

### Comment 4
<location> `src/utils/fpsdisplaymanager.h:17` </location>
<code_context>
+class QQuickWindow;
+class QScreen;
+
+class FpsDisplayManager : public QObject
+{
+    Q_OBJECT
</code_context>

<issue_to_address>
Consider removing unused slots and moving implementation details from the header to the source file to simplify the public interface.

```cpp
// 1) Remove the unused private slot
--- a/FpsDisplayManager.h
@@ private:
-    void clampFpsToRefreshRate();


// 2) Move the two constexprs out of the public header into the .cpp
--- a/FpsDisplayManager.h
@@ private:
-    static constexpr int MAX_SAMPLES = 120;           // 2 seconds of samples at 60Hz
-    static constexpr int UPDATE_INTERVAL_MS = 500;    // UI update frequency in milliseconds

--- a/FpsDisplayManager.cpp
@@ top of file
+namespace {
+    constexpr int kMaxSamples       = 120; // 2 seconds at 60Hz
+    constexpr int kUpdateIntervalMs = 500; // UI update frequency (ms)
+}

// in your code replace MAX_SAMPLES → kMaxSamples, UPDATE_INTERVAL_MS → kUpdateIntervalMs


// 3) (Optional) Group the two QColor members into a small Style struct
--- a/FpsDisplayManager.h
@@ private:
-    QColor m_textColor   = QColor(0, 0, 0);
-    QColor m_shadowColor = QColor(255, 255, 255, 150);
+    struct Style {
+        QColor text   = QColor(0, 0, 0);
+        QColor shadow = QColor(255, 255, 255, 150);
+    } m_style;

--- a/FpsDisplayManager.h
@@ public:
-    void setTextColor(const QColor &color)   { m_textColor   = color; }
-    void setShadowColor(const QColor &color) { m_shadowColor = color; }
+    void setTextColor(const QColor &c)   { m_style.text   = c; }
+    void setShadowColor(const QColor &c) { m_style.shadow = c; }
```

These changes remove the dead slot, shrink your public header, and push implementation details into the .cpp without altering any functionality.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Dami-star Dami-star force-pushed the FPS branch 2 times, most recently from 976c9de to 254da9b Compare September 10, 2025 03:41
@Dami-star Dami-star requested review from wineee and zccrs September 10, 2025 03:41
wineee
wineee previously approved these changes Sep 10, 2025
@deepin-bot
Copy link

deepin-bot bot commented Sep 18, 2025

TAG Bot

New tag: 0.7.1
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #560

@Dami-star Dami-star force-pushed the FPS branch 2 times, most recently from b7e4227 to 7779098 Compare September 18, 2025 07:04
@Dami-star Dami-star marked this pull request as draft September 18, 2025 07:08
@Dami-star Dami-star marked this pull request as ready for review September 18, 2025 11:20
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • All user-facing FPS strings are hardcoded in English; wrap them in tr()/qsTr() so the overlay can be localized.
  • The QML item creation and signal wiring in Helper adds a lot of UI logic to that class—consider moving it into a dedicated controller to keep Helper focused on input/session handling.
  • Rather than manually new/deleteLater the QQuickItem, set its parent or use a QScopedPointer/QPointer to manage the lifecycle more robustly and avoid potential leaks.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- All user-facing FPS strings are hardcoded in English; wrap them in tr()/qsTr() so the overlay can be localized.
- The QML item creation and signal wiring in Helper adds a lot of UI logic to that class—consider moving it into a dedicated controller to keep Helper focused on input/session handling.
- Rather than manually new/deleteLater the QQuickItem, set its parent or use a QScopedPointer/QPointer to manage the lifecycle more robustly and avoid potential leaks.

## Individual Comments

### Comment 1
<location> `src/utils/fpsdisplaymanager.cpp:32-41` </location>
<code_context>
+    m_updateTimer.stop();
+    m_vsyncTimer.stop();
+
+    if (m_targetWindow) {
+        disconnect(m_targetWindow, nullptr, this, nullptr);
+    }
+}
+
+void FpsDisplayManager::setTargetWindow(QQuickWindow *window)
+{
+    if (m_targetWindow == window)
+        return;
+
+    if (m_targetWindow) {
+        disconnect(m_targetWindow, nullptr, this, nullptr);
+    }
+
+    invalidateCache();
+    m_targetWindow = window;
+
+    if (m_targetWindow) {
+        updateRefreshAndInterval();
+        connect(m_targetWindow, &QQuickWindow::screenChanged,
+                this, &FpsDisplayManager::onScreenChanged, Qt::UniqueConnection);
+    }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Consider handling QQuickWindow destruction to avoid dangling pointers.

Since m_targetWindow is a QPointer, it will become nullptr if QQuickWindow is destroyed, but signals may remain connected. Connect to the destroyed() signal or implement a cleanup mechanism to ensure proper disconnection and prevent use-after-free issues.

Suggested implementation:

```cpp
    if (m_targetWindow) {
        disconnect(m_targetWindow, nullptr, this, nullptr);
        // Disconnect from destroyed signal if previously connected
        disconnect(m_targetWindow, &QObject::destroyed, this, &FpsDisplayManager::onTargetWindowDestroyed);
    }
}

```

```cpp
void FpsDisplayManager::setTargetWindow(QQuickWindow *window)
{
    if (m_targetWindow == window)
        return;

    if (m_targetWindow) {
        disconnect(m_targetWindow, nullptr, this, nullptr);
        disconnect(m_targetWindow, &QObject::destroyed, this, &FpsDisplayManager::onTargetWindowDestroyed);
    }

    invalidateCache();
    m_targetWindow = window;

    if (m_targetWindow) {
        updateRefreshAndInterval();
        connect(m_targetWindow, &QQuickWindow::screenChanged,
                this, &FpsDisplayManager::onScreenChanged, Qt::UniqueConnection);
        connect(m_targetWindow, &QObject::destroyed,
                this, &FpsDisplayManager::onTargetWindowDestroyed, Qt::UniqueConnection);
    }

```

```cpp
void FpsDisplayManager::onTargetWindowDestroyed()
{
    if (m_targetWindow) {
        disconnect(m_targetWindow, nullptr, this, nullptr);
        disconnect(m_targetWindow, &QObject::destroyed, this, &FpsDisplayManager::onTargetWindowDestroyed);
    }
    m_targetWindow = nullptr;
    invalidateCache();
}

```

You must declare the slot `void onTargetWindowDestroyed();` in the `FpsDisplayManager` class definition (likely in the header file, e.g., `fpsdisplaymanager.h`) and ensure it is marked as a slot if you use the Q_OBJECT macro.
</issue_to_address>

### Comment 2
<location> `src/utils/fpsdisplaymanager.cpp:205-209` </location>
<code_context>
+    }
+
+    // Environment variable override for debugging/testing
+    QString envRefreshRate = qgetenv("TREELAND_REFRESH_RATE");
+    if (!envRefreshRate.isEmpty()) {
+        bool ok;
+        int rate = envRefreshRate.toInt(&ok);
+        if (ok && rate > 0 && rate <= 240) {
+            m_displayRefreshRate = rate;
+        }
</code_context>

<issue_to_address>
**suggestion:** Hardcoded upper limit for refresh rate may restrict future hardware.

Consider allowing the maximum refresh rate to be configurable or increasing the limit to accommodate newer displays.

Suggested implementation:

```cpp
    // Environment variable override for debugging/testing

    // Allow maximum refresh rate to be configurable via environment variable
    int maxRefreshRate = 240; // Default upper limit
    QString envMaxRefreshRate = qgetenv("TREELAND_MAX_REFRESH_RATE");
    if (!envMaxRefreshRate.isEmpty()) {
        bool ok;
        int rate = envMaxRefreshRate.toInt(&ok);
        if (ok && rate > 0) {
            maxRefreshRate = rate;
        }
    }

```

```cpp
    QString envRefreshRate = qgetenv("TREELAND_REFRESH_RATE");
    if (!envRefreshRate.isEmpty()) {
        bool ok;
        int rate = envRefreshRate.toInt(&ok);
        if (ok && rate > 0 && rate <= maxRefreshRate) {
            m_displayRefreshRate = rate;
        }

```
</issue_to_address>

### Comment 3
<location> `src/seat/helper.cpp:2259-2254` </location>
<code_context>
+            m_fpsDisplay = nullptr;
+        }
+    } else {
+        if (!m_fpsDisplay) {
+            m_fpsDisplay = qmlEngine()->createFpsDisplay(m_renderWindow->contentItem());
+            if (m_fpsDisplay) {
+                connect(m_fpsDisplayManager, &FpsDisplayManager::fpsDataChanged,
+                        this, [this](const QString &currentFpsText, const QString &maximumFpsText) {
</code_context>

<issue_to_address>
**suggestion:** Consider handling errors from qmlEngine()->createFpsDisplay more robustly.

Log an error or warning if createFpsDisplay returns nullptr to improve visibility of QML loading failures.
</issue_to_address>

### Comment 4
<location> `src/core/qml/FpsDisplay.qml:16-25` </location>
<code_context>
+    property bool fpsVisible: false
+    property real scaleFactor: 1.0
+
+    Rectangle {
+        id: fpsDisplay
+        width: Math.max(200 * scaleFactor, 180)
+        height: Math.max(80 * scaleFactor, 70)
+        color: "transparent"
+        radius: 8 * scaleFactor
+        border.color: "transparent"
+        border.width: 0
+        
+        anchors {
+            top: parent.top
+            right: parent.right
+            margins: 20 * scaleFactor
+        }
+        
+        visible: fpsVisible
+        opacity: fpsVisible ? 1.0 : 0.0
+        scale: fpsVisible ? 1.0 : 0.8
+        
</code_context>

<issue_to_address>
**suggestion:** Consider accessibility and contrast for text colors.

Since the background is transparent, text may be hard to read on varying backgrounds. Adding a semi-transparent background or shadow can improve accessibility.

Suggested implementation:

```
        color: "#AA222222" // semi-transparent dark background for better contrast

```

```
        radius: 8 * scaleFactor
        border.color: "transparent"
        border.width: 0

        // Add shadow for accessibility
        layer.enabled: true
        layer.effect: DropShadow {
            color: "#80000000"
            radius: 8 * scaleFactor
            samples: 16
            horizontalOffset: 0
            verticalOffset: 2 * scaleFactor
        }

        anchors {
            top: parent.top
            right: parent.right
            margins: 20 * scaleFactor
        }

        visible: fpsVisible
        opacity: fpsVisible ? 1.0 : 0.0
        scale: fpsVisible ? 1.0 : 0.8

```
</issue_to_address>

### Comment 5
<location> `src/utils/fpsdisplaymanager.cpp:13` </location>
<code_context>
+
+FpsDisplayManager::FpsDisplayManager(QObject *parent)
+    : QObject(parent)
+    , m_updateTimer(this)
+    , m_vsyncTimer(this)
+{
</code_context>

<issue_to_address>
**issue (complexity):** Consider replacing manual vsync and refresh logic with a frame counter using QQuickWindow::frameSwapped for simpler and more maintainable FPS calculation.

Here’s a way to collapse all of the manual vsync‐jitter, queue, refresh detection, etc., into one simple “count frames between timer ticks” flow using QQuickWindow::frameSwapped:

1) Remove m_vsyncTimer, onVSyncTimer(), m_vSyncTimes, detectDisplayRefreshRate(), findBestOutput(), getOutputForWindow(), invalidateCache(), etc.  
2) In setTargetWindow() connect to frameSwapped instead of screen/window timers:  
```cpp
void FpsDisplayManager::setTargetWindow(QQuickWindow *window) {
    if (m_targetWindow == window) return;
    if (m_targetWindow) {
        disconnect(m_targetWindow, nullptr, this, nullptr);
    }
    m_targetWindow = window;
    if (m_targetWindow) {
        connect(m_targetWindow,
                &QQuickWindow::frameSwapped,
                this,
                &FpsDisplayManager::onFrameSwapped,
                Qt::UniqueConnection);
    }
}
```

3) Keep just one QTimer (m_updateTimer) and a simple frame counter:  
```cpp
// in header:
qint64    m_lastUpdate = 0;
int       m_frameCount  = 0;

// slot:
void FpsDisplayManager::onFrameSwapped() {
    if (!m_visible) return;
    ++m_frameCount;
}

// called by m_updateTimer every kUpdateIntervalMs
void FpsDisplayManager::updateFps() {
    qint64 now = m_timer.elapsed();
    qint64 dt  = now - m_lastUpdate;
    if (dt < kUpdateIntervalMs) return;

    // raw fps
    double rawFps = (m_frameCount * 1000.0) / dt;
    m_frameCount  = 0;
    m_lastUpdate  = now;

    // optional smoothing
    const double α = 0.15;
    if (m_currentFps == 0) {
        m_currentFps = rawFps;
    } else {
        m_currentFps = m_currentFps*(1-α) + rawFps*α;
    }

    emit fpsDataChanged(
        QStringLiteral("Current FPS: %1").arg(qRound(m_currentFps)),
        QStringLiteral("Maximum FPS: %1").arg(qRound(m_currentFps)) );
}
```

This:
- Drops manual vsync‐jitter and queue logic  
- Drops custom refresh‐rate detection (you’ll still get whatever the GPU/OS is actually delivering)  
- Keeps smoothing entirely in one place  
- Preserves the existing “update every N ms” behavior  
- All functionality and public API remain unchanged.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Dami-star Dami-star requested review from wineee and zccrs September 18, 2025 11:32
@Dami-star Dami-star marked this pull request as draft September 18, 2025 12:02
@Dami-star Dami-star marked this pull request as ready for review September 18, 2025 13:25
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Dami-star, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-bot
Copy link

deepin-bot bot commented Sep 19, 2025

TAG Bot

New tag: 0.7.2
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #562

Copy link
Member

@zccrs zccrs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对fpsdisplaymanager的改造添加一些todo,以后再做。比如绑定为WOutput(或者是WOutputViewport?)

@Dami-star
Copy link
Collaborator Author

@sourcery-ai resolve

@Dami-star
Copy link
Collaborator Author

对fpsdisplaymanager的改造添加一些todo,以后再做。比如绑定为WOutput(或者是WOutputViewport?)

已经在src/utils/fpsdisplaymanager.h 添加TODO,为多屏每个屏幕计算FPS。

zccrs
zccrs previously approved these changes Sep 22, 2025
@deepin-bot
Copy link

deepin-bot bot commented Sep 23, 2025

TAG Bot

New tag: 0.7.3
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #569

Introduces an on-screen FPS overlay with timer-based sampling aligned
to the active screen’s refresh rate. automatic refresh-rate handling
on screen changes.
@zccrs zccrs merged commit 16240cb into linuxdeepin:master Sep 26, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants