Skip to content

ios: implement required mtkView:drawableSizeWillChange: selector#642

Merged
not-fl3 merged 2 commits into
not-fl3:masterfrom
benface:metal-mtkview-size-change
Jun 15, 2026
Merged

ios: implement required mtkView:drawableSizeWillChange: selector#642
not-fl3 merged 2 commits into
not-fl3:masterfrom
benface:metal-mtkview-size-change

Conversation

@benface

@benface benface commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

MTKViewDelegate declares two @required methods: mtkView:drawableSizeWillChange: and drawInMTKView:. The QuadViewDlg class only registered the latter, so any actual drawable-size change (window resize, rotation under a non-locked orientation set, split-view drag on iPad) crashed:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[QuadViewDlg mtkView:drawableSizeWillChange:]: unrecognized selector sent to instance 0x...'
... [MTKView _resizeDrawable]
... [UIView setFrame:]
... [UIWindow _rotateWindowToOrientation:...]

Implementing the selector as a no-op fixes the immediate crash, but the handler also needs to sync native_display's screen_width / screen_height to the new drawable size and emit Message::Resize before the next drawInMTKView:. The fallback resize-detect path in draw_in_rect polls UIScreen.mainScreen.bounds, which lags MTKView's drawableSize during rotation animations — anything that depends on the framebuffer dimensions for the current pass then computes against stale values and fails Metal validation:

-[MTLDebugRenderCommandEncoder setScissorRect:]: failed assertion
`Set Scissor Rect Validation
(rect.y(688) + rect.height(2064))(2752) must be <= render pass height(2064)'

Reproduced on iPad Air 11-inch and iPad Pro 13-inch simulators on iOS 27 by rotating the device. Apps that lock orientation via Info.plist (or runtime supported-orientations) never see a drawable-size change and so don't hit either crash.

The full path: drawableSizeWillChange updates native_display immediately and sends Message::Resize; draw_in_rect's own UIScreen.bounds poll still runs as a fallback (e.g. for size changes that don't go through the delegate).

`MTKViewDelegate` declares two `@required` methods:
`mtkView:drawableSizeWillChange:` and `drawInMTKView:`. The
`QuadViewDlg` class only registered the latter, so any actual
drawable-size change (window resize, rotation under a non-locked
orientation set, split-view drag on iPad) crashed:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
    reason: '-[QuadViewDlg mtkView:drawableSizeWillChange:]:
    unrecognized selector sent to instance 0x...'
    ... [MTKView _resizeDrawable]
    ... [UIView setFrame:]
    ... [UIWindow _rotateWindowToOrientation:...]

Reproduced on the iPad Air 11-inch simulator on iOS 27 by rotating
the device. Did not reproduce on the iPhone 17 simulator there
because CHOMP's Info.plist locks orientation, so the drawable size
never actually changes.

Implementation is a stub: `draw_in_rect` already polls
`UIScreen.mainScreen.bounds` every frame and emits `Message::Resize`
on a delta, so a no-op satisfies the protocol without changing the
existing resize path.
@benface benface force-pushed the metal-mtkview-size-change branch 2 times, most recently from 92ec060 to b8062d0 Compare June 13, 2026 23:19
Per Apple's MTKView contract, `drawableSizeWillChange:` is invoked
before the next `drawInMTKView:` whenever the drawable's pixel
dimensions change (window resize, rotation under a non-locked
orientation set, split-view drag on iPad). The previous commit added
a no-op stub to satisfy the protocol; that prevents the
"unrecognized selector" crash but leaves `native_display`'s stored
dimensions stale until the next frame's
`UIScreen.mainScreen.bounds` poll catches up.

During iPad rotation animations the stored dimensions stay one frame
behind the resized drawable. Anything that depends on the
framebuffer dimensions for the current pass — `setScissorRect` is
the common case — gets computed against the old size and fails
Metal validation:

    -[MTLDebugRenderCommandEncoder setScissorRect:]: failed assertion
    `Set Scissor Rect Validation
    (rect.y(688) + rect.height(2064))(2752) must be <=
    render pass height(2064)'

Update `native_display`'s `screen_width`/`screen_height` from the
size argument immediately and send `Message::Resize` so the event
handler resizes before the next draw. `draw_in_rect`'s own
`UIScreen.bounds` poll still runs as a fallback (e.g. for full-screen
size changes that don't go through the delegate).
@benface benface force-pushed the metal-mtkview-size-change branch from b8062d0 to b83cdd2 Compare June 13, 2026 23:56
@not-fl3 not-fl3 merged commit b3e5e0d into not-fl3:master Jun 15, 2026
11 checks passed
@benface benface deleted the metal-mtkview-size-change branch June 15, 2026 12:23
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