A new version: Deploying SDL3 app on Android using SDL3-x.y.z.aar
New version for SDL 3.3: Setting Up SDL 3.3 for Android Development
Result of testing: Discord
Testing of the GitHub - madebr/sdlcross: Little SDL application buildable on Desktop + Android example with SDL3 Renderer API that shows squares when we touch the screen:

Example in pure OpenGL ES 2.0 that draws a simple green triangle:
I used the https://github.com/Genymobile/scrcpy app to create a screenshot on PC using USB cable from the phone.
Added the following info to the guide: Setting Up SDL 3.3 for Android Development
- Important! The project name in
CMakeLists.txt:
# Declare the project
project(my-project)
- Must be the same as the project name in the
.javafile located atapp\src\main\java\com\example\sdlcross, inside thegetLibraries()method:
package com.example.sdlcross;
import org.libsdl.app.SDLActivity;
public class MyActivity extends SDLActivity {
protected String[] getLibraries() {
return new String[] { "my-project" };
}
}
There is my mistake above. The executable name should be the same with the return new String[] { "sdlcross" };:
- Important! The executable name in
CMakeLists.txt:
add_executable(sdlcross src/main.c)
- Must be the same as the project name in the
.javafile located atapp\src\main\java\com\example\sdlcross, inside thegetLibraries()method:
package com.example.sdlcross;
import org.libsdl.app.SDLActivity;
public class MyActivity extends SDLActivity {
protected String[] getLibraries() {
return new String[] { "sdlcross" };
}
}
Note. The SDL 3.3 is not release yet. I call the currect master branch like 3.3.
Drawing a triangle using SDL3 (OpenGL, WebAssembly)
Guide: Setting up SDL3 with OpenGL ES 3.0 for WebAssembly
Note. You can disable multisampling if you delete this code:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); // can be 2, 4, 8 or 16
Note 2. There is no difference between 2 and 4 (value of multisampling) at least in this triangle.
Drawing a rotated rectangle using cglm (OpenGL, WebAssembly)
Guide: Setting up cglm with SDL3 and OpenGL ES 3.0 for WebAssembly
Size of the Release build - 942 KB:
Drawing a texture using SDL3_image (OpenGL, WebAssembly)
Guide: Setting up SDL3_image with OpenGL ES 3.0 (Wasm)
Drawing a texture using stb_image (OpenGL, WebAssembly)
Rendering a text using SDL3_ttf (OpenGL, WebAssembly)
Guide: Setting up SDL3_ttf (OpenGL, WebAssembly)
Size of the Release build - 1.81 MB:
Asset: LiberationSans-Regular.ttf file - 401 KB (link)
[Workaround] Background music looping in Wasm (SDL3_mixer)
I’ve been running into an issue where MIX_SetTrackLoops(..., -1) doesn’t loop background music infinitely in my Wasm/Emscripten build:
The Issue: The track stops after it completes its first run, and the loop command is ignored:
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
App *myApp = (App *)appstate;
// Handle initial music trigger on any input
bool isInput = (event->type == SDL_EVENT_KEY_DOWN ||
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN);
if (!myApp->musicStarted && isInput)
{
MIX_SetTrackLoops(myApp->musicTrack, -1); // -1 loops infinitely, 0 disables looping
MIX_PlayTrack(myApp->musicTrack, 0);
myApp->musicStarted = true;
}
The Workaround: You must create an explicit options packet using SDL_CreateProperties(), assign your infinite loop instruction to MIX_PROP_PLAY_LOOPS_NUMBER, and feed that packet into MIX_PlayTrack:
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
App *myApp = (App *)appstate;
// Handle initial music trigger on any input
bool isInput = (event->type == SDL_EVENT_KEY_DOWN ||
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN);
if (!myApp->musicStarted && isInput)
{
// Create an options configuration packet
SDL_PropertiesID props = SDL_CreateProperties();
// Pack the "infinite loop" instruction (-1) into the container
SDL_SetNumberProperty(props, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
// Hand the configuration properties over to SDL3_mixer
MIX_PlayTrack(myApp->musicTrack, props);
// Clean up the handle container (SDL copies properties internally)
SDL_DestroyProperties(props);
myApp->musicStarted = true;
}
// Handle rest of events...
return SDL_APP_CONTINUE;
}
Playing a background music and sound effect using SDL3_mixer (OpenGL, WebAssembly)
Guide: Setting up SDL3_mixer (OpenGL, WebAssembly)
Release build size:
C and C++ Release builds has the same sizes - 4.18 MB:
Asset sizes:
- Winds Of Stories.ogg - 2.43 MB
- Picked Coin Echo 2.wav - 296 KB (after
Audacityconversion)
Playing a background music and sound effect using OpenAL (OpenGL, WebAssembly)
Guide: Setting up OpenAL (OpenGL, WebAssembly)
Source code: GitHub Repository
Release build size - 3.84 MB:
Asset sizes:
- Winds Of Stories.ogg - 2.43 MB
- Picked Coin Echo 2.wav - 296 KB (after
Audacityconversion)
Read comments:
if (EMSCRIPTEN)
target_link_options(app PRIVATE
"-Oz" # Optimize for smallest code size (aggressively strips metadata and optimizes for binary footprint).
"-sMALLOC=emmalloc" # Use 'emmalloc', a smaller, simpler memory allocator suitable for memory-constrained web apps.
"-sUSE_SDL=0" # Disable the legacy Emscripten-provided SDL1/SDL2 port (allows using custom or system-integrated SDL3).
"-sMAX_WEBGL_VERSION=2" # Limit the maximum WebGL context version to 2.0.
"-sMIN_WEBGL_VERSION=2" # Set the minimum required WebGL version to 2.0 (disallows fallback to 1.0).
"-sFULL_ES3=1" # Enable full WebGL 2.0 / OpenGL ES 3.0 feature set support.
)
endif()
Short comments:
if (EMSCRIPTEN)
target_link_options(app PRIVATE
"-Oz" # Maximize code size optimization
"-sMALLOC=emmalloc" # Use minimal memory allocator
"-sUSE_SDL=0" # Disable built-in SDL
"-sMAX_WEBGL_VERSION=2" # Set WebGL 2.0 max
"-sMIN_WEBGL_VERSION=2" # Require WebGL 2.0 min
"-sFULL_ES3=1" # Enable full GLES3/WebGL 2
)
endif()
Failed to enable VSync on Intel(R) HD Graphics 630 (i7-7700)
I cannot enable it on Desktop:
int status = SDL_GL_SetSwapInterval(1);
if (status != 0)
{
SDL_Log("VSync failed: %s", SDL_GetError());
}
Solution is to limit FPS:
SDL_AppResult SDL_AppIterate(void *appState)
{
App *app = (App *)appState;
// High-precision timing variables
static Uint64 lastFrameTime = 0;
const Uint64 targetFrameTimeNS = 16666666; // ~16.6ms for 60 FPS
Uint64 now = SDL_GetTicksNS();
// If we haven't hit the target time, yield the CPU
if ((now - lastFrameTime) < targetFrameTimeNS)
{
// Sleep to yield control back to the Windows scheduler
// This drops CPU usage from 15% to <1%
SDL_Delay(1);
return SDL_APP_CONTINUE;
}
// Update our last frame time
lastFrameTime = now;
glClear(GL_COLOR_BUFFER_BIT);
Before:
After:
P.S. I use the latest Intel drivers:
The thread is about building SDL3 ‘for Android and WebAssembly’ so when you say “on desktop” do you mean specifically when running in a browser, or more generally?
I have moved this problem to the topic: Failed to enable VSync on Intel(R) HD Graphics 630 (i7-7700)
Android: Building SDL3_image from source to support WebP, BMP, JPG, and PNG formats
- Download
SDL3_imagesource code (the current release):
git clone -b release-3.4.4 https://github.com/libsdl-org/SDL_image.git C:\libs\SDL_image
- Go to the source folder:
cd C:\libs\SDL_image
- Open the
C:\libs\SDL_image\build-scripts\release-info.jsonand enable WebP:
"android": {
"cmake": {
"args": [
"-DBUILD_SHARED_LIBS=ON",
"-DSDLIMAGE_AVIF=OFF",
"-DSDLIMAGE_BMP=ON",
"-DSDLIMAGE_GIF=OFF",
"-DSDLIMAGE_JPG=ON",
"-DSDLIMAGE_JXL=OFF",
"-DSDLIMAGE_LBM=OFF",
"-DSDLIMAGE_PCX=OFF",
"-DSDLIMAGE_PNG=ON",
"-DSDLIMAGE_PNM=OFF",
"-DSDLIMAGE_QOI=OFF",
"-DSDLIMAGE_SVG=OFF",
"-DSDLIMAGE_TGA=OFF",
"-DSDLIMAGE_TIF=OFF",
"-DSDLIMAGE_WEBP=ON",
"-DSDLIMAGE_XCF=OFF",
"-DSDLIMAGE_XPM=OFF",
"-DSDLIMAGE_XV=OFF",
"-DSDLIMAGE_SAMPLES=OFF",
"-DSDLIMAGE_TESTS=OFF",
"-DSDLIMAGE_VENDORED=ON"
]
},
- Download dependencies:
git submodule update --init external/libpng
git submodule update --init external/jpeg
git submodule update --init external/libwebp
git submodule update --init external/zlib
- Build
SDL3_image:
python build-scripts/build-release.py --force --actions download android --android-home "H:\AndroidSDK" --android-ndk-home "H:\AndroidSDK\ndk\27.0.12077973"
Result:
Discord post
WebAssembly: Building SDL3_image from source to support WebP, BMP, JPG, and PNG formats
- Download
SDL3_imagesource code:
git clone https://github.com/libsdl-org/SDL_image.git C:\libs\SDL_image
cd C:\libs\SDL_image
- Download dependencies:
git submodule update --init external/libpng
git submodule update --init external/jpeg
git submodule update --init external/libwebp
git submodule update --init external/zlib
- Configure
SDL3_imagein PowerShell:
emcmake cmake -S . -B dist `
-DCMAKE_INSTALL_PREFIX="C:/libs/SDL3_image-devel-3.5.0-wasm" `
-DSDL3_DIR="C:/libs/SDL3-devel-3.4.12-wasm/lib/cmake/SDL3" `
-DCMAKE_BUILD_TYPE=Release `
-DSDLIMAGE_VENDORED=ON `
-DSDLIMAGE_BMP=ON `
-DSDLIMAGE_JPG=ON `
-DSDLIMAGE_PNG=ON `
-DSDLIMAGE_WEBP=ON `
-DSDLIMAGE_AVIF=OFF `
-DSDLIMAGE_GIF=OFF `
-DSDLIMAGE_JXL=OFF `
-DSDLIMAGE_LBM=OFF `
-DSDLIMAGE_PCX=OFF `
-DSDLIMAGE_PNM=OFF `
-DSDLIMAGE_QOI=OFF `
-DSDLIMAGE_SVG=OFF `
-DSDLIMAGE_TGA=OFF `
-DSDLIMAGE_TIF=OFF `
-DSDLIMAGE_XCF=OFF `
-DSDLIMAGE_XPM=OFF `
-DSDLIMAGE_XV=OFF `
-DSDLIMAGE_SAMPLES=OFF `
-DSDLIMAGE_TESTS=OFF
- Build:
cmake --build dist -j8
- Install:
cmake --install dist
Result:
Discord post
Windows (MinGW, static): Building SDL3_image from source to support WebP, BMP, JPG, and PNG formats
- Download
SDL3_imagesource code:
git clone https://github.com/libsdl-org/SDL_image.git C:\libs\SDL_image
cd C:\libs\SDL_image
- Download dependencies:
git submodule update --init external/libpng
git submodule update --init external/jpeg
git submodule update --init external/libwebp
git submodule update --init external/zlib
- Configure
SDL3_imagein PowerShell:
cmake -S . -B dist-static `
-DCMAKE_INSTALL_PREFIX="C:/libs/SDL3_image-devel-3.5.0-mingw-static" `
-DSDL3_DIR="C:/libs/SDL3-devel-3.4.12-mingw/lib/cmake/SDL3" `
-DCMAKE_BUILD_TYPE=Release `
-G "MinGW Makefiles" `
-DBUILD_SHARED_LIBS=OFF `
-DSDLIMAGE_VENDORED=ON `
-DSDLIMAGE_DEPS_SHARED=OFF `
-DSDLIMAGE_BMP=ON `
-DSDLIMAGE_JPG=ON `
-DSDLIMAGE_PNG=ON `
-DSDLIMAGE_WEBP=ON `
-DSDLIMAGE_AVIF=OFF `
-DSDLIMAGE_GIF=OFF `
-DSDLIMAGE_JXL=OFF `
-DSDLIMAGE_LBM=OFF `
-DSDLIMAGE_PCX=OFF `
-DSDLIMAGE_PNM=OFF `
-DSDLIMAGE_QOI=OFF `
-DSDLIMAGE_SVG=OFF `
-DSDLIMAGE_TGA=OFF `
-DSDLIMAGE_TIF=OFF `
-DSDLIMAGE_XCF=OFF `
-DSDLIMAGE_XPM=OFF `
-DSDLIMAGE_XV=OFF `
-DSDLIMAGE_SAMPLES=OFF `
-DSDLIMAGE_TESTS=OFF
- Build:
cmake --build dist-static -j8
- Install:
cmake --install dist-static
Result:
Animation switcher (C++, OpenGL, SDL3)
I use the ozz-animation library to switch between animations. The robot and animations were downloaded from Mixamo. I’ve built this example for Windows, Android, and WebAssembly.
Tools:
- cgltf to load the
.glbfiles - ozz-animation to load animations
- ImGui for GUI
- SDL for window, key/mouse events, and so on
- SDL_image to load the
.webpfiles - SDL_ttf to draw text with OpenGL
- cglm to work with matrices and vectors




















