Skip to content

Adds support for Linux ARM GLESv2 - #2912

Open
imsys wants to merge 13 commits into
nesbox:mainfrom
imsys:build-linux-arm64-gles2
Open

Adds support for Linux ARM GLESv2#2912
imsys wants to merge 13 commits into
nesbox:mainfrom
imsys:build-linux-arm64-gles2

Conversation

@imsys

@imsys imsys commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

This basically adds supports to many devices of Linux handhelds firmwares, like Rocknix, Knulli and others.

# ========================================================
# Dockerfile to build TIC-80 for TrimUI (AArch64)
# ========================================================

FROM ubuntu:22.04

# Install build dependencies
RUN apt-get update && apt-get install -y \
    cmake git make xz-utils wget curl python3 ruby rake pkg-config \
    && rm -rf /var/lib/apt/lists/*

# Install Arm GNU Toolchain (GCC 10.3.1, AArch64)
WORKDIR /opt
RUN wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz \
    && tar -xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz \
    && rm gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz

# Define Toolchain Paths
ENV CROSS_ROOT=/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu
ENV PATH="${CROSS_ROOT}/bin:${PATH}"
ENV CROSS_COMPILE=aarch64-none-linux-gnu-

# Install symbol extraction dependencies
RUN apt-get update && apt-get install -y binutils libsdl2-dev libgles2-mesa-dev libegl1-mesa-dev

# Create stub libraries for linking (satisfied by device firmware at runtime)
# We extract the symbol names from the builder's libraries and generate empty C stubs.
# This prevents glibc versioning issues while satisfying the linker.
RUN for lib in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0 /usr/lib/x86_64-linux-gnu/libGLESv2.so.2 /usr/lib/x86_64-linux-gnu/libEGL.so.1; do \
        outname=$(basename $lib | sed 's/-2.0//; s/\.so\..*/.so/') && \
        echo "Generating stubs for $outname from $lib" && \
        nm -D $lib | grep " T " | awk '{print "void " $3 "(){}"}' > stubs.c && \
        ${CROSS_COMPILE}gcc -shared -o ${CROSS_ROOT}/aarch64-none-linux-gnu/libc/usr/lib/$outname stubs.c; \
    done

# --- Fetch TIC-80 ---
WORKDIR /wrk
#RUN git clone https://github.com/nesbox/tic-80.git && \
#    cd tic-80 && git submodule update --init --recursive
COPY . tic-80

# --- Build TIC-80 ---
WORKDIR /wrk/tic-80/build/trimui

RUN cmake ../.. \
      -DCMAKE_SYSTEM_NAME=Linux \
      -DCMAKE_SYSTEM_PROCESSOR=aarch64 \
      -DCMAKE_C_COMPILER=${CROSS_COMPILE}gcc \
      -DCMAKE_CXX_COMPILER=${CROSS_COMPILE}g++ \
      -DCMAKE_SYSROOT=${CROSS_ROOT}/aarch64-none-linux-gnu/libc \
      -DCMAKE_FIND_ROOT_PATH=${CROSS_ROOT}/aarch64-none-linux-gnu/libc \
      -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
      -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
      -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
      -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \
      -DCMAKE_BUILD_TYPE=Release \
      -DBUILD_PRO=OFF \
      -DBUILD_WITH_ALL=ON \
      -DCMAKE_C_FLAGS_RELEASE="-mcpu=cortex-a53 -Ofast -flto" \
      -DCMAKE_CXX_FLAGS_RELEASE="-mcpu=cortex-a53 -Ofast -flto " \
      -DBUILD_SDL=ON \
      -DBUILD_SDLGPU=ON \
      -DBUILD_EDITORS=OFF \
      -DBUILD_SURF=ON \
      -DPREFER_SYSTEM_SDL2=ON \
      -DBUILD_STATIC=ON \
      -DTIC_DATA_PATH="/userdata/roms/tic80/"

RUN cmake --build . --target tic80 --config Release --parallel

RUN mkdir /output

# then get the file out with:

# docker run --rm -v "$PWD":/output tic-trimui:latest cp /wrk/tic-80/build/trimui/bin/tic80 /output 

RUN ["/bin/bash"]

