Skip to content

Commit

Permalink
platform/android: prevent rendering without context, fix android_slee…
Browse files Browse the repository at this point in the history
…p using surfaceless mode or dummy surface if possible
  • Loading branch information
mittorn committed Oct 30, 2023
1 parent 11a38a4 commit 253eb25
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 50 deletions.
32 changes: 22 additions & 10 deletions engine/platform/android/android_nosdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ DECLARE_JNI_INTERFACE( int, nativeInit, jobject array )
jni.getGLAttribute = (*env)->GetStaticMethodID(env, jni.actcls, "getGLAttribute", "(I)I");
jni.deleteGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "deleteGLContext", "()Z");
jni.getSelectedPixelFormat = (*env)->GetStaticMethodID(env, jni.actcls, "getSelectedPixelFormat", "()I");
jni.getSurface = (*env)->GetStaticMethodID(env, jni.actcls, "getNativeSurface", "()Landroid/view/Surface;");
jni.getSurface = (*env)->GetStaticMethodID(env, jni.actcls, "getNativeSurface", "(I)Landroid/view/Surface;");

/* Run the application. */

Expand Down Expand Up @@ -810,12 +810,12 @@ void Platform_PreCreateMove( void )

/*
========================
Android_RunEvents
Android_ProcessEvents
Execute all events from queue
========================
*/
void Platform_RunEvents( void )
static void Android_ProcessEvents( void )
{
int i;

Expand Down Expand Up @@ -859,15 +859,15 @@ void Platform_RunEvents( void )
{
SNDDMA_Activate( true );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
Android_UpdateSurface( true );
Android_UpdateSurface( surface_active );
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
}

if( events.queue[i].arg )
{
SNDDMA_Activate( false );
Android_UpdateSurface( false );
Android_UpdateSurface( !android_sleep->value ? surface_dummy : surface_pause );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
}
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
Expand All @@ -880,14 +880,14 @@ void Platform_RunEvents( void )
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
Con_DPrintf("resize event\n");
Android_UpdateSurface( false );
Android_UpdateSurface( true );
Android_UpdateSurface( surface_pause );
Android_UpdateSurface( surface_active );
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
VID_SetMode();
}
else
{
Con_DPrintf("resize skip %d %d %d %d %d", jni.width, jni.height, refState.width, refState.height, host.status );
Con_DPrintf("resize skip %d %d %d %d %d\n", jni.width, jni.height, refState.width, refState.height, host.status );
}
break;
case event_joyadd:
Expand Down Expand Up @@ -939,14 +939,14 @@ void Platform_RunEvents( void )
#endif
// disable sound during call/screen-off
SNDDMA_Activate( false );
host.status = HOST_SLEEP;
//host.status = HOST_SLEEP;
// stop blocking UI thread
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );

break;
case event_onresume:
// re-enable sound after onPause
host.status = HOST_FRAME;
//host.status = HOST_FRAME;
SNDDMA_Activate( true );
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
break;
Expand Down Expand Up @@ -995,4 +995,16 @@ void Platform_RunEvents( void )
pthread_mutex_lock( &events.framemutex );
}

void Platform_RunEvents( void )
{
Android_ProcessEvents();

// do not allow running frames while android_sleep is 1, but surface/context not restored
while( android_sleep->value && host.status == HOST_SLEEP )
{
usleep( 20000 );
Android_ProcessEvents();
}
}

#endif // XASH_DEDICATED
10 changes: 9 additions & 1 deletion engine/platform/android/android_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ extern struct jnimethods_s
int width, height;
} jni;

typedef enum surfacestate_e
{
surface_pause,
surface_active,
surface_dummy,

} surfacestate_t;


extern struct jnimouse_s
{
Expand All @@ -41,6 +49,6 @@ extern struct jnimouse_s
//
// vid_android.c
//
void Android_UpdateSurface( qboolean active );
void Android_UpdateSurface( surfacestate_t state );

#endif // ANDROID_PRIV_H
36 changes: 32 additions & 4 deletions engine/platform/android/eglutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,39 @@ destroy old surface, recreate and make context current
must be called with valid context
=========================
*/
qboolean EGL_UpdateSurface( void *window )
qboolean EGL_UpdateSurface( void *window, qboolean dummy )
{
if( !eglstate.valid )
return false;

egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
host.status = HOST_SLEEP;

if( eglstate.surface )
{
egl.DestroySurface( eglstate.dpy, eglstate.surface );
eglstate.surface = EGL_NO_SURFACE;
}

if( !window )
{
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
return false;

if( dummy && eglstate.support_surfaceless_context )
{
if( egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglstate.context ))
{
Con_Reportf( S_NOTE "EGL_UpdateSurface: using surfaceless mode\n" );
return true;
}
else
{
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
eglstate.support_surfaceless_context = false;
}
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
}

return false; // let platform fallback to dummy surface or pause engine
}

if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE )
Expand All @@ -261,8 +282,10 @@ qboolean EGL_UpdateSurface( void *window )
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
return false;
}

