Exporting a Unity Game for muOS on the Anbernic RG35XX

 

Exporting a Unity Game for muOS on the Anbernic RG35XX

Developing a Unity game for muOS (MustardOS) on the Anbernic RG35XX is challenging due to both software and hardware limitations. Unity does not natively support the RG35XX’s ARM-based Linux environment, and the device’s modest specs impose strict performance constraints. Below we detail the available build targets, performance considerations, export settings, runtime requirements, and distribution options (standalone .muxapp vs PortMaster) for getting a Unity game running on muOS.

1. Unity Support for ARM Linux on muOS

Official Build Target: Unity’s standard editor does not support building Linux players for ARMv7 (32-bit) or ARM64 (AArch64) under normal licenses. By default, Unity produces Linux binaries for x86_64 (and optionally x86) architectures docs.unity3d.com. In other words, there is no out-of-the-box Unity export for ARM Linux devices like the RG35XX. Unity has an “Embedded Linux” offering (for industrial/embedded licenses) that includes ARM support, but this is not part of the regular Unity Free/Personal toolset community.arm.comcommunity.arm.com.

Implication: Without an official ARM Linux build, a Unity game cannot run natively on muOS. The community consensus is that Unity-engine games are currently not feasible on RG35XX-class handheldssuggestions.portmaster.games. For example, PortMaster (the platform for community ports) flatly rejects Unity game suggestions as “not possible” on these devicessuggestions.portmaster.games. Likewise, users on the muOS forum have noted that games made with Unity or Unreal Engine “won’t work” on the RG35XX due to platform limitscommunity.muos.dev. In summary, Unity doesn’t directly target the RG35XX’s environment, so you must rely on workarounds (detailed below) if you insist on using Unity.

2. Performance Considerations on RG35XX (muOS)

Even if you can get a Unity game running through emulation or other tricks, performance will be a major concern. The RG35XX’s hardware is equivalent to an older smartphone or Raspberry Pi, and muOS is a stripped-down Linux firmware focused on emulators. Key considerations include:

  • Hardware Specs: The original RG35XX (“OG”) uses a quad-core ARM Cortex-A9 with only 256 MB of RAMrg35xx.com, and a PowerVR SGX544MP GPU limited to OpenGL ES 2.0. Newer models like the RG35XX Plus/H have a Cortex-A53 with 1 GB RAM and a Mali G31 MP2 GPUanbernic.com, which is better but still low-end. Memory is extremely tight for Unity – the OG model’s 256 MB is below Unity’s typical minimum, and even 1 GB on the Plus is easily consumed by Unity’s engine overhead and assets. Expect to aggressively optimize memory usage (textures, audio, etc.) and possibly target only the 1 GB models for a playable experiencecommunity.muos.dev.

  • Screen Resolution: The device’s display is a 3.5-inch 4:3 panel at 640×480 resolutionrg35xx.com. Running at native 640×480 is recommended for clarity, but you may consider rendering at a lower internal resolution and upscaling if performance is an issue. Avoid high-resolution UI assets or full-screen effects beyond this resolution. Also note, muOS and most retro handheld firmwares use double buffering for vsync at 60 Hz (the screen refresh), so aim for frame rates up to 60 FPS. In practice, however, a Unity game on this hardware may only achieve ~30 FPS or less; consider providing a 30 FPS cap to maintain consistency if full speed is unattainable.

  • Graphics API: OpenGL ES 2.0 is the highest supported graphics API on these devicesportmaster.games. There is no support for Vulkan or modern desktop OpenGL profiles in muOS. In fact, most custom firmwares (including muOS) lack X11/Wayland drivers or full OpenGL, and instead use a framebuffer with OpenGL ES via the kernel’s DRM/KMS or SDL2 for renderingportmaster.gamesportmaster.games. Unity’s Linux player by default tries to use OpenGL core (and newer Unity may attempt Vulkan), which will not work on muOS. To mitigate this, you’ll need to force the game to use an OpenGL 2.0 (ES2) path. This may involve using an older Unity version or command-line flags and a translation layer (see Export Settings below). Additionally, the community uses the GL4ES wrapper library to translate desktop OpenGL calls to ES2.0 at runtimeportmaster.gamesportmaster.games. Bottom line: use only fixed-function or Shader Model 2.0 level effects; avoid advanced shaders, post-processing, or anything requiring OpenGL 3+ features, as they likely won’t render correctly on RG35XX hardwareportmaster.games.

  • CPU and Complexity: The CPU in the RG35XX (especially the OG) is relatively slow (Cortex-A9/A53 at ~1.5GHz) with no SIMD optimizations beyond NEON. Complex physics, scripts, or AI should be kept to a minimum. Expect that even simple Unity scenes will tax the device. Prefer 2D games or very low-polygon 3D with minimal on-screen objects. Optimize scripts and consider using IL2CPP (ahead-of-time compilation) for better runtime speed – though IL2CPP increases build size, it may improve performance of your game logic. However, note that IL2CPP will produce native x86 code (if building for x86), which then has to be emulated, so the speed trade-off versus Mono (JIT) under emulation is uncertain.

  • Input Mapping: The RG35XX has a D-pad, four face buttons, start/select, and typically two shoulder buttons (on some models also analog sticks on newer variants). muOS will expose these controls either as a Linux gamepad device or via a key-mapping layer. Plan your input scheme around a controller layout. In Unity’s Input System, the device may register as a generic gamepad – ensure you map actions to the DPAD and buttons. If your Unity build only reads keyboard input, you can use PortMaster’s gptokeyb tool to map gamepad buttons to keyboard/mouse inputs at runtimeportmaster.games. However, it’s preferable to support gamepad natively. Test that all necessary buttons (including Start/Select which might map to “Menu” or “Escape”) are usable. Keep in mind there is no touchscreen on the RG35XX, so your UI should be navigable with buttons only.

