Close
0%
0%

OP5U (Orange Pi 5 Ultra) 2D Game Engine

A GPU-accelerated 2D sprite engine built for the Orange Pi 5 Ultra using OpenGL ES 3.1 and SDL2.

Similar projects worth following
OP5U 2D Engine is a lightweight OpenGL ES 3.1 sprite engine running entirely on the Orange Pi 5 Ultra (RK3588S). It renders thousands of rotating sprites at 60 FPS using hardware instancing through the Panfrost driver. Built with C++17, SDL2, and pure GLES 3.1—no Unity, no middleware—just raw control of the GPU on ARM Linux. The goal is to build a full 2D game engine from scratch: camera, animation, parallax, audio, and input, optimized for low-power ARM hardware. Source code: GitHub → jmstein7/op5u-2d-engine

🧠 Project Details

OP5U 2D Engine is my attempt to build a full 2D game engine from scratch — no Unity, no Godot, no middleware — just raw OpenGL ES 3.1 on the Orange Pi 5 Ultra.

The Orange Pi 5 Ultra packs an RK3588S SoC with an 8-core CPU and a Mali-G610 GPU.
That GPU is fully supported by the open-source Panfrost driver in Mesa, which means we finally have a small ARM board that can run real hardware-accelerated graphics without binary blobs.

I wanted to see what it would take to push that GPU directly — so I wrote a renderer in C++17 using SDL2 and GLES 3.1, targeting pure performance and simplicity.
The result is an engine that can draw thousands of sprites at 60 FPS with instancing, full camera control, and smooth continuous rotation.

✳ Current Features

  • GPU instanced sprite rendering (each sprite is a hardware instance)

  • OpenGL ES 3.1 shaders written by hand

  • Pan, zoom, and vsync toggle

  • Per-sprite rotation and dynamic UVs

  • FPS logging and real-time performance readouts

  • A simple texture atlas system (512 × 512 pixels)

🧩 Why Build This?

Most people use pre-built engines that abstract away the GPU.
I wanted to understand how far an inexpensive single-board computer could go when you don’t hide the hardware.
The Orange Pi 5 Ultra turned out to be a perfect playground — enough horsepower to hit 60 FPS, but low-level enough that you still feel every draw call.

🔮 What’s Next

The next milestone is sprite animation — Pac-Man’s mouth opening and closing using UV frame switching, ghost blinking, and time-based flipbooks.
From there: tilemaps, parallax scrolling, sound, and a small playable demo called Pac Field.

🛠 Build Environment

  • Ubuntu 22.04 (Jammy) Desktop GNOME on NVMe

  • Mesa 23.x Panfrost driver

  • SDL2 2.0.5 + SDL_image

  • CMake + GCC 13.3

💡 The Goal