Con_DPrintf( S_NOTE "restored current context\n" );
host.status = HOST_FRAME;
if( !dummy)
host.status = HOST_FRAME;

return true;

Expand Down Expand Up @@ -321,6 +344,11 @@ qboolean EGL_CreateContext( void )
eglstate.valid = true;
eglstate.imported = false;

// now check if it's safe to use surfaceless context here without surface fallback
if( eglstate.extensions && Q_strstr( eglstate.extensions, "EGL_KHR_surfaceless_context" ))
eglstate.support_surfaceless_context = true;


return true;
}

Expand Down
3 changes: 2 additions & 1 deletion engine/platform/android/eglutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern struct eglstate_s
EGLContext context;
EGLConfig cfg;
EGLint numCfg;
qboolean support_surfaceless_context;

const char *extensions;
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
Expand Down Expand Up @@ -49,7 +50,7 @@ void * EGL_GetProcAddress( const char *name );
void EGL_Terminate( void );
qboolean EGL_ImportContext( void );
qboolean EGL_CreateContext( void );
qboolean EGL_UpdateSurface( void *window );
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
int EGL_GetAttribute( int attr, int *val );
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
size_t EGL_GenerateConfig( EGLint *attribs, size_t size );
Expand Down
72 changes: 38 additions & 34 deletions engine/platform/android/vid_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,63 +119,63 @@ Android_UpdateSurface
Check if we may use native EGL without jni calls
========================
*/
void Android_UpdateSurface( qboolean active )
void Android_UpdateSurface( surfacestate_t state )
{
vid_android.nativeegl = false;
Con_Printf("1\n");
if( glw_state.software || ( eglstate.valid && !eglstate.imported ) )
qboolean active = state == surface_active;

if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
{
Con_Printf("2\n");
if( vid_android.window && !active )
if( vid_android.window )
{
EGL_UpdateSurface( NULL, false );
nw.release( vid_android.window );
vid_android.window = NULL;
}
if( state == surface_dummy && glw_state.software )
return;
// first, ask EGL for surfaceless mode
if( state == surface_dummy && EGL_UpdateSurface( NULL, true ))
{
vid_android.nativeegl = true;
return;
}

if( active )
if( state != surface_pause )
{
EGLint format = WINDOW_FORMAT_RGB_565;
jobject surf;
if( vid_android.window )
nw.release( vid_android.window );
surf = (*jni.env)->CallStaticObjectMethod(jni.env, jni.actcls, jni.getSurface);
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.actcls, jni.getSurface, state );
Con_DPrintf("Surface handle %p\n", surf);
vid_android.window = nw.fromSurface(jni.env, surf);
Con_DPrintf("NativeWindow %p\n", vid_android.window);
if( surf )
{
vid_android.window = nw.fromSurface(jni.env, surf);
Con_DPrintf("NativeWindow %p\n", vid_android.window);

if( eglstate.valid )
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
if( eglstate.valid )
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );

nw.setBuffersGeometry(vid_android.window, 0, 0, format );
nw.setBuffersGeometry(vid_android.window, 0, 0, format );

(*jni.env)->DeleteLocalRef( jni.env, surf );
(*jni.env)->DeleteLocalRef( jni.env, surf );
}
}

if( Sys_CheckParm( "-egl" ))
if( eglstate.valid && !eglstate.imported )
{
EGL_UpdateSurface( vid_android.window );
EGL_UpdateSurface( vid_android.window, state == surface_dummy );
vid_android.nativeegl = true;
}
return;
}
Con_Printf("3\n");

if( !vid_android.has_context )
return;

//if( ( active && host.status == HOST_FRAME ) || !active )
if( !active )
{
Con_Printf("toggleEGL 0\n");
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
}
host.status = HOST_SLEEP;

if( active )
{
Con_Printf("toggleEGL 1\n");
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
host.status = HOST_FRAME;
}
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, (int)state );
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;

// todo: check opengl context here and set HOST_SLEEP if not

Expand Down Expand Up @@ -257,9 +257,13 @@ qboolean R_Init_Video( const int type )
if( glw_state.software )
{
uint arg;
// Con_Reportf( S_ERROR "Native software mode isn't supported on Android yet! :(\n" );
// return false;
Android_UpdateSurface( true );

if( !nw.release )
{
Con_Reportf( S_ERROR "Native software mode unavailiable\n" );
return false;
}
Android_UpdateSurface( surface_active );
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
return false;
}
Expand Down Expand Up @@ -339,7 +343,7 @@ qboolean VID_SetMode( void )
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();

if( vid_android.has_context )
Android_UpdateSurface( true );
Android_UpdateSurface( surface_active );
else
return false;
}
Expand Down

0 comments on commit 253eb25

Please sign in to comment.