metal: honor Conf.sample_count for MSAA on iOS + matching pipelines#640
Open
benface wants to merge 3 commits into
Open
metal: honor Conf.sample_count for MSAA on iOS + matching pipelines#640benface wants to merge 3 commits into
benface wants to merge 3 commits into
Conversation
added 3 commits
June 13, 2026 00:24
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.
246c371 to
7c74c42
Compare
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.