Skip to content

Android Build - #6992

Merged
BMagnu merged 46 commits into
scp-fs2open:masterfrom
Shivansps:android-build
Nov 5, 2026
Merged

BMagnu merged 46 commits into
scp-fs2open:masterfrom
Shivansps:android-build

Conversation

@Shivansps

@Shivansps Shivansps commented Aug 23, 2025 •

Copy link
Copy Markdown
Contributor

Android OS:

  • Currently working on all archs with 16KB alignment too
  • Running on GLES 3.2 (minimum req, uses functions from it).
  • Running on Vulkan as well.
  • Limited FFmpeg lib to 6.1 as current master does not work for playing sound on cutscenes. Yet this version seems to work OK.

-Added "-get_flags json_v2": It is a minimal version of the v1 removing all info related to configuration. To avoid doing sdl inits while getting flags. This is mostly intended to list cmdline flag data for the "configure" option in knossos mods.

Note: It is now possible to compile both fso and the prebuilt libs with just an script on a linux x64 system with only having the same dependencies needed to compile normally.
https://github.com/Shivansps/Fso-Android-Prebuilts

A docker file was also added.

Note2: without #7489 android builds can only be compiled for Vulkan and will work if the device supports hardware clipping. 7489 fixes GLES compile, adds support in internal shaders and adds SW fallback for clip in vulkan.

For compiling, as it is in the script, its petty much two operations, first compile the embedded file, then the normal builds by turning off QTFRED and OPENXR. Android NDK is needed, R29 is recommended as it enables 16KB alignment.

# Make embedfile
mkdir tool && cd tool
cmake .. -DFSO_BUILD_WITH_OPENXR=OFF -DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TOOLS=ON -DFSO_BUILD_WITH_VULKAN=OFF -G Ninja
ninja embedfile

#Compile arm64-v8a debug and release builds
export ANDROID_NDK_HOME=../../android_ndk_r29 #path to the root of extracted folder of the NDK
export ANDROID_PLATFORM=android-28
export TARGET_ABI=arm64-v8a
mkdir "$TARGET_ABI"_debug && cd "$TARGET_ABI"_debug
cmake .. -DFSO_BUILD_WITH_OPENGL_DEBUG=ON -DFSO_BUILD_WITH_OPENXR=OFF -DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_WITH_OPENGL_ES=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_ABI=$TARGET_ABI -DANDROID_PLATFORM=$ANDROID_PLATFORM -DEMBEDFILE_PATH=../tool/bin/embedfile -G Ninja
ninja
cd ..

mkdir "$TARGET_ABI"_release && cd "$TARGET_ABI"_release
cmake .. -DFSO_BUILD_WITH_OPENGL_ES=ON -DFSO_BUILD_WITH_OPENXR=OFF -DFSO_BUILD_QTFRED=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_ABI=$TARGET_ABI -DANDROID_PLATFORM=$ANDROID_PLATFORM -DEMBEDFILE_PATH=../tool/bin/embedfile -G Ninja
ninja
cd ..

While testing FSO and Knossos i did build x86 and arm32 bit builds, but in the end this is not worth it and i dont even think im going to ship Knossos with 32bits support either, so it is recommended not to waster time and space in 32bit builds.

@notimaginative

Copy link
Copy Markdown
Contributor

Regarding point 1, the prebuilt override bug, that's fixed in the SDL3 branch. I keep forgetting to split that off into it's own thing and PR it.

Another thing is that since we've moved to a newer cmake version we can technically replicate embedfile with a platform agnostic cmake script. That's been on my todo list for a while since it's the only thing holding up Windows arm64 builds.

@wookieejedi wookieejedi added the build An issue related to the build systems label Aug 24, 2025
@Shivansps
Shivansps force-pushed the android-build branch 2 times, most recently from 2b6fca8 to ca6b8a7 Compare September 23, 2025 22:55
@BMagnu BMagnu added the Waiting for Stable Marks a pull request that is to be merged after the next stable release, due to a release cycle label May 31, 2026
@BMagnu BMagnu removed the Waiting for Stable Marks a pull request that is to be merged after the next stable release, due to a release cycle label Jul 5, 2026
@Shivansps
Shivansps marked this pull request as ready for review July 26, 2026 17:48

@dustinspace217 dustinspace217 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Read this against master and ran a desktop regression on master+this branch: no change on OpenGL or Vulkan, and the json_v1 output is the same structurally. Things I found:

  1. Prebuilts: the Android archives come from your personal release under the reusable prebuilts-cmake tag. The download is checked for TLS only, and reuse is keyed on PREBUILT_VERSION_NAME, so replacing an archive under the same tag never re-downloads. Until they move to scp-prebuilt (your TODO), an EXPECTED_HASH SHA256=... on the download would pin them.
  2. Vulkan pre-transform: master now marks the swap chain for rebuild on any eSuboptimal from acquire or present. If Android returns SUBOPTIMAL when preTransform differs from currentTransform (I believe it does on 10+, but haven't checked on a device), a phone in landscape would rebuild every frame. Ignoring suboptimal on Android when the extent hasn't changed would avoid that. Also, the comment above it has the mechanism reversed: the engine rotates when preTransform differs from currentTransform. Identity is still the right choice for content that isn't pre-rotated.
  3. The build recipe's sed for -lusb-1.0 suggests a prebuilt's link interface pulls it in. Dropping it under ANDROID and adding a configure-only NDK job would keep this from rotting (master's speech_android.cpp is still on SDL2 names, for example).
  4. JNI: the four osapi.cpp helpers never DeleteLocalRef the activity from SDL_GetAndroidActivity() (SDL says the caller must release it), and they don't check for exceptions after CallStatic*Method. The overlay pair runs on every option change. One shared helper like the one in speech_android.cpp would fix both in one place.
  5. Smaller:
    • The getWorkingFolder fallback appends /files/ to SDL_GetAndroidExternalStoragePath(), which already ends in files.
    • set(VAR ON FORCE) without CACHE sets a normal variable to ON;FORCE; an ANDROID default on the option would be cleaner (master has the same idiom at line 147 with OFF, filed as #7984).
    • The Borderless default only applies on the in-game-options path.
    • Under USE_OPENGL_ES the ImGui SDL3 backend is never initialized, so the lab and options screens assert; that's on master already, and your #7489 may cover it.
    • The json_v2 comment says flags only, but it includes pref_path, which seems intended for the launcher.

@Shivansps

Shivansps commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Read this against master and ran a desktop regression on master+this branch: no change on OpenGL or Vulkan, and the json_v1 output is the same structurally. Things I found:

  1. Prebuilts: the Android archives come from your personal release under the reusable prebuilts-cmake tag. The download is checked for TLS only, and reuse is keyed on PREBUILT_VERSION_NAME, so replacing an archive under the same tag never re-downloads. Until they move to scp-prebuilt (your TODO), an EXPECTED_HASH SHA256=... on the download would pin them.

  2. Vulkan pre-transform: master now marks the swap chain for rebuild on any eSuboptimal from acquire or present. If Android returns SUBOPTIMAL when preTransform differs from currentTransform (I believe it does on 10+, but haven't checked on a device), a phone in landscape would rebuild every frame. Ignoring suboptimal on Android when the extent hasn't changed would avoid that. Also, the comment above it has the mechanism reversed: the engine rotates when preTransform differs from currentTransform. Identity is still the right choice for content that isn't pre-rotated.

  3. The build recipe's sed for -lusb-1.0 suggests a prebuilt's link interface pulls it in. Dropping it under ANDROID and adding a configure-only NDK job would keep this from rotting (master's speech_android.cpp is still on SDL2 names, for example).

  4. JNI: the four osapi.cpp helpers never DeleteLocalRef the activity from SDL_GetAndroidActivity() (SDL says the caller must release it), and they don't check for exceptions after CallStatic*Method. The overlay pair runs on every option change. One shared helper like the one in speech_android.cpp would fix both in one place.

  5. Smaller:

  1. added version tag and sha256 to android lib prebuilts

  2. Update to take eSuboptimal into consideration, please check this code as i dont know much of vulkan.

  3. This was about "spacemouse" used by fred/qtfred linking hidapi, i belive this was already refactored to use SDL3 hidapi so libusb1.0 should not being linked anymore, but i have not checked yet.
    i had already updated speed_android.cpp to SDL3 names.

  4. Implemented shared helper in osapi

-getWorkingFolder, fixed fallback
-the issue #7984 is fixed in other PR on #7489
-fixed bordeless only being applied with the option system on
-The ImGui SDL3 init on ES is fixed on #7489
-json_v2 updating comment. Its not just flags, i added that because a modern launcher that does not sets the settings and let FSO use its internal option system would only need the pref_path.

Ill check on device now to make sure i didnt break anything.

EDIT: it still works fine. Also i confirmed libusb1.0 is not longer being linked.

@dustinspace217 dustinspace217 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, I went through the new commits. The suboptimal handling looks right to me: out-of-date still always rebuilds, and on Android a suboptimal is skipped only when the surface reports a non-identity transform and the extent hasn't changed, which is the compositor compensating for the identity preTransform. A size change still rebuilds. The local frame in the JNI helper covers every exit path, and the folder and json_v2 fixes check out.

One leftover: CMakeLists.txt:62-66 still use set(X ON FORCE) without CACHE, the same idiom #7489 fixed for #7984. set(X ON CACHE BOOL "" FORCE) would match.

@dustinspace217 dustinspace217 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a code-reading review of the two new commits, and nothing was built or run.

The leftover from my last comment is resolved: CMakeLists.txt:62-66 now use set(X ON CACHE BOOL "" FORCE).

Small cleanup, not a blocker: of those five, only SDL3_USE_PRECOMPILED and OPENAL_USE_PRECOMPILED (:64-65) actually take effect. USING_PREBUILT_LIBS (:63) and USING_PREBUILT_VULKAN (:66) get shadowed by the plain set() calls in SDL3.cmake:41, OpenAL.cmake:34, FFmpeg.cmake:61 and vulkan.cmake:96, and Android already gets the Vulkan prebuilt through the OR ANDROID at vulkan.cmake:98.

FSO_BUILD_INCLUDED_LIBS (:62) repeats the OR ANDROID default at :121, and the FORCE means it can't be overridden from the command line, so lines 62, 63 and 66 could go.

The touch overlay string IDs 1936 to 1939 are unused on master, where the highest is 1935 (2d.cpp:908), and the XSTR_SIZE note now says 1940, so that matches the convention.

The other hunks in the new diff (the GLES log lines, the Vulkan clip distance and ETC2 changes, the ImGui init move) came in with the master merge and aren't part of this PR's own diff.

Everything else is unchanged from the head I approved, so the approval stands.

@dustinspace217

Copy link
Copy Markdown
Contributor

Heads up: #7694 also takes XSTR 1936 and 1937 (tracing.cpp:345-346), so whichever of these merges second will need to move up. 1940 and later are free on master today.

@BMagnu BMagnu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good with the newest round of changes.
We should get the prebuilts into the SCP organization ASAP post-merge.

@BMagnu
BMagnu merged commit 1d0dd68 into scp-fs2open:master Nov 5, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build An issue related to the build systems

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants