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.getGLAttribute = (*env)->GetStaticMethodID(env, jni.actcls, "getGLAttribute", "(I)I");
|
||||||
jni.deleteGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "deleteGLContext", "()Z");
|
jni.deleteGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "deleteGLContext", "()Z");
|
||||||
jni.getSelectedPixelFormat = (*env)->GetStaticMethodID(env, jni.actcls, "getSelectedPixelFormat", "()I");
|
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. */
|
/* Run the application. */
|
||||||
|
|
||||||
@ -810,12 +810,12 @@ void Platform_PreCreateMove( void )
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
========================
|
========================
|
||||||
Android_RunEvents
|
Android_ProcessEvents
|
||||||
|
|
||||||
Execute all events from queue
|
Execute all events from queue
|
||||||
========================
|
========================
|
||||||
*/
|
*/
|
||||||
void Platform_RunEvents( void )
|
static void Android_ProcessEvents( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -859,7 +859,7 @@ void Platform_RunEvents( void )
|
|||||||
{
|
{
|
||||||
SNDDMA_Activate( true );
|
SNDDMA_Activate( true );
|
||||||
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
|
// (*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
|
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
|
||||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||||
}
|
}
|
||||||
@ -867,7 +867,7 @@ void Platform_RunEvents( void )
|
|||||||
if( events.queue[i].arg )
|
if( events.queue[i].arg )
|
||||||
{
|
{
|
||||||
SNDDMA_Activate( false );
|
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.toggleEGL, 0 );
|
||||||
}
|
}
|
||||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
|
(*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, 0 );
|
||||||
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
|
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
|
||||||
Con_DPrintf("resize event\n");
|
Con_DPrintf("resize event\n");
|
||||||
Android_UpdateSurface( false );
|
Android_UpdateSurface( surface_pause );
|
||||||
Android_UpdateSurface( true );
|
Android_UpdateSurface( surface_active );
|
||||||
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
|
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
|
||||||
VID_SetMode();
|
VID_SetMode();
|
||||||
}
|
}
|
||||||
else
|
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;
|
break;
|
||||||
case event_joyadd:
|
case event_joyadd:
|
||||||
@ -939,14 +939,14 @@ void Platform_RunEvents( void )
|
|||||||
#endif
|
#endif
|
||||||
// disable sound during call/screen-off
|
// disable sound during call/screen-off
|
||||||
SNDDMA_Activate( false );
|
SNDDMA_Activate( false );
|
||||||
host.status = HOST_SLEEP;
|
//host.status = HOST_SLEEP;
|
||||||
// stop blocking UI thread
|
// stop blocking UI thread
|
||||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case event_onresume:
|
case event_onresume:
|
||||||
// re-enable sound after onPause
|
// re-enable sound after onPause
|
||||||
host.status = HOST_FRAME;
|
//host.status = HOST_FRAME;
|
||||||
SNDDMA_Activate( true );
|
SNDDMA_Activate( true );
|
||||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||||
break;
|
break;
|
||||||
@ -995,4 +995,16 @@ void Platform_RunEvents( void )
|
|||||||
pthread_mutex_lock( &events.framemutex );
|
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
|
#endif // XASH_DEDICATED
|
||||||
|
@ -32,6 +32,14 @@ extern struct jnimethods_s
|
|||||||
int width, height;
|
int width, height;
|
||||||
} jni;
|
} jni;
|
||||||
|
|
||||||
|
typedef enum surfacestate_e
|
||||||
|
{
|
||||||
|
surface_pause,
|
||||||
|
surface_active,
|
||||||
|
surface_dummy,
|
||||||
|
|
||||||
|
} surfacestate_t;
|
||||||
|
|
||||||
|
|
||||||
extern struct jnimouse_s
|
extern struct jnimouse_s
|
||||||
{
|
{
|
||||||
@ -41,6 +49,6 @@ extern struct jnimouse_s
|
|||||||
//
|
//
|
||||||
// vid_android.c
|
// vid_android.c
|
||||||
//
|
//
|
||||||
void Android_UpdateSurface( qboolean active );
|
void Android_UpdateSurface( surfacestate_t state );
|
||||||
|
|
||||||
#endif // ANDROID_PRIV_H
|
#endif // ANDROID_PRIV_H
|
||||||
|
@ -236,18 +236,39 @@ destroy old surface, recreate and make context current
|
|||||||
must be called with valid context
|
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 );
|
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||||
host.status = HOST_SLEEP;
|
host.status = HOST_SLEEP;
|
||||||
|
|
||||||
if( eglstate.surface )
|
if( eglstate.surface )
|
||||||
|
{
|
||||||
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||||
|
eglstate.surface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
if( !window )
|
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 )
|
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() );
|
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Con_DPrintf( S_NOTE "restored current context\n" );
|
Con_DPrintf( S_NOTE "restored current context\n" );
|
||||||
host.status = HOST_FRAME;
|
if( !dummy)
|
||||||
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -321,6 +344,11 @@ qboolean EGL_CreateContext( void )
|
|||||||
eglstate.valid = true;
|
eglstate.valid = true;
|
||||||
eglstate.imported = false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ extern struct eglstate_s
|
|||||||
EGLContext context;
|
EGLContext context;
|
||||||
EGLConfig cfg;
|
EGLConfig cfg;
|
||||||
EGLint numCfg;
|
EGLint numCfg;
|
||||||
|
qboolean support_surfaceless_context;
|
||||||
|
|
||||||
const char *extensions;
|
const char *extensions;
|
||||||
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
|
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
|
||||||
@ -49,7 +50,7 @@ void * EGL_GetProcAddress( const char *name );
|
|||||||
void EGL_Terminate( void );
|
void EGL_Terminate( void );
|
||||||
qboolean EGL_ImportContext( void );
|
qboolean EGL_ImportContext( void );
|
||||||
qboolean EGL_CreateContext( void );
|
qboolean EGL_CreateContext( void );
|
||||||
qboolean EGL_UpdateSurface( void *window );
|
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
|
||||||
int EGL_GetAttribute( int attr, int *val );
|
int EGL_GetAttribute( int attr, int *val );
|
||||||
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
|
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
|
||||||
size_t EGL_GenerateConfig( 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
|
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;
|
vid_android.nativeegl = false;
|
||||||
Con_Printf("1\n");
|
qboolean active = state == surface_active;
|
||||||
if( glw_state.software || ( eglstate.valid && !eglstate.imported ) )
|
|
||||||
|
if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
|
||||||
{
|
{
|
||||||
Con_Printf("2\n");
|
if( vid_android.window )
|
||||||
if( vid_android.window && !active )
|
|
||||||
{
|
{
|
||||||
|
EGL_UpdateSurface( NULL, false );
|
||||||
nw.release( vid_android.window );
|
nw.release( vid_android.window );
|
||||||
vid_android.window = NULL;
|
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;
|
EGLint format = WINDOW_FORMAT_RGB_565;
|
||||||
jobject surf;
|
jobject surf;
|
||||||
if( vid_android.window )
|
if( vid_android.window )
|
||||||
nw.release( 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);
|
Con_DPrintf("Surface handle %p\n", surf);
|
||||||
vid_android.window = nw.fromSurface(jni.env, surf);
|
if( surf )
|
||||||
Con_DPrintf("NativeWindow %p\n", vid_android.window);
|
{
|
||||||
|
vid_android.window = nw.fromSurface(jni.env, surf);
|
||||||
|
Con_DPrintf("NativeWindow %p\n", vid_android.window);
|
||||||
|
|
||||||
if( eglstate.valid )
|
if( eglstate.valid )
|
||||||
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
|
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;
|
vid_android.nativeegl = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Con_Printf("3\n");
|
|
||||||
if( !vid_android.has_context )
|
if( !vid_android.has_context )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//if( ( active && host.status == HOST_FRAME ) || !active )
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, (int)state );
|
||||||
if( !active )
|
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: check opengl context here and set HOST_SLEEP if not
|
// 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 )
|
if( glw_state.software )
|
||||||
{
|
{
|
||||||
uint arg;
|
uint arg;
|
||||||
// Con_Reportf( S_ERROR "Native software mode isn't supported on Android yet! :(\n" );
|
|
||||||
// return false;
|
if( !nw.release )
|
||||||
Android_UpdateSurface( true );
|
{
|
||||||
|
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 ) )
|
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -339,7 +343,7 @@ qboolean VID_SetMode( void )
|
|||||||
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
|
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
|
||||||
|
|
||||||
if( vid_android.has_context )
|
if( vid_android.has_context )
|
||||||
Android_UpdateSurface( true );
|
Android_UpdateSurface( surface_active );
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user