After creating my first game, Unicopia, with Godot 4.x, the Steam Deck had always been my target platform.
Developing the game on both Windows and macOS, I added controller support early on and was grateful to find the game worked effortlessly with the Steam Deck, initially using Proton, and then using a specific Linux build.
Apart from a minor hurdle ensuring the Steam overlay worked properly, developing for the Steam Deck proved itself the dream platform for modern retro games.
However, given Unicopia’s roots in 80s-90s arcade games, I also wanted to do something to honour its arcade ancestors, so after getting it running on the Steam Deck I decided what better way than to also port it to the Picade arcade cabinet. Since the game is fundamentally retro, and isn’t CPU or GPU intensive—running at 3,000 FPS on my dev machine—I hoped it’d be a pretty easy port.
Assembling the cabinet
The Picade is, at heart, a simple thing. A small arcade cabinet with a 8” or 10” display, running on a Raspberry Pi, and perfectly suited for a desktop or a coffee table.
Ordering a 10” Picade with a Raspberry Pi 4 Model B (4GB), a Power Supply, and a 32GB SD micro card, I cleared a weekend and settled in for a fast build.
Fuelled by naïve optimism and caffeine, assembling the Picade cabinet wasn’t hard, and aside from temporarily misplacing a couple of tiny screws, withint 90 minutes I’d got a functioning cabinet booting up the recommended OS, RetroPie 4.8.
Choosing an OS
Although RetroPie is fine for emulators, since Godot needs an X11 or Wayland display server to render graphics, the next step was either installing a display server onto RetroPie, or choosing an OS with a display server included.
Compiling Unicopia for Linux arm32 and arm64, I worked my way through a variety of alternatives OSes.
RetroPie 4.8—based on Raspberry Pi OS Lite Buster 32-bit—with X11 installed on-top worked without too much fiddling, although the game performance was atrocious.
In contrast, deploying the game to Raspberry Pi OS with Desktop Bookworm 32-bit and 64-bit performed perfectly without any tweaks.
Finally, Raspberry Pi OS with Desktop Bullseye 32-bit and 64-bit performed mostly fine, although there were various rendering glitches that’d need tracking down.
While Bookworm was clearly going to be the best choice for Godot, unfortunately I couldn’t get the Picade’s HAT working with either Bookworm or a 64-bit OS, so I finally settled on Raspberry Pi OS Bullseye 32-bit with Desktop.
Configuring Bullseye to work with Godot meant installing both GLES and Vulkan, so I opted for piKiss as the easiest way to install them both.
Once installed, the key OS versions and graphics libraries were as follows:
Raspbian Bullseye 32Bit
Kernel 6.1.21-v8 +
Mesa 20.3.5
OpenGL ES 3.1
OpenGL 2.1
Vulkan 1.2.162
Although the game performance was mostly okay, there were a couple of game scenes such as the Unicorn exiting a level, which used a Godot GPUParticles2D node and suffered from performance stutters when the textures were first loaded.
Checking the terminal, I noticed a warning that Godot couldn’t use Vulkan due to platform limitations:
Warning: Platform supports less than 48 textures per stage which is less than required by the Clustered renderer. Defaulting to Mobile renderer.
After a bit of research, and failing to find any way to fix the Vulkan rendering, I decided to work around the mobile renderer’s performance stutter. Swapping the problematic Godot scenes to use CPUParticles2D nodes instead of GPUParticles2D, I recompiled, deployed to the Picade and was pleased to see the stutters had gone.
Although I’d like to revisit Vulkan rendering later, given Bookworm performed better—using a later version of Mesa, and using Wayland instead of X11—I suspect the issue could be resolved by moving to Bookworm.
Enabling the Picade’s joystick, buttons and speaker
With the game now working well, the final piece of hardware to sort was the Picade HAT which connects the cabinet’s joystick, buttons, and speaker to the Raspberry Pi.
Installing the Picade HAT software was easy with Bullseye although the scripts target Raspberry Pi OS’s legacy directory structure, and don’t work with Bookworm or later versions of the OS. Although I did try updating the scripts for the new directory structure, I couldn’t get the HAT working with Bookworm, which is why I decided to settle on Bullseye.
Once the Picade software was installed, the final step was configuring its buttons to align with the game’s default control configuration, which involved updating /boot/firmware/config.txt with dtparam parameters for each of the Picade’s buttons.
Rebooting the cabinet and running Unicopia, I was greeted by the glorious retro music, which coupled with the functioning and loud clickety-clack of the joystick, added a whole new level of authenticity to the game.
Game porting
Having got the game performing well and integrated with the Picade, it quickly became clear the game needed a couple of tweaks to adjust to the Picade’s screen resolution and controls, also stubbing out its integration to Steam.
As the game was designed for resolution of 640x360 pixels, I’d already configured the Picade’s desktop resolution to 640x480, with the game running authentic feeling black bars at the top and bottom of the screen. However, as the splash screen sized itself to fill the whole screen, it effectively cut off some text, which meant creating a picade-specific 640x480 resolution version of the splash screen.
While the cabinet’s controls were all working, since the joystick’s up direction was mapped to the up key, pushing up on the joystick resulted in the player unintentionally jumping, which required a small tweak to the game to disable the up key triggering jumps.
The final change was to disable Steam integration, something I’d already coded for with an earlier Itch.io demo version. Swapping the game’s Steam integration class with a stubbed integration class, cloud saves were replaced with local file saves, and the remaining calls to Steam were replaced with stubbed alternatives.
Kiosk mode
Now the game was running as expected, the final step was to ensure the game would run in kiosk mode, starting when the cabinet was turned on, and shutting down the cabinet when the game exited.
To trigger the game launching when the desktop server started, I added a unicopia.desktop file to ~/.config/autostart/:
[Desktop Entry]
Type=Application
Name=Unicopia
Exec=/home/cornelia/unicopia.sh
I then wrote a simple bash script, /home/cornelia/unicopia.sh to run the game in the background, set the focus on the game’s window by using xdotool to trigger a mouse click, and then waiting for the game’s process to finish before shutting down the OS.
#!/bin/bash
/home/cornelia/Unicopia.arm32&
pid=$!
xdotool click --delay 1000 --repeat 1 1
wait $pid
shutdown 0
Rebooting, I nervously waited as the cabinet loaded, and within a minute was greeted by the game loading in all its retro goodness.
Lessons learned
Although I’d originally planned to port the game over a weekend, testing various different OSes to find the one that performed well and worked with the Picade HAT was time consuming, and quickly ate up the weekend.
Along with a few dead-ends—like trying to build more recent versions of Mesa for Bullseye, or trying to update the Picade HAT to work with Bookworm—ate up another few evenings. However, once I’d settled on using Raspberry Pi OS with Desktop Bullseye 32-bit, things moved quickly.
While I never got Vulkan working on Bullseye, Godot automatically falling back to the mobile renderer made it easy to get the game working, which then only needed a couple of minor changes, swapping a couple of problematic particles from the GPU to CPU. Given Godot performs notably better on Bookworm than Bullseye, enabling the Picade HAT to work with Bookworm is likely going to be key to getting higher-performance Godot games working on the Picade, but until then the Picade is clearly a suitable home for 2D retro games.
Otherwise, the requisite game changes were minimal, and after some fiddly OS configuration to ensure the Kiosk mode worked as expected, the game finally found its spiritual home in a small, but perfectly formed Picade cabinet.
If you like the idea of owning a Picade but don’t want to build your own, then I’m currently running a competition over on Steam to win the Picade mentioned in this article. You’ve read the article, now win the cabinet!
Although the game is undoubtably easier to play with the Steam Deck’s control sticks than the Picade’s noisy joystick, there’s something visceral about wrestling with a old school joystick, its click and clack ringing out just like unicorn hooves on platforms.