3. Recommended Unity Export Settings for muOS Compatibility

To maximize the chance of your Unity game running on muOS, use the following export settings and practices:

  • Build Target: Since Unity can’t target ARM Linux directly, build a Linux x86 or x86_64 standalone player. For the RG35XX OG (32-bit OS) or devices running a 32-bit userland, you’ll need a 32-bit (x86) build to use Box86 (an x86-to-ARM emulator). For devices running 64-bit muOS (RG35XX Plus/H with 64-bit OS), a 64-bit x86_64 build can be used with Box64 emulatorportmaster.games. In Unity Hub, add Linux support and select “Linux” with the appropriate architecture. Tip: If using a newer Unity version that only outputs x86_64, you may need to force 32-bit via an older Unity release if targeting 32-bit devices.

  • Scripting Backend: Use IL2CPP for a release build if possible, as it compiles C# to native code which can improve performance. Unity will generate a GameAssembly.so and native code for x86/x64docs.unity3d.comdocs.unity3d.com. However, note that IL2CPP builds take more storage and memory. If memory is a bigger concern than speed (e.g. on the 256MB model), a Mono build might be considered to reduce binary size. Be prepared to experiment – IL2CPP might yield better CPU performance under emulation, but Mono could consume less RAM.

  • Graphics API and Quality: Disable any unsupported graphics backends. In Unity Player Settings for Linux, remove Vulkan and any OpenGL Core/4.x entries. If available, add or enable OpenGL 2.1 / OpenGL ES 2.0 support. Unity’s older versions allowed an “OpenGL 2” (legacy) mode; in newer versions, Unity defaults to GL Core but will fallback to GL2 on unsupported hardware if forced. You can try launching the game with the flag -force-opengl which often forces a legacy OpenGL 2 context. Additionally, include the GL4ES library (as libGL.so.1) alongside your game to translate OpenGL calls to GLES (more on this in the next section)portmaster.gamesportmaster.games. Set quality settings to the lowest: no anti-aliasing, simple lighting or unlit materials, minimal shadows (or none), and use the simplest render pipeline (the built-in forward renderer or a 2D renderer). Avoid Unity features that rely on compute shaders or GPU skinning (these won’t work on GLES2). Use compressed textures and disable real-time lighting/global illumination to save on both CPU and GPU load.

  • Resolution and UI: Target 640×480 resolution to match the device screenrg35xx.com. In Unity, set the default screen width/height accordingly (in Player Settings or via command line args -screen-width 640 -screen-height 480). If your game uses a different aspect ratio, you’ll likely letterbox or scale; 4:3 is ideal. Make sure UI canvas reference resolution is 640×480 or similar to ensure readability on the small screen. Testing at this low resolution on PC will help identify UI scaling issues early.

  • Asset Optimizations: Treat it like a mobile game on old hardware:

    • Limit texture sizes (most sprites/textures should be 256×256 or 512×512 at most; use compression). The total texture memory must be well under the available RAM once uncompressed.

    • Use shorter audio clips and compress audio (prefer tracker music or very short loops if possible; streaming large audio files might not be feasible).

    • Remove unnecessary assets from the Resources and StreamingAssets, as they bloat the build. The entire game + Unity engine should fit in memory.

    • If using Unity’s new Input System, include the old Input System backends as a fallback (muOS might not have all drivers, so flexibility can help).

  • Testing on Similar Hardware: Before packaging for muOS, test your Linux build on an ARM single-board computer if available (e.g. Raspberry Pi 3/4 running a Linux OS). Although you cannot run the binary natively, you can test via Box86/Box64 on a Raspberry Pi or in an ARM VM to see if it launches. Also test a WebGL build on a PC to gauge performance – WebGL uses GLES2 and can approximate how your game might run if limited to ES2 features. (WebGL builds have in fact been used as a workaround to run Unity games on Raspberry Pi via a browsermedium.commedium.com, though on muOS a full browser is not readily available.)

