Class DisplayScale
- Namespace
- Stride.CommunityToolkit.Rendering
- Assembly
- Stride.CommunityToolkit.dll
The factor anything measured in pixels should be multiplied by to look the size it was designed at on the display the game is on: 1 on a 100% display, 1.5 on a 150% one, 2 on a Retina screen.
public sealed class DisplayScale : GameSystemBase, IDisposable, ICollectorHolder, IGameSystemBase, IComponent, IReferencable, IUpdateable, IDrawable, IContentable
- Inheritance
-
DisplayScale
- Implements
- Inherited Members
Examples
var scale = DisplayScale.GetOrCreate(game);
borderWidth = 3f * scale.Value;
scale.Changed += (_, _) => RebuildFontAtlas(scale.Value);
Remarks
"4K" is two different things, and only the DPI tells them apart. A 4K laptop at 200% scaling has the same physical area as a 1080p one, so 16-pixel text is now half the height to the eye - a bug. A 4K monitor at 100% has more area, and its owner bought it to see more, not bigger - the same text is correct there. Scaling by the window size would get one of those wrong; scaling by this gets both right. It is what every game's "UI scale" slider defaults to.
It applies to what is measured in pixels: a debug overlay's font, a screen-space label, a shape outline that is "3 pixels wide". Anything measured in world units already scales with the view and needs nothing.
Where the number comes from. Two sources, and the larger wins. ScaleFactor is drawable pixels per window unit: 1 on Windows and X11, 2 on a Retina display or a scaled Wayland desktop, where the window is measured in points and the backbuffer is finer. On Windows the backbuffer matches the window and the whole difference is the operating system's scale setting, which SDL reports as the display DPI over 96; it follows the process's DPI awareness, so an unaware process - one Windows is already stretching - correctly reads 1. Stride draws sprites in backbuffer pixels either way, which is why one number serves both cases rather than the two the Box2D samples keep apart.
Verified on Windows. On X11 with a scale set through Xft.dpi or GDK_SCALE nothing
here can see it - SDL's DPI there is the panel's physical density, not the setting - so the value
stays 1; supply a Source that reads the setting if that matters to you.
The value is re-read when the window changes size, which is also what happens when it moves to a monitor with a different scale, and every second regardless as a safety net. Changed fires when it differs; consumers holding a rasterised font at the old size rebuild it then.
Override is the user's setting and always wins: a game's own UI-scale option, or a developer who wants the overlay small. Source replaces the detection itself, for a platform where the built-in query is wrong or a better one exists.
Constructors
DisplayScale(IServiceRegistry)
Initializes a new instance. Prefer GetOrCreate(IGame), which shares one instance.
public DisplayScale(IServiceRegistry registry)
Parameters
registryIServiceRegistryThe service registry the game is running in.
Fields
MinScale
The smallest value ever reported, so a broken query cannot make everything vanish.
public static readonly float MinScale
Field Value
Properties
Detected
Gets the factor the display reports, ignoring any Override. 1 until the window exists and has been queried.
public float Detected { get; }
Property Value
Override
Gets or sets a value that replaces detection altogether: the user's own UI-scale setting, or a fixed size for a screenshot. null, the default, uses Detected.
public float? Override { get; set; }
Property Value
Source
Gets or sets a replacement for the built-in detection, given the window and returning the factor, or null to fall back to the built-in query. For a platform where the SDL answer is wrong, or a better source - a Windows DPI helper, a settings file.
public Func<GameWindow, float?>? Source { get; set; }
Property Value
- Func<GameWindow, float?>
Value
Gets the factor to multiply pixel sizes by: Override if set, otherwise Detected, never below MinScale.
public float Value { get; }
Property Value
Methods
Detect(GameWindow)
The built-in query: the larger of Stride's drawable-per-window-unit factor and the SDL display DPI over 96, for the reasons given on the class.
public static float Detect(GameWindow window)
Parameters
windowGameWindowThe window to measure for.
Returns
- float
The factor, or 1 when nothing could be read.
GetOrCreate(IGame)
Returns the display scale registered with the game, creating and registering one if there is none, so every consumer reads the same number and reacts to the same change.
public static DisplayScale GetOrCreate(IGame game)
Parameters
gameIGameThe game to attach to.
Returns
- DisplayScale
The shared instance.
Refresh()
Re-reads the display now rather than waiting for the next window change or poll.
public void Refresh()
Update(GameTime)
public override void Update(GameTime gameTime)
Parameters
gameTimeGameTime
Events
Changed
Raised after Value changes - the window moved to a differently scaled monitor, or Override was set. Consumers that rasterise at the scale rebuild here.
public event EventHandler? Changed