feat: profile the Batocera and Recalbox LRPS2

Batocera 43.1 builds libretro/ps2 at 416291a with 001.bios-dir.patch and
Recalbox 10.1.1 builds it at 9485a53 with 0001-recalbox-paths.patch. Both
patches move the BIOS scan from pcsx2/bios to ps2, and Recalbox also moves
the data root to system/ps2. Each build gets its own built_by profile:
lrps2-416291a under Batocera's pcsx2 name, lrps2-9485a53 under Recalbox's
ps2 name.

A platform's own build now answers for its own build mode only on a
dual_mode_cores name, so Batocera keeps standalone PCSX2 beside its
libretro build.
This commit is contained in:
Abdessamad Derraz committed 2026-11-10 11:38:03 +01:00
1 parent d457948143
commit 7cb0e67eb6
5 files changed
+371 -4

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
# LRPS2 at 416291a with Batocera's BIOS directory patch
# Source: https://github.com/libretro/parallel-ps2
# Upstream: https://github.com/PCSX2/pcsx2
emulator: "LRPS2 (416291a, Batocera)"
type: libretro
core_classification: community_fork
bios_mode: agnostic
source: "https://github.com/libretro/parallel-ps2"
upstream: "https://github.com/PCSX2/pcsx2"
profiled_date: "2026-11-10"
source_commit: "416291ad7dc3caf5df4501c9249cbbe30cbef811"
pin_frozen: "Batocera, the only platform that ships it, builds this revision with package/batocera/emulators/retroarch/libretro/libretro-ps2/001.bios-dir.patch (Batocera package/batocera/emulators/retroarch/libretro/libretro-ps2/libretro-ps2.mk:7 at batocera-43.1). Later commits are not part of that build."
pin_build:
- platform: batocera
repo: "https://github.com/batocera-linux/batocera.linux"
revision: "batocera-43.1"
path: "package/batocera/emulators/retroarch/libretro/libretro-ps2/libretro-ps2.mk"
variable: LIBRETRO_PS2_VERSION
value: "416291ad7dc3caf5df4501c9249cbbe30cbef811"
core_version: null
version_basis:
kind: none
display_name: "Sony - PlayStation 2 (LRPS2 416291a for Batocera)"
cores: [pcsx2]
built_by: [batocera]
systems: [sony-playstation-2]
bios_directory: "ps2/"
resources_directory: "pcsx2/resources/"
notes: |
Batocera installs the build as pcsx2_libretro.so (Batocera
package/batocera/emulators/retroarch/libretro/libretro-ps2/libretro-ps2.mk:35-36)
and launches it as the libretro core pcsx2 of the ps2 system (Batocera
package/batocera/emulationstation/batocera-es-system/es_systems.yml:2293-2294).
The library version is the short commit hash git reports at build time
(cmake/BuildParameters.cmake:4-9, libretro/main.cpp:1423-1427).
Its patch moves the BIOS scan from pcsx2/bios to ps2 below the system
directory (libretro/main.cpp:1806) and the BIOS folder default to
/userdata/bios/ps2, the same folder on Batocera (pcsx2/Pcsx2Config.cpp:1042).
The data root stays system/pcsx2, so resources are read from
pcsx2/resources and memory cards are written to pcsx2/memcards
(libretro/main.cpp:1910-1912).
BIOS detection is filename-agnostic: ps2/ is scanned for any file between
4 and 8 MB with a RESET and a ROMVER romdir entry, no hash is checked, and
the list fills the pcsx2_bios core option whose default is the first BIOS
found (libretro/main.cpp:1800-1838). retro_load_game refuses to start when
no BIOS was found (libretro/main.cpp:1927-1931). The companion files take
their path from the selected BIOS.
The DEV9 hard disk image is user storage the core creates, not a file to
obtain.
files:
- name: "<bios>.bin"
found_by: content
path: "ps2/<bios>.bin"
required: true
description: "PS2 BIOS binary"
min_size: 4194304
max_size: 8388608
validation: [size]
config_key: "pcsx2_bios"
source_ref: "source libretro/main.cpp:1800-1838, source libretro/main.cpp:360-365, source libretro/main.cpp:1927-1931, source pcsx2/ps2/BiosTools.cpp:31-32, 60-187, 231-323, source pcsx2/Pcsx2Config.cpp:994-1000, 1042, 1051-1061"
note: >
Any file of 4 to 8 MB in ps2/ whose romdir holds RESET and ROMVER. The
pcsx2_bios core option picks one, and the first valid image found is used
when the configured one is missing.
- name: "<bios>.rom1"
path: "ps2/<bios>.rom1"
required: false
max_size: 4194304
description: "DVD player ROM"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-213, 314, source pcsx2/MemoryTypes.h:24"
note: "Tries <bios path>.rom1, then the BIOS path with its extension replaced by rom1. Skipped when neither exists."
- name: "<bios>.rom2"
path: "ps2/<bios>.rom2"
required: false
max_size: 524288
description: "Chinese ROM extension"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-213, 315, source pcsx2/MemoryTypes.h:25"
note: "Same naming as rom1. Present only on Chinese consoles."
- name: "<bios>.nvm"
path: "ps2/<bios>.nvm"
required: false
hle_fallback: true
size: 1024
description: "NVRAM / EEPROM data"
source_ref: "source pcsx2/CDVD/CDVD.cpp:59-60, source pcsx2/CDVD/CDVD.cpp:160-184"
note: >
Read at the BIOS path with the extension replaced by nvm. Region and
language defaults are filled in when the file is missing, short, or has
no language or region parameters.
- name: "<bios>.mec"
path: "ps2/<bios>.mec"
required: false
hle_fallback: true
size: 4
description: "Mechacon version"
source_ref: "source pcsx2/CDVD/CDVD.cpp:62, source pcsx2/CDVD/CDVD.cpp:186-196"
note: "Read at the BIOS path with the extension replaced by mec. Written as 0x00020603 when missing."
- name: "GameIndex.yaml"
path: "pcsx2/resources/GameIndex.yaml"
required: false
installed_on: [batocera]
description: "Per-game fixes and settings database"
source_ref: "source pcsx2/GameDatabase.cpp:48, source pcsx2/GameDatabase.cpp:880-885, source libretro/main.cpp:2324-2361"
note: >
Read from pcsx2/resources at the first game lookup. Without it no game
fix applies. Batocera installs the copy of the built tree in
bios/pcsx2/resources (Batocera
package/batocera/emulators/retroarch/libretro/libretro-ps2/libretro-ps2.mk:37-39).
- name: "cheats_ws.zip"
path: "pcsx2/resources/cheats_ws.zip"
required: false
description: "widescreen patches archive"
source_ref: "source pcsx2/VMManager.cpp:333-348, source libretro/main.cpp:2315-2322"
note: "Read when widescreen patches are enabled and pcsx2/cheats_ws holds no patch for the game."
- name: "cheats_ni.zip"
path: "pcsx2/resources/cheats_ni.zip"
required: false
description: "no-interlacing patches archive"
source_ref: "source pcsx2/VMManager.cpp:366-383, source libretro/main.cpp:2315-2322"
note: "Read when no-interlacing patches are enabled and pcsx2/cheats_ni holds no patch for the game."
- name: "eeprom.dat"
load_from: working_directory
required: false
hle_fallback: true
size: 64
description: "DEV9 EEPROM"
source_ref: "source pcsx2/DEV9/DEV9.cpp:107-116, source pcsx2/DEV9/DEV9.cpp:152-167"
note: "Opened from the working directory when DEV9 starts and mapped over 64 bytes. A compiled-in image stands in when the file is missing."
- name: "flash.dat"
load_from: working_directory
required: false
hle_fallback: true
size: 8650752
description: "DEV9 flash memory with ECC"
source_ref: "source pcsx2/DEV9/flash.cpp:21-28, source pcsx2/DEV9/flash.cpp:74-101"
note: "Read from the working directory when DEV9 starts. The flash is blank (0xFF) when the file is missing."
+151
View File
@@ -0,0 +1,151 @@
# LRPS2 at 9485a53 with Recalbox's path patch
# Source: https://github.com/libretro/parallel-ps2
# Upstream: https://github.com/PCSX2/pcsx2
emulator: "LRPS2 (9485a53, Recalbox)"
type: libretro
core_classification: community_fork
bios_mode: agnostic
source: "https://github.com/libretro/parallel-ps2"
upstream: "https://github.com/PCSX2/pcsx2"
profiled_date: "2026-11-10"
source_commit: "9485a53fa5aa2bff17e04518116107f81a8c82e3"
pin_frozen: "Recalbox, the only platform that ships it, builds this revision with package/libretro-ps2/0001-recalbox-paths.patch (Recalbox package/libretro-ps2/libretro-ps2.mk:9 at tag 10.1.1). Later commits are not part of that build."
pin_build:
- platform: recalbox
repo: "https://gitlab.com/recalbox/recalbox"
revision: "10.1.1"
path: "package/libretro-ps2/libretro-ps2.mk"
variable: LIBRETRO_PS2_VERSION
value: "9485a53fa5aa2bff17e04518116107f81a8c82e3"
core_version: null
version_basis:
kind: none
display_name: "Sony - PlayStation 2 (LRPS2 9485a53 for Recalbox)"
cores: [ps2]
built_by: [recalbox]
systems: [sony-playstation-2]
bios_directory: "ps2/"
resources_directory: "ps2/resources/"
notes: |
Recalbox installs the build as ps2_libretro.so (Recalbox
package/libretro-ps2/libretro-ps2.mk:31-33) and lists it as the libretro
core ps2 of the ps2 system (Recalbox
package/recalbox-romfs2/systems/ps2/system.ini:65-69).
The library version is the short commit hash git reports at build time
(cmake/BuildParameters.cmake:4-9, libretro/main.cpp:1424-1428).
Its patch moves the BIOS scan from pcsx2/bios to ps2 below the system
directory (libretro/main.cpp:1807), the data root from system/pcsx2 to
system/ps2, so resources are read from ps2/resources
(libretro/main.cpp:1911-1913), the BIOS folder default to
/recalbox/share/bios/ps2, the same folder on Recalbox, and memory cards to
/recalbox/share/saves/ps2 (pcsx2/Pcsx2Config.cpp:1042-1043, 1061-1062).
BIOS detection is filename-agnostic: ps2/ is scanned for any file between
4 and 8 MB with a RESET and a ROMVER romdir entry, no hash is checked, and
the list fills the pcsx2_bios core option whose default is the first BIOS
found (libretro/main.cpp:1801-1839). retro_load_game refuses to start when
no BIOS was found (libretro/main.cpp:1928-1932). The companion files take
their path from the selected BIOS.
The DEV9 hard disk image is user storage the core creates, not a file to
obtain.
files:
- name: "<bios>.bin"
found_by: content
path: "ps2/<bios>.bin"
required: true
description: "PS2 BIOS binary"
min_size: 4194304
max_size: 8388608
validation: [size]
config_key: "pcsx2_bios"
source_ref: "source libretro/main.cpp:1801-1839, source libretro/main.cpp:360-365, source libretro/main.cpp:1928-1932, source pcsx2/ps2/BiosTools.cpp:31-32, 60-187, 231-323, source pcsx2/Pcsx2Config.cpp:994-1000, 1042, 1051-1061"
note: >
Any file of 4 to 8 MB in ps2/ whose romdir holds RESET and ROMVER. The
pcsx2_bios core option picks one, and the first valid image found is used
when the configured one is missing.
- name: "<bios>.rom1"
path: "ps2/<bios>.rom1"
required: false
max_size: 4194304
description: "DVD player ROM"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-213, 314, source pcsx2/MemoryTypes.h:24"
note: "Tries <bios path>.rom1, then the BIOS path with its extension replaced by rom1. Skipped when neither exists."
- name: "<bios>.rom2"
path: "ps2/<bios>.rom2"
required: false
max_size: 524288
description: "Chinese ROM extension"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-213, 315, source pcsx2/MemoryTypes.h:25"
note: "Same naming as rom1. Present only on Chinese consoles."
- name: "<bios>.nvm"
path: "ps2/<bios>.nvm"
required: false
hle_fallback: true
size: 1024
description: "NVRAM / EEPROM data"
source_ref: "source pcsx2/CDVD/CDVD.cpp:59-60, source pcsx2/CDVD/CDVD.cpp:160-184"
note: >
Read at the BIOS path with the extension replaced by nvm. Region and
language defaults are filled in when the file is missing, short, or has
no language or region parameters.
- name: "<bios>.mec"
path: "ps2/<bios>.mec"
required: false
hle_fallback: true
size: 4
description: "Mechacon version"
source_ref: "source pcsx2/CDVD/CDVD.cpp:62, source pcsx2/CDVD/CDVD.cpp:186-196"
note: "Read at the BIOS path with the extension replaced by mec. Written as 0x00020603 when missing."
- name: "GameIndex.yaml"
path: "ps2/resources/GameIndex.yaml"
required: false
installed_on: [recalbox]
description: "Per-game fixes and settings database"
source_ref: "source pcsx2/GameDatabase.cpp:48, source pcsx2/GameDatabase.cpp:880-885, source libretro/main.cpp:2265-2302"
note: >
Read from ps2/resources at the first game lookup. Without it no game fix
applies. Recalbox installs the copy of the built tree in
bios/ps2/resources (Recalbox package/libretro-ps2/libretro-ps2.mk:34-37).
- name: "cheats_ws.zip"
path: "ps2/resources/cheats_ws.zip"
required: false
description: "widescreen patches archive"
source_ref: "source pcsx2/VMManager.cpp:333-348, source libretro/main.cpp:2256-2263"
note: "Read when widescreen patches are enabled and ps2/cheats_ws holds no patch for the game."
- name: "cheats_ni.zip"
path: "ps2/resources/cheats_ni.zip"
required: false
description: "no-interlacing patches archive"
source_ref: "source pcsx2/VMManager.cpp:366-383, source libretro/main.cpp:2256-2263"
note: "Read when no-interlacing patches are enabled and ps2/cheats_ni holds no patch for the game."
- name: "eeprom.dat"
load_from: working_directory
required: false
hle_fallback: true
size: 64
description: "DEV9 EEPROM"
source_ref: "source pcsx2/DEV9/DEV9.cpp:107-116, source pcsx2/DEV9/DEV9.cpp:152-167"
note: "Opened from the working directory when DEV9 starts and mapped over 64 bytes. A compiled-in image stands in when the file is missing."
- name: "flash.dat"
load_from: working_directory
required: false
hle_fallback: true
size: 8650752
description: "DEV9 flash memory with ECC"
source_ref: "source pcsx2/DEV9/flash.cpp:21-28, source pcsx2/DEV9/flash.cpp:74-101"
note: "Read from the working directory when DEV9 starts. The flash is blank (0xFF) when the file is missing."
+19 -3
View File
@@ -3308,6 +3308,11 @@ def _platform_profiles(
}
index = upstream_profile_index(profiles)
platform = str(config.get("_key") or "")
dual_names = {str(c) for c in config.get("dual_mode_cores") or []}
def build_modes(p: dict) -> set[str]:
kind = str(p.get("type", ""))
return {mode for mode in ("standalone", "libretro") if mode in kind}
def designated(name: str) -> set[str]:
# A build the platform compiles itself (built_by) is what its
@@ -3319,10 +3324,21 @@ def _platform_profiles(
p for p in index.get(name, ())
if platform and platform in (profiles[p].get("built_by") or [])
}
if own:
return own
preferred = preferred_profile(index, name)
return {preferred} if preferred is not None else set()
if not own:
return {preferred} if preferred is not None else set()
# The own builds stand for the modes they are built in only.
# Batocera builds LRPS2 as pcsx2_libretro.so and launches
# standalone PCSX2 under the same name.
own_modes = set().union(*(build_modes(profiles[p]) for p in own))
if (
name in dual_names
and preferred is not None
and preferred not in own
and not build_modes(profiles[preferred]) & own_modes
):
own.add(preferred)
return own
result = {profile for c in core_set for profile in designated(c)}
# A name the platform launches both ways designates its libretro
+45
View File
@@ -160,5 +160,50 @@ class APlatformsOwnBuildWinsItsName(unittest.TestCase):
self.assertEqual(resolve_platform_cores(retropie, profiles), {"uae4all"})
class APatchedLibretroBuildTakesItsNameOnly(unittest.TestCase):
"""Batocera and Recalbox compile LRPS2 with a patch that reads the BIOS
from ps2/ instead of pcsx2/bios/. Their own build replaces the buildbot
LRPS2 under the name they ship, and Batocera's standalone PCSX2, under
the same name, stays."""
def test_own_libretro_build_keeps_the_standalone_of_a_dual_name(self):
from common import resolve_platform_cores
profiles = {
"pcsx2": {"type": "standalone", "source": "s", "cores": ["pcsx2"]},
"lrps2": {"type": "libretro", "source": "l", "cores": ["lrps2", "pcsx2"]},
"lrps2-own": {"type": "libretro", "source": "l", "cores": ["pcsx2"],
"built_by": ["x"]},
}
config = {"_key": "x", "cores": ["pcsx2"], "standalone_cores": ["pcsx2"],
"dual_mode_cores": ["pcsx2"]}
self.assertEqual(resolve_platform_cores(config, profiles), {"pcsx2", "lrps2-own"})
del config["dual_mode_cores"]
self.assertEqual(resolve_platform_cores(config, profiles), {"lrps2-own"})
def test_the_registry_resolves_each_platform_build(self):
from common import load_emulator_profiles, load_platform_config, resolve_platform_cores
profiles = load_emulator_profiles(str(REPO_ROOT / "emulators"))
platforms = str(REPO_ROOT / "platforms")
def ps2_cores(platform: str) -> set[str]:
config = load_platform_config(platform, platforms)
return {
c for c in resolve_platform_cores(config, profiles)
if c.startswith(("lrps2", "pcsx2", "pcee2"))
}
self.assertEqual(ps2_cores("batocera"), {"lrps2-416291a", "pcsx2", "pcee2"})
self.assertEqual(ps2_cores("recalbox"), {"lrps2-9485a53", "pcsx2"})
for platform in ("retroarch", "retrobat", "emudeck", "retrodeck"):
with self.subTest(platform=platform):
cores = ps2_cores(platform)
self.assertIn("lrps2", cores)
self.assertFalse({"lrps2-416291a", "lrps2-9485a53"} & cores)
self.assertEqual(profiles["lrps2-416291a"]["files"][0]["path"], "ps2/<bios>.bin")
self.assertEqual(profiles["lrps2-9485a53"]["files"][0]["path"], "ps2/<bios>.bin")
if __name__ == "__main__":
unittest.main()
+4 -1
View File
@@ -195,7 +195,10 @@ resolved. Three strategies exist:
- **Explicit list**: `cores: [beetle_psx, dolphin, ...]` - match by profile key name
or by any name in a profile's `cores:`. When a profile's `built_by` names this
platform, that profile answers for the name (ROCKNIX's `yabadabadoo`). Used by
platform, that profile answers for the name (ROCKNIX's `yabadabadoo`). On a
`dual_mode_cores` name it answers for its own build mode only: Batocera's
patched LRPS2 (`lrps2-416291a`) takes the libretro `pcsx2` and the standalone
PCSX2 stays. Used by
Batocera, Recalbox, RetroBat, RomM, KNULLI, AmberELEC, EmuELEC, MinUI, NextUI,
MyMinUI, ROCKNIX, RetroPie, EmuDeck, RetroDECK. A list that names `retroarch`
(the last three) also takes every libretro profile, as `all_libretro` does,