CNA-GAP-013: METAL runs custom ShaderEffects only through SpriteBatch, refuses a partial MultiSampleMask for custom and compiled effects, and presents PresentInterval.Two as One

CNA snapshot c1c316b9  ·  Known Issues › Functional gaps  ·  source links pinned to c1c316b9

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

Since the Apple campaign METAL has MRT, occlusion queries, instancing, readback, MSAA and compiled effects; a ShaderEffect on a 3D draw is still refused, as is a partial MultiSampleMask for custom and compiled effects, and Two presents as One.

Identifier
CNA-GAP-013
Category
Functional gap
Subsystem
Graphics & renderers
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA c1c316b9 (c1c316b9c7a846ce8002809c151fcd1af14942c9)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
ShaderEffect on 3D draws, BlendState.MultiSampleMask with custom or compiled effects, and PresentationParameters.PresentationInterval on the METAL renderer

Expected behaviour

A renderer identity is expected to support the XNA HiDef surface or refuse clearly. XNA draws any Effect on any primitive draw, applies BlendState.MultiSampleMask to every draw on a multisampled target, and PresentInterval.Two presents every second vertical retrace.

Actual behaviour at TARGET

  • Fixed since first recorded, by the Apple campaign: multiple render targets (AM4-097), occlusion queries (AM4-038), instancing and multi-stream vertex input (AM4-143), back-buffer readback (AM4-025), multisampling chosen per device (AM4-141), sampler MaxMipLevel and LOD bias (AM4-034; the bias only from macOS/iOS 26), ColorWriteChannels on every target (AM4-079, AM4-146), MultiSampleMask on single-sample targets (AM4-135), SpriteBatch custom effects in MSL (AM4-077) and compiled XNA effects through MojoShader and SPIRV-Cross (AM4-144, opt-in with CNA_METAL_COMPILED_EFFECTS). MetalSupportsCapability in MetalPolicy.hpp now answers true for all of them.
  • Still refused, with System::NotSupportedException, in MetalRenderer.mm: a 3D draw with a ShaderEffect bound (‘Metal custom effects are a SpriteBatch facility … 3D draws with one are not supported’; metal-shader-effect-contract.md), and a MultiSampleMask that keeps only some samples of a multisampled target when the draw uses a SpriteBatch custom effect or a compiled effect, because neither kind of MSL is given a [[sample_mask]] output (AM4-141).
  • Still approximated: SetSwapInterval maps the interval onto CAMetalLayer.displaySyncEnabled, which is a boolean, so PresentInterval.Two presents like One, without an error.

Source locations

Evidence

Checked by reading the named sources at c1c316b9; nothing was built or executed for this entry. The refusals are explicit and documented in the messages; macOS was not available.

Re-verified at c1c316b9: read MetalSupportsCapability, every NotSupportedException in MetalRenderer.mm, SetSwapInterval and the macOS status table of apple-platforms.md, whose ‘Left’ column for METAL names the same SpriteBatch-scoped custom effects and the PresentInterval.Two mapping; not executed. CNA's own records (AM4-208) report the full METAL test tree passing on a Mac mini M4.

Independently reported as CNA-VGAP-050 (folded into this entry by the adversarial audit): The Metal examples now register the SpriteBatch custom-effect pixel test and MetalRenderer runs SpriteBatch custom effects in MSL, but a 3D draw with a custom effect is still refused.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

The Metal examples now register 18 Metal tests of their own (among them the formerly unregistered SpriteBatch custom-effect test), and the shared pixel fixtures and renderer-neutral oracles run on Metal; MetalPolicyTests.cpp pins the multisample-mask judgement. No test draws a 3D primitive with a ShaderEffect on Metal or measures the cadence of PresentInterval.Two.

Regression test

A Metal pixel test that draws a 3D primitive with a custom effect, one that applies a partial MultiSampleMask under a compiled effect on a multisampled target, and a presentation-cadence check for PresentInterval.Two, each enabled with the feature.

Blast radius

Games on macOS or iOS with the METAL renderer that draw 3D geometry with a ShaderEffect, combine a custom or compiled effect with a partial MultiSampleMask, or rely on PresentInterval.Two halving the frame rate. Stock effects, SpriteBatch with or without custom effects, and every other renderer are unaffected.

Workaround

Write 3D custom shading as a compiled XNA effect (CNA_METAL_COMPILED_EFFECTS=ON) rather than a ShaderEffect, avoid partial multisample masks with custom effects, and pace frames in the game when a 30 Hz cap is needed; or use another renderer on Apple platforms.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.