Skip to content

Commit 6797c80

Browse files
committed
fix: prevent OpenGL context errors on Android by skipping progress bar rendering in worker threads
fix: handle EGL context threading issues on Android by preventing multi-thread access
1 parent 3fe8e07 commit 6797c80

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

app/src/main/jni/tuxpaint/src/debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Verbose logging adds metadata to printf, including the source file location
3434
* from where printf was called and the time it was called at runtime.
3535
*/
36-
#if defined(DEBUG) && defined(VERBOSE) && defined(__GNUC__)
36+
#if defined(DEBUG) && defined(VERBOSE) && defined(__GNUC__) && !defined(__ANDROID__)
3737
#include <stdio.h>
3838
#include <time.h>
3939

app/src/main/jni/tuxpaint/src/progressbar.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,23 @@ void show_progress_bar_(SDL_Surface *screen, SDL_Texture *texture, SDL_Renderer
4949
if (progress_bar_disabled)
5050
return;
5151

52+
#ifdef __ANDROID__
53+
/* On Android, skip all rendering operations in progress bar because:
54+
* 1. It's called from worker threads (font loading, file scanning, etc.)
55+
* 2. OpenGL/EGL contexts are thread-local and cannot be used from worker threads
56+
* 3. Even with valid renderer/texture/screen parameters, the GL context is not
57+
* current on the worker thread, causing SIGSEGV when GL functions are called
58+
*
59+
* We still allow the function to continue to update internal state like prog_bar_ctr
60+
* and oldtime, but skip all SDL rendering calls. */
61+
newtime = SDL_GetTicks();
62+
if (newtime > oldtime + 500) {
63+
prog_bar_ctr++;
64+
}
65+
oldtime = newtime;
66+
return;
67+
#endif
68+
5269
newtime = SDL_GetTicks();
5370
if (newtime > oldtime + 15) /* trying not to eat some serious CPU time! */
5471
{

app/src/main/jni/tuxpaint/src/tuxpaint.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,14 @@ static void do_wait(int counter)
23882388
SDL_Rect r;
23892389
#endif
23902390

2391+
#ifdef __ANDROID__
2392+
/* On Android, skip splash screen wait because:
2393+
* 1. Android provides its own splash screen
2394+
* 2. Touch events are not properly recognized
2395+
* 3. Users expect apps to start immediately after loading */
2396+
return;
2397+
#endif
2398+
23912399
if (bypass_splash_wait)
23922400
return;
23932401

@@ -22327,6 +22335,7 @@ static void load_magic_plugins(void)
2232722335
while (num_magics[magic_group] == 0 && tries < MAX_MAGIC_GROUPS)
2232822336
{
2232922337
magic_group++;
22338+
tries++;
2233022339
if (magic_group >= MAX_MAGIC_GROUPS)
2233122340
{
2233222341
magic_group = 0;
@@ -29786,6 +29795,16 @@ static void setup(void)
2978629795
if (!fullscreen)
2978729796
init_flags |= SDL_INIT_NOPARACHUTE; /* allow debugger to catch crash */
2978829797

29798+
/* Fix Android EGL threading issues - ensure GL context stays on render thread */
29799+
#ifdef __ANDROID__
29800+
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1");
29801+
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
29802+
SDL_SetHint(SDL_HINT_ANDROID_TRAP_BACK_BUTTON, "1");
29803+
SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, "0");
29804+
/* Prevent EGL context from being made current on multiple threads */
29805+
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
29806+
#endif
29807+
2978929808
/* Init SDL */
2979029809
if (SDL_Init(init_flags) < 0)
2979129810
{
@@ -29997,7 +30016,12 @@ static void setup(void)
2999730016

2999830017
/* FIXME: Check window_screen for being NULL, and abort?! (Also see below) -bjk 2024.12.20 */
2999930018

30019+
#ifdef __ANDROID__
30020+
/* On Android, use accelerated renderer to ensure proper GL context threading */
30021+
renderer = SDL_CreateRenderer(window_screen, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
30022+
#else
3000030023
renderer = SDL_CreateRenderer(window_screen, -1, 0);
30024+
#endif
3000130025
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
3000230026

3000330027
if (native_screensize)
@@ -30180,7 +30204,12 @@ static void setup(void)
3018030204
SDL_SetWindowMaximumSize(window_screen, WINDOW_WIDTH, WINDOW_HEIGHT);
3018130205

3018230206

30207+
#ifdef __ANDROID__
30208+
/* On Android, use accelerated renderer to ensure proper GL context threading */
30209+
renderer = SDL_CreateRenderer(window_screen, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
30210+
#else
3018330211
renderer = SDL_CreateRenderer(window_screen, -1, 0);
30212+
#endif
3018430213
SDL_GL_GetDrawableSize(window_screen, &ww, &hh);
3018530214
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STATIC, ww, hh);
3018630215

@@ -30237,6 +30266,7 @@ static void setup(void)
3023730266

3023830267
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
3023930268

30269+
#ifndef __ANDROID__
3024030270
dest.x = ((WINDOW_WIDTH - img_title->w - (img_title_tuxpaint->w / 2)) / 2) + (img_title_tuxpaint->w / 2) + 20;
3024130271
dest.y = (WINDOW_HEIGHT - img_title->h);
3024230272

@@ -30254,6 +30284,7 @@ static void setup(void)
3025430284
dest.y = 5;
3025530285

3025630286
SDL_BlitSurface(img_title_credits, NULL, screen, &dest);
30287+
#endif
3025730288

3025830289
prog_bar_ctr = 0;
3025930290
show_progress_bar(screen);
@@ -30293,6 +30324,7 @@ static void setup(void)
3029330324

3029430325
/* Let Pango & fontcache do their work without locking up */
3029530326

30327+
#ifndef __ANDROID__
3029630328
fontconfig_thread_done = 0;
3029730329

3029830330
DEBUG_PRINTF("Spawning Pango thread\n");
@@ -30318,6 +30350,11 @@ static void setup(void)
3031830350
}
3031930351
DEBUG_PRINTF("Done generating cache\n");
3032030352
}
30353+
#else
30354+
/* On Android, skip font cache generation to speed up startup */
30355+
fontconfig_thread_done = 1;
30356+
DEBUG_PRINTF("Android: Skipping fontconfig cache generation\n");
30357+
#endif
3032130358

3032230359

3032330360
#ifdef FORKED_FONTS
@@ -30343,14 +30380,17 @@ static void setup(void)
3034330380

3034430381
safe_snprintf(tmp_str, sizeof(tmp_str), "Version: %s – %s", VER_VERSION, VER_DATE);
3034530382

30383+
#ifndef __ANDROID__
3034630384
tmp_surf = render_text(medium_font, tmp_str, black);
3034730385
dest.x = 10;
3034830386
dest.y = WINDOW_HEIGHT - img_progress->h - tmp_surf->h;
3034930387
SDL_BlitSurface(tmp_surf, NULL, screen, &dest);
3035030388
SDL_FreeSurface(tmp_surf);
30389+
#endif
3035130390

3035230391
DEBUG_PRINTF("%s\n", tmp_str);
3035330392

30393+
#ifndef __ANDROID__
3035430394
safe_snprintf(tmp_str, sizeof(tmp_str), "© 2002–2024 Bill Kendrick, et al.");
3035530395
tmp_surf = render_text(medium_font, tmp_str, black);
3035630396
dest.x = 10;
@@ -30359,12 +30399,20 @@ static void setup(void)
3035930399
SDL_FreeSurface(tmp_surf);
3036030400

3036130401
SDL_Flip(screen);
30402+
#endif
3036230403

3036330404

3036430405
#ifdef FORKED_FONTS
3036530406
reliable_write(font_socket_fd, &no_system_fonts, sizeof no_system_fonts);
3036630407
#else
30408+
#ifndef __ANDROID__
3036730409
font_thread = SDL_CreateThread(load_user_fonts_stub, "font_thread", NULL);
30410+
#else
30411+
/* On Android, skip font loading thread - fonts will be loaded on demand */
30412+
DEBUG_PRINTF("Android: Skipping font loading thread\n");
30413+
font_thread_done = 1;
30414+
font_thread_aborted = 0;
30415+
#endif
3036830416
#endif
3036930417

3037030418
/* continuing on with the rest of the cursors... */
@@ -30754,8 +30802,10 @@ static void setup(void)
3075430802
for (i = 0; i < NUM_TIP_TUX; i++)
3075530803
img_tux[i] = loadimagerb(tux_img_fnames[i]);
3075630804

30805+
3075730806
show_progress_bar(screen);
3075830807

30808+
3075930809
img_mouse = loadimagerb(DATA_PREFIX "images/ui/mouse.png");
3076030810
img_mouse_click = loadimagerb(DATA_PREFIX "images/ui/mouse_click.png");
3076130811

@@ -30764,6 +30814,7 @@ static void setup(void)
3076430814
img_color_picker = loadimagerb(DATA_PREFIX "images/ui/color_picker.png");
3076530815
img_color_picker_val = loadimagerb(DATA_PREFIX "images/ui/color_picker_val.png");
3076630816

30817+
3076730818
/* Create toolbox and selector labels: */
3076830819

3076930820
for (i = 0; i < NUM_TITLES; i++)
@@ -30789,8 +30840,10 @@ static void setup(void)
3078930840

3079030841

3079130842

30843+
3079230844
/* Generate color selection buttons: */
3079330845

30846+
3079430847
/* Create appropriately-shaped buttons: */
3079530848
img1 = loadimage(DATA_PREFIX "images/ui/paintwell.png");
3079630849
img_paintwell = thumbnail(img1, color_button_w, color_button_h, 0);
@@ -31013,6 +31066,7 @@ static void claim_to_be_ready(void)
3101331066

3101431067
/* Let the user know we're (nearly) ready now */
3101531068

31069+
#ifndef __ANDROID__
3101631070
dest.x = 0;
3101731071
dest.y = WINDOW_HEIGHT - img_progress->h;
3101831072
dest.h = img_progress->h;
@@ -31024,6 +31078,7 @@ static void claim_to_be_ready(void)
3102431078
src.y = img_title->h - img_progress->h;
3102531079
dest.x = ((WINDOW_WIDTH - img_title->w - (img_title_tuxpaint->w / 2)) / 2) + (img_title_tuxpaint->w / 2) + 20;
3102631080
SDL_BlitSurface(img_title, &src, screen, &dest);
31081+
#endif
3102731082

3102831083
SDL_FreeSurface(img_title);
3102931084
SDL_FreeSurface(img_title_credits);

0 commit comments

Comments
 (0)