Table of Contents

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

registry IServiceRegistry

The 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

float

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

float

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

float?

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

float

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

window GameWindow

The 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

game IGame

The 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

gameTime GameTime

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

Event Type

EventHandler