ios: honour Conf::high_dpi on the Metal path - #654
Conversation
|
Checked on device with an app pointed at this branch.
Placement is covered in the description: two earlier revisions set the scale inside |
5e1ffea to
4fb2ac3
Compare
`create_metal_view` took `_high_dpi` and never used it. `MTKView` sizes its drawable from `bounds * contentScaleFactor`, which defaults to the screen's native scale, so `high_dpi: false` had no effect and the drawable was always native resolution. The display-size branch that reads `contentScaleFactor` then reported that same native size, so the two agreed only because neither honoured the flag. Applied once the view is in a window rather than at creation, for two reasons. Moving a view into a window re-derives its `contentScaleFactor` from that window's screen, so a value set at creation does not survive. And changing it resizes the drawable, whose `drawableSizeWillChange:` reaches for `NATIVE_DISPLAY` — which at creation time the backend has not initialized yet. Placed after `makeKeyAndVisible`, this covers the OpenGL view as well, which sets the scale at creation and loses it the same way.
4fb2ac3 to
f0a0882
Compare
create_metal_viewtakes_high_dpiand never uses it.MTKViewderives its drawable frombounds * contentScaleFactor, which defaults to the screen's native scale, soConf::high_dpi: falsehas no effect on the Metal path: the drawable is always native resolution.The display-size code compounds it:
With
high_dpi: false, theelsebranch reads acontentScaleFactorthat was never set down, so it reports the native size too. The reported size and the drawable agree only because neither honours the flag.Where the fix goes
Not in
create_metal_view, which is where I tried it first. Two revisions failed there on device, so it is worth recording why the placement is not arbitrary:!high_dpipath. The resize triggersdrawableSizeWillChange:, which reaches forNATIVE_DISPLAYbefore the backend has initialized it.MTKViewdoes not keep acontentScaleFactorset before it has a window, because moving it in re-derives the scale from that window's screen.So it is applied after
makeKeyAndVisible, once the view is in a window and the backend is up.GLKViewdoes not behave that way: it keeps whatcreate_opengl_viewsets at creation. I checked that on device by removing this patch's call and running the OpenGL backend withhigh_dpi: false, which still reported a scale of 1.0 on a screen at 2.0. So the new call is a no-op on that path, andcreate_opengl_viewis left alone.Why it matters
Found on tvOS. An Apple TV 4K reports
boundsof 1920×1080 at2.0x, so the drawable is 3840×2160, four times the pixels of 1080p. On a first-generation Apple TV 4K (A10X) a 2D game was running at roughly 10–15 fps, with no way to opt out short of reaching into the view from the app's ownmain.m:window.rootViewController.view.contentScaleFactor = 1.0;With that, the same build is smooth. This patch makes it
high_dpi: falseinstead, which is what the setting is for.iOS is affected in the same way: any app that sets
high_dpi: falseon the Metal backend silently gets a native-resolution drawable.Checks
cargo check --target aarch64-apple-iosand--target aarch64-apple-tvos, both ok.high_dpi: trueon iPhone and the iPad simulator, no visual difference, sinceUIScreen.scaleis what UIKit was defaulting the view to anyway.high_dpi: falseon a first-generation Apple TV 4K, drawable 3840×2160 down to 1920×1080, and roughly 10–15 fps up to smooth.I deliberately did not run
cargo fmt; master isn't rustfmt-clean and it rewrites a dozen unrelated files. The added lines follow the surrounding style.