RetroRun is a lightweight libretro frontend for Linux handhelds and desktop systems. It was originally designed for Anbernic devices using the GO2/DRM graphics stack and now provides a platform abstraction for input, audio and video, with an additional SDL2 backend for macOS and Linux.
- Fix bezel alignment, transparency and rotated display viewports.
- Improve Flycast LE option handling and video geometry.
- Share Flycast profiles by Rockchip SoC and align Soul Calibur profiles across RG351 devices.
See changelog.txt for release history.
- Save states: create and load states from the on-screen menu or controller shortcuts, choose between multiple slots, and optionally save and restore a state automatically when starting or closing a game.
- Multi-disc games: change the active CD, GD-ROM or other removable image while playing, using RetroRun's file browser and the libretro disk-control interface exposed by compatible cores.
- Bezels and screen decorations: automatically reuse installed AmberELEC and ArkOS bezel packs, select artwork per game or system, honour custom libretro and Batocera-style viewports, or download and manage a curated set directly from the menu. Alpha-composited artwork is cached and accelerated by RGA on supported GO2 devices.
- RetroAchievements: sign in from the frontend, identify supported games, browse locked and unlocked achievements with their badges, and display game identification and unlock notifications. Official achievements, optional unofficial achievements and Encore mode are supported in softcore mode, and the integration can be disabled.
- Complete on-screen interface: pause and resume games, inspect device, core, graphics and network information, change runtime video, audio, volume and brightness settings, manage save states and exit cleanly without leaving the frontend.
- Fast-forward and frame control: uncapped fast-forward with configurable frame presentation, optional adaptive or fixed frameskip, VSync and frontend frame pacing.
- Flexible video output: software and OpenGL/OpenGL ES cores, automatic or selectable aspect ratios, pixel-perfect scaling, Tate rotation, nearest or linear filtering, scanlines, CRT effects and optional screen decorations.
- Handheld-oriented input: controller remapping, analog-to-D-pad modes, Tate-aware directional controls, analog sticks, triggers, rumble and configurable controller shortcuts.
- Useful frontend tools: screenshots, an unrestricted FPS counter, a startup loading screen, icon-and-text notifications and an on-screen keyboard with upper- and lowercase input.
- Portable backends: native GO2/DRM support for compatible Anbernic devices and an SDL2 backend for Linux handhelds, Linux desktops and macOS.
- Configurable cores and diagnostics: per-core libretro options, separate frontend and core log levels, timestamped logs and selectable save, system and screenshot directories.
The native backend remains available for the RG351 M/P/V/MP, RG552, RG503, RG353M, RG353V and Miniloong Pocket 1. The Pocket 1's portrait DRM panel is rotated natively, including both Tate directions and direct scanout. The SDL2 backend provides an alternative implementation for Linux handheld distributions such as AmberELEC, ArkOS/dArkOS and other devices that provide SDL2, KMSDRM and OpenGL ES 3.
The Linux SDL2 backend must still be tested on each physical device. Controller mapping, screen rotation, audio driver and performance can vary between models and distributions.
On-screen interface icons are derived from Streamline Core Line Free, licensed under CC BY 4.0. Icons by Streamline.
| Host or target | Backend | Build command | Output |
|---|---|---|---|
| Anbernic Linux, default | Native GO2/DRM | make config=release |
retrorun |
| Linux handheld or desktop | SDL2 + OpenGL ES | make sdl2 config=release |
retrorun-sdl2 |
| macOS | SDL2 + Desktop OpenGL | make |
retrorun |
On Linux, the GO2 backend intentionally remains the default for compatibility
with existing AmberELEC packages and supported Anbernic devices. Building the
SDL2 target produces a separate executable and does not replace retrorun.
RetroRun includes an OSD menu shared by the native GO2/DRM and SDL2 backends.
It can pause and resume the active core and provides access to device, core and
game information, runtime settings, save states, credits and clean shutdown.
Each menu remembers its selected item when entering a submenu and returning.
The read-only Info > Graphics page reports the active platform backend,
renderer, software or hardware core path, output and core resolutions, pixel
format, aspect ratio, filter, shader, VSync, pixel-perfect state and UI profile.
On native DRM builds, Info > DRM diagnostics reports the selected direct
scanout policy, DRM driver and panel mode, connector/CRTC and plane identifiers,
plane format and rotation support, page-flip fallback state, direct-scanout
result and sampled VBlank latency/failures. These values make it easier to
compare device-specific DRM behaviour without enabling permanent debug timing.
Pressing A from this page opens a confirmation prompt for a three-second test
on the running game. During the test RetroRun temporarily forces direct scanout,
suppresses frontend/game input and overlays, then restores the previous state
and reopens the diagnostics page; the configured policy is not changed.
The default controller shortcut is L3 + R3; alternative Select/F2 shortcuts
can be enabled with retrorun_alternative_input_mode.
The menu uses clipped, time-based text scrolling for labels wider than the available area. Its UI profile can be changed under Settings > Video:
autokeeps the original compact layout on recognized Anbernic devices and selects the responsive desktop layout on macOS, Windows and regular Linux PCs;handheldalways uses the original 240x160 menu canvas;desktopderives the menu canvas from the window size so that text remains approximately 16 pixels high instead of being enlarged with the game image.
Core compatibility depends on the backend, architecture and distribution. The following families have historically been tested with RetroRun:
- Dreamcast, Naomi and Atomiswave: Flycast and Flycast 2021.
- Nintendo 64: ParaLLEl N64.
- PlayStation: SwanStation, DuckStation and PCSX-ReARMed.
- PSP: PPSSPP.
- Super Nintendo: Snes9x variants and bsnes2014.
- Game Boy Advance: mGBA and VBA-M.
- Mega Drive/Genesis: Genesis Plus GX and PicoDrive.
- Atari: Stella and Virtual Jaguar.
- DOS: DOSBox Pure and DOSBox Core.
- Other cores including Beetle VB and Yaba Sanshiro.
A core shared library must use the same CPU architecture as RetroRun. For example, a 32-bit core requires a 32-bit RetroRun executable and compatible libraries.
Clone the repository first:
git clone https://github.com/navy1978/retrorun.git
cd retrorunOn a supported Linux toolchain, the default command builds the historical Anbernic backend:
make config=releaseThe native build uses DRM/GBM, EGL/OpenGL ES, RGA, evdev, ALSA and OpenAL. It is normally cross-compiled inside the AmberELEC or device-distribution build environment, where those libraries and their target headers are available.
The backend can also be selected explicitly:
make go2 config=releaseArkOS/dArkOS and AmberELEC normally expose the unversioned EGL, GLES and GBM
linker names through the same proprietary RK3326 Mali GBM library. Building on
a generic Linux VM can instead record versioned GLVND/Mesa dependencies such as
libEGL.so.1, causing EGL initialization to fail on an otherwise supported
handheld.
The helper can download the dArkOS RK3326 blob pinned to a known source commit, verify its SHA-256 and retain it outside the repository in the user cache:
tools/build-rk3326-mali.sh --download-maliThe download is never implicit. For offline builds, pass an existing AArch64 RK3326 Mali GBM blob instead:
tools/build-rk3326-mali.sh \
--mali-lib /path/to/libmali-bifrost-g31-rxp0-gbm.soThe output is dist/retrorun-rk3326-mali. The helper temporarily presents the
blob as libEGL.so, libGLESv2.so and libgbm.so, performs a clean release
GO2 build, and then removes all temporary links and intermediate build files.
It rejects GLVND/Mesa-style DT_NEEDED entries and prints the highest GLIBC
version required by the executable.
To enforce the ABI ceiling of the oldest target distribution, pass its GLIBC version explicitly:
tools/build-rk3326-mali.sh \
--download-mali \
--max-glibc 2.31The version above is only an example; determine the actual ceiling on the oldest supported image. Passing the ELF checks prevents the known EGL loader mismatch, but a release should still be tested on both ArkOS/dArkOS and AmberELEC before being labelled as a universal binary.
Required target dependencies are:
- a C++20 compiler;
- SDL2 development files;
- libpng and pkg-config;
- EGL, OpenGL ES 3 headers and
libGLESv2; - an SDL2 build with KMSDRM support when running without X11 or Wayland.
Build the alternative backend with either command:
make PLATFORM=sdl2 config=releasemake sdl2 config=releaseBoth commands create retrorun-sdl2. The build variables CXX, SDL_CONFIG,
PKG_CONFIG, SDL_CFLAGS, SDL_LIBS, PNG_CFLAGS, PNG_LIBS,
GLES_CFLAGS and GLES_LIBS can be overridden for a cross-compilation
sysroot. For example:
make sdl2 config=release \
CXX=aarch64-linux-gnu-g++ \
SDL_CONFIG=/path/to/sysroot/usr/bin/sdl2-config \
PKG_CONFIG=/path/to/target-pkg-configDo not copy a macOS or x86-64 Linux executable to an ARM handheld. RetroRun, the libretro core and all linked libraries must be built for the target CPU and ABI.
The experimental hybrid target retains the native GO2/DRM video and evdev input paths while including both the native OpenAL and SDL2 queued-audio providers:
make PLATFORM=linux-go2-hybrid config=releaseThe output is retrorun-hybrid. Select the playback provider before launch in
retrorun.cfg:
retrorun_audio_backend = sdl2Accepted values are auto, go2 (or openal) and sdl2 (or sdl). auto
preserves the GO2 default. SDL2 initializes only its audio subsystem in this
build; it does not acquire KMSDRM or replace the GO2 presenter. The selected
provider is logged at startup and recorded as audio_backend in integrated
benchmark JSON.
For a non-persistent benchmark comparison, override it on the command line:
./retrorun-hybrid --benchmark 60 --benchmark-set audio_backend=sdl2 CORE ROMBenchmark-only overrides also include audio_buffer and a deterministic
warm-up confirmation sequence. The latter is useful for save states that stop
at a prompt before reaching the measured scene:
./retrorun-hybrid --benchmark 60 --benchmark-warmup 10 \
--benchmark-frames 1800 \
--benchmark-set confirm_input=true \
--benchmark-set confirm_input_delay=4 \
--benchmark-set audio_buffer=512 CORE ROMThis injects one A press at the requested delay and one B press 0.75 seconds
later. Both are restricted to warm-up and therefore never enter benchmark
metrics. The warm-up must be longer than the configured delay plus one second,
so both synthetic presses occur before metric collection starts.
--benchmark-frames stops measurement after exactly the requested number of
core frames; the duration remains a safety deadline. This makes alternating
comparisons independent of the performance of the candidate being measured.
These overrides are not persisted to retrorun.cfg.
The validated low-end compensation can be enabled in retrorun.cfg. It is
SDL2-specific, explicitly trades a small amount of audio accuracy for queue
stability, and remains disabled by default:
retrorun_sdl_audio_stretch_percent = 5
retrorun_sdl_audio_stretch_low_ms = 40The SDL2 provider also has diagnostic environment controls. The STRETCH
variables override the corresponding configuration-file values for isolated
tests; all controls preserve existing behavior when unset:
RETRORUN_SDL_AUDIO_PREFILL_MS=20
RETRORUN_SDL_AUDIO_TARGET_MS=80
RETRORUN_SDL_AUDIO_STRETCH_PERCENT=5
RETRORUN_SDL_AUDIO_STRETCH_LOW_MS=40PREFILL_MS delays initial playback until the requested reserve exists;
TARGET_MS controls the high-watermark used for submission backpressure. The
two STRETCH settings enable an explicitly inaccurate low-end mode:
below the low watermark, SDL2 linearly resamples a batch to add at most the
configured percentage of frames. This can reduce queue starvation when a core
supplies slightly less audio than the output device consumes, but it may alter
pitch or synchronization. RG351V automated tests across Sonic Adventure 2,
Soul Calibur, Crazy Taxi, Dead or Alive 2 and Power Stone found no audio drops
and a neutral aggregate frame count; the first manual Sonic test judged the
result almost perfect. Keep it opt-in until music-loop, transition and A/V-sync
checks cover a wider game set.
The native GO2/OpenAL backend provides the same opt-in low-watermark compensation. It remains disabled in the recommended configuration:
retrorun_go2_audio_stretch_percent = 0
retrorun_go2_audio_stretch_low_ms = 20It is disabled by default and is also disabled automatically when
retrorun_audio_stable_buffer = true. The percentage is clamped to 0–10
and the low watermark to 0–200 ms. Environment variables
RETRORUN_GO2_AUDIO_STRETCH_PERCENT and
RETRORUN_GO2_AUDIO_STRETCH_LOW_MS override the configuration for isolated
tests. GO2 tracks the number of audio frames remaining in each OpenAL buffer;
when the usable queue falls below the watermark, it linearly expands only the
next submitted batch. Benchmark JSON records the resolved settings, queue
depth observations and adaptive_stretch_frames.
This GO2 mode is experimental. Controlled RG351V measurements selected
3 percent below 20 ms as the least costly candidate, but the subsequent
Soul Calibur listening test found no substantial improvement and still heard
the soundtrack slow when emulation fell behind. It can soften short queue
shortages, but it cannot decouple audio playback from emulation speed. Keep
the percentage at 0 for normal play; larger values can make pitch and A/V
synchronization errors more noticeable.
For repeatable tests the values can also be supplied without editing
retrorun.cfg:
./retrorun-hybrid --benchmark 60 \
--benchmark-set audio_backend=go2 \
--benchmark-set go2_audio_stretch_percent=3 \
--benchmark-set go2_audio_stretch_low_ms=20 CORE ROMAmberELEC already builds SDL2 with KMSDRM and OpenGL ES. To include both RetroRun variants in an AmberELEC image, its RetroRun package must:
- retain the existing default
make config=releasenative build; - add SDL2 to the package dependencies;
- run
make PLATFORM=sdl2 config=releaseusing the AmberELEC target sysroot; - install
retrorun-sdl2alongside/usr/bin/retrorun.
Keeping the two executable names separate makes it possible to select the backend per system or per game without changing the existing launcher.
ArkOS historically includes retrorun and retrorun32. The SDL2 variant can
be built using a matching 32-bit or 64-bit distribution toolchain. Check the
architecture of the selected core before choosing the compiler. Since device
images can ship different SDL2 builds, confirm that the target SDL2 provides
the kmsdrm video driver.
Install SDL2 and libpng with Homebrew:
brew install sdl2 libpng
makeThis creates retrorun using SDL2 and Desktop OpenGL. The default window is
960x720 and can be overridden with:
RETRORUN_WINDOW_WIDTH=1280 RETRORUN_WINDOW_HEIGHT=960 ./retrorun ...The general command syntax is:
retrorun [options] CORE_LIBRETRO GAME
Common options:
| Option | Description |
|---|---|
-s DIR, --savedir DIR |
Save and save-state directory. |
-d DIR, --systemdir DIR |
BIOS/system directory exposed to the core. |
-c FILE |
Configuration file path. |
-a RATIO, --aspect RATIO |
Force a numeric aspect ratio. |
-v VALUE, --volume VALUE |
Initial volume. |
-b VALUE, --backlight VALUE |
Initial backlight level on supported devices. |
-f, --fps |
Show the FPS counter. |
-t, --triggers |
Enable trigger support. |
-n, --analog |
Disable forced left-analog-to-D-pad mapping. |
-A MODE, --analog-to-digital MODE |
Analog-to-D-pad mode: none, left, right, left_forced or right_forced. Overrides the configuration file. |
-g |
Enable the GPIO joypad path used by some native devices. |
-r, --restart |
Enable the restart behaviour used by distribution launchers. |
Validated and retained per-game configurations for Flycast 2022 Low-End are
stored in
profiles/flycast2022-lowend.
The profile filenames include the Dreamcast product number so launchers can
select them independently of the ROM filename.
The modified Flycast core can also expose the Product number to RetroRun before content startup. Enable automatic selection with:
retrorun_flycast_game_profile = best_validateddisabled keeps the normal configuration, best_validated selects the
visually approved profile and best_performance selects the fastest retained
profile, including documented compromises. RetroRun contains catalog version
20260930 and checks for a strictly newer flycast-game-catalog.ini beside
its executable. With catalog updates set to auto (the default), an
at-most-daily background check downloads a newer valid catalog from the
navy1978/retrorun repository into the active configuration directory; it is
used on the next launch. Invalid files, unknown games and metadata-only
baseline entries leave the normal configuration untouched. Only RetroRun-aware Flycast builds that expose the
pre-launch Product-number extension show Info > Flycast catalog; stock
Flycast and every other core hide it. The submenu shows the short recognition,
Product number, profile, version and source status, while Catalog lists only
games with a validated global, chip or device-specific profile and their known
retail Product numbers. Untested title-only metadata is deliberately hidden.
Catalog schema 3 shares tuned profiles by SoC: RK3326 uses the profiles
validated on RG351MP, RK3566 those validated on RG353M, and RK3399 those
validated on RG552. A sparse device-specific profile may override individual
settings after the chip profile. Existing device-name detection remains the
first choice; only an unmapped name falls back to the NUL-separated Device
Tree compatible property in /proc/device-tree/compatible (or its sysfs
mirror). The effective order is global, chip, then device override.
A profile may also request a validated Flycast binary variant before content
startup. In addition to the existing upstream snapshots, renderq_wait8
selects flycast_renderq_wait8_libretro.so beside the requested core, or the
path configured as retrorun_flycast_renderq_wait8_core. RetroRun performs a
single guarded restart and then reapplies the complete transient game profile.
mkdir -p saves system
./retrorun \
-s ./saves \
-d ./system \
"$HOME/Library/Application Support/RetroArch/cores/bsnes2014_performance_libretro.dylib" \
"$HOME/Downloads/Super Ghouls 'N Ghosts (USA).sfc"Load the distribution environment first, then launch the SDL2 executable:
. /etc/profile
SDL_VIDEODRIVER=kmsdrm SDL_AUDIODRIVER=alsa \
./retrorun-sdl2 \
-s /storage/roms/saves \
-d /roms/bios \
/path/to/core_libretro.so \
/path/to/game.romIf the distribution already exports the correct SDL drivers, omit the
SDL_VIDEODRIVER and SDL_AUDIODRIVER assignments. AmberELEC may use ALSA or
PulseAudio depending on its configuration.
The Linux SDL2 target starts fullscreen using the current display mode. To test it in a window under X11 or Wayland:
RETRORUN_WINDOWED=1 \
RETRORUN_WINDOW_WIDTH=960 \
RETRORUN_WINDOW_HEIGHT=720 \
./retrorun-sdl2 -s ./saves -d ./system /path/to/core.so /path/to/game.rom#!/bin/sh
. /etc/profile
CORE="$1"
ROM="$2"
PLATFORM="$3"
exec /usr/bin/retrorun-sdl2 \
--triggers \
-s "/storage/roms/$PLATFORM" \
-d /roms/bios \
"$CORE" \
"$ROM"RetroRun reads a simple key = value configuration file.
The parser accepts Unix or Windows line endings, UTF-8 BOMs, blank lines,
comments beginning with # or ;, inline comments after whitespace, and
single- or double-quoted values. Quotes are useful when a value contains #,
;, leading/trailing whitespace or escape sequences. Duplicate keys are
reported and the last value wins. Malformed entries and invalid typed values
produce a line-numbered warning or error instead of being silently accepted.
- Native GO2 default:
/storage/.config/distribution/configs/retrorun.cfg. - SDL2 default:
./retrorun.cfgin the current working directory. - Every backend: pass
-c /path/to/retrorun.cfgto select another file. An explicit-calways takes precedence over aretrorun.cfgin the current working directory.
The configuration file (retrorun.cfg) contains settings for different cores.
Example:
# ---- RETRORUN INTERNAL SETTINGS ----
retrorun_screenshot_folder = /storage/roms/screenshots
# ---- FLYCAST ----
flycast_threaded_rendering = enabled
flycast_internal_resolution = 640x480
flycast_anisotropic_filtering = off
flycast_enable_dsp = disabled
flycast_synchronous_rendering = disabled
flycast_enable_rtt = disabled
flycast_enable_rttb = disabled
flycast_delay_frame_swapping = disabled
# Alpha sorting should be set to per strip
flycast_alpha_sorting = per-strip (fast, least accurate)
flycast_div_matching = auto
# Texupscale should be off
flycast_texupscale = off
# Vibration support should be on
flycast_enable_purupuru = enabled
flycast_auto_skip_frame = disabled
flycast_gdrom_fast_loading = enabled
flycast_volume_modifier_enable = disabled
flycast_framerate = fullspeed
flycast_anisotropic_filtering = disabled
# ---- FLYCAST2021 ----
flycast2021_threaded_rendering = enabled
flycast2021_internal_resolution = 640x480
flycast2021_anisotropic_filtering = off
flycast2021_enable_dsp = disabled
flycast2021_synchronous_rendering = disabled
flycast2021_enable_rtt = disabled
flycast2021_enable_rttb = disabled
flycast2021_delay_frame_swapping = disabled
# Alpha sorting should be set to per strip
flycast2021_alpha_sorting = per-strip (fast, least accurate)
flycast2021_div_matching = auto
# Texupscale should be off
flycast2021_texupscale = off
# Vibration support should be on
flycast2021_enable_purupuru = enabled
flycast2021_gdrom_fast_loading = enabled
flycast2021_volume_modifier_enable = disabled
flycast2021_framerate = fullspeed
flycast2021_anisotropic_filtering = disabled
# ---- PARALLEL N64 ----
parallel-n64-framerate = fullspeed
parallel-n64-filtering = nearest
parallel-n64-audio-buffer-size = 1024
parallel-n64-gfxplugin-accuracy = medium
parallel-n64-screensize = 640x480
parallel-n64-gfxplugin = rice
parallel-n64-pak1 = rumble
parallel-n64-pak2 = memory
parallel-n64-pak3 = none
parallel-n64-pak4 = none
# ---- JAGUAR ----
virtualjaguar_doom_res_hack = enabled
virtualjaguar_pal = disabled
virtualjaguar_usefastblitter = enabled
virtualjaguar_bios = enabled
# ---- PPSSPP ----
ppsspp_cpu_core = JIT
#ppsspp_detect_vsync_swap_interval = disabled
ppsspp_fast_memory = enabled
ppsspp_frameskip = 0
ppsspp_frameskiptype = Number of frames
ppsspp_ignore_bad_memory_access = enabled
ppsspp_internal_resolution = 480x272
ppsspp_rendering_mode=buffered
# ---- DUCKSTATION ----
duckstation_CPU.Overclock = 100
duckstation_Controller1.Type=AnalogController
# ---- SWANSTATION ----
swanstation_CPU_Overclock = 100
swanstation_GPU_Renderer = Software(*) Pay attention to the parameter names, as they follow the naming convention
of the core. For example, in some distributions, the Flycast core is named
Reicast. In such cases, parameters should be prefixed accordingly—e.g.,
flycast_threaded_rendering should be renamed to
reicast_threaded_rendering.
RetroRun integrates the official rcheevos client in softcore mode. Enable it
in retrorun.cfg and provide a RetroAchievements username and token:
retrorun_achievements_enabled = true
retrorun_achievements_username = your_username
# Token generated by a previous rcheevos login. This is not the Web API Key.
retrorun_achievements_token = your_login_token
retrorun_achievements_unofficial = false
retrorun_achievements_encore = falseThe Web API Key displayed in the RetroAchievements website authentication page
is not a login token and cannot be used here. For the first login, omit the
token and set retrorun_achievements_password. After a successful login,
RetroRun stores the token returned by RetroAchievements and removes the
plaintext password from the configuration file. Login, game identification
and unlock requests run in the background. RetroRun displays a small
notification when a game is identified or an achievement is unlocked.
Hardcore mode is intentionally not enabled yet because it requires enforcing
restrictions on save states, fast-forward and other frontend features.
The service can also be configured at runtime under Settings > RetroAchievements. The status row reports whether it is disabled, waiting for credentials, signing in, or logged in. Username and password are entered with the physical keyboard on SDL2 or the shared virtual keyboard on GO2. Password text is masked; after a successful login it is replaced in the configuration file by the rcheevos login token.
Set retrorun_achievements_encore = true to reactivate achievements already
unlocked by the current user. This is useful for testing notifications; the
server does not award the same achievement or its points twice.
RetroAchievements configuration reference:
| Setting | Description |
|---|---|
retrorun_achievements_enabled |
Enables the service; default is false. |
retrorun_achievements_username |
RetroAchievements account name. |
retrorun_achievements_password |
Plaintext password used only for the first login; removed after a token is obtained. |
retrorun_achievements_token |
Login token saved after authentication. This is not the Web API Key. |
retrorun_achievements_unofficial |
Includes unofficial achievements when true; default is false. |
retrorun_achievements_encore |
Reactivates already unlocked achievements for local testing; default is false. |
Static PNG decorations can fill the unused area around the game without stretching the emulated image. Enable them under Settings > Video > Screen decorations or with:
retrorun_decorations = auto
# Optional. The default is a decorations directory next to retrorun.cfg.
retrorun_decorations_path = /storage/.config/retrorun/decorationsRetroRun loads the first matching file and keeps the converted RGB565 surface in memory. Explicit RetroRun files take priority; after them it can reuse a bezel already installed by the host distribution:
decorations/games/<system>/<rom name>.png
decorations/games/<rom name>.png
decorations/systems/<system>.png
decorations/default.png
AmberELEC packs are detected in /tmp/overlays/bezels and
/storage/roms/bezels. RetroRun reads the active pack and optional system
override from distribution.conf, supports its full-name, short-name,
numbered and default per-game .cfg files, then falls back to the system PNG.
Compatible packs in /roms/bezels or /roms2/bezels are also detected for
ArkOS and user installations, either below a named pack such as default or
with systems directly below bezels. If AmberELEC has generated
/tmp/raappend.cfg, its custom viewport is reused. Detection and parsing occur
once when the game starts; no distribution-specific work is done per frame.
RetroRun only reads artwork already installed by the distribution and does not
redistribute it.
An optional .info file beside a PNG can define the exact game viewport using
Batocera-style width, height, top, left, bottom and right values.
For example, default.png can be accompanied by default.info:
{
"width": 1920,
"height": 1080,
"top": 0,
"left": 240,
"bottom": 0,
"right": 240
}The values describe the artwork's reference resolution and border sizes; RetroRun scales the resulting viewport to the current display and fits the game inside it without changing the game's aspect ratio. The viewport never affects menus or other frontend pages. Parsing happens only when the decoration is loaded, not during normal frame rendering.
The Settings > Video > Decorations menu can download a small selection of
static borders directly from libretro/common-overlays. RetroRun downloads
only the selected PNG, converts its libretro viewport to a local .info file
and stores attribution beside it under downloads/libretro. It never downloads
or extracts the complete repository. Installed artwork is licensed under
CC BY 4.0 and can be updated or
removed from the same menu. Downloads run in the background while the menu
remains responsive.
The same menu separates the configured source from the artwork currently in
use. Source: Automatic follows an installed distribution pack, while
Source: RetroRun, Source: AmberELEC: <pack> and Source: ArkOS: <pack>
select one explicitly. Using: reports the source that actually matched the
current game. Distribution choices appear only when their directories are
present; the scan runs during menu initialization and never per frame.
<system> is the first directory after roms or roms2 (falling back to the
ROM's parent directory), and <rom name> is the filename without its
extension. This also works when games are grouped in subdirectories. The local
layout is compatible with the core of Batocera's decoration naming scheme.
Images are installed separately and no third-party artwork is bundled with
RetroRun. If no PNG matches, no decoration is composited and the game keeps
its regular video layout. PNG alpha is preserved and matching artwork is
composited over the game, allowing curved frames to mask the rectangular core
image correctly. On GO2 this source-over operation is handled by RGA hardware;
the full artwork is cached in all three presenter framebuffers and normally
only the game-damaged rectangle is blended again.
Frontend video settings:
| Setting | Values and behaviour |
|---|---|
retrorun_aspect_ratio |
auto, 2:1, 4:3, 5:4, 16:9, 16:10, 1:1 or 3:2. |
retrorun_pixel_perfect |
true or false; default is disabled. |
retrorun_tate_mode |
auto, enabled, disabled or reversed (reverted remains accepted for compatibility). |
retrorun_fps_counter |
Enables the on-screen FPS counter with true, enabled or 1. |
retrorun_show_loading_screen |
Shows the logo and loading message while a core initializes, for at least 700 ms. |
retrorun_ui_profile |
auto, handheld or desktop; default is auto. It can also be changed at runtime under Settings > Video. |
retrorun_video_filter |
off, nearest or linear; default is off. |
retrorun_video_shader |
off, scanlines or crt; default is off. |
retrorun_decorations |
off or auto; loads a matching local PNG or uses the generated fallback. |
retrorun_decorations_path |
Optional root directory for locally installed decoration sets. |
retrorun_decoration_source |
auto, retrorun or the identifier of an installed AmberELEC/ArkOS pack. Normally managed from the Decorations menu. |
retrorun_decoration_pack |
Identifier of the selected downloadable RetroRun/libretro pack. Normally managed from the Decorations menu. |
retrorun_loop_declared_fps |
Paces the frontend using the frame rate declared by the core. |
retrorun_adaptive_frameskip |
Enables adaptive presentation skipping; experimental and false by default. |
retrorun_frameskip |
Fixed number of video callbacks skipped after each presented frame, from 0 to 5; default is 0 and takes precedence over adaptive frameskip. |
retrorun_drm_direct_scanout |
GO2/DRM only: true or false; default is false. Direct scanout bypasses the RGA copy for compatible hardware-rendered frames. Enable it only after testing the relevant device and core; some cores, including parallel_n64, may be incompatible. The DRM diagnostics page can test it temporarily without changing this setting. |
retrorun_video_renderer |
SDL2 only: auto, software, opengl or vulkan. Requires restart. Vulkan is not implemented yet. On Linux opengl means OpenGL ES. |
retrorun_vsync |
SDL2 only; default is false and can also be changed from the menu. |
General and input settings:
| Setting | Description |
|---|---|
retrorun_log_level |
INFO, DEBUG, WARNING or ERROR. |
retrorun_core_log_level |
Independent log level for libretro cores; defaults to ERROR. Set it explicitly to INFO or DEBUG for core diagnostics while keeping RetroRun's level independent. |
retrorun_log_to_file |
Duplicates RetroRun and libretro core logs to retrorun.log in the directory containing the active retrorun.cfg (for example /storage/.config/distribution/configs/retrorun.log on AmberELEC). The file is recreated at each launch; defaults to false. |
retrorun_device_name |
Overrides automatic device identification (for example, Miniloong Pocket 1). |
retrorun_screenshot_folder |
Destination for screenshots. |
retrorun_audio_buffer |
Audio buffer value such as -1, 256, 512 or 1024. |
retrorun_audio_stable_buffer |
Optional extra audio buffering for difficult cores on SDL2 and GO2 (false by default). |
retrorun_sdl_audio_stretch_percent |
SDL2-only low-watermark audio compensation, clamped to 0–10; 0 disables it and is the default. The tested RG351V low-end value is 5. |
retrorun_sdl_audio_stretch_low_ms |
SDL2 queue threshold for compensation, clamped to 0–200 ms; defaults to 40. |
retrorun_go2_audio_stretch_percent |
GO2/OpenAL low-watermark audio compensation, clamped to 0–10; 0 disables it and is the recommended default. The measured 3 percent profile remains experimental after an inconclusive manual listening test. |
retrorun_go2_audio_stretch_low_ms |
GO2/OpenAL queue threshold for compensation, clamped to 0–200 ms; defaults to 40; the experimental RG351V profile used 20. |
retrorun_go2_audio_prebuffer_ms |
GO2/OpenAL startup prebuffer, clamped to 0–200 ms; defaults to 60. Values below twice retrorun_audio_buffer are raised to that safe minimum. |
retrorun_force_audio_multithread |
Runs blocking audio submission on a dedicated bounded worker thread. It can help demanding cores, especially on RG552; defaults to false. |
retrorun_auto_save |
Saves automatically during shutdown. |
retrorun_auto_load |
Loads the automatic save at startup. A missing first-run state is reported as the short informational message No auto state, not as an error. |
retrorun_analog_to_digital |
Analog-to-D-pad mode: none, left, right, left_forced or right_forced. Non-forced modes are disabled automatically when the core requests native analog input. Defaults to left_forced for backward compatibility. |
retrorun_force_left_analog_stick |
Deprecated compatibility setting. true maps to left_forced, false maps to none; ignored when retrorun_analog_to_digital is present. |
retrorun_swap_l1r1_with_l2r2 |
Exchanges shoulder buttons and triggers. |
retrorun_swap_sticks |
Exchanges left and right analog sticks. |
retrorun_alternative_input_mode |
Uses the ArkOS-style Select/F2 hotkeys. |
retrorun_mouse_speed_factor |
Mouse emulation speed; default is 5. |
retrorun_force_video_multithread |
Legacy boolean which requests threaded hardware-frame presentation on RG552 and the RG353 family. In the default auto mode, RG552 also retains its historical automatic Flycast 2021-family path. |
retrorun_video_multithread_mode |
Selects auto (backward-compatible behaviour), enabled, or disabled. Unlike the legacy boolean, disabled also turns off the automatic RG552/Flycast 2021-family path, allowing a real controlled A/B test. Unsupported devices still ignore threaded presentation. |
retrorun_flycast_game_profile |
Flycast-only Product-number catalog: disabled (default), best_validated or best_performance. A newer valid flycast-game-catalog.ini beside RetroRun overrides the built-in catalog. |
retrorun_flycast_catalog_update |
auto (default) or disabled. When a Flycast game profile is active, auto checks GitHub at most once per day in a separate process and atomically caches only a newer, valid catalog. |
retrorun_enable_key_log |
Logs logical button names at DEBUG level. |
Native-device overrides:
retrorun_extra_retrogame_nameretrorun_extra_osh_nameretrorun_extra_evdev_nameretrorun_rumble_type(pwmorevent)retrorun_rumble_eventretrorun_rumble_pwm_fileretrorun_disable_rumble
Settings not beginning with retrorun_ are forwarded as libretro core
options. Their names depend on the core library name. If a distribution calls
the core reicast rather than flycast, its option prefix may also need to be
changed.
The Settings menu writes user-facing choices back to the active
retrorun.cfg. Saves, controls, video, audio, performance,
RetroAchievements and diagnostics are kept in separate submenus. Settings
labelled (restart) are stored immediately but take effect when RetroRun or
the core is restarted. Backend-specific entries are only shown where they are
usable: SDL renderer and VSync on SDL2, DRM direct scanout on GO2/DRM, and
forced threaded video on RG552 and the RG353 family. Fixed and adaptive frameskip are
mutually exclusive.
The device information page also reports the detected SoC. On Rockchip
handhelds RetroRun reads the device-tree compatibility data first (for example
Rockchip RK3326, Rockchip RK3566 or Rockchip RK3399) and only falls back
to its known-device table when that data is unavailable.
Example Flycast options:
flycast_threaded_rendering = enabled
flycast_internal_resolution = 640x480
flycast_enable_dsp = disabled
flycast_synchronous_rendering = disabled
flycast_alpha_sorting = per-strip (fast, least accurate)
flycast_texupscale = off
flycast_enable_purupuru = enabled
flycast_gdrom_fast_loading = enabledSDL-compatible controllers are detected automatically. The default keyboard mapping for the SDL2 backend is:
| Keyboard | RetroPad control |
|---|---|
| Arrow keys | D-pad |
X, Z, S, A |
A, B, X, Y |
| Return, Backspace | Start, Select |
Q, W |
L1, R1 |
1, 2 |
L2, R2 |
3, 4 |
L3, R3 |
| Escape or window close | Quit |
Default controller hotkeys:
| Combination | Action |
|---|---|
| L3 + R3 | Open or close the RetroRun menu. |
| Select + Start | Exit RetroRun; hold/repeat for confirmation. |
| Select + Y | Toggle FPS display. |
| Select + B | Take a screenshot. |
| Select + A | Pause or resume. |
| Select + R2 | Toggle fast-forward. |
| Select + R1 | Save the current state slot. |
| Select + L1 | Load the current state slot. |
| Select + Up/Down | Select the next/previous state slot. |
On Miniloong Pocket 1, the dedicated Menu button replaces Select as the frontend hotkey modifier for all combinations above. Select remains available to the emulated game.
With retrorun_alternative_input_mode = true, Select or F2 is used with X to
open the menu, Y for FPS, B for screenshots, A for pause and Start for exit.
Logical controls can be assigned in retrorun.cfg:
retrorun_mapping_button_up = DPadUp
retrorun_mapping_button_down = DPadDown
retrorun_mapping_button_left = DPadLeft
retrorun_mapping_button_right = DPadRight
retrorun_mapping_button_a = A
retrorun_mapping_button_b = B
retrorun_mapping_button_x = SELECT
retrorun_mapping_button_y = Y
retrorun_mapping_button_select = SELECT
retrorun_mapping_button_start = START
retrorun_mapping_button_l1 = TopLeft
retrorun_mapping_button_r1 = TopRight
retrorun_mapping_button_l2 = TriggerLeft
retrorun_mapping_button_r2 = TriggerRight
retrorun_mapping_button_l3 = F1
retrorun_mapping_button_r3 = F2
retrorun_mapping_button_f1 = F1
retrorun_mapping_button_f2 = F2To discover the logical name generated by a device, enable:
retrorun_enable_key_log = true
retrorun_log_level = DEBUGThe log then prints entries such as:
Joypad button pressed: [BTN_TRIGGER_HAPPY2] - [F2]
Use the second value, F2 in this example, in a mapping entry. Directional
values are named DPadUp, DPadDown, DPadLeft and DPadRight in mapping
entries.
The frontend accesses input, audio and graphics through
src/platform/platform.h.
The native implementation is in src/platform/platform_go2.cpp; the macOS and
Linux implementation is in src/platform/platform_sdl.cpp. Menus and OSD composition are
shared by both backends. See PORTING.md for the backend contract.
Current SDL2 Linux limitations:
- actual compatibility must be validated on every handheld model;
- KMSDRM display rotation depends on the SDL2 patches shipped by the distro;
- battery and brightness integration is less complete than in the native GO2 backend;
- Vulkan is visible as a configuration value but is rejected because the libretro Vulkan interface is not implemented;
- the SDL2 build currently targets OpenGL ES 3 for hardware-rendered cores.
For supported Anbernic devices, GO2/DRM remains the safest production backend. SDL2/KMSDRM is intended as an alternative and as the portable path for new devices.
The Build RetroRun binaries workflow can be started manually from the repository's Actions tab. It produces three downloadable artifacts:
retrorun-linux-go2-aarch64for the native GO2/DRM backend;retrorun-linux-sdl2-aarch64for Linux handhelds using SDL2/KMSDRM;retrorun-macos-sdl2-arm64for Apple Silicon macOS.
The macOS and SDL2 Linux jobs run on GitHub-hosted Apple Silicon and ARM64
runners. The GO2 job runs on a standard GitHub Ubuntu runner but compiles
inside the AmberELEC build container, using the same RG351P ARM64 toolchain,
librga and target sysroot as the distribution. The initial GO2 build may take
longer while that environment is prepared; its toolchain, sources and compiler
cache are retained between runs to speed up later builds. No self-hosted runner
is required for this public repository.
When launching the workflow, select only the artifacts needed for the test. After it completes, open the run summary and download the corresponding artifact from Artifacts. Artifacts are kept for 30 days.
RetroRun was initially developed by OtherCrashOverride until 2020. Development has been continued by navy1978 since 2021. This version integrates and extends libgo2 and rg351p-js2box.
- rcheevos, integrated in
deps/rcheevos, provides the RetroAchievements runtime and hashing client under the MIT License. - SDL2, libpng, libcurl and zlib provide the portable window, input, audio, PNG, network and compression facilities used by the SDL2 and macOS builds.
- The native GO2/DRM backend additionally uses Linux system libraries for DRM/GBM, EGL/OpenGL ES, RGA, ALSA, OpenAL Soft and libevdev.
The optional downloadable screen decorations are sourced from libretro/common-overlays and are licensed under CC BY 4.0. RetroRun records this attribution beside each downloaded artwork and does not bundle the artwork in the source repository.
Thanks to Cebion, Christian_Haitian, dhwz, madcat1990, pkegg, superdealloc and Szalik for their contributions and support.

