Skip to content

ios: report view pixel size + contentScaleFactor as dpi_scale#649

Merged
not-fl3 merged 1 commit into
not-fl3:masterfrom
benface:pr-ios-view-metrics
Jun 15, 2026
Merged

ios: report view pixel size + contentScaleFactor as dpi_scale#649
not-fl3 merged 1 commit into
not-fl3:masterfrom
benface:pr-ios-view-metrics

Conversation

@benface

@benface benface commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Two related changes to make iOS's reported metrics match the actual rendering surface:

  1. Populate dpi_scale from contentScaleFactor. Upstream left native_display().dpi_scale at 1.0 on iOS. macroquad's screen_width() / mouse_position() divide by dpi_scale to return density-independent units — so without this, iOS callers got pixel values where macOS got points, and dp-positioned UI landed at the wrong place. Now iOS joins macOS in reporting a real content scale.

  2. Measure the view, not UIScreen. draw_in_rect reported UIScreen.bounds × UIScreen.scale as the rendered size. Switched to payload.view.bounds × contentScaleFactor, which is more direct (the view IS the rendering surface) and avoids the global UIScreen.mainScreen call that has gotchas with multi-window configurations.

Both halves go together: the natural scale to multiply the view's bounds by is the view's own contentScaleFactor, and once we're reading it for that, exposing it as dpi_scale is essentially free.

The high_dpi toggle is no longer consulted here — the view's contentScaleFactor is already set to UIScreen.scale when high_dpi=true and 1.0 when high_dpi=false (see create_opengl_view), so the resulting screen_size / dpi_scale match upstream's high_dpi-aware branches on real iPhone / iPad.

What this fixes

In a downstream macroquad app, iOS-on-Mac windowed mode was rendering at ~50 % of the window size. The fix is the dpi_scale half — macroquad's screen_width() was returning physical-pixel counts where the macOS desktop returned points, so the rest of the app drew at half the expected scale.

(Side note on the bounds half: iOS-on-Mac windowed reports the same view.bounds as fullscreen — the window chrome clips a fixed-size view rather than shrinking it. So the change from UIScreen.bounds is more about avoiding the UIScreen.mainScreen global and being more direct than about fixing the windowed-rendering bug per se.)

Test plan

  • iPhone 17 Pro (contentScaleFactor = 3): screen_width() reports 402 dp instead of 1206 px.
  • iPad Pro 13" simulator: 1032 dp instead of 2064 px.
  • iPad mini 8.3" simulator: 744 dp.
  • iOS-on-Mac fullscreen + windowed: app renders at the correct scale (was 50 %).

draw_in_rect reported UIScreen.bounds * UIScreen.scale as the rendered
size. On real iPhone / iPad that matches the view's framebuffer (the
view fills the screen), but on iOS-on-Mac the view can be a window
smaller than the Mac display — so screen_width / screen_height
overstated the real rendering surface and apps drew at the wrong scale
in windowed mode. Switch to the view's own bounds * contentScaleFactor,
which is correct in both cases.

Also populate native_display().dpi_scale with the view's
contentScaleFactor — upstream left it at the 1.0 default on iOS, which
breaks higher-level APIs (e.g. macroquad's screen_width() divides by
dpi_scale to return density-independent units). With this change, iOS
joins macOS in reporting a real content scale, and the same
dp-positioned UI lands at matching screen positions across both
platforms.
@not-fl3 not-fl3 merged commit cdc1a25 into not-fl3:master Jun 15, 2026
11 checks passed
@benface benface deleted the pr-ios-view-metrics branch June 15, 2026 12:22
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.

2 participants