Adding Dynamic Resolution in Godot
As mentioned in the Previous Post, an option for dynamic resolution has been added to our upcoming game. This allows the optimal resolution scale to be identified at runtime, helping it run smoothly on a wider range of hardware.
The primary cause of the performance issues on macOS was the notably high resolution of the HiDPI screen. Since the MacBook used for testing had fixed specifications, we could find an optimal resolution scale for that device. However, using a single scale across all Apple devices would be less than ideal for players with higher-end machines - enter dynamic resolution scaling.
Resolution scaling is quite common in most games nowadays. It offers the ability for users to reduce the rendering resolution of the game without having to endure annoying resolution changes when alt-tabbing out of a game. The naming convention is not always consistent, for example, in Far Cry 6 it is known as "adaptive resolution", whereas in Final Fantasy XIV it is known as "dynamic resolution", but they all do the same thing.

By creating a node that is capable of monitoring the frame rate of the game against a target frame rate, it's possible to have the game itself find the ideal resolution scale, without having to expose a resolution scale setting that may not be ideal for users who:
- Don't fully understand what the graphics settings are outside of using presets like "Low", "Normal", "High", "Ultra High", "Super Ultra High Turbo Alpha 2"
- Don't want to have to fine-tune a slider that exposes the full range of values from
0.0to1.0(or higher if you want to enable super sampling).
The current implementation of the resolution scaler can be found below. It includes 3 properties that need to be set in the editor:
- Frames to Ignore: when your game is initialising, there's going to be some low reported frame rates. If you don't ignore an arbitrary number of frames, the resolution scaler will start to reduce the resolution scale far below what the user needs. The optimal amount found during testing for this is
120and is the default value. - Maximum Scale: if the frame rate is above the target frame rate, the scaler will begin to raise the resolution scale again. If you want to avoid super sampling, then leave this set to
1.0. - Target FPS: the FPS that the scaler should aim to bring the user toward.
## A utility node that will poll the frame rate of the game every second
## and change the resolution scale accordingly to attempt to keep the game
## running at the desired frame rate.
class_name ResolutionScaler
extends Node
@export var enabled: bool = false
## The number of frames to ignore on startup before scaling the resolution.
## [br][br]
## [b]Note[/b]: This will reduce the likelihood of unnecessarily reducing the
## scale to very low values during initialisation.
@export var frames_to_ignore: int = 120
## The maximum scale value to be applied once the target frame rate is reached.
@export var maximum_scale: float = 1.0
## The FPS that the scaling aims to achieve and maintain.
@export_range(20, 200, 1.0) var target_fps: int = 60
var _ignored_frames: int = 0
var _timer: Timer
func _ready() -> void:
_timer = Timer.new()
_timer.wait_time = 1.0
_timer.timeout.connect(_on_timer_timeout)
add_child(_timer)
func _process(delta: float) -> void:
if _ignored_frames < frames_to_ignore:
_ignored_frames += 1
return
if enabled and _timer.is_stopped():
_timer.start()
elif not enabled and not _timer.is_stopped():
_timer.stop()
func _on_timer_timeout() -> void:
var fps := Engine.get_frames_per_second()
var viewport := get_viewport()
var adjustment_multiplier: float = fps / target_fps
viewport.scaling_3d_scale = minf(
viewport.scaling_3d_scale * adjustment_multiplier,
maximum_scale
)
Any updates to this script will be published on GitHub in the following repository: https://github.com/FiveNineGames/godot-resolution-scaler
To use it, simply drop the script [resolution_scaler.gd] in your preferred location and add a ResolutionScaler to your scene. Set up the properties as explained above, and the scaler will dynamically handle everything for you as long as the enabled property is set to true.
Alternatively, you can install directly from the AssetLib tab by searching for "Resolution Scaler"