For devices with little RAM. Ori and the Will of the Wisps creates thousands of shaders on its title screen (18,432 in one run) while only a few hundred are ever drawn, and PipelineCache keeps every one of them for the device's lifetime. Since d4c38a2 (#6) SM50Initialize no longer keeps the parsed program, but each shader object still holds the resource maps, the argument buffer layout, the signatures and a copy of the bytecode in the host heap. This PR drops the object until a variant compile needs it: about 300 MB of host memory in this game.
willfaust/Madeira#219 is the Madeira side of the same low-RAM work (swap tier freezes); the two PRs do not depend on each other.
What changes
CachedSM50Shadertakes the reflection and the argument info at creation, keeps a copy of the bytecode (a few KB on the PE heap) and destroys the shader object.handle(), called only by the variant compile tasks, creates the object again from the bytecode under a per-shader mutex the first time, keeps it and frees the copy. A disk shader-cache hit never calls it. A shader's first compile now parses its bytecode twice.- The destructor frees the argument buffer also when the object is gone.
dxmt = d3d11.keepShaderIR=1keeps every shader object asSM50Initializereturns it (the behaviour before this PR).[shader-ir] ml1222 N unique shaders cached, shader objects dropped; bytecode kept K KB; recreated for a compile: Ris logged at the first shader and every 1024th.- If creating the object again ever failed,
handle()would return null, whichSM50Compileand the pipeline compiles report as invalid bytecode since #6. The same bytecode was parsed once already, so this is not expected.
Testing
On the device (iPad, A16, iPadOS 26.6.1), Ori and the Will of the Wisps, on top of #6:
- the host's default malloc zone stays at 38-81 MB for the whole run, against 340-372 MB with #6 alone;
- 18,432 shaders cached, 131 MB of bytecode kept, 55 objects created again for a compile;
- the game starts and plays with
d3d11.mipClampBC=2and a 640 MB JIT pool; without this change that configuration ran out of memory at launch (the app may use ~4.0 GB); - used in every run of the game since; no rendering problems noticed in play.
Not tested in this form with other games.
After merging
Please rebuild arm64ec-windows/d3d11.dll (DXMT PE meson build) and the i386 DXMT DLLs (build/wine-i386/build.sh) and move Madeira's dxmt pin. No binaries are included.
🤖 Generated with Claude Code