diff --git a/engine/platform/android/android_nosdl.c b/engine/platform/android/android_nosdl.c index ba430478..c226b45b 100644 --- a/engine/platform/android/android_nosdl.c +++ b/engine/platform/android/android_nosdl.c @@ -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 diff --git a/engine/platform/android/android_priv.h b/engine/platform/android/android_priv.h index 3af27197..e7776e4b 100644 --- a/engine/platform/android/android_priv.h +++ b/engine/platform/android/android_priv.h @@ -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 diff --git a/engine/platform/android/eglutil.c b/engine/platform/android/eglutil.c index 1f276af7..17c43351 100644 --- a/engine/platform/android/eglutil.c +++ b/engine/platform/android/eglutil.c @@ -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; } diff --git a/engine/platform/android/eglutil.h b/engine/platform/android/eglutil.h index 35268d08..ce30bfa3 100644 --- a/engine/platform/android/eglutil.h +++ b/engine/platform/android/eglutil.h @@ -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 ); diff --git a/engine/platform/android/vid_android.c b/engine/platform/android/vid_android.c index 374684a7..21b88562 100644 --- a/engine/platform/android/vid_android.c +++ b/engine/platform/android/vid_android.c @@ -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; }