Files
psxrecomp/docs/HD_TEXTURE_PACKS.md
Matt Stanley f9db2561d0 Fix persistent HD texture cache churn and missing live background dumps (#626)
* fix: reuse resident HD textures and publish live background dumps

* test: keep residency stubs local to the filtering fixture
2026-10-10 12:55:54 -07:00

112 lines
6.8 KiB
Markdown

# HD texture packs
The **HD Texture Packs** mod loads compatible DuckStation PNG/JPEG/WebP images and can
dump original textures encountered during gameplay. It is disabled by default.
Use **OpenGL** to display replacements. Software and Vulkan can collect dumps
but continue to display the original artwork. Tomba USA (`SCUS-94236`) is the
first integrated game target; game projects can supply their own manifest for
the same `psx.hd-textures` plugin.
A title manifest can also ship a pack inside its own package and point the
`pack` resource at it with `default = "<folder>"` (see
[MOD_PACKAGES.md](MOD_PACKAGES.md#owner-selected-resources)); a folder the
player selects still takes precedence.
Tomba provides an [optional drop-in example pack](https://github.com/mstan/TombaRecomp/tree/master/examples/hd-texture-pack)
with five synthetic checkerboards and a README inside its `SCUS-94236` pack
directory. It includes no original game artwork or dumps and remains opt-in.
Copy its `mods` folder into the game's writable directory, then enable the mod
and select OpenGL to see the example title textures.
## Install a pack
1. Open the launcher's **Mods** page and enable **HD Texture Packs**.
2. Under **Texture pack folder**, click **Open folder**. On first use the
launcher creates `mods/texture-packs/<game-id>` beside the executable, with
empty `replacements` and `dumps` directories.
3. Copy the pack's replacement PNG, JPEG, or WebP images into `replacements`, preserving their
filenames. Subdirectories are supported. If the download already contains
`replacements`, copy that directory's contents into this one.
4. Leave **Load replacements** enabled and **Dump textures** disabled.
5. Select **OpenGL** in Settings, then click **Play**.
**Change folder** selects another pack root. Empty folders are valid; their
`replacements` and `dumps` directories are created when the pack is configured.
You can also select a pack's `replacements` directory directly, with `dumps`
beside it. Keep editable packs outside `mods/bundled`, which builds regenerate.
## Dump and edit textures
1. Enable **HD Texture Packs**, disable **Load replacements**, and enable
**Dump textures**.
2. Click **Play** and visit the scenes you want to capture. The runtime collects
the used area of each texture source across its lifetime and publishes
changed captures periodically while playing, including resident backgrounds.
3. Exit the game to finish capture and allow the writer to complete. Copy
selected PNGs from `dumps` into `replacements`, then edit or
enlarge them while keeping the filenames, aspect ratio, and an integer
size multiplier.
4. Enable **Load replacements**, disable **Dump textures**, and click **Play**
using OpenGL to check the artwork.
The switches apply on **Play**. Restart after adding or editing pack files so
the runtime scans them again. Disabling the mod restores the original artwork.
The plugin does not write replacement pixels into native VRAM or change the
save namespace.
HD replacements and dumping run on the render thread when it is enabled:
residency changes travel with the recorded commands, and native VRAM (CPU
raster under HD authority) is published to the guest at every sync point.
A GP0(A0) upload holds the context from its header to its commit, so its mask
checks and partial readbacks see every earlier draw; that also holds when HD
turns on mid-upload or a savestate restores a state mid-upload. Smooth motion
generates frames with HD replacements too: in-between draws resolve the same
replacements, never write native VRAM and never dump. Dynamic resolution is available.
Capture defaults follow the referenced DuckStation policy: track uploads,
union their used rectangles per palette, skip direct-color C16 textures, ignore
results smaller than 16x16, and reduce palette ranges to used indices. Small
sprites or parts can therefore be absent until you lower the thresholds.
Dumping texture pages is optional and often produces more duplicate-looking
images. PSX sprites are assembled from texture parts, palettes, and drawing
commands; dumps are editable source textures, not reconstructed characters.
The Tomba example includes an inactive `config.yaml.example`. Copy it to
`config.yaml` at the pack root to choose authoring settings. Option keys go
directly at the YAML root, without an `Options:` section. `Aliases:` can map a
canonical identity to a friendly PNG/JPEG/WebP filename relative to
`replacements`; aliases do not alter the matching identity. See the format
guide for the supported keys and their bounds.
## Compatibility and diagnostics
Pack artwork is supplied separately. Matching depends on native game pixels
and palettes; a different region or revision may not match. PNG, JPEG, and static WebP are supported,
with a maximum of 8192 pixels per side, 64 MiB encoded, and 64 MiB decoded RGBA.
Unsupported identities, configuration features, or images fall back to the
original artwork. A savestate load or rewind restages VRAM; Beetle-keyed
upload rectangles already seen in the session are then re-admitted when their
restored words still hash to the same key. That re-hash is bounded: at most
256 rectangles covering at most one VRAM's worth of words (about 1 MiB of
CRC per load or rewind step, oldest dropped first). Saving a state also writes the Beetle-format upload
residency beside the slot (`*.hdres`, host metadata only, never in the `.pst`).
Loading that slot restores it when the restored VRAM is exactly the VRAM it
was saved with and the same pack is active (the sidecar carries a CRC of the
whole native VRAM and the pack's identity, a hash of its replacement keys),
so a HUD uploaded once per race keeps its replacement. Other loads (no
sidecar, a different pack, DuckStation `texupload` names, rewind or netplay
states) need fresh texture uploads from the game before upload-based
replacements match again; page-based matching remains available. See [DuckStation texture format notes](DUCKSTATION_TEXTURE_FORMAT.md)
for the exact supported filenames, hashing, alpha behavior, and limitations.
Development builds expose the [TCP `hd_textures` command](TCP_COMMANDS.md).
It reports the selected root, switches, backend support, pack size, and matched,
ready, and applied draw counts. Optional integer fields `replacements: 0|1`,
`dump: 0|1`, and `reload: 1` control an already configured pack during a test
session. `pending_dump_sources` counts sources with capture usage awaiting
publication; `dumped_textures` counts queued PNG jobs, which can precede files
appearing. Exit the game to finish capture. Use `present_shot` to capture the composed OpenGL window; native VRAM
screenshots retain the original artwork.
Cache counters report composition hits/builds/pixels, GL uploads/evictions,
decoded images/evictions, and decoded bytes. Repeated builds and uploads in a
stationary scene indicate cache pressure rather than one-time pack loading.