Hyprland VRR Configuration: Enabling Variable Refresh Rate Per-Monitor and Globally
TLDR: Hyprland enables Variable Refresh Rate through a monitor rule parser that reads vrr values in src/config/shared/monitor/Parser.cpp, applies them via CMonitorRuleManager::ensureVRR() in MonitorRuleManager.cpp, and falls back to the misc:vrr integer setting when no per-monitor rule exists.
Hyprland VRR configuration controls adaptive sync behavior across displays in the Hyprland Wayland compositor. The repository implements a tiered system where per-monitor rules override a global misc:vrr fallback, with runtime state tracked in each CMonitor instance. Understanding this pipeline is essential for eliminating screen tearing without sacrificing performance.
Parsing Hyprland VRR Configuration Rules
When a configuration line contains vrr = <int>, Hyprland routes the string to CMonitorRuleParser::parseVRR in src/config/shared/monitor/Parser.cpp. This method validates that the input is numeric, converts it with std::stoi, and stores the result in CMonitorRule::m_vrr.
The parser treats negative values as an explicit disable, assigning std::nullopt, while zero or positive values are stored as an active optional integer:
// src/config/shared/monitor/Parser.cpp
bool CMonitorRuleParser::parseVRR(const std::string& value) {
if (!isNumber(value)) { m_error += "invalid vrr "; return false; }
const auto VRR = std::stoi(value);
m_rule.m_vrr = VRR < 0 ? std::nullopt : std::optional(VRR);
return true;
}
(source: Parser.cpp L64‑L73)
Applying VRR Settings to Monitors
CMonitorRuleManager::ensureVRR and Global Fallback
After the monitor configuration loads, CMonitorRuleManager::ensureVRR() is invoked for each output. The implementation in src/config/shared/monitor/MonitorRuleManager.cpp first queries the global fallback from misc:vrr using CConfigValue<Config::INTEGER>("misc:vrr").
The effective VRR setting, USEVRR, prioritizes the monitor rule if present; otherwise it inherits the global value:
// src/config/shared/monitor/MonitorRuleManager.cpp (excerpt)
void CMonitorRuleManager::ensureVRR(PHLMONITOR pMonitor) {
static auto PVRR = CConfigValue<Config::INTEGER>("misc:vrr");
const auto USEVRR = m->m_activeMonitorRule.m_vrr.has_value()
? m->m_activeMonitorRule.m_vrr.value() : *PVRR;
// … logic that enables/disables VRR based on USEVRR and fullscreen state …
}
(source: MonitorRuleManager.cpp L195‑L210)
Depending on USEVRR, the compositor either enables adaptive sync, forces it off, or decides dynamically based on fullscreen and window state.
Runtime VRR State Tracking
Each CMonitor instance maintains a boolean flag reflecting whether VRR is currently active. In src/output/Monitor.hpp, the member m_vrrActive is initialized to false and updated after ensureVRR() succeeds:
// src/output/Monitor.hpp
bool m_vrrActive = false; // true when adaptive‑sync (VRR) is active
(source: Monitor.hpp L107)
Global VRR Fallback Behavior
The misc:vrr Config Values
The global default is defined in src/config/values/ConfigValues.cpp under the key misc:vrr. According to the Hyprland source code, this integer controls the default adaptive sync policy when no per-monitor rule overrides it:
- 0 – VRR is never enabled.
- 1 – VRR is enabled unless a window explicitly disables it with the
no_vrrrule. - 2 – VRR is enabled only when a fullscreen window is present.
- 3 – VRR is enabled for fullscreen windows and when the content type is a game or video.
// src/config/values/ConfigValues.cpp
MS<Int>("misc:vrr", "controls the VRR (Adaptive Sync) of your monitors", 0,
(source: ConfigValues.cpp L483‑L485)
Interaction with Fullscreen Windows and Window Rules
When a window specifies the no_vrr rule, ensureVRR() respects that restriction and may temporarily disable adaptive sync while that window is fullscreen. This logic is handled inside the fullscreen controller. You can force VRR off for specific applications with a window rule:
windowrule = no_vrr, class:Firefox
Practical Hyprland VRR Configuration Examples
Per-Monitor VRR Rules
To enable VRR on a single display, define the monitor rule with the vrr value. The following example sets a monitor and enables its adaptive sync:
monitor=HDMI-A-1,2560x1440,60,1 # last “1” enables VRR for this monitor
Global VRR Settings
Use the misc:vrr key to set compositor-wide behavior. For instance, disabling VRR entirely or limiting it to fullscreen contexts:
misc:vrr = 0
misc:vrr = 2
The first snippet disables VRR globally. The second enables it only when a fullscreen window is active.
Lua Configuration
For Lua-based setups, assign the rule table directly and set the global fallback:
-- Enable VRR for the primary monitor
monitorRule = {
name = "eDP-1",
vrr = 1,
}
-- Global fallback: VRR only when a fullscreen window is active
Config.misc.vrr = 2
Summary
- Per-monitor parsing:
CMonitorRuleParser::parseVRRinsrc/config/shared/monitor/Parser.cppvalidates and stores thevrrinteger asstd::optional<int>inm_rule.m_vrr. - Rule application:
CMonitorRuleManager::ensureVRR()insrc/config/shared/monitor/MonitorRuleManager.cppresolves the effective VRR value by checking the monitor rule first, then the globalmisc:vrrfallback. - State tracking: Each output stores its live adaptive sync status in
CMonitor::m_vrrActive, defined insrc/output/Monitor.hpp. - Global fallback values:
misc:vrraccepts0through3, controlling whether VRR is off, always on, fullscreen-only, or content-type aware. - Window-level overrides: The
no_vrrwindow rule suppresses VRR for specific applications, even when fullscreen.
Frequently Asked Questions
How do I enable VRR for a specific monitor in Hyprland?
Define a per-monitor rule with the vrr field. As implemented in src/config/shared/monitor/Parser.cpp, parseVRR() converts a positive integer into an enabled rule stored in CMonitorRule::m_vrr, which ensureVRR() then applies to that output. For example, set monitor=HDMI-A-1,2560x1440,60,1 to target that display.
What does the misc:vrr setting control?
misc:vrr acts as the global fallback when no per-monitor rule exists. Defined in src/config/values/ConfigValues.cpp, it accepts values 0 through 3: 0 disables adaptive sync entirely, 1 enables it by default, 2 restricts it to fullscreen windows, and 3 includes game or video content types.
Can I disable VRR for individual windows?
Yes. The no_vrr window rule instructs the fullscreen controller to temporarily suspend adaptive sync for matching clients. CMonitorRuleManager::ensureVRR() checks this condition and can force VRR off while the restricted window is active.
Where is the active VRR state stored at runtime?
Each monitor object tracks its current adaptive sync status in the m_vrrActive boolean, declared in src/output/Monitor.hpp at line 107. Additional layout-wide queries are available through isVRRActiveOnAnyMonitor() in src/state/MonitorLayoutController.hpp.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →