Skip to content

Android: add command mechanism so that SDLActivity#14962

Open
1bsyl wants to merge 1 commit into
libsdl-org:mainfrom
1bsyl:br_android_RPC_v2
Open

Android: add command mechanism so that SDLActivity#14962
1bsyl wants to merge 1 commit into
libsdl-org:mainfrom
1bsyl:br_android_RPC_v2

Conversation

@1bsyl

@1bsyl 1bsyl commented Feb 3, 2026

Copy link
Copy Markdown
Contributor
  • I confirm that I am the author of this code and release it to the SDL project under the Zlib license. This contribution does not contain code from other sources, including code generated by a Large Language Model ("AI").

Add some RPC commands so that SDLActivity defers most of SDL code internal execution it to the SDL main thread
see #14925

Most SDLActivity code is deferred to main SDL C thread with some command RPC.
except:

  • lifecycle event (which remains in main SDL C thread).
  • code to count recreation of activity because it is SDLActivity only.
  • code to initialize (nativeSetupJNI / nativeQuit), because it occurs before C Thread.
  • code which doesn't return void. (nativeGetHint()). because, value is needed immediately .
  • nativeInitMainThread() / nativeInitMainThread(), already in C thread.

(SDL_Window *)Android_Window global variable is removed.
Android ActivityMutex is removed.
Android_LifecycleMutex, is used to lock the SDLActivity state. (Android_WaitActiveAndLockActivity()).
since it prevents the SDLActivity to add new lifecylce message, it prevents it to change state.
factorisation of EGLSurface/native_window handling. (use in surfaceChanged/Created/Destroy, and SDLCreate/DestroyWindow()

It seem to work quite nicely from my side. I tested various stuff, but not fully.
(onNativeFileDialog() was the less easy to update, and I really have to tested).
other functions are always simple. I guess, the ways it's written with named struct, prevent lot of type mistake.

Still a draft. please give a try.
I'll try it also in production maybe in a while

maybe 2 todo:

  • I didn't add the HID native functions .. I am not familiar with them. but then didn't rely on SDL and use no locking.
    so maybe it makes not difference. (they could be added anyway afterwards).

  • we probably lose some event timestamp precision because event are sent from Main thread, and not SDLActivity thread. maybe it's not a big deal.
    but if we need it for some command, we could add. (just enabled the timestamp, and then send it with the event).
    maybe we wait to see, if this is really useful

@1bsyl

1bsyl commented Feb 3, 2026

Copy link
Copy Markdown
Contributor Author

still need comment: "We still need to pump events for lifecycle activity even if there's no window or video hasn't been initialized."

  • done

Comment thread src/events/SDL_events.c Outdated
@slouken slouken added this to the 3.6.0 milestone Feb 3, 2026
@slouken

slouken commented Feb 3, 2026

Copy link
Copy Markdown
Collaborator

I'm marking this as draft until you have a chance to test it more thoroughly in production.

@AntTheAlchemist, any chance you can try this patch in a production release and provide feedback?

@slouken
slouken marked this pull request as draft February 3, 2026 15:19
@slouken

slouken commented Feb 3, 2026

Copy link
Copy Markdown
Collaborator

FWIW, right now there is only one window, but conceptually the pump call would get all life cycle events and events for all windows.

@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 769a432 to de582b3 Compare February 4, 2026 11:13
@1bsyl

1bsyl commented Feb 5, 2026

Copy link
Copy Markdown
Contributor Author

I remember I did a while ago a patch to have multiple SDL_Window on Android, there were several SurfaceView and several Activity involved. I don't remember how it worked though.. just that it didn't provide all the functionality of SDL. maybe I could dust it out and give a try.

Btw, I am trying the patch in production. I need a one or two week to have more information.

@1bsyl

1bsyl commented Feb 12, 2026

Copy link
Copy Markdown
Contributor Author

ok, so far that's ok. it's been 1 week, and 138k users.
no user complain (I've collapsed the tab comment)

Production console says:
User-perceived crash rate 0.01%
User-perceived ANR rate 0.08%

Still some low crashes in EGL libs and ANR in nativePollOnce. but maybe not SDL related.

Screenshot From 2026-02-12 21-26-33

@MoNTE48

MoNTE48 commented Feb 15, 2026

Copy link
Copy Markdown

MultiCraft Open Source is on the line 😀
https://play.google.com/store/apps/details?id=com.multicraft.game
We decided to try this PR on the beta version of our game and will let you know if anything goes wrong.
We use Sentry to track crashes, by the way.

@1bsyl

1bsyl commented Feb 16, 2026

Copy link
Copy Markdown
Contributor Author

@MoNTE48 nice, thanks for sharing. Let us know !

BTW: "the compare vs ALL Release" metric is not really relevant. because my SDL lib was a modified version.
Now, the SDL in production is more or less a vanilla version, with:
forced opengles2, openSLES audio, no HID, use the flags SDL_ANDROID_GAMEPAD_AS_RPC

@MoNTE48

MoNTE48 commented Feb 17, 2026

Copy link
Copy Markdown

After 30K sessions, I can see that the ANR issue has been resolved. I can clearly see new ANRs with AppMetrica or the advertising library, but libSDL is no longer the cause.

I didn't enable the GAMEPAD_AS_RPC build flag, but I'm not sure how many of my players use gamepads.

Just one new, rare crash:

SIGSEGV: Segfault
  libandroid          0xaffaa894   ANativeWindow_setBuffersGeometry
  libMultiCraft       0x86b7726e   SDL_EGL_CreateSurface (SDL_egl.c:1287)
  libMultiCraft       0x86b7726e   Android_nativeSurfaceChanged (SDL_androidwindow.c:210)
  libMultiCraft       0x86b4ba52   Android_PumpRPC (SDL_android.c:3414)
  libMultiCraft       0x86b75f28   Android_WaitActiveAndLockActivity (SDL_androidevents.c:274)
  libMultiCraft       0x86b76f92   Android_CreateWindow (SDL_androidwindow.c:58)
  libMultiCraft       0x86b34844   SDL_CreateWindowWithProperties (SDL_video.c:2572)
  libMultiCraft       0x86b35614   SDL_CreateWindow (SDL_video.c:2615)
  libMultiCraft       0x8694fe98   irr::CIrrDeviceSDL::createWindowWithContext (CIrrDeviceSDL.cpp:502)
  libMultiCraft       0x869514be   irr::CIrrDeviceSDL::createWindow (CIrrDeviceSDL.cpp:280)
  libMultiCraft       0x869514be   irr::CIrrDeviceSDL::CIrrDeviceSDL (CIrrDeviceSDL.cpp:171)
  libMultiCraft       0x86260804   createDeviceEx (Irrlicht.cpp:103)
  libMultiCraft       0x86260804   RenderingEngine::RenderingEngine (renderingengine.cpp:168)
  libMultiCraft       0x86260804   ClientLauncher::init_engine (clientlauncher.cpp:432)
  libMultiCraft       0x86260804   ClientLauncher::run (clientlauncher.cpp:124)
  libMultiCraft       0x86463b4e   real_main (main.cpp:246)
  libMultiCraft       0x86489c6a   SDL_main (porting_android.cpp:66)
  libMultiCraft       0x86b4905a   SDL_CallMainFunction (SDL_main_callbacks.c:164)
  libMultiCraft       0x86b4905a   SDL_RunApp (SDL_runapp.c:37)
  libMultiCraft       0x86b4905a   Java_org_libsdl_app_SDLActivity_nativeRunMain (SDL_android.c:1062)
  base.odex           0x939a4b95   oatexec

@1bsyl

1bsyl commented Feb 17, 2026

Copy link
Copy Markdown
Contributor Author

Ok thanks for the info ! do you have information like how your crash rate or anr rate is now ?.

I also have the ANativeWindow_setBuffersGeometry crash in SDL_CreateWindow,
But this is something that we've already seen before, it doesn t seems to be new

I have also some rare crash in:
SDL_EGL_SwapBuffers
Android_nativeSurfaceDestroyed
GLES2_RunCommandQueue (glClear)
but they were also there before.

I believe it's possible that some ANR becomes Crash. or inverse. or change name.
So, the global ANR / Crash has to be considered.

(Of course, if this is something reproducible, even with adding SDL_Delay() in code, this is has to be debugged...)

@1bsyl

1bsyl commented Feb 18, 2026

Copy link
Copy Markdown
Contributor Author

looking at aosp code, setBuffersGeometry calls set_buffer_format, which doesn't check the handle validity.
maybe a check would be good anyway.

int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
        int32_t width, int32_t height, int32_t format) {
    int32_t err = native_window_set_buffers_format(window, format);
    ....
}

static inline int native_window_set_buffers_format(
        struct ANativeWindow* window,
        int format)
{
    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
}

@AntTheAlchemist

Copy link
Copy Markdown
Contributor

I'm late to the party - sorry guys. I'm now taking a proper look at this and report back with results from a production release.

Currently, my gamepad heavy app stands at 0.02% crash rate and 0.18% ANR rate.

Current common crashes (without this pull):
android.view.View.onResolvePointerIcon (probably AdMob)
android.database.sqlite.SQLiteConnection.nativeOpen (I don't even use SQL!)
GLES2_RunCommandQueue
SDL_EGL_SwapBuffers
Android_SetWindowFullscreen (I think this is fixable. Happens during a quit and the app is in the background; will create a new issue)

Current common ANRs (without this pull):
SDL_DispatchEventWatchList
org.libsdl.app.HIDDeviceUSB.close
android.os.MessageQueue.nativePollOnce
org.libsdl.app.HIDDeviceUSB.open
chromium-TrichromeWebViewGoogle.aab-stable-755910930 - org.chromium.components.policy.CombinedPolicyProvider.b (AdMob for sure)
Java_org_libsdl_app_SDLActivity_onNativeSurfaceDestroyed

Watch this space.

@1bsyl

1bsyl commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

nice!
I guess
Crash of Android_SetWindowFullscreen , ANR SDL_DispatchEventWatchList
should disappear/
Others are also there for me, and probably unrelated to SDL

@MoNTE48

MoNTE48 commented Feb 24, 2026

Copy link
Copy Markdown

@1bsyl what about Android_GLES_SwapWindow crash, introduced with this PR?

backtrace:
  #00  pc 0x0000000000012564  /vendor/lib/egl/libGLES_mali.so (__egl_platform_color_conversion_needed+4)
  #01  pc 0x0000000000012178  /vendor/lib/egl/libGLES_mali.so (__egl_platform_surface_post_processing_needed_android+12)
  #02  pc 0x000000000006afc8  /vendor/lib/egl/libGLES_mali.so (__egl_mali_post_color_buffer+268)
  #03  pc 0x000000000006ad50  /vendor/lib/egl/libGLES_mali.so (__egl_mali_post_to_window_surface+104)
  #04  pc 0x000000000006a054  /vendor/lib/egl/libGLES_mali.so (_egl_swap_buffers+392)
  #05  pc 0x0000000000068108  /vendor/lib/egl/libGLES_mali.so (eglSwapBuffers+72)
  #06  pc 0x000000000000ca45  /system/lib/libEGL.so (eglSwapBuffersWithDamageKHR+236)
  #07  pc 0x0000000000c8ea75  /data/app/com.multicraft.game-_b6TlGVZWfBmsZ1umVPPJA==/lib/arm/libMultiCraft.so (Android_GLES_SwapWindow+1242) (BuildId: 022c00bc78f244a538bbdc2b32f09fe9083f3ebb)
  #08  pc 0x0000000000b746e7  /data/app/com.multicraft.game-_b6TlGVZWfBmsZ1umVPPJA==/lib/arm/libMultiCraft.so (irr::video::COGLES1Driver::endScene()+290) (BuildId: 022c00bc78f244a538bbdc2b32f09fe9083f3ebb)
  #

@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 36daee4 to 4359ae4 Compare February 26, 2026 20:12
@1bsyl

1bsyl commented Feb 26, 2026

Copy link
Copy Markdown
Contributor Author

@MoNTE48
not sure if this is really introduce by the PR :/ I've seen that before.

I adding this anyway
4359ae4
so that onNativeSurface Created/Changed/Destroyed methods of SDLActivity don't return to quickly:
onNativeSurfaceCreated will wait max 100ms that the C Thread creates the EGL surface. and same for Changed/Destroyed.
I am curious to see if that helps.

@1bsyl

1bsyl commented Feb 26, 2026

Copy link
Copy Markdown
Contributor Author
Screenshot From 2026-02-26 21-17-14

So this is 3 weeks.
95 crashes/383 anr.
seems to say: same number of crashes. less anr ...
no bad comment

This doesn't take into account :

Android: check native_window is valid before calling ANativeWindow_setBuffersGeometry

Android: add semaphores so that nativeSurface methods can wait up to

going to try another test with the two previous commits
and I will also re-base to latest head so that it has another android fix inside ( a35bcad )

@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 4359ae4 to 224c331 Compare February 26, 2026 20:26
@1bsyl

1bsyl commented Mar 6, 2026

Copy link
Copy Markdown
Contributor Author

So it's 1 week after starting 2nd test.

that includes in addition:

  • Android: check native_window is valid before calling ANativeWindow_setBuffersGeometry 0da4d25
  • Android: add semaphores so that nativeSurface methods 224c331
  • ( another android fix inside from main rebase:
    Android: prevent SDLActivity and Main Thread to access mJoystick
    a35bcad )

Install base is the same as 1st test: ~130k users.

So far, number of crash are reduced: 15
more ANR maybe ? 86 vs 63
I see no crash in SDL_EGL_CreateSurface ( ANativeWindow_setBuffersGeometry )
nor Android_GLES_SwapWindow().

Screenshot From 2026-03-06 15-52-46

edit: as difference with 1st test, I rolled out the 2nd test directly to 100%. (whereas I waited 1 day before doing that for the 1st one).

@AntTheAlchemist

Copy link
Copy Markdown
Contributor

This patch doesn't work for my apps. It seems to block all input events, which only come through when the app enters background. The 2nd time I leave the app and return, I get a black screen. Am I missing something?

@AntTheAlchemist

Copy link
Copy Markdown
Contributor

SDL_AppEvent isn't being called for input events. Is anyone else using the SDL_App* stuff?

@1bsyl

1bsyl commented Mar 7, 2026

Copy link
Copy Markdown
Contributor Author

@AntTheAlchemist I didn't try SDL_AppEvent, but now it's ok with last commit. It also takes into account block on pause (very last commit separated).

but there are more changes inside: all cycle event are moved with the RPC command flow, instead of being a separate channel.

this is going to be a new test in a few weeks, once the v2 finished.
but the reason I wanted to try this are:

  • pause/resume acknowledge with C thread. SDLActivity doesn't change state without knowing that C thread processed the event.
  • pause/resume are inserted correctly within the flow, especially regarding the NativeSurface commands that create/destroy EGL surface.
  • before: handling Background very quickly should be fine, but if Resume is handled to quickly, I guess it can happen before EGL surface creation and create issues.
  • block_on_pause code is more clear: it waits for Java Resume semaphore, in a separate function, only used in PollEvent() and SDL_AppEvent()
  • Fore/Background events must still be handled as WatchEvent.
  • also, overall code is more clear

NB:
SDL_WakeUp() is not clear to me, currently no op

@AntTheAlchemist

AntTheAlchemist commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Thanks for that. Seems to work, but I've found a problem. After a SDL_WINDOW_RESTORED, the first frame drawn produces a black screen. This used to be fixed with a pre-emptive duplicated call to SDL_RenderPresent(), but that no longer works. My app doesn't redraw every SDL_AppIterate. It sets a redraw and refresh flag after a SDL_WINDOW_RESTORED event is recieved, then in the following SDL_AppIterate call, no draw methods are valid. No other events are sent, so the app is juts a black screen. There's no way to fix this unless my app redraws every SDL_AppIterate.

@1bsyl

1bsyl commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

@AntTheAlchemist
.... just testing with testsprite (modified, see below !). and that seems to work when drawing only once, as you describe.

to be clear:

  • SDL_EVENT_WINDOW_RESTORED occurs when it comes from background (not at start).
  • I draw only once. and I've got a frame:
diff --git a/test/testsprite.c b/test/testsprite.c
index 575be1163..010a8b49c 100644
--- a/test/testsprite.c
+++ b/test/testsprite.c
@@ -79,6 +79,7 @@ static bool LoadSprite(const char *file)
     return true;
 }
 
+static int g_draw = 0; // or can start at 1 also.
 static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
 {
     int i;
@@ -86,6 +87,10 @@ static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
     SDL_FRect temp;
     SDL_FRect *position, *velocity;
 
+    if (g_draw) {
+        SDL_Log("will draw...");
+        g_draw = 0;
+    } else { return; }
     /* Query the sizes */
     SDL_SetRenderViewport(renderer, NULL);
     SDL_GetRenderSafeArea(renderer, &viewport);
@@ -565,6 +570,10 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
     if (event->type == SDL_EVENT_RENDER_DEVICE_RESET) {
         LoadSprite(icon);
     }
+    if (event->type == SDL_EVENT_WINDOW_RESTORED) {
+        SDL_Log("SDL_EVENT_WINDOW_RESTORED !!!");
+        g_draw = 1;
+    }
     return SDLTest_CommonEventMainCallbacks(state, event);
 }

here's simplified log, when going to FG

11:26:04.785 25616 25616 V [                           SDL] onNativeSurfaceCreated
11:26:04.785 25616 25616 I [                   SurfaceView] 170029209 surfaceChanged -- format=4 w=1080 h=2121
11:26:04.785 25616 25616 V [                           SDL] surfaceChanged()
11:26:04.785 25616 25616 V [                           SDL] Window size: 1080x2121
11:26:04.785 25616 25616 V [                           SDL] Device size: 1080x2340
11:26:04.785 25616 25616 V [                           SDL] onNativeSurfaceChanged
11:26:04.785 25616 25616 V [                           SDL] nativeResume()
11:26:04.785 25616 25700 I [                       SDL/APP] BlockOnPause...resume
11:26:04.786 25616 25700 I [                       SDL/APP] pixel format wanted SDL_PIXELFORMAT_RGBA8888 (1), got SDL_PIXELFORMAT_RGBA8888 (1)

11:26:04.786 25616 25700 I [                       SDL/APP] SDL_EVENT_WINDOW_RESTORED !!!
11:26:04.786 25616 25700 I [                       SDL/APP] will draw...

11:26:04.786 25616 25616 V [                           SDL] nativeResume() done

11:26:04.788 25616 25700 I [                       SDL/APP] 825634.23 frames per second
11:26:04.789 25616 25616 I [                   SurfaceView] 170029209 surfaceRedrawNeeded
11:26:04.789 25616 25616 I [                   SurfaceView] 170029209 finishedDrawing
11:26:04.789 25616 25616 V [                   SurfaceView] Layout: x=0 y=84 w=1080 h=2121, frame=Rect(0, 0 - 1080, 2121)
11:26:04.790 25616 25657 D [                   SurfaceView] 170029209 updateSurfacePosition RenderWorker, frameNr = 1, position = [0, 84, 1080, 2205]
                                                            surfaceSize = 1080x2121
11:26:04.810 25616 25616 V [                           SDL] onWindowFocusChanged(): true
11:26:04.810 25616 25700 V [                           SDL] nativeFocusChanged()
------------------- more than 2 seconds ------------------------

MoNTE48 pushed a commit to MoNTE48/SDL that referenced this pull request Jun 12, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@icculus icculus changed the title Android: add command mecanism so that SDLActivity Android: add command mechanism so that SDLActivity Jun 16, 2026
@slouken slouken modified the milestones: 3.6.0, 3.8.0 Jun 16, 2026
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 21, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 2af682d to 1fc9ffb Compare June 21, 2026 18:24
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 21, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)

