Consistent licensing
Add .gitignore
Add new compiliation units from libretro-common
The retro_frontend component is a Genode native runtime for Libretro. It is the Genode analogue to the Retroarch reference frontend. A Libretro application, typically an game engine or emulator, implements the Libretro API and is linked as a shared library, referred to as a "core". A Libretro frontend loads these cores and registers callbacks for features implemented in the frontend to the core. The frontend is responsible for managing facilities such as framebuffers, audio, input, and driving the core once per-video frame.
This frontend is a from-scratch implementation with a few algorithms borrowed from the libretro-common repository. It is Genode specific and unportable. The current implementation is approximately 2.5 KSLOC, may it serve as a reference for creating other Libretro frontends or Genode components.
To build the frontend this repository must be placed in a super-repository with
a Tup build system and a Genode SDK must be available.
Please refer to the authors super-repo
as an example. The typical workflow is to define a Genode runtime package that
bundles a core and frontend together, build a "mini-depot" using the tup
command, and copy this a running Sculpt instance.
Most features present in Retroarch are not found in this frontend. Some are appropriate to internalize and others are best implemented as additional components.
To list a few:
Patches are welcome!
The 'retro_frontend' requires at minimum 'Timer', 'Nitpicker'. Multiple
additional 'Input' sessions are requested when the frontend is configured with
multiple controllers. 'Audio_out' sessions are only requested if a core
indicates that it has audio output, in which case the 'Audio_out' service is not
optional. Should a core request a hardware rendering context the frontend will
dynamically load the Genode EGL library and the Genode environment must route
the request for EGL driver library appropriately. Hardware rendering is
otherwise an experimental frontend feature and is undocumented.
The most important configuration choice is the core. Core selection is not managed by the frontend but by the parent environment. In the common case every Libretro core linked for Genode will be named libretro.so and the core is selected during packaging. The frontend has no interface or logic for selecting a core at runtime.
For many cores it is sufficient that the frontend will search the root of its
file-system for an appropriate image using file extension matching. To invoke
this behavior the frontend must have an empty <game/>
node within its
configuration. To load a specific image file or data directory the a path
attribute may be added to the game node. A second meta attribute is supported,
but its semantics are core-specific and it is seldom used. When no 'game' node
is present a core must explicitly indicated to the frontend that no game data is
required.
To Load a data file:
<config ...>
<game path="cartridge.bin"/>
...
</config>
The frontend supports multiple controllers and maps input codes from Genode to
Libretro. Controllers are specified by the default-controller and controller
nodes within the configuration. The default-controller configuration is
applied to the Nitpicker Input session and is always connected.
For each controller it is recommended to specify a device type. The frontend and
core will assume by default that the controller is a joypad and will likely only
poll for joypad input. Defining a device type at the frontend does not restrict
or mask controller input from other types, but determines which inputs the core
will poll and how inputs are interpreted. There are several basic device types
and cores may define special device types by sub-classing from a basic type. A
ore will publish its device types and descriptions through the frontend via the
'controllers' report described later in this document. Cores may additionally
publish textual descriptions of each button on each port via an 'input' report.
Base supported device types: 1 | Joypad 2 | Mouse (axes not supported) 3 | Keyboard
Mapping Nitpicker input to a Libretro keyboard on port 0, a joypad with remapping to port 1, and a joypad derived device on port 2:
<config ...>
<default-controller port="0" device="3"/>
<controller port="1" device="1">
<map from="BTN_TR" to="R2"/>
<map from="BTN_TR2" to="R"/>
<map from="BTN_TL" to="L2"/>
<map from="BTN_TL2" to="L"/>
</controller>
<controller port="2" device="257"/>
</config>
Port 1 in the example above port show four key remappings. In this example the
four trigger or bumper buttons on a gamepad are vertically reversed. The from
attribute on a map node indicates a Genode input code and the to attribute
indicates a Libretro input code. Genode input codes may be determined externally
using the test-input component and Libretro input codes may be found in
input report described later. Mappings may only be made within the base
device. Mapping keyboards to joypads is supported but remapping keyboard keys is
not. The input_merger component may be used to remap the Libretro keyboard
device.
Cores usually request their own configuration options from the frontend and
these are in turn resolved from the XML configuration provided to the frontend.
These options are published by the core via the frontend variables report
described later. A variable node within the configuration binds a
configuration value to a configuration key.
<config ... >
<variable key="region" value="PAL"/>
...
</config>
The frontend initializes a POSIX environment for cores by preemptively linking to the Genode C runtime. In this regard the frontend should be configured with a VFS and connections for standard I/O.
<config>
<vfs>
<tar name="..."/>
<dir name="dev"> <log label="core"/> </dir>
</vfs>
<libc stdout="/dev/log" stderr="/dev/log"/>
</config>
The frontend published information from the core in the form of Report sessions. The reports are variables controllers, and inputs.
The variables report contains pairs of keys and possible values. These inform what variables should be included in the configuration passed to the frontend. Valid options for a given variable are separated by the '|' character.
<variables>
<variable key="nospritelimit" value="No Sprite Limit; disabled|enabled"/>
<variable key="overscan_v" value="Crop Overscan (Vertical); enabled|disabled"/>
<variable key="region" value="Region Override; Auto|NTSC|PAL|Dendy"/>
</variables>
The controllers report conveys which device types a core recognizes or expects and informs how inputs to the frontend should be configured.
<controllers>
<controller port="0">
<type desc="Gamepad" id="1"/>
<type desc="Keyboard/Mouse" id="3"/>
<type desc="Zapper" id="258"/>
</controller>
</controllers>
The input report describes the function of different inputs over different controller ports. The value of an 'id' attribute on a descriptor node may be used to map from a Genode input to a Libretro input as described previously.
<inputs>
<descriptor port="0" device="JOYPAD" index="0" id="LEFT" description="D-Pad Left"/>
<descriptor port="0" device="JOYPAD" index="0" id="UP" description="D-Pad Up"/>
<.../>
<descriptor port="0" device="JOYPAD" index="0" id="SELECT" description="Toggle console"/>
<descriptor port="0" device="JOYPAD" index="0" id="START" description="Menu"/>
</inputs>
The frontend recognizes the Pause key found on standard keyboards and acts
accordingly. When the frontend pauses the core is halted and save RAM is dumped
to file for games that are loaded from ROM. When a game warns "do not turn of
the power" it is recommended to tap pause twice after the warning to dump the
RAM. When unpausing the frontend will load back save RAM and synchronize the
framebuffer and audio-out buffer.
The frontend will restart when it receives CTRL-ALT-DELETE (if none of these keys are swallowed by the desktop environment). These will not replace the core but it will cause a game reload. For cores that load cartridge data into memory, this allows the user to replace cartridge files while the frontend is running and a three-finger-salute will cause the frontend to reset with a new cartridge.