Repository navigation
Conversation
A multisampled render target's samples are stored at the end of every pass (`StoreAndMultisampleResolve`), so a later pass into the same target can load them back. An app that clears the target each frame and only reads what it resolves into never loads them, but still writes them out every frame, and the multisampled texture still takes up memory: about 50 MB at an iPhone 17 Pro's full resolution with 4× antialiasing. `TextureParams::transient` says a render texture's contents only last as long as the pass drawing into it. Metal then stores nothing of it when a pass ends but what it resolves into (`MultisampleResolve`, or `DontCare` without a resolve texture), a pass that doesn't clear it starts with `DontCare`, and on a GPU with tile memory, every Apple GPU, the texture is `MTLStorageModeMemoryless` and takes up no memory at all. Consecutive passes into the same target are still merged into one encoder, so a target drawn by one draw call after another keeps its samples throughout. A transient depth texture isn't stored either. OpenGL keeps a transient texture as it does any other, which the contract allows. Everything else is unchanged for textures that aren't transient. Drawing a full-screen 4× target that's cleared each frame and resolved once took an iPhone 17 Pro's GPU from 5.08 to 4.85 ms a frame, and the app's footprint from 319 to 269 MB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai>
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.
Why
On Metal, a multisampled render target stores its samples at the end of every pass (
StoreAndMultisampleResolve), so a later pass into the same target can load them back. An app that clears its target each frame and only reads what it resolves into never loads them. It still writes them out every frame, and the multisampled texture still takes up memory. A full-screen 4× target on an iPhone 17 Pro is about 50 MB of both, every frame.On a tile-based GPU, which every Apple GPU is, those samples can live in tile memory alone (
MTLStorageModeMemoryless), if nothing ever stores or loads them.Change
TextureParams::transientsays a render texture's contents only last as long as the pass drawing into it. For a transient texture, on Metal:MultisampleResolve, orDontCarewithout a resolve texture.DontCare.MTLGPUFamilyApple1, the texture isMTLStorageModeMemorylessand takes up no memory at all. Elsewhere it staysPrivate, with the same load and store actions.Consecutive passes into the same target are still merged into one encoder, so a target drawn by one draw call after another, as macroquad draws, keeps its samples throughout. OpenGL keeps a transient texture as it does any other, which the contract allows. Textures that aren't transient are unchanged.
TextureParamsgains a field, so a struct literal that doesn't use..Default::default()needstransient: false. The one innew_texture_from_rgba8has it.Measurements
A macroquad game (CHOMP) draws each frame into a full-screen 4× target, resolved once and copied to the screen. On an iPhone 17 Pro, with a level held idle at 60 Hz, traced with Instruments' Metal System Trace:
The final copy to the screen took 1.28 ms in both traces, so the GPU ran at the same clock.
Verification
MTL_DEBUG_LAYER=1withMTL_DEBUG_LAYER_ERROR_MODE=assert.cargo checkpasses foraarch64-apple-darwin,aarch64-apple-iosandaarch64-apple-tvos.🤖 Generated with Claude Code