- Zig 78.8%
- Lua 13.8%
- GLSL 4%
- Python 1.7%
- PowerShell 1.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Port of beetle-engine to Raspberry Pi 4 Model B (VideoCore VI, Mesa v3dv, labwc). Verified: selftest (90 frames, mesh + cutout foliage + text), Euro City boots and runs, --benchmark: 35 fps avg / 21 worst-second at 480x270 internal res with 341 draws. - Platform layer: src/win_linux.zig (from the steam-deck port), X11/XCB window + input, VK-code key mapping unchanged for Lua scripts - WSI: VK_KHR_xcb_surface via vkGetInstanceProcAddr; present mode queried (FIFO default, MAILBOX for benchmarks); depth format queried D32/D16 - Device pick prefers non-CPU Vulkan devices (V3D over llvmpipe) - CPU probe: AT_HWCAP (NEON/AES/SHA2/CRC32), board name from device tree - Audio: miniaudio ALSA backend with vendored alsa headers (no dev pkgs) - Build: Linux-only, ReleaseFast default, system libs via third_party/linux symlinks, UPX/dist step dropped; --script <path> override for benchmarks - Dropped: blender/, art-direction/, districts/ authoring trees and Windows-only tooling (stay in beetle-engine) |
||
| .pi/tasks | ||
| assets | ||
| docs | ||
| game | ||
| games | ||
| src | ||
| third_party | ||
| tools | ||
| .gitignore | ||
| agent.md | ||
| BLENDER.md | ||
| build.zig | ||
| build.zig.zon | ||
| PLAN.md | ||
| README.md | ||
Raspberry Engine
beetle-engine ported to Raspberry Pi 4 Model B (aarch64-linux, VideoCore VI). Same engine, same games, same Lua API — the whole PS1-style renderer survives, including the 480×270 internal-res post pipeline, CSM sun shadows, rig animation, streamed props, rain, time-of-day and the music-FFT games.
┌───────────────────────────────────────────┐
│ Raspberry Pi 4 Model B Rev 1.1 │
│ Cortex-A72 ×4 · 4 GB · VideoCore VI │
│ Vulkan 1.3 (Mesa v3dv, V3D 4.2) │
│ Raspberry Pi OS / labwc (Wayland) │
└───────────────────────────────────────────┘
Status
Ported and running. Selftest presents 90 frames (mesh + cutout foliage +
font + shadows, 8.8 MB VRAM); Euro City boots and runs; --benchmark works.
The machine vs the beetle
| BEETLE /MIII (original) | Pi 4 (this port) | |
|---|---|---|
| CPU | Celeron G3900, 2×2.8 GHz, SSE4.2 | Cortex-A72, 4×1.8 GHz, NEON |
| GPU | Quadro K620 (Maxwell, 2 GB DDR3, ~29 GB/s) | VideoCore VI (shared RAM, ~4–8 GB/s effective) |
| API | Vulkan 1.3 (NVIDIA) | Vulkan 1.3 (Mesa v3dv, conformant) |
| OS | Windows 10 IoT | Raspberry Pi OS / labwc |
The engine's design rules hold: two threads, fixed low-res scene target,
instanced draws, batched uploads. V3D is a tiled GPU — the engine's
single 480×270 render target and small uniform/push payloads suit it well.
Everything is UMA here: "VRAM" is ordinary RAM, so vram_bytes is a budget
metric, not a separate heap.
Building
Requires Zig 0.16.0 on PATH (aarch64-linux build). No other toolchain, no
dev packages — system libraries are linked through symlinks in
third_party/linux/ (libvulkan, libasound; recreate with ln -s if the
sonames differ).
zig build # ReleaseFast by default
zig build run # launcher (games menu)
zig build test # unit + Lua harness tests
./zig-out/bin/engine --selftest
Optional: zig build shaders regenerates the committed .spv files from GLSL
(needs glslang; the committed SPIR-V builds fine without it).
Running
./zig-out/bin/engine # launcher
./zig-out/bin/engine --script games/eurocity/main.lua # Euro City directly
./zig-out/bin/engine --script games/eurocity/main.lua --benchmark
--benchmark (with a game script): 2 s warmup, then 15 s flying a fixed line
through the city, reporting avg fps, worst second, draws and tris.
Audio: miniaudio's ALSA backend with vendored headers
(third_party/alsa/, LGPL headers from the freedesktop SDK — see its README),
so sound works without installing alsa-lib dev files. ALSA reaches PipeWire
via pipewire-alsa.
What was ported (differences from beetle-engine)
- Platform layer:
src/win.zig(Win32) →src/win_linux.zig— X11/XCB window + input, keys mapped to the same VK codes so Lua scripts are unchanged. Taken from the beetle-enginesteam-deckbranch (XWayland under labwc runs it natively). F11 fullscreen preserved (EWMH). - Vulkan WSI:
VK_KHR_xcb_surface, surface created throughvkGetInstanceProcAddr(the loader's export stub is unreliable); present mode is queried — FIFO by default, MAILBOX only when the driver lists it. - Device pick: prefers any non-CPU Vulkan device (V3D over llvmpipe); no NVIDIA vendor check. Depth format queried (D32 with D16 fallback).
- CPU probe:
cpuid/SSE bits → AT_HWCAP (NEON/AES/SHA2/CRC32); board name from the device tree. - FS/time: raw libc (
open/read/clock_gettime//proc/self/exe) — same reason the Win32 impl skipped std churn. - Audio: vendored ALSA headers +
-lasound; Pulse/JACK disabled. - Build: Linux-only; ReleaseFast by default (the beetle build shipped ReleaseSafe); no UPX step. Everything else (C deps, shaders, Lua, assets, tests) is unchanged.
Not carried over: the blender/, districts/ and art-direction/ authoring
trees live in beetle-engine; tools/*.ps1 and third_party/upx are Windows
tooling.
Performance notes (Pi 4)
- The 480×270 internal res is the single biggest win on VideoCore — keep it.
- Governor: the default
ondemandclocks down between frames. For measurements or max fps:echo performance | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_governor. --benchmarkruns uncapped (MAILBOX) when v3dv offers it; FIFO is the vsync-locked default.- v3dv is a Vulkan 1.3 conformant driver; D32 depth and the D16 CSM array are both supported natively.