librashader built for arm64 and pinned, wired into GSDeviceMTL, and a preset
library behind it that can name a file the same way twice across a
reinstall.
The chain runs from DoApplyShaderChain, after ShadeBoost and before present,
on the same ping-pong the FXAA path uses. Two things about it are load-
bearing rather than incidental. EndRenderPass comes first, because the chain
opens its own passes and Metal aborts if ours is still encoding. And
FlushEncoders comes last, because librashader recycles its per-frame objects
over a ring shallower than our deferred-submit window, so a chain frame has
to end the batch. A failure latches on the preset that caused it, or a
preset that will not compile recompiles every frame forever.
Static archive rather than dylib, decided by building both against a working
tracer and measuring, and the loser was deleted rather than left as an option.
The library underneath is where the reinstall problem lives. Both preset
roots sit under a container UUID that changes on every sideload, so a
selection stored as an absolute path is stale within days. A preset is
stored as a marker plus a root-relative path -- bundle: or data: -- and re-
rooted at launch. The separator is a colon because Files refuses one in a
name and it is not a path separator, so the relative half never needs
escaping.
Packs come in as a picked zip or folder through an extractor that keeps the
directory tree, because a .slangp names its stages by relative path and the
tree is part of the pack rather than an arrangement of it. That is the
opposite of the skin extractor's flattening policy, so a test fences the two
apart. Sixteen presets ship in the app, each cleared against its own header
rather than a blanket grant.
librashader's own cache goes to Library/Caches through XDG_CACHE_HOME, set
before anything loads it. Latent today because the Metal runtime never
reaches that cache, but a pin bump that adds caching would otherwise put a
disposable file somewhere iOS can neither purge nor keep out of a backup.