4. Running a Unity Game on muOS: Tools & Instructions

Since we cannot run a Unity Linux ARM executable natively, the strategy is to use compatibility layers and include the needed libraries so that the x86/x64 build can run in muOS. Here’s how to get your Unity game running on muOS:

  • Box86/Box64 Emulation: muOS and PortMaster rely on Box86 and Box64 to run PC games compiled for x86 on ARM devicesportmaster.gamesportmaster.games. Box86 is a user-space emulator for 32-bit x86 Linux binaries on ARM, and Box64 does the same for 64-bit binariesgithub.com. You will need to ensure one of these is available and configured. On muOS, PortMaster’s installation typically includes Box86/64 as part of its runtimes (especially on devices like RG35XX)portmaster.games. If you are distributing a standalone app, you may need to instruct users to install Box86/Box64 or bundle the emulator. In practice, if PortMaster is installed on muOS, those emulators are already present system-wide. Choose your build (32-bit vs 64-bit) based on the target device’s support: for RG35XX OG or any 32-bit OS install of muOS, use 32-bit and Box86; for RG35XX Plus/H with 64-bit muOS, a 64-bit build can utilize Box64.

  • GL4ES (OpenGL-to-GLES wrapper): Unity’s rendering will issue OpenGL calls that the device’s GPU drivers may not support. GL4ES is a crucial wrapper library that converts OpenGL 1.x/2.x/3.x calls to OpenGL ES 2.0 calls that the RG35XX’s GPU can executeportmaster.gamesportmaster.games. You should include the libGL.so.1 from GL4ES with your game (replacing Unity’s expectation of system libGL). PortMaster ports often package GL4ES for games requiring OpenGLportmaster.games. Also, set environment variables for GL4ES at launch: for muOS devices the recommended settings are:

    export LIBGL_ES=2 # target OpenGL ES 2.0 export LIBGL_GL=21 # pretend OpenGL 2.1 context export LIBGL_FB=4 # use framebuffer output (no X11)

    These variables ensure GL4ES knows it’s running on a framebuffer with GLES2portmaster.games. They can be set in a launch script or included in your PortMaster package config.

  • SDL2 and Video Output: Because muOS has no X11/Wayland windowing system running (to save resources), standard Unity player window creation would fail. Instead, the output must go to the framebuffer. Some ports use SDL2’s KMS/DRM backend to create a window directly on the framebuffer deviceportmaster.games. Unity itself doesn’t natively support SDL out-of-the-box for windowing, but Weston (below) or certain environment hacks might redirect it. Ensure muOS’s minimal dependencies are installed: typically ALSA or PulseAudio for sound (Unity may try PulseAudio – muOS’s audio stack should have compatibility), and libSDL2 (if using Westonpack). When packaging, check for any Unity dependency (like libmono if Mono build, but usually Unity’s libraries are bundled in the build folder). The Westonpack runtime (discussed next) can simplify running apps that expect a window manager.

  • Weston/Wayland (Westonpack): A recent development is Westonpack, a runtime that provides a lightweight Wayland compositor (Weston) on these devicesportmaster.gamesportmaster.games. It essentially allows running GUI applications that normally require X/Wayland by launching a minimal session just for that app. Westonpack has enabled previously impossible ports (Godot 4 games, Java apps, etc.) by providing an offscreen or transient display server. For a Unity game, Westonpack could be used to create a surface for the Unity player to render into, even though muOS has no desktop environment. If you choose to use Westonpack, you would include it as a dependency and launch your game through it. This is an advanced approach, but it may be necessary if the Unity build absolutely requires a windowing system (some Unity versions might require X11 even for fullscreen). The PortMaster team notes that “with the new WestonPack runtime, a lot of [previously incompatible apps] may work now” on devices without X11portmaster.games. So, if your Unity game didn’t run at all under pure framebuffer, try integrating Westonpack.

  • Launch Script and Environment: Prepare a launch script (.sh) to set up the environment on the device. This script would:

    1. Export the GL4ES environment variables (as above).

    2. Possibly export SDL_VIDEODRIVER=KMSDRM or similar if using SDL for output.

    3. Execute the Unity binary via Box86/Box64. For example:

      #!/bin/sh export LIBGL_ES=2; export LIBGL_GL=21; export LIBGL_FB=4 # Use box86 or box64 to run the game if [ "$(getconf LONG_BIT)" = "32" ]; then box86 ./YourGame.x86 else box64 ./YourGame.x86_64 fi

      (The above is a conceptual script – the actual invocation may vary based on muOS’s environment and ensuring it finds box86/64 and your libraries.)

    4. If using Westonpack, the script would instead call weston or a provided wrapper to launch the game in a Weston session, and you wouldn’t manually call box86/64 as Westonpack might handle it.

  • Testing on Device: Install muOS on an SD card for your RG35XX and enable SSH or USB networking (muOS supports connectivity toolsmuos.devmuos.dev). This lets you transfer builds and run them from a terminal for testing. You can stop the muOS frontend to free resources while testing (muOS uses a lightweight frontend, but you can terminate it via killall -q frontend.sh muxlaunch as noted in PortMaster docsportmaster.games). Then run your launch script from SSH and watch for errors. Common issues will include missing libraries (check for errors about .so files – you might need to copy over Unity’s UnityPlayer.so or others into the same folder), segmentation faults (often from unsupported instructions – ensure you chose the right emulator), or graphics failing to initialize (if so, double-check GL4ES is being loaded and that your env vars are set). Debugging on-device can be tricky; use verbose logging if possible or an attached screen to see any output.

  • Alternative Route – WebGL: As a last resort, consider the WebGL build approach. On a Raspberry Pi, developers have run Unity games by serving a WebGL build on a local web server and opening it in the browsermedium.commedium.com. muOS does not include a full browser by default, but there was a community QtWebEngine browser port (though reports say it’s currently brokencommunity.muos.dev). If a lightweight browser with WebGL support can be installed (for example, a minimal Chromium build via Westonpack), you could theoretically load the Unity WebGL build. This avoids the CPU cost of emulating x86, since the WebGL runs natively in the browser with ARM JavaScript/WebGL. However, browser overhead is heavy and memory usage might be even higher than the Box86 method. This is an experimental idea – proceed only if other methods fail, and be prepared for suboptimal performance.

Important: Given the above, many developers have chosen to rebuild their games in engines that support ARM/Linux natively (like Godot or Love2D) to target devices like the RG35XX. The muOS community often recommends using lightweight frameworks (SDL2, Raylib, Love2D, etc.) for homebrewcommunity.muos.devcommunity.muos.dev. Unity, being heavyweight, is operating outside its comfort zone here. The tools and steps listed can sometimes get a Unity game running, but “running” might still mean single-digit FPS or frequent crashes on a 256MB device. Keep expectations realistic.

5. Distribution: Standalone .muxapp vs PortMaster Submission

Once you have a build that runs (or if you’re determined to share it anyway), you have two main distribution options on muOS: a standalone muxapp package or an entry in PortMaster. Each has pros and cons:

  • Standalone App (.muxapp): muOS allows installing applications via its Archive Manager in the form of .mux* filesmuos.devmuos.dev. A .muxapp file is essentially a ZIP archive renamed with the .muxapp extensionmuos.dev. When placed in the Archive folder and installed, it will extract to the MUOS/application directory on the devicemuos.dev. This means your game will appear in the muOS “Applications” list (the frontend’s muxapp module lists all apps)github.com, and the user can launch it from the menu. To create a muxapp:

    • Structure your zip with the correct paths (e.g. mnt/mmc/MUOS/application/YourGame/** for SD card installs) so that files go into the application directorymuos.dev.

    • Include your game folder with all binaries, libraries (UnityPlayer.so, etc.), assets (*_Data folder), and your launch script. Also include an icon PNG for the menu (place it under opt/muos/default/MUOS/theme/active/glyph/muxapp/yourappicon.png and reference it in an update script if using .muxupd)muos.devmuos.dev.

    • Optionally use .muxupd if you need to run a script upon installation (for example, to set file permissions or create symlinks)muos.devmuos.dev.

    • Once packaged, users can install it by copying the .muxapp to their Archive folder and using Archive Manager in muOS to unpack itmuos.dev.

    Muxapp Pros: You have full control over the package. It’s great for distributing your own homebrew game directly to users. They don’t need PortMaster; it works on stock muOS. You can also include exactly the libraries and configurations your game needs without worrying about PortMaster’s standards. This is likely the best (and maybe only) choice if your Unity game is experimental.

    Muxapp Cons: It’s muOS-specific. Only users on muOS (MustardOS) can install a .muxapp easily. Other CFWs (GarlicOS, JELOS, etc.) would not use this format. You also won’t get the visibility of the PortMaster catalog. Distribution is manual (forums, Reddit, etc.), and updates mean asking users to install a new .muxapp file. There is also no dependency management – you bundle everything, which could lead to duplication (for example, many apps might bundle Box86, whereas PortMaster would have one shared Box86). Make sure to warn users of any prerequisites (e.g. “Requires Box86 runtime installed” if you didn’t include it).

  • PortMaster Submission: PortMaster is a unified platform that many retro handheld firmwares (muOS, GarlicOS, ArkOS, etc.) use to manage game portsretrogamecorps.comretrogamecorps.com. If you submit your game to PortMaster’s repository, users can install it through the PortMaster app on any supported device. In theory, this greatly broadens your audience and simplifies installation for end-users (one-click install). PortMaster also handles providing common runtimes (Box86, Box64, SDL, etc.) so you don’t need to package those each timeportmaster.games. To distribute via PortMaster, you would need to:

    • Ensure license compliance: PortMaster typically hosts open-source game engines or free games. If your game is closed-source or commercial, they might not accept it, unless you just provide a port that requires the user to supply data files. If it’s your original game and you’re willing to share it free, this could be fine.

    • Follow the PortMaster packaging guidelines: There are specific JSON/Markdown files and folder structures needed to create a “PortMaster port”. The documentation provides a Packaging Guide and build environment instructionsportmaster.gamesportmaster.games. You would create a port script that downloads/installs your game files into the right place on the device (likely under the Ports directory used by PortMaster).

    • Work with the devs: Given that Unity games are officially marked “Low feasibility” or “Not possible” by PortMaster devs as of 2024suggestions.portmaster.gamessuggestions.portmaster.games, you’ll need to convince them with a working solution. It might involve using the Westonpack runtime and extensive tweaking. If you have a demo working on your device, you could reach out on the PortMaster Discord to get guidance on how to package it. The PortMaster team is active and may help if you’ve achieved what was previously thought impossible.

    PortMaster Pros: Users on multiple firmwares and devices can play your game – not just muOS on RG35XX, but potentially other Linux handhelds supported by PortMaster. PortMaster also makes updating easier (you can push updates to the port). It handles dependency installation (for example, ensuring Box86/64 and GL4ES are in place globally). And your game will appear in a curated list alongside popular ports (great visibility for your project).

    PortMaster Cons: At present, Unity games have no proven track record on PortMaster – all suggestions for Unity-based games have been rejected due to the lack of an ARM buildsuggestions.portmaster.games. You would be venturing into uncharted territory, and there’s a risk that even if you get it semi-working, the PortMaster team might not want to maintain the complexities involved. Also, packaging for PortMaster has a learning curve and requires adherence to their Port JSON schema and potentially providing source or build scripts for verification. If your game cannot run at acceptable speed, they may decline to list it to avoid user frustration. In short, PortMaster is ideal for supported engines (they explicitly support Godot, Love2D, GameMaker via runner, etc. which have ARM-compatible runtimesportmaster.gamesportmaster.games), but Unity is not officially supported in that way.

Recommendation: For a personal project or a tech demo, distributing as a .muxapp is the fastest route – you control the environment and can instruct users specifically for muOS. This lets you test the waters on the RG35XX. If somehow you optimize the game to a point it’s enjoyable and you want to reach more players, you could then attempt a PortMaster release (possibly after porting the game to a friendlier engine or working closely with PortMaster devs to use Westonpack for Unity). As it stands, the best practice in the community is to avoid Unity for RG35XX and instead use engines with native ARM supportcommunity.muos.dev. But if Unity is a must, use the guidance above to give your game the best shot at running on muOS.

Sources:

Comments

Popular posts from this blog

Exporting a Godot 4.4 Game to the Anbernic RG35XX H

Game Publishing Platforms and Methods

Godot Game Engine