imsys added 2 commits March 16, 2026 21:46
[Gemini]
1.  **Resolved Nintendo Switch Build**: The issue was that
`PREFER_SYSTEM_SDL2` was defined before the Switch platform block could
override the library preference. I moved all flag definitions in
CMakeLists.txt to the end of the platform detection block. This ensures
the Switch correctly identifies that it should use the system SDL2,
fixing the "Threads are needed" error.
2.  **Fixed GLES/EGL on Native ARM64 runners**: The previous logic
forced GLES on any Linux ARM system, which broke standard Linux ARM
runners that expect desktop OpenGL. I've updated the logic to only
auto-enable `USE_GLES2` and `USE_EGL` when `CMAKE_CROSSCOMPILING` is
`ON`.
*   **Handhelds**: Since your Docker builds cross-compile, they will
still have GLES enabled automatically.
*   **Native CI**: Standard native Linux runners will now default to
desktop OpenGL, fixing the `/usr/bin/ld: cannot find -lGLESv2` error.
3.  **Resolved `INTERFACE_SDL2_SHARED` conflict**: In sdl.cmake, the
`sdlgpu` target was sometimes linking to both `SDL2` and `SDL2-static`
aliases. When those both pointed to the same system shared library,
CMake crashed due to property conflicts. I've consolidated the linking
logic to ensure only one of them is linked, prioritizing the generic
`SDL2` target when using system libraries.
@imsys

imsys commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

I plan to add the linux-arm64-gles2 to the Github CI/CD, but I will wait for the PR #2910 to be closed, as to avoid the git conflict.

There is also some other things I need to test and review.

imsys added 9 commits March 17, 2026 10:41
tic80: error while loading shared libraries:
/usr/lib/aarch64-linux-gnu/libSDL2.so: cannot open shared object file:
No such file or directory

The issue stems from the way the stub libraries are generated in the
Github workflow. When the loop creates libSDL2.so using sudo gcc -shared
-o ..., it outputs the custom shared object directly into the host
runner's absolute path /usr/lib/aarch64-linux-gnu/libSDL2.so. Since we
did not provide an explicit SONAME (which is typically built into
standard shared objects to tell the linker their "short name"), when ld
resolves the links dynamically, it bakes the absolute path
/usr/lib/aarch64-linux-gnu/libSDL2.so directly into the final tic80
binary's DT_NEEDED dependencies.

Now, the resulting executable will only encode the canonical library
name (libSDL2.so) rather than the absolute build-time path, restoring
the expected runtime linking behavior on the device!
@imsys

imsys commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

The failed Ubuntu build is likely due to some instability on the Ubuntu servers—they’ve been targeted by DDoS attacks lately.

tic80-trimui

Anyway, this GitHub workflow build works nicely on my TrimUI under the Knulli firmware.

There are a few points that need to be addressed:

  • The cursor stays at the top-left. → I think this could be handled in a different PR. ([SDL] Uses right stick to move cursor + only shows after first move #2936) One option would be to start it hidden until the first movement and move it with the right stick. Additionally, there could be a hide timeout under a build flag when there is no movement—maybe the timeout would only be desirable during gameplay, not when using the studio.
  • There is quite a border compared to the libretro version, which is stripped. I know this is the normal behavior of TIC-80, and this was probably discussed before. Not sure if a menu option or build flag to remove the border would be acceptable.
  • I added the build var TIC_DATA_PATH to set the folder it uses when browsing, but setting the folder this way makes the built binary not compatible across different OS/firmware. For example, for Knulli it should be /userdata/roms/tic80/, but on Rocknix I believe it is /storage/roms/tic80. This won’t be a problem since they have their own build workflows with device-specific optimizations, but it would still be nice for anyone to just grab a nightly build here to test things out.

Aside from this, I got Gemini to write a library stub linker that prevents errors from version-specific glibc issues, so I think I’ll later try to unify the two linux-x86_64 versions (linux-gcc12-glibc235 and linux-gcc14-glibc239).

@imsys
imsys marked this pull request as ready for review May 5, 2026 01:47
-DBUILD_SDLGPU=ON \
-DUSE_GLES2=ON \
-DUSE_EGL=ON \
-DBUILD_EDITORS=OFF \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-DBUILD_EDITORS=OFF, I think this is a bit of an assumption here. Just because they're on arm64 linux doesn't mean the user only intends to play the games.

I'm doing edits on my armhf board.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, it's a bit opinionated. I'm sending new PRs to enable a easier integration with gamepads without requiring to disable the editor tools. I also wonder how much BUILD_EDITORS affects performance, EMUUROM is the one that has a bit of slow down in some sections. I will test the difference sometime later.

Ideally we could make many builds, but then it takes forever the Github CI, maybe if we enable caching the compilation of the vendor src would help quite a bit.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to my suggestion on the other PR, this sounds like something better suited for a configuration file, rather than a parallel build.

If this shipped with the editor, desktop linux arm64 users would be able to grab a prebuilt binary, and if it were a config, that would also make for a great feature for those handhelds.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After @nesbox approves #2952, I can then change this to BUILD_EDITORS=ON

@computermouth

Copy link
Copy Markdown

Left a comment about editors, but just wanted to say I built this on my armhf board and it worked great 👍

(I didn't realize my build was using glx/gl swrast via mesa, tic80 is hitting 60fps no problem now on my old board)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants