A deferred module that only another deferred module names (PSNCommon, needed by
PSNCore) started after the plugins that use it (SPFXUnityPlugin) and crashed
Soul Hackers 2 on Windows. The first title load of any deferred module now starts
every deferred module some module depends on, in dependency order, with that
load's start arguments, and logs the sweep. Boot is unchanged.
On Windows a module the executable needs or imports from stays deferred, but its
dependencies were deferred too and started only when the title loads it, so a title
that calls it first ran them uninitialised (Soul Hackers 2, #15370 rerun). They start
at startup again, as on main. The loader prints one line per deferred start.
Since #12621 a Windows runtime module that another runtime module needs is deferred instead of started at boot, but loading a deferred module only started that module. A Unity plugin such as SPFXUnityPlugin that calls into a deferred module it needs (Il2CppUserAssemblies in Media/Modules) ran against code whose initializers had never run, and PPSA03743 crashed about 2.6 s in.
A deferred module's initialization table now lists the deferred modules it depends on (names, after the initializer array, behind a magic number so older output reads as having none). DynamicLoader starts those first, transitively and once each through the existing per-module state, with the start arguments of the load that began it, then starts the module itself. The module start result stays the module's own. Boot still starts no deferred module.
Linux is unchanged: its deferred modules still start only when loaded.
Reapplies the code, tests and USAGE.md change of 420b6a064e (#12621 by Ragbie), which commit 987ebe9855 (#15360) reverted because Soul Hackers 2 (PPSA03743) crashed on Windows: SPFXUnityPlugin calls into Il2CppUserAssemblies, which #12621 defers, and loading a deferred module did not start the deferred modules it needs. The next commit makes the loader start them, so the deferral and the start come back together.
This reverts the code, tests and USAGE.md change of commit 420b6a064e
(#12621). The docs/dev/debt/relinker.md line is left for the follow-up
that brings the deferral back with dependency start, to keep a running
batch that edits the same file valid.
Soul Hackers 2 (PPSA03743) stops about 2.6 s into boot on Windows with an
access violation on UnityGfxDeviceWorker inside SPFXUnityPlugin.prx since
this change. klosixgaming-arch bisected main's merge commits to 420b6a064e
and confirmed that undoing its dependency filter makes the title boot again
(https://github.com/boykopovar/AnyPS5/pull/12621#issuecomment-6587462742).
SPFXUnityPlugin (Media/Plugins) calls into Il2CppUserAssemblies
(Media/Modules). With #12621 that dependency is deferred, and loading a
deferred module does not start the deferred modules it needs, so it is
never started. The revert restores the previous Windows behaviour, where a
module another module needs starts at startup.
Resolve guest providers separately from host exports, require matching
exports and resolution edges, and prefer exact filenames before suffix
fallback. Preserve real host gaps and import reference counts.
Add synthetic CLI regressions and clarify named module classification.
Fixes#14322
Check the enabled layers before querying pipeline binary features. A
validation or gfxreconstruct layer older than Vulkan 1.3.294 wraps
handles but passes the extension's commands to the driver unchanged, so
keep the driver pipeline cache path there and when enumeration fails.
Cover the layer decisions with a fake enumerator.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A costly build whose binaries cannot be extracted or stored, and a
rejected capture build, now leave a capture-failure marker, so later
runs build that recipe through the driver cache instead of repeating a
capture build with a null pipeline cache. Lowering the time threshold
does not retry these markers; a driver change does. Existing
below-threshold markers stay compatible and retryable.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Capture costly compute builds and restore matching recipes after checking
full recipes, driver fingerprints and Vulkan compatibility keys. Add size
and time thresholds, opt-out, atomic persistence and corruption/rejection
fallback.
Remember below-threshold recipes in separate files so competing decisions
cannot overwrite captured binaries. Prefer saved binaries and retry
capture when the time threshold is lowered.
Cover compatibility, fallback, deterministic competing writers and
cross-process capture, restore and corruption.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keep driver blobs outside source-version cleanup and import compatible
legacy caches. Persist equal-size content changes and retry incomplete
snapshots without replacing the previous file.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The run report now records how far a run got (loaded, started, first draw,
first present), the frames presented and the average frame rate, the selected
GPU, the number of shaders compiled, failed and served from the cache, the
instructions the shader recompiler could not translate, the guest image
formats looked up or rejected, and the descriptor kinds that shaders bind.
The counters are relaxed atomics and are only touched while a report is being
collected. The window system's request to quit is recorded as the reason a run
ended.
The limit only lowers the rate below the output's refresh, delays no title
that is already slower, does not burst after a stall, sleeps then spins,
handles window events between flips, can show uneven refresh counts under
fifo, and is a host choice.