metal: honor Conf.sample_count for MSAA on iOS + matching pipelines#640
Merged
Conversation
benface
force-pushed
the
metal-msaa-support
branch
from
June 13, 2026 15:30
246c371 to
7c74c42
Compare
added 3 commits
July 23, 2026 14:52
Three coupled changes that together light up MSAA on the iOS Metal backend: 1. `create_metal_view` calls `setSampleCount:` on `MTKView` from `Conf.sample_count` (the param was previously prefixed `_` and silently dropped). macOS already did this. 2. `new_pipeline` reads the view's `sampleCount` and sets it on `MTLRenderPipelineDescriptor`. A pipeline's sampleCount must match every render-pass color attachment it draws to; using the view's value as the canonical app-wide count keeps the main drawable and `render_target_msaa()` targets compatible with the same pipeline. 3. `new_texture` for `RenderTarget` access with `sample_count > 1` creates the texture as `MTLTextureType::D2Multisample` with the matching `setSampleCount:`, `setMipmapLevelCount:1`, and `RenderTarget`-only usage. The single-sample resolve texture for the same render target is created separately by the caller (e.g. `render_target_ex` in macroquad) and passed in via `new_render_pass_mrt`'s `resolve_img` slice. Constraint: every render-pass color attachment must use the view's sample count. Mixing single-sample and multisample targets in one app would require per-target pipeline states, which Metal allows but miniquad's "one pipeline per material" model does not currently express. Callers that opt into `Conf.sample_count > 1` should use `render_target_msaa()` (or matching) for every offscreen color target.
`begin_pass` unconditionally set the color attachment's storeAction to
`MTLStoreAction::Store`. That clobbered:
- MTKView's `currentRenderPassDescriptor`, which already wires a
`resolveTexture` (and matching `MultisampleResolve` storeAction)
on the color attachment when the view's `sampleCount > 1`.
- The descriptor built in `new_render_pass_mrt` for offscreen MSAA
targets, which has the same shape.
Both paths require `MultisampleResolve` — `Store` on a color attachment
with a resolve texture trips Metal validation:
RenderPass Descriptor Validation
MTLRenderPassAttachmentDescriptor resolveTexture must have
storeAction of MTLStoreActionMultisampleResolve,
MTLStoreActionStoreAndMultisampleResolve or MTLStoreActionUnknown
Inspect the attachment's `resolveTexture` and pick the storeAction
accordingly.
…eResolve) The previous commit replaced an unconditional `Store` with `MultisampleResolve` whenever the color attachment had a resolveTexture, fixing the validation crash. But Metal allows `MultisampleResolve` to discard the multisample texture's contents after the resolve, and macroquad issues one Metal pass per draw call with `loadAction = Load` so it can accumulate draws on top of a single clear at frame start. On the iOS 27 simulator the discarded contents are loaded back as magenta, so every draw after the clear renders on top of magenta and the frame ends up magenta-tinted everywhere except the pixels touched by the very last draw call. `StoreAndMultisampleResolve` both writes the resolved data to the drawable AND preserves the multisample texture, so a subsequent `Load` reads back the accumulated frame.
benface
force-pushed
the
metal-msaa-support
branch
from
July 23, 2026 19:21
7c74c42 to
7ce5c1a
Compare
Contributor
Author
|
@not-fl3 – I just rebased this, since it had conflicts. Ready for your review. 🙏 |
benface
added a commit
to benface/miniquad
that referenced
this pull request
Jul 25, 2026
`aarch64-apple-tvos` and `aarch64-apple-tvos-sim` are stable Rust tier-3 targets installable via plain `rustup target add`, but miniquad currently misses tvOS from every `target_os = "ios"` cfg gate, so a tvOS build fails to compile. This commit widens the Apple-family gates so tvOS reuses the iOS event loop (`native::ios::run`), UIKit link, Objective-C runtime, and Metal storage-mode selection. No new tvOS-specific code is added — the same iOS surface is compiled and dispatched for tvOS. Files touched: - `Cargo.toml` — pull `objc-rs` on tvOS as well. - `src/lib.rs` — `start()` dispatch and `apple_view_ctrl()`. Without the dispatch widen, `start()` returns immediately on tvOS (the enclosing app exits voluntarily on launch). - `src/native.rs` — `pub mod apple`, `pub mod ios`, and the `NativeDisplayData::view_ctrl` field + its initializer. - `src/native/apple/frameworks.rs` — UIKit link (GLKit stays iOS-only since tvOS has no OpenGL ES). - `src/graphics/metal.rs` — `UNIFORM_BUFFER_ALIGN` selection and the three `MTLResourceOptions` branches (matched to the post-not-fl3#640 shape now on master). Verified with `cargo build` against all five Apple targets: - `aarch64-apple-darwin` — clean - `aarch64-apple-ios` — clean - `aarch64-apple-ios-sim` — clean - `aarch64-apple-tvos` — now builds - `aarch64-apple-tvos-sim` — now builds Not in scope (deliberate): - **Input.** miniquad's iOS event loop reacts to `UITouch` on the `MTKView`. On tvOS, touch events only arrive from the Siri Remote's touch surface; menu / D-pad navigation goes through `UIPress` + the focus engine and is not wired here. An app built with this patch will render but won't accept remote-native input yet. - **App-level scaffolding.** Info.plist scene manifest, `main.m` bridging, asset catalogs, LaunchScreen setup — all app-owned and out of scope for miniquad itself. Sibling PRs of the same shape: - raphamorim/objc-rs#3 — Apple runtime cfg widen (merged) - not-fl3/macroquad#1056 — `load_file` CWD chdir for tvOS
Owner
|
Thanks for PR! |
not-fl3
pushed a commit
that referenced
this pull request
Jul 25, 2026
`aarch64-apple-tvos` and `aarch64-apple-tvos-sim` are stable Rust tier-3 targets installable via plain `rustup target add`, but miniquad currently misses tvOS from every `target_os = "ios"` cfg gate, so a tvOS build fails to compile. This commit widens the Apple-family gates so tvOS reuses the iOS event loop (`native::ios::run`), UIKit link, Objective-C runtime, and Metal storage-mode selection. No new tvOS-specific code is added — the same iOS surface is compiled and dispatched for tvOS. Files touched: - `Cargo.toml` — pull `objc-rs` on tvOS as well. - `src/lib.rs` — `start()` dispatch and `apple_view_ctrl()`. Without the dispatch widen, `start()` returns immediately on tvOS (the enclosing app exits voluntarily on launch). - `src/native.rs` — `pub mod apple`, `pub mod ios`, and the `NativeDisplayData::view_ctrl` field + its initializer. - `src/native/apple/frameworks.rs` — UIKit link (GLKit stays iOS-only since tvOS has no OpenGL ES). - `src/graphics/metal.rs` — `UNIFORM_BUFFER_ALIGN` selection and the three `MTLResourceOptions` branches (matched to the post-#640 shape now on master). Verified with `cargo build` against all five Apple targets: - `aarch64-apple-darwin` — clean - `aarch64-apple-ios` — clean - `aarch64-apple-ios-sim` — clean - `aarch64-apple-tvos` — now builds - `aarch64-apple-tvos-sim` — now builds Not in scope (deliberate): - **Input.** miniquad's iOS event loop reacts to `UITouch` on the `MTKView`. On tvOS, touch events only arrive from the Siri Remote's touch surface; menu / D-pad navigation goes through `UIPress` + the focus engine and is not wired here. An app built with this patch will render but won't accept remote-native input yet. - **App-level scaffolding.** Info.plist scene manifest, `main.m` bridging, asset catalogs, LaunchScreen setup — all app-owned and out of scope for miniquad itself. Sibling PRs of the same shape: - raphamorim/objc-rs#3 — Apple runtime cfg widen (merged) - not-fl3/macroquad#1056 — `load_file` CWD chdir for tvOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three coupled changes that together light up MSAA on the iOS Metal backend.
1.
create_metal_viewcallssetSampleCount:onMTKViewThe
sample_countargument was prefixed_and silently dropped, soConf.sample_counthad no effect on iOS Metal. macOS already does this.2.
new_pipelinematches the view'ssampleCountA pipeline's
sampleCountmust match every render-pass color attachment it draws to. Reading the view's value at pipeline-creation time keeps the main drawable andrender_target_msaa()targets compatible with the same pipeline.3.
new_texturecreatesD2Multisampletextures whensample_count > 1For
RenderTargetaccess withsample_count > 1, the color texture has to be aD2Multisamplewith matchingsetSampleCount:andmipmapLevelCount = 1, and can only carryRenderTargetusage (notShaderRead/ShaderWrite). The single-sample resolve texture for the same target is created separately by the caller (e.g. macroquad'srender_target_ex) and passed in vianew_render_pass_mrt'sresolve_imgslice — handled in #638.Constraint
Every render-pass color attachment must use the view's sample count. Mixing single-sample and multisample targets in one app would require per-target pipeline states, which Metal allows but miniquad's "one pipeline per material" model does not currently express. Callers that opt into
Conf.sample_count > 1should userender_target_msaa()(or pass a matchingsample_count) for every offscreen color target.Builds on #634, #635, #636, #637, #638, #639.