Skip to content

Correct the drawing surface density on non-HiDPI displays - #1

Open
hard25670559 wants to merge 1 commit into
stevschmid:macos-portfrom
hard25670559:fix/macos-display-scaling
Open

Correct the drawing surface density on non-HiDPI displays#1
hard25670559 wants to merge 1 commit into
stevschmid:macos-portfrom
hard25670559:fix/macos-display-scaling

Conversation

@hard25670559

Copy link
Copy Markdown

Problem

On a display reporting a 1x backing scale, the layer being rendered into can be left at a 2x contents scale. The real drawing surface is then twice the size the window system reports, and everything is drawn into the lower-left quarter of the window. Resizing the window or dragging it to another display rebuilds the surface and restores it, which is why the problem looks like it "fixes itself".

This is the startup bug described in stevschmid/PathOfBuilding-Mac#3, which is currently worked around by running the macOS bundle without the Retina/DPI_AWARE renderer path, and noted there as External display/DPI change is out of scope for the moment.

Cause

GLFW pushes the window's backing scale onto the layer only from updateContentScale, i.e. when the scale changes:

if (window->ns.scaleFramebuffer && window->ns.layer)
    [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];

A window that opens with the wrong scale and then stays on one display never sees a change, so it is never corrected.

Change

Compare the layer's contents scale against the window's backing scale each frame, correct it when they diverge, and re-read the framebuffer size when it does. The check is a float comparison against a cached value and does nothing in the common case.

This also keeps the surface correct when a window is moved between displays of differing density, rather than relying on the resize that happens to accompany it.

Verification

Built for arm64-osx and run on a three-display setup (2560x1440 @1x main, 1728x1117 @2x built-in, 1920x1080 @1x).

  • Before: launching on the 1x main display renders into the lower-left quarter until the window is resized or dragged across displays.
  • After: renders correctly on launch on every display, and stays correct when dragged between displays of different density.

Measured on the affected display before the change: viewBounds=1280x720 layerScale=2.00 winBacking=1.00 screenBacking=1.00.

Notes

Non-Apple platforms are unaffected — SyncSurfaceScale is compiled out and the new helper lives in the existing macOS platform file.

If this lands, the workaround in stevschmid/PathOfBuilding-Mac#3 can be reverted so the macOS bundle regains the Retina renderer path.

The layer being rendered into can be left at a 2x contents scale while
the window reports a 1x backing scale, making the real drawing surface
twice the size the window system reports. Everything is then drawn into
the lower-left quarter of the window, and only resizing the window or
dragging it to another display — either of which rebuilds the surface —
restores it.

GLFW pushes the window's backing scale onto the layer only when the
content scale changes, so a window that opens with the wrong scale and
stays on one display is never corrected.

Compare the layer's scale against the window's backing scale each frame,
correct it when they diverge, and re-read the framebuffer size when it
does. This also keeps the surface right when the window moves between
displays of differing density.
@hard25670559

Copy link
Copy Markdown
Author

Also submitted upstream as PathOfBuildingCommunity#113, since the fix belongs to the engine rather than to packaging. Keeping this open in case you'd like it in the macOS branch sooner — happy to close it if you'd rather wait for upstream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant