Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions docs/motion-and-high-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Summary of current engine behavior (Flutter 3.24+ / Impeller). Sources in §7.
| Platform | Renders at display Hz by default? | How to unlock > 60 Hz | Notes |
|----------|-----------------------------------|------------------------|-------|
| **Windows** | Usually yes (follows monitor via DWM) | No app API needed | Verify on a 120/144 Hz monitor; engine vsyncs to the compositor. |
| **Linux** | Depends on compositor (GTK embedder) | No app API; compositor-dependent | Wayland compositors with VRR may need monitor config; X11 follows monitor. |
| **Linux** | Depends on compositor (GTK embedder) | **No app unlock** — `RefreshRate.enable()` is a **no-op** | Plugin is **query-only** (`gdk_monitor_get_refresh_rate`). Overlay shows compositor-reported Hz; it does **not** force 120+. Configure the Wayland/X11 compositor / monitor for VRR/high-Hz. |
| **macOS** | Capped to 60 on some setups | macOS 14+ can opt into ProMotion/high-Hz | Historically Flutter macOS did not always hit ProMotion; needs verification. |
| **iOS** (future) | No — capped to 60 | `CADisableMinimumFrameDurationOnPhone=true` in `Info.plist` | Not applicable today (no `ios/`), document for when mobile lands. |
| **Android** (future) | No — often picks 60 | `flutter_displaymode` / `Surface.setFrameRate()` | Not applicable today (no `android/`). |
Expand All @@ -64,9 +64,10 @@ Root cause (engine): per `flutter/flutter#160952`, the engine "can render at 120

### Practical implication for Querya (desktop)

- **Windows / Linux:** most likely already render at monitor Hz; the job is to **measure and verify**, then ensure no app-side code caps frames (e.g. heavy `setState`, unbounded rebuilds during animation).
- **macOS:** the real high-Hz work — confirm ProMotion behavior; unlock via `refresh_rate` if capped at 60.
- Use `refresh_rate` (or a thin wrapper) primarily for **diagnostics**: a debug-only FPS/Hz overlay and a benchmark to prove smoothness on each machine, plus the macOS unlock call in `main()`.
- **Windows:** usually follows DWM monitor Hz; **measure and verify**.
- **Linux:** **query-only** — `enable` / prefer-max are no-ops in `third_party/refresh_rate` Linux plugin. Overlay/`RefreshRate.info` report what GDK sees; actual frame pacing is compositor-dependent. Do not treat a 120/144 reading as “unlocked by Querya”.
- **macOS:** unlock via `RefreshRate.enable()` when capped at 60 (ProMotion / high-Hz).
- Use `refresh_rate` for **diagnostics** (debug overlay / benchmark) plus the macOS unlock in `main()`.
- **Implementation:** `lib/core/motion/display_refresh_service.dart` calls `RefreshRate.enable()` in `main()`. Debug Hz badge: `flutter run --dart-define=QUERYA_REFRESH_OVERLAY=true`.

---
Expand Down Expand Up @@ -167,7 +168,7 @@ The table below shows the measured refresh rates and frame times on target monit
| Platform | Monitor Target | Before 0.4.4 | After 0.4.4 | Frame Build/Raster Time (Max) | Status |
|----------|----------------|--------------|-------------|--------------------------------|--------|
| **Windows 11 (DWM)** | 120 Hz | 120 Hz | 120 Hz | 4.2 ms / 2.8 ms (under 8.3ms) | verified |
| **Linux (Ubuntu X11)** | 144 Hz | 144 Hz | 144 Hz | 3.5 ms / 3.0 ms (under 6.9ms) | verified |
| **Linux (Ubuntu X11)** | 144 Hz | 144 Hz | 144 Hz | 3.5 ms / 3.0 ms (under 6.9ms) | verified (compositor Hz; query-only) |
| **macOS 14+ (ProMotion)** | 120 Hz | 60 Hz | 120 Hz | 4.8 ms / 3.2 ms (under 8.3ms) | verified (unlocked) |

*Note: macOS ProMotion requires `RefreshRate.enable()` called in `main()` to bypass the default 60 Hz cap.*
1 change: 1 addition & 0 deletions docs/perf-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ To verify that the motion system conforms to the budget and does not cause jank
- 120 Hz budget: **8.3 ms** per frame
- 144 Hz budget: **6.9 ms** per frame
6. **Hz Verification**: Run the app with `--dart-define=QUERYA_REFRESH_OVERLAY=true` in a debug/profile build. The floating overlay must show the correct target Hz.
- **Linux:** overlay is **query-only** (`RefreshRate.enable` is a no-op). Confirm the compositor/monitor is actually driving that Hz (Wayland/X11 settings); Querya cannot unlock a higher rate.
7. **Animation Smoothness (DevTools)**:
- Record the timeline in the **Performance** tab while triggering animations (dialog fade-in, tree expand/collapse, tab cross-fading, dropdown show).
- Ensure the frame build and raster times stay below the respective Hz budget (e.g., < 8.3 ms on a 120 Hz monitor).
Expand Down
10 changes: 7 additions & 3 deletions lib/core/motion/display_refresh_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import 'package:refresh_rate/refresh_rate.dart';

/// Desktop display refresh-rate unlock and diagnostics (UI-A4 / #174).
///
/// Calls [RefreshRate.enable] once at startup (macOS 14+ ProMotion unlock;
/// query on Windows/Linux). Debug overlay: run with
/// `--dart-define=QUERYA_REFRESH_OVERLAY=true`.
/// Calls [RefreshRate.enable] once at startup:
/// - **macOS 14+:** ProMotion / high-Hz unlock
/// - **Windows:** typically follows DWM (enable is effectively a no-op unlock)
/// - **Linux:** **query-only** — enable is a no-op; [RefreshRate.info] / overlay
/// report GDK monitor refresh (compositor decides actual pacing)
///
/// Debug overlay: `flutter run --dart-define=QUERYA_REFRESH_OVERLAY=true`.
abstract final class DisplayRefreshService {
static const bool _overlayFromEnvironment = bool.fromEnvironment(
'QUERYA_REFRESH_OVERLAY',
Expand Down
Loading