docs: user-facing documentation and signing key
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
<!-- Generated from the Runi source repository at v0.4.0. -->
|
||||
<!-- Edit the original there, not this copy. -->
|
||||
|
||||
# Customize profiles
|
||||
|
||||
Community workarounds for unofficial/leaked upscaler builds (new FSR
|
||||
versions, DLSS/XeSS swaps, and similar) recur — a "customize profile" is a
|
||||
named, reusable recipe for one of these, so applying (and cleanly reverting)
|
||||
one doesn't mean hand-editing files each time.
|
||||
|
||||
Validated for real: FSR 4.1.1 INT8 on non-RDNA4 hardware, applied to a real
|
||||
game via OptiScaler, checksum-verified to reproduce a manually-confirmed
|
||||
working in-game result exactly. The equivalent non-OptiScaler ("native")
|
||||
path was also investigated for real, in depth, and does **not** work on
|
||||
this hardware/Proton build — see "Follow-up investigation" below for the
|
||||
full root cause (it's not just a per-game quirk: a specific vkd3d-proton
|
||||
compile-time flag is missing). OptiScaler is the correct tool for forcing
|
||||
an upscaler backend/version a game wouldn't otherwise offer, not merely a
|
||||
fallback.
|
||||
|
||||
## Where profiles live
|
||||
|
||||
`~/.config/runi/profiles/<name>.toml`. `runi customize apply <id> <name>`
|
||||
looks there by name; you can also pass a direct file path instead of a name
|
||||
for a one-off profile you don't want to save centrally.
|
||||
|
||||
## Format
|
||||
|
||||
```toml
|
||||
# ~/.config/runi/profiles/fsr411-workaround.toml
|
||||
[profile]
|
||||
name = "fsr411-workaround"
|
||||
description = "Community FSR 4.1.1 INT8 workaround for non-RDNA4 GPUs (via OptiScaler)"
|
||||
|
||||
[[files]]
|
||||
src = "/home/user/Downloads/FidelityFX-Samples-v2.3.0-prebuilt/Samples/Upscalers/FidelityFX_FSR/dx12/x64/Release/amd_fidelityfx_upscaler_dx12.dll"
|
||||
dest = "amd_fidelityfx_upscaler_dx12.dll" # relative to the game's exe directory
|
||||
|
||||
[[ini_edits]]
|
||||
file = "OptiScaler.ini" # relative to the game dir; errors if missing
|
||||
[ini_edits.set]
|
||||
Fsr4Update = "true"
|
||||
|
||||
[env]
|
||||
FSR4_UPGRADE = "1" # only matters on a non-OptiScaler path; harmless otherwise
|
||||
```
|
||||
|
||||
- **`[[files]]`** — each entry copies `src` (a local path; leaked/unofficial
|
||||
builds have no stable official URL to automate) to `dest`, relative to the
|
||||
game's own exe directory. Goes through the same `core/backup.py` safety
|
||||
net every other game-file write in Runi uses — a colliding existing
|
||||
file is backed up first, never silently overwritten.
|
||||
- **`[[ini_edits]]`** — patches specific `key=value` lines in a target ini
|
||||
file (also relative to the game dir), leaving every other line/comment
|
||||
untouched. The target file must already exist (e.g. OptiScaler must
|
||||
already be installed) — this errors rather than silently skipping, since
|
||||
that usually means a prerequisite step was missed.
|
||||
- **`[env]`** — merged into the game's own `[env]` (overwrites, since
|
||||
applying a profile is a deliberate action). Only the keys a profile sets
|
||||
are removed again on `customize remove` — other env vars you've set
|
||||
yourself (e.g. `WINEDLLOVERRIDES` from an OptiScaler install) are left
|
||||
alone.
|
||||
|
||||
A profile that only needs the non-OptiScaler path (relying on a game's own
|
||||
native upscaler support rather than OptiScaler's proxy) simply omits
|
||||
`[[ini_edits]]` entirely — there's no conditional branching inside one
|
||||
profile; write two profiles if you want both paths available.
|
||||
|
||||
### The non-OptiScaler (native) path is not universally reliable
|
||||
|
||||
Tried for real on Gothic 1 Remake, immediately after the OptiScaler path
|
||||
above was confirmed working: swapping `amd_fidelityfx_upscaler_dx12.dll` and
|
||||
setting `FSR4_UPGRADE=1` **with OptiScaler removed had no effect** — the
|
||||
in-game menu still showed the game's original FSR 3.1.4, not 4.1.1.
|
||||
`PROTON_LOG=1` (`runi run <id> --debug --log`) confirmed why: the game
|
||||
never loaded `amd_fidelityfx_upscaler_dx12.dll` as a module at all, even
|
||||
after several minutes of actual play — strongly suggesting this title's
|
||||
FidelityFX integration is compiled directly into the `.exe` rather than
|
||||
deployed as the separate, swappable DLL some other games/the reference
|
||||
FidelityFX SDK samples use.
|
||||
|
||||
**OptiScaler works regardless of how a game is built** because it
|
||||
intercepts at the DXGI/D3D12 layer itself (hijacking `dxgi.dll`) and loads
|
||||
its own upscaler module unconditionally — it doesn't depend on the target
|
||||
game choosing to dynamically load that DLL by name. The non-OptiScaler path
|
||||
only works for games that already do that dynamic loading themselves.
|
||||
|
||||
**Practical takeaway**: prefer the OptiScaler path by default. Before
|
||||
relying on a non-OptiScaler profile for a new game, verify the target DLL
|
||||
actually gets loaded — `runi run <id> --debug --log`, play for a
|
||||
minute, then check the Proton debug log
|
||||
(`~/.local/share/runi/logs/<id>/steam-*.log`) for the DLL's filename
|
||||
in a `loaddll` trace line. If it never appears, the swap won't do anything
|
||||
for that game, no matter what env vars are set.
|
||||
|
||||
### Follow-up investigation: why the non-OptiScaler path can't work here at all
|
||||
|
||||
Pushed further using AMD's own official FidelityFX SDK sample app
|
||||
(`FidelityFX_FSR.exe`, which ships natively alongside the swappable DLL) as
|
||||
a clean, decoupled test case, fully rendering and running (its media assets
|
||||
had to be fetched separately via its bundled `MediaDelivery.exe` tool first —
|
||||
the "prebuilt" download didn't include them). Along the way this also
|
||||
surfaced and fixed a real, general bug: Runi wasn't setting the
|
||||
launched process's working directory to the game's own folder (see
|
||||
`docs/architecture.md`'s cwd design point) — the sample couldn't even parse
|
||||
its own bundled config file until that was fixed. That fix is unrelated to
|
||||
FSR specifically and helps any game relying on relative-path resource
|
||||
loading.
|
||||
|
||||
With the sample actually running: `amd_fidelityfx_upscaler_dx12.dll`
|
||||
genuinely loaded, and the GPU was confirmed non-RDNA4 (AMD Strix Halo/RDNA
|
||||
3.5) — exactly the target hardware for this workaround. But the sample's
|
||||
own "Override FSR Version" UI only offered FSR 2.3/3.1 — **no FSR4 entry at
|
||||
all**, regardless of the newer DLL being loaded. The downloaded
|
||||
`amdxcffx64.dll` was never loaded by anything either (checked the debug log
|
||||
directly) — it appears to target a real Windows AMD driver install
|
||||
(replacing a system32 file that only exists there), which doesn't map onto
|
||||
Wine at all.
|
||||
|
||||
The actual root cause: vkd3d-proton (the D3D12-to-Vulkan layer Proton uses)
|
||||
already has its own internal FSR4 support and vendor-hacks, but the INT8/
|
||||
older-GPU emulation path that would make a non-RDNA4 GPU qualify is **not
|
||||
enabled by default and requires building vkd3d-proton from source with
|
||||
specific compile flags** — it's not a runtime env var or a droppable file,
|
||||
it's a compile-time choice baked into a specific Proton build. The
|
||||
FidelityFX SDK's own hardware capability query correctly (from its
|
||||
perspective) declined to offer FSR4 without that underlying capability.
|
||||
|
||||
**Conclusion**: OptiScaler isn't a workaround-of-last-resort here — it's
|
||||
the actually-correct tool for this job. It intercepts the game's upscaler
|
||||
calls itself and has its own explicit force-override setting
|
||||
(`Fsr4Update=true`), so it never depends on the game's own auto-detection,
|
||||
the FidelityFX SDK's own UI, or a specific vkd3d-proton build having a
|
||||
particular compile-time flag. Replicating what OptiScaler does without
|
||||
OptiScaler would mean rebuilding OptiScaler itself — not reasonable scope
|
||||
for Runi (same philosophy as wrapping `umu-run` instead of
|
||||
reimplementing its runtime). **Use the OptiScaler path for any game where
|
||||
you need to force an upscaler backend/version the game or SDK wouldn't
|
||||
otherwise offer.**
|
||||
|
||||
## Commands
|
||||
|
||||
- `runi customize list [--json]` — profiles found in
|
||||
`~/.config/runi/profiles/`.
|
||||
- `runi customize apply <id> <profile-name-or-path> [--json]` —
|
||||
applies a profile. **If a different profile is already applied to that
|
||||
game, it's fully reverted first** (via its own tracked manifest), then the
|
||||
new one is applied — no simultaneous stacking.
|
||||
- `runi customize remove <id> [--json]` — reverts whatever the
|
||||
currently-applied profile changed: restores backed-up files exactly,
|
||||
removes files the profile added, and clears the env vars it set.
|
||||
|
||||
## How it composes with OptiScaler
|
||||
|
||||
Nothing here is OptiScaler-specific — the mechanism is generic (file copies
|
||||
+ ini edits + env vars against any game directory). It happens that the
|
||||
proven example edits `OptiScaler.ini`, since that's what the real workaround
|
||||
needed. A profile for the non-OptiScaler path (native FSR4 support some
|
||||
games already ship) would have no `[[ini_edits]]` at all, just the file
|
||||
copies and `FSR4_UPGRADE=1`.
|
||||
|
||||
See architecture.md (source repository) for the design
|
||||
rationale, and [config-schema.md](config-schema.md) for the `[customize]`
|
||||
per-game config section this feature adds.
|
||||
Reference in New Issue
Block a user