fix build
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 1fc9ffb to a7a37a8 Compare June 21, 2026 18:33
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 21, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)

fix build

fix build
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from a7a37a8 to fa6f0ce Compare June 21, 2026 18:35
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 22, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from fa6f0ce to 99109f5 Compare June 22, 2026 13:01
@1bsyl

1bsyl commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

rebase to latest with merges, no changes

@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 99109f5 to 392d947 Compare June 26, 2026 19:41
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 26, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jun 26, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from 392d947 to a0f4da7 Compare June 26, 2026 19:45
@1bsyl

1bsyl commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

updated to latest, manual merge with Android: decouple video/audio subsystems from JNI initialization #15199

1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jul 3, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from a0f4da7 to b9ffb7c Compare July 3, 2026 19:56
@1bsyl

1bsyl commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

updated to latest, manual merge with Android: decouple JNI setup from unused subsystems #15895

1bsyl added a commit to 1bsyl/SDL that referenced this pull request Jul 11, 2026
- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
@1bsyl
1bsyl force-pushed the br_android_RPC_v2 branch from b9ffb7c to 6267b81 Compare July 11, 2026 08:50
@1bsyl

1bsyl commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

updated to latest, manual merge with: for 'pinch end' events on mobile devices, send dummy value -1 for (focus|span)(x|y)_ 46dcc0c

