The launcher and studio ship as Retro Launcher and Retro Studio now,
from the RetroPortingToolKit org, so the old product name is gone from
display text, documentation and release asset filenames.
The split is by case, and it is not cosmetic. CamelCase RetComM was
always the product; lowercase retcomm and RETCOMM_ are identifiers --
the C++ namespace, the binaries, the data directories, the CMake and
environment variables, the Cloudflare service names, the readme markers.
Renaming those would orphan existing installs for no benefit, so they
are untouched: 1101 lowercase retcomm and 205 RETCOMM_ still stand in
the launcher alone.
Four things are deliberately still spelled RetComM, and three of them
would have been real breakage:
- RetComM-Data is CamelCase but it is a directory on disk --
<exe_dir>\RetComM-Data\{runtime,config,data} for a portable install.
Renaming it strands every portable user's config, toolchains and
catalog cache.
- TechnicallyComputers/RetComM-Launcher in readme_has_launcher() is the
historical half of a both-slugs test. Renaming it makes it a duplicate
of the line above and sends every port built before the transfer back
to reporting its launcher section missing.
- _LEGACY_LAUNCHER_RE matched "^## RetComM Launcher". A sweep renamed it,
which would have silently stopped it matching every README already out
there; it now accepts both headings.
- The portable-stub lookup gained the pre-rename filenames back as
fallbacks, because old zips stay on the releases page and a rollback
downloads one.
Release assets become Retro-Launcher-* / Retro-Studio-*. That is safe
for installed clients: pick_launcher_asset() gates on *linux*/*windows*/
*macos* plus extension and arch, not on the product name, and the
Windows portable stub is identified by its RCM1 trailer rather than its
filename.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013DpaQqVguHFpBuCmdoFYWY
DuckStation oracle (dynamic comparison harness)
PSXRecomp v4 uses a patched build of stenzek/duckstation as a live oracle for the recompiled BIOS. Our runtime speaks JSON-over-TCP on port 4370; the patched DuckStation speaks the same protocol on 4371, so tools like debug_client.py compare can diff live state between the two at any moment.
Layout
duckstation/(git submodule) — pristine upstream DuckStation source tree, pinned to commitffb33c281d196eb8ee0f559085ca285de7cdd51b(release-20260328 era). Never edited directly.tools/duckstation/psxrecomp_oracle.patch— our changes as a unified diff against the pinned upstream base. Touches 7 files (~1200 lines). Addssrc/core/psxrecomp_debug_server.{cpp,h}, wiresPSXRecompDebug::Initialize(4371)intoSystem::Initialize, exposes three GPU debug accessors, registers a log channel.tools/duckstation/setup.sh— idempotent. Initializes submodule, fetches + verifies + extracts prebuilt Windows deps (SDL3, Qt6, ffmpeg, …), normalizes the absolute paths baked into the prebuilt CMake metadata, applies the oracle patch.tools/duckstation/build.sh— runs CMake (Visual Studio 17 2022, x64, Release) and MSBuild onduckstation-qt. Requires the Visual Studio 2022 "Desktop development with C++" workload (CMake + MSBuild come with it).tools/fix_duckstation_deps_paths.py— helper used bysetup.shto rewrite stale_IMPORT_PREFIXvalues in the extracted prebuilt deps.
First-time setup -- Linux / macOS
Use tools/duckstation_oracle.py. It installs outside any game repo, into the
shared Retro data root, so one build serves every title:
~/.local/share/retcomm/oracle/duckstation/ ($RETCOMM_DATA_DIR, or $RETCOMM_ORACLE_DIR)
src/ pinned upstream checkout with the oracle patch applied
build/ cmake/ninja tree
app/ the portable install that actually gets run
oracle.json
P=psxrecomp/tools
python3 $P/duckstation_oracle.py doctor # can this machine build it?
python3 $P/duckstation_oracle.py all # fetch + patch + build + install
python3 $P/duckstation_oracle.py start --disc disc/game.cue
python3 $P/duckstation_oracle.py status
python3 $P/duckstation_oracle.py stop
gpu_parity.py --start-oracle --disc <cue> will do the start step for you
when nothing is answering on 4371.
Arch, CachyOS, NixOS: the build runs in a container
DuckStation's CMake refuses to configure on Arch-family and NixOS hosts, and the note above that check states you do not have permission to distribute patches modifying its build system. Its build scripts are CC-BY-NC-ND-4.0.
So the tool detects the refusal up front and builds in an environment upstream
supports: ubuntu:22.04 via podman/docker, installing packages with upstream's
own scripts/appimage/install-packages.sh, copied verbatim out of the pinned
checkout. On a distro upstream accepts, the build runs directly on the host.
Force either path with build --container / build --no-container.
Notes that cost an afternoon to find
- The binary's RUNPATH points at the build environment, and Qt needs its plugin
tree.
installcopiesdep/prebuilt/<platform>/{lib,plugins}next to the binary and writes arun-oraclelauncher that setsLD_LIBRARY_PATHandQT_PLUGIN_PATH, then verifies withlddthat nothing is unresolved. - An unofficial build shows a modal warning dialog before the core thread
starts. Under
-noguiit is invisible, so the process sits blocked with no port and no error.installsets DuckStation's own[UI] UnofficialBuildWarningConfirmed = truekey instead of patching that behavior. installseeds DuckStation's own defaultsettings.iniby running it briefly, then merges only the handful of keys an oracle needs.- Wayland support is off by default (
-DENABLE_WAYLAND=OFF) because an offscreen oracle never opens a Wayland surface.build --waylandre-enables it. - The oracle server only starts when a system boots. An idle DuckStation with nothing loaded will never open the port.
The pin
tools/duckstation/pin.json is the single source of truth for the upstream
base. Both this tool and the Windows setup.sh read it, so the two platforms
cannot drift onto different trees. The prebuilt-dependency version and SHA-256
come from the checkout's own dep/PREBUILT-VERSION and
dep/PREBUILT-SHA256SUMS.
First-time setup -- Windows
cd <psxrecomp-v4>
bash tools/duckstation/setup.sh # ~5 min: clone submodule + fetch/extract deps + apply patch
bash tools/duckstation/build.sh # ~15-30 min: compile duckstation-qt Release x64
The resulting binary is at duckstation/build/bin/duckstation-qt.exe. Launch for headless oracle use:
./duckstation/build/bin/duckstation-qt.exe -bios -nogui -fastboot &
# Wait ~5s for BIOS boot, then:
echo '{"cmd":"ping"}' | ncat -w2 localhost 4371
Regenerating the patch
If our oracle changes need to be updated, edit files in duckstation/ directly, then regenerate the patch against the pinned upstream base:
cd duckstation
git diff ffb33c281d196eb8ee0f559085ca285de7cdd51b > ../tools/duckstation/psxrecomp_oracle.patch
The pinned base SHA lives in one place only: UPSTREAM_BASE at the top of tools/duckstation/setup.sh. Update it there if we ever rebase onto a newer upstream commit.
Why this layout (vs a hosted fork)
- Keeps the upstream source untracked in v4's git history — no 2.1GB of upstream code in our blame.
- Keeps our 1200-line patch reviewable as a single text diff in
tools/duckstation/— in-tree, versioned, diffable across sessions. - Matches the nestopia setup in sibling project
<nesrecomp>/runner\nestopia_cmake.cmake+runner/nestopia_oracle.patch. Same mental model: submodule upstream, patch on top, auto-apply at setup time. - No private/public GitHub fork to maintain or keep in sync.
Protocol parity with native runtime
Both servers implement the same JSON-over-newline command set where possible so that tools/debug_client.py compare <cmd> diffs state between them. See docs/TCP_COMMANDS.md for the full command table with "native-only / duckstation-only / both" annotations.
First-time setup: the duckstation-qt.rcc resource file
The MSBuild duckstation-qt target does NOT include the Qt resource compile
step. You must also build the duckstation-qt-rcc target, which produces
build/bin/resources/duckstation-qt.rcc (~740 KB). Without it the binary
opens a dialog "duckstation-qt.rcc could not be loaded. Your installation is not complete." and exits. tools/duckstation/build.sh builds both targets;
do not short-cut to -t:duckstation-qt alone.
After the rcc is in place, a first-time GUI launch is also required so
DuckStation's setup wizard can write out a working settings.ini. Launch
without any command-line flags:
python3 tools/launch_ds_detached.py # spawns GUI, no flags
Click through the wizard (BIOS directory → pick duckstation/build/bin/bios/,
then continue, then quit). After that, headless launches work forever:
python3 tools/launch_ds_detached.py -bios -nogui -fastboot
Verify with a quick ping:
NC='/c/Program Files (x86)/Nmap/ncat'
(printf '{"cmd":"ping"}\n'; sleep 1) | "$NC" localhost 4371
# expect: {"id":0,"ok":true,"frame":N} with N > 0
The settings.ini that the wizard writes is needed but not tracked (it's under
the gitignored duckstation/build/). If you rebuild from scratch (clobbering
build/), repeat the GUI-first-launch once.
Troubleshooting
- "oracle patch does not apply cleanly" — either upstream commit has been moved past the pinned base (check
git -C duckstation log --oneline -1), or the patch file was regenerated against a different base. Fix by either resetting the submodule to$UPSTREAM_BASEor updating the pin. - "sha256 mismatch" on deps archive — the prebuilt deps version in
duckstation/dep/PREBUILT-VERSIONhas been bumped. Either updatePREBUILT_SHA256insetup.shto the new hash fromduckstation/dep/PREBUILT-SHA256SUMS, or pin the submodule to an older commit that expects the cached archive's version. - "UNSUPPORTED CONFIGURATION" warning from DuckStation CMake — cosmetic. The upstream build system prefers
msbuilddriven via a VS solution (which is whatbuild.shdoes). The warning fires any time CMake runs on Windows; safe to ignore.