Skip to content

Correct the drawing surface density on non-HiDPI displays (macOS) - #113

Open
hard25670559 wants to merge 1 commit into
PathOfBuildingCommunity:masterfrom
hard25670559:upstream/macos-display-scaling
Open

Correct the drawing surface density on non-HiDPI displays (macOS)#113
hard25670559 wants to merge 1 commit into
PathOfBuildingCommunity:masterfrom
hard25670559:upstream/macos-display-scaling

Conversation

@hard25670559

Copy link
Copy Markdown

Problem

On macOS, the layer being rendered into can be left at a 2x contents scale while the window reports a 1x backing 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.

The macOS packaging fork currently works around this by disabling the Retina/DPI_AWARE renderer path entirely (stevschmid/PathOfBuilding-Mac#3), noting there that 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 depending on the resize that may 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 compiles to nothing and the helper lives in the existing macOS platform file.

If this lands, the workaround in the macOS packaging fork can be reverted so that build 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.
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