emulators.xemu
xemu launcher (original Xbox): FATX-level save sync on a raw HDD image.
xemu launcher (original Xbox): FATX-level save sync on a raw HDD image.
xemu keeps game saves inside the one hard-disk image its xemu.toml points at, and QEMU exposes that image only as an opaque block device, so the previous design shipped the entire qcow2 as the save artifact. This version syncs at the filesystem level instead: the image is kept in raw format so pyfatx (userspace libfatx bindings: no FUSE, no NBD, container-safe) can read and write the FATX E partition directly, and the save archive carries only the launched title's save data.
How a session moves saves in and out of the image:
- image: the first launch after deploy finds the configured qcow2 and
converts it in place with qemu-img (same filename, raw content, sparse on
disk), keeping the original alongside as
<name>.backup. A raw image cannot hold QEMU internal snapshots, so the save-state interface is gone; save data is the whole artifact now. - launch: when the activate restored an archive, its files are written into E:/UDATA and E:/TDATA before xemu boots (pre-launch hook).
- exit: once xemu has stopped and flushed, the launched title's UDATA and TDATA trees are extracted from the image into the staging dir (post-close hook), where the standard dump zips them.
- title: the title id (the UDATA directory name) is read from the disc's default.xbe certificate; if the disc cannot be parsed, extraction falls back to every title on the disk rather than losing the session's saves.
attributelog= logging.getLogger(__name__)attributeROM_ROOT= Path(os.environ.get('ROM_ROOT', '/romm'))Library root a resolved ROM must live under (env ROM_ROOT, default /romm).
attributeXEMU_BIN= os.environ.get('XEMU_BIN', '/opt/xemu/AppRun')The xemu executable to spawn (env XEMU_BIN, default /opt/xemu/AppRun).
attributeXEMU_LOG_PATH= Path(os.environ.get('XEMU_LOG_PATH', '/config/xemu.log'))The emulator log file (env XEMU_LOG_PATH, default /config/xemu.log).
attributeXEMU_RENDERER= os.environ.get('XEMU_RENDERER', 'OPENGL').strip().upper()Renderer pinned into xemu.toml before each launch (env XEMU_RENDERER, default OPENGL).
Vulkan aborts xemu on the AMD Renoir/RADV stack these containers run on, and
the choice persists in xemu.toml, so one session spent switching renderers
leaves every later launch broken. Pinned before each launch; set XEMU_RENDERER
to VULKAN where the driver is known good, or to KEEP to leave the file alone.
attributeXEMU_SOFTWARE_GL= _truthy(os.environ.get('XEMU_SOFTWARE_GL', ''))Whether xemu renders on the CPU via LIBGL_ALWAYS_SOFTWARE (env XEMU_SOFTWARE_GL, default off).
Which renderer xemu asks for and whether the driver can answer are separate
problems: on the AMD Renoir stack these containers run on, xemu aborts in
gl_fence on the OpenGL path and in RADV on the Vulkan one. Set
XEMU_SOFTWARE_GL to render xemu on the CPU there, which the container-wide
LIBGL_ALWAYS_SOFTWARE cannot do without dragging every other emulator down
with it. Slow, so it stays off unless the host needs it.
attributeXEMU_TOML= Path(os.environ.get('XEMU_TOML', str(_default_toml_path())))The xemu.toml the HDD path is read from and display settings are pinned into (env XEMU_TOML).
Defaults to the SDL pref dir location _default_toml_path computes.
attributeFALLBACK_HDD_IMAGE= Path(os.environ.get('XEMU_HDD_IMAGE', '/config/xemu/xbox_hdd.qcow2'))HDD image assumed when xemu.toml cannot say (env XEMU_HDD_IMAGE).
Defaults to /config/xemu/xbox_hdd.qcow2, and is used only when xemu.toml
cannot tell us: a fresh container where xemu has never run, or a config with
no usable hdd_path.
attributeSAVE_STAGING_DIRNAME= 'saves'Name of the staging directory next to the HDD image.
The generic dump/restore reads and writes host files here, and the launch/exit hooks move them in and out of the FATX filesystem.
attributeQCOW2_MAGIC= b'QFI\xfb'The four-byte header that marks a qcow2 image; its absence means raw content.
attributeROM_EXTENSIONS= ('.iso',)Bootable disc formats: only XISO, always named .iso, including the .xiso.iso double extension.