Skip to content

Fix macOS Retina startup bugs on 1.21.1 (unsupported-resolution dialog + invisible first-person hand)#78

Open
seapancakes1 wants to merge 1 commit into
Zolo101:1.21.1from
seapancakes1:macos-startup-fix
Open

Fix macOS Retina startup bugs on 1.21.1 (unsupported-resolution dialog + invisible first-person hand)#78
seapancakes1 wants to merge 1 commit into
Zolo101:1.21.1from
seapancakes1:macos-startup-fix

Conversation

@seapancakes1
Copy link
Copy Markdown

Summary

On macOS Retina displays, RenderScale 1.3.5 on the 1.21.1 branch causes two cosmetic-but-disruptive startup bugs:

  1. Vanilla MC pops an "unsupported resolution (1708×960)" dialog on launch (1708×960 = 854×480 × 2, the real Retina framebuffer).
  2. The first-person hand doesn't render until the window is resized by even one pixel, after which it works fine for the session.

Both have the same root cause and a single load-bearing fix.

Root cause

MixinWindow.scale(int) had:

private int scale(int value) {
    if (CommonClass.getInstance() != null) {
        ...
    } else {
        return 0;   // ← bug
    }
}

The mixin runs from MC's bootstrap path before the loader entrypoint has called CommonClass.init(). During that window, Window.getWidth() and Window.getHeight() mixin-return 0, which propagates into:

  • the vanilla "supported resolution" check (which then reports the real GLFW framebuffer size as "unsupported" because MC's internal sizing got desynced),
  • the main render target sizing path, leaving mainRenderTarget at 0×0 until a real GLFW framebuffer-resize event fires (the manual one-pixel nudge users do as a workaround).

The same return 0; was changed to return value; on the stonecutter branch in commit 8de1073 ("Better scaling implementation"), but that commit was part of a larger 1.21.5+ GpuTexture rewrite and never landed on the 1.21.1 branch.

Changes (3 files, +14 −5)

1. common/.../mixin/MixinWindow.java — load-bearing fix. return 0;return value; so callers that hit scale() before CommonClass.init() get a sane value back instead of zeroing out.

2. common/.../CommonClass.java — defense in depth. Wrapped every window.getWidth()/getHeight() in setShouldScale, resize(RenderTarget), and resize(PostChain) with Math.max(1, …) so any latent zero can't recreate a zero-sized target. Also incidentally protects against issue #23 (scale factor 0.0 causing 0×0 windows).

3. common/.../mixin/MixinGameRenderer.java — when the existing 5-frame counter expires, also fire Minecraft.getInstance().resizeDisplay() once. That re-runs MC's full framebuffer-resize chain against the real GLFW size — same chain a real window-drag triggers — to harden against the hand-glitch path on systems where MC sized its mainRenderTarget against a stale 0×0 window before CommonClass.init() ran.

Test plan

Tested by the reporter on macOS 15 / Apple Silicon Retina, MC 1.21.1, NeoForge 21.1.x, RenderScale built from this branch:

  • Cold launch — no "unsupported resolution (1708×960)" dialog.
  • First-person hand visible from frame 1 in a fresh world load — no manual window nudge required.
  • RenderScale config screen (Mod Menu / NeoForge config) still works; rescaling still applies.
  • Window resize still fires onResolutionChanged cleanly.

Suggested additional CI / cross-platform checks before merging:

  • Build still compiles for both Fabric and NeoForge on the 1.21.1 branch (tested NeoForge locally; Fabric not tested but common/ changes are loader-agnostic).
  • Sanity check on Windows/Linux that the Math.max(1, …) clamps don't regress anything (they shouldn't — they only kick in when the existing code would already have been passing 0).

Notes / out of scope

On macOS Retina, MixinWindow.scale() returned 0 whenever
CommonClass.getInstance() was null - exactly the case during MC's
bootstrap before the mod entrypoint runs. With Window.getWidth/
getHeight returning 0 in that window, vanilla MC's "supported
resolution" check fired against the real GLFW framebuffer (e.g.
1708x960) as if it were unsupported, and the main render target
got sized to 0x0 - causing the first-person hand to remain
invisible until a manual window resize triggered MC's framebuffer
resync.

Three changes:

1. MixinWindow: return the original value instead of 0 when
   CommonClass isn't yet initialized. This is the load-bearing
   fix - mirrors the change in stonecutter commit 8de1073.

2. CommonClass: clamp window.getWidth()/getHeight() to >= 1
   in setShouldScale, resize(RenderTarget), resize(PostChain).
   Defense in depth so any latent zero can't recreate a zero-
   sized target.

3. MixinGameRenderer: when the existing 5-frame counter
   expires, also fire Minecraft.getInstance().resizeDisplay()
   once. Re-runs MC's full framebuffer-resize chain against
   the real GLFW size, hardening against the hand-glitch path
   on systems where MC sized its mainRenderTarget against a
   stale 0x0 window.

Tested on macOS 15 (Apple Silicon Retina) with Minecraft 1.21.1
NeoForge 21.1.x: no more "unsupported resolution" dialog on
launch, hand renders from frame 1.
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