Make a full, open-source 2D engine that others can use as a foundation for ARM-based indie projects — something that runs on an Orange Pi, Raspberry Pi 5, or even an old Chromebook.
No binary drivers, no proprietary toolchains — just open graphics, open code, and real-time performance.

  • 1 × Orange Pi 5 Ultra SBC with Rockchip RK3588 8-core 64-bit processor
  • 1 × Ubuntu Jammy Ubuntu 22.04.5 LTS
  • 1 × SDL2 Simple DirectMedia Layer (SDL2)
  • 1 × Panfrost Open-source Gallium3D driver for ARM Mali Midgard and Bifrost GPUs

  • The Vulkan Odyssey: Lessons from the Orange Pi 5 Ultra

    Jonathan Stein10/24/2025 at 16:40 0 comments

    When I started this project, my goal was to take full advantage of the Mali G610 GPU on the Orange Pi 5 Ultra by running a modern Vulkan-based 2D game engine.

    On paper, the RK3588 and its G610 core should be a dream: high fill-rate, low power, and full support for OpenGL ES 3.2 and Vulkan 1.2.

    In reality? It’s complicated.

    🧩 The Experiment

    Over several days I worked with ChatGPT (and even asked Grok for a second opinion) to bring Vulkan WSI (Wayland Surface Integration) online under the stock Orange Pi Ubuntu Jammy (22.04) image.

    We rebuilt the Vulkan Loader from source with explicit Wayland WSI flags:

    -D BUILD_WSI_WAYLAND_SUPPORT=ON
    -D BUILD_WSI_XCB_SUPPORT=OFF
    -D BUILD_WSI_XLIB_SUPPORT=OFF
    
    
    

    The resulting libvulkan.so contained the correct entry points:

    vkCreateWaylandSurfaceKHR
    vkGetPhysicalDeviceWaylandPresentationSupportKHR
    
    
    

    Everything looked right,  until we ran vulkaninfo.

    The extension VK_KHR_wayland_surface never appeared.
    No matter what environment variables we exported, how many custom loaders we built, or how many times we recompiled vkcube, Vulkan simply refused to acknowledge Wayland.

    ⚙️ The Investigation

    After hours of tracing dynamic loads, running with VK_LOADER_DEBUG=all, and examining every shared library involved, we confirmed the truth:

    • The Rockchip-provided Mali Vulkan ICD (libmali-valhall-g610-g6p0-wayland-gbm-vulkan.so) includes only headless and direct-display WSI backends.

    • The Wayland entry points are present as stubs, but never registered.
      The extension fails during loader initialization because the driver refuses to advertise it.

    • Result: no windowed Vulkan apps, not with Wayland, not with X11.

    In short, Vulkan runs, but only for off-screen rendering.
    That’s why even vkcube --wsi wayland segfaults: the driver literally has no functioning Wayland path.

    🧠 The Root Cause

    This isn’t a misconfiguration or missing library.
    It’s a driver limitation baked into Rockchip’s proprietary Mali stack.
    The vendor-provided Ubuntu Jammy kernel (5.10) and userspace drivers are frozen snapshots from Rockchip’s SDK; they predate working Vulkan WSI support.

    As one Hacker News commenter put it:

    “Sadly, there does not seem to be any kind of GPU support in the version that I have chosen… there was just a software pipe for rendering.”

    That’s not quite true (Vulkan does work) but it’s crippled.

    🔧 The Workaround

    If you stay on the stock Orange Pi Ubuntu image, OpenGL ES 3.0 via EGL is the right path.
    It’s fully functional, hardware-accelerated, and compatible with SDL2 and most engines.
    You’ll get consistent performance, working display output, and no headaches.

    If you must have Vulkan + Wayland, you’ll need to move to:

    • Armbian “Edge”

      with a mainline kernel (6.7 +) and Mesa Panthor drivers, or

    • The emerging BredOS

      distribution, which promises a proper mainline graphics stack.

    On those, vulkaninfo finally lists:

    VK_KHR_wayland_surface : extension revision 6
    
    
    

    …and vkcube --wsi wayland opens a real window.

    ⚠️ A Warning to Fellow Developers

    If you’re building software meant to run on most Orange Pi 5 Ultras in the wild today, assume OpenGL ES only.
    The Vulkan path simply isn’t viable yet on the vendor image, as you’ll just waste days chasing a feature that’s been intentionally disabled. Trust me on that one.

    ✅ TL;DR

    • Vulkan works headless-only on Orange Pi’s Ubuntu Jammy images.

    • Wayland and X11 Vulkan surfaces do not.

    • OpenGL ES 3.0 via EGL is stable and widely supported.

    • Full Vulkan support exists only in Armbian Edge / Mesa Panthor builds.

    • For engines targeting the mainstream Orange Pi user base, target GLES 3.0.

    Filed under “lessons learned the hard way.”
    Thinking about going down this same path? Don’t.
    Save yourself a week and start with OpenGL ES. Vulkan can wait until Rockchip’s software catches up with its silicon. Looking at you, Ubuntu....

    Read more »

  • Parallax Layers + Tile-Based Lighting (GPU, 60 FPS)

    Jonathan Stein10/16/2025 at 00:46 0 comments

    ### 🔦 Tile-Based Lighting + Parallax Layers

    The OP5U 2D Engine now renders **three GPU tilemap layers** (BG/MID/FG) with a **world-space lightmap** that adds per-pixel illumination and adjustable ambient. Everything runs at **~60 FPS** on the Orange Pi 5 Ultra (Mali-G610 via Panfrost, GLES 3.1).

    **Controls**
    - WASD/Arrows = pan, Q/E = zoom, R = reset, V = vsync
    - 1/2/3 = toggle BG/MID/FG
    - - / = = adjust parallax (BG & MID)
    - L = toggle lighting
    - [ / ] = ambient down/up
    - , / . = light strength down/up
    - ESC = quit

    **What’s happening under the hood**
    - Tilemaps are **instanced**; CPU only updates small buffers.
    - The lightmap is a repeating **R8 texture** sampled in the fragment shader,
      combined as `color.rgb *= ambient + strength * light`.
    - Parallax is applied in the vertex shader so each layer scrolls at a different rate.

    **Status**
    - Jammy + Mesa Panfrost (GLES 3.1)
    - Engine written in C++17 with SDL2 / SDL_image
    - Pac-Man “chomp” anim updates via a single `glTexSubImage2D` on the FG tilemap.

    **Next**
    1) Sprite lighting (apply light to instanced sprites too)
    2) Tiled (TMX) map import
    3) Audio (SDL_mixer)

    Screenshots + code: https://github.com/jmstein7/op5u-2d-engine

  • GPU Tilemap and Animated Pac-Man Demo Running on OP5U

    Jonathan Stein10/13/2025 at 23:15 0 comments

    The OP5U 2D Engine just hit a major milestone — our first fully GPU-driven tilemap with live animation.

    The engine now renders hundreds of Pac-Man and Ghost sprites at 60 FPS using OpenGL ES 3.1 and the Mesa Panfrost driver on the Orange Pi 5 Ultra.

    The tilemap is drawn entirely via instancing; the CPU only updates a small 128×128 byte array representing the map. Even the classic Pac-Man “chomp” animation (open/closed mouth) runs with a single glTexSubImage2D call every 250 ms.

    The result: rock-solid 60 FPS, minimal CPU load, and perfect GPU pacing — our first real proof that the Panfrost driver can handle fully dynamic tile animation.

    Next up: Parallax background layers for multi-depth scrolling, building the foundation for full 2D game scenes.

    🖥️ Specs:
    • Orange Pi 5 Ultra (RK3588S, 16 GB RAM)
    • Ubuntu 22.04 Jammy Desktop
    • SDL2 + OpenGL ES 3.1 (Panfrost Mesa 23.x)

  • Devlog #2 – Sprite Animation, Camera, and GitHub Integration

    Jonathan Stein10/13/2025 at 21:11 0 comments

    This update turns the original rotating Pac-Man demo into a real mini-engine.
    The sprites now animate with flip-book style UV frame switching, Pac-Man chomps at 4 FPS, ghosts blink once per second, and everything rotates smoothly under full GPU acceleration.

    I also added camera controls and a zoomable viewport, so you can now pan around the sprite grid or zoom in and out of the scene in real time.
    All controls run directly on the Orange Pi 5 Ultra’s Mali-G610 GPU using the open-source Panfrost driver, driven by a compact C++17 engine built with SDL2 and OpenGL ES 3.1.

    Key ControlsAction
    Arrows / WASDPan camera
    Q / EZoom in/out
    RReset camera
    [ / ]Adjust Pac-Man animation speed
    VToggle VSync
    ESCQuit

    On the technical side, the engine now includes:
    • Frame-based animation system (timed UV swapping)
    • Per-sprite instancing and rotation
    • Adjustable zoom and viewport scaling
    • FPS counter and vsync toggle
    • Clean git repository with .gitignore for build outputs

    The project’s now live and synced to GitHub:
    👉 https://github.com/jmstein7/op5u-2d-engine

    Next up: adding tilemap rendering and sprite culling for massive worlds — to turn this from a demo into a proper 2D engine.

  • Devlog #1 – Getting Real-Time Sprites Running on the Orange Pi 5 Ultra

    Jonathan Stein10/13/2025 at 13:21 0 comments

    I’ve been building a 2D GPU engine from scratch on the Orange Pi 5 Ultra.
    This first milestone: rendering hundreds of animated Pac-Man sprites in real time using OpenGL ES 3.1 and SDL2.
    The engine runs at 60 FPS on the Panfrost driver with vsync, zoom, and camera control.

    What works so far:

    • GPU instanced sprite rendering (~10 000 sprites)

    • Continuous per-sprite rotation

    • Camera pan/zoom, vsync toggle, FPS logging

    • Texture atlas system (512×512)

    Next up: sprite animation (frame-flipping Pac-Man, blinking ghosts), and eventually a tilemap background.

    Full source and setup guide are on GitHub:
    👉 https://github.com/jmstein7/op5u-2d-engine

View all 5 project logs

Enjoy this project?

Share

Discussions

Does this project spark your interest?

Become a member to follow this project and never miss any updates