mirror of
https://github.com/FWGS/xash3d-fwgs
synced 2024-11-25 11:19:59 +01:00
platform/android: prevent rendering without context, fix android_sleep using surfaceless mode or dummy surface if possible
This commit is contained in:
parent
61d39e7253
commit
0cd45dbbad
@ -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. */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -859,7 +859,7 @@ 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;
|
||||
}
|
||||
@ -867,7 +867,7 @@ void Platform_RunEvents( void )
|
||||
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 );
|
||||
@ -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:
|
||||
@ -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;
|
||||
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
@ -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
|
||||
|
@ -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 )
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
@ -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 );
|
||||
|
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user