lxgz12345 added a commit to lxgz12345/SDL that referenced this pull request Jul 15, 2026
Brings in upstream libsdl-org#14962 (br_android_RPC_v2, commit 6267b81):
reworks SDLActivity so most internal state (window/surface lifecycle,
events, gamepad) is serialized through the SDL main C thread via an
RPC command mechanism instead of being raced directly from the Java UI
thread. Suggested by contributor 1bsyl on our issue libsdl-org#15985 as a more
complete fix for the background/foreground native_window race than our
single NULL-check patch (50276aa) alone.

Merges cleanly with the ~617 commits upstream/main gained since we last
synced (at dd6d49a) - no conflicts, only src/video/android/SDL_androidvulkan.c
needed auto-merging (our null-check patch, present on both sides, collapsed
to a single copy as expected).

On-device testing (logcat2.log, 07-15 13:54, OnePlus PLR110): 4 full
background/foreground cycles, 0 crashes. Two cycles hit the transient
'Android native window is not currently available' retry path (expected
under the race) and recovered gracefully without getting stuck, unlike
prior logcat1.log session where the same message preceded the app being
force-killed. Considered a significant improvement over 50276aa alone.
@1bsyl

1bsyl commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

update to latest, manual merge with: Clear SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER when ANativeWindow is freed (#16024) 8319d69

- now SDLActivity defers most of SDL code internal execution to the Main thread.
  Since all code is now in Main thread, this prevents any race conditions within SDL code.

- WatchEvents, including user ones, are now exected in SDL Main C thread
  This prevents race conditions that a user could add.

- Simplify the locking/mutex internals between SDLActivity and Main.
  SDLActivity native code / synchronization is reduced to the minimum
  and fastest.

- ordering between pause/resume and java surface create/changed/destroyed is kept.
  (prevent to do a "resume" before java surface isn't set up)

- Fixed bug libsdl-org#11324 - Android opengles2: First SDL_RenderPresent() broken after resize
  Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized )

NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c
so that the code that sends gamepad events is moved to main SDLThread

(see libsdl-org#14925, libsdl-org#14962)
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.

6 participants