engine: platform: android: remake video backend to use EGL through Java code

This commit is contained in:
Alibek Omarov 2019-12-01 23:51:48 +03:00
parent 077bc7323c
commit 8399107826
3 changed files with 140 additions and 124 deletions

View File

@ -246,7 +246,7 @@ DECLARE_JNI_INTERFACE( int, nativeInit, jobject array )
/* Init callbacks. */ /* Init callbacks. */
jni.env = env; jni.env = env;
jni.actcls = (*env)->FindClass(env, "in/celest/xash3d/XashActivity"); jni.actcls = (*env)->FindClass(env, "su/xash/engine/XashActivity");
jni.enableTextInput = (*env)->GetStaticMethodID(env, jni.actcls, "showKeyboard", "(I)V"); jni.enableTextInput = (*env)->GetStaticMethodID(env, jni.actcls, "showKeyboard", "(I)V");
jni.vibrate = (*env)->GetStaticMethodID(env, jni.actcls, "vibrate", "(I)V" ); jni.vibrate = (*env)->GetStaticMethodID(env, jni.actcls, "vibrate", "(I)V" );
jni.messageBox = (*env)->GetStaticMethodID(env, jni.actcls, "messageBox", "(Ljava/lang/String;Ljava/lang/String;)V"); jni.messageBox = (*env)->GetStaticMethodID(env, jni.actcls, "messageBox", "(Ljava/lang/String;Ljava/lang/String;)V");
@ -259,6 +259,13 @@ DECLARE_JNI_INTERFACE( int, nativeInit, jobject array )
jni.showMouse = (*env)->GetStaticMethodID(env, jni.actcls, "showMouse", "(I)V"); jni.showMouse = (*env)->GetStaticMethodID(env, jni.actcls, "showMouse", "(I)V");
jni.shellExecute = (*env)->GetStaticMethodID(env, jni.actcls, "shellExecute", "(Ljava/lang/String;)V"); jni.shellExecute = (*env)->GetStaticMethodID(env, jni.actcls, "shellExecute", "(Ljava/lang/String;)V");
jni.swapBuffers = (*env)->GetStaticMethodID(env, jni.actcls, "swapBuffers", "()V");
jni.toggleEGL = (*env)->GetStaticMethodID(env, jni.actcls, "toggleEGL", "(I)V");
jni.createGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "createGLContext", "([I[I)Z");
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");
/* Run the application. */ /* Run the application. */
status = Host_Main( argc, argv, getenv("XASH3D_GAMEDIR"), false, NULL ); status = Host_Main( argc, argv, getenv("XASH3D_GAMEDIR"), false, NULL );
@ -844,8 +851,8 @@ void Platform_RunEvents( void )
{ {
host.status = HOST_FRAME; host.status = HOST_FRAME;
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(); Android_UpdateSurface();
SetBits( gl_vsync->flags, FCVAR_CHANGED ); // set swap interval SetBits( gl_vsync->flags, FCVAR_CHANGED ); // set swap interval
host.force_draw_version = true; host.force_draw_version = true;
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME; host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
@ -855,18 +862,18 @@ void Platform_RunEvents( void )
{ {
host.status = HOST_NOFOCUS; host.status = HOST_NOFOCUS;
SNDDMA_Activate( false ); SNDDMA_Activate( false );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 ); (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
// negl.valid = false; negl.valid = false;
} }
break; break;
case event_resize: case event_resize:
// reinitialize EGL and change engine screen size // reinitialize EGL and change engine screen size
if( host.status == HOST_NORMAL && ( refState.width != jni.width || refState.height != jni.height ) ) if( host.status == HOST_FRAME &&( refState.width != jni.width || refState.height != jni.height ) )
{ {
// (*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 );
// Android_UpdateSurface(); Android_UpdateSurface();
SetBits( gl_vsync->flags, FCVAR_CHANGED ); // set swap interval SetBits( gl_vsync->flags, FCVAR_CHANGED ); // set swap interval
VID_SetMode(); VID_SetMode();
} }

View File

@ -23,6 +23,12 @@ extern struct jnimethods_s
jmethodID loadID; jmethodID loadID;
jmethodID showMouse; jmethodID showMouse;
jmethodID shellExecute; jmethodID shellExecute;
jmethodID swapBuffers;
jmethodID toggleEGL;
jmethodID createGLContext;
jmethodID getGLAttribute;
jmethodID deleteGLContext;
jmethodID getSelectedPixelFormat;
int width, height; int width, height;
} jni; } jni;

View File

@ -1,5 +1,4 @@
#include "platform/platform.h" #include "platform/platform.h"
#if XASH_VIDEO == VIDEO_ANDROID
#include "input.h" #include "input.h"
#include "client.h" #include "client.h"
#include "filesystem.h" #include "filesystem.h"
@ -21,7 +20,8 @@ Android_SwapInterval
*/ */
static void Android_SwapInterval( int interval ) static void Android_SwapInterval( int interval )
{ {
eglSwapInterval( negl.dpy, interval ); if( negl.valid )
eglSwapInterval( negl.dpy, interval );
} }
/* /*
@ -65,7 +65,68 @@ Update screen. Use native EGL if possible
*/ */
void GL_SwapBuffers( void ) void GL_SwapBuffers( void )
{ {
eglSwapBuffers( negl.dpy, negl.surface ); if( negl.valid )
{
eglSwapBuffers( negl.dpy, negl.surface );
}
else
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.swapBuffers );
}
}
/*
========================
Android_UpdateSurface
Check if we may use native EGL without jni calls
========================
*/
void Android_UpdateSurface( void )
{
negl.valid = false;
if( !Sys_CheckParm("-nativeegl") )
return; // enabled by user
negl.dpy = eglGetCurrentDisplay();
if( negl.dpy == EGL_NO_DISPLAY )
return;
negl.surface = eglGetCurrentSurface(EGL_DRAW);
if( negl.surface == EGL_NO_SURFACE )
return;
// now check if swapBuffers does not give error
if( eglSwapBuffers( negl.dpy, negl.surface ) == EGL_FALSE )
return;
// double check
if( eglGetError() != EGL_SUCCESS )
return;
__android_log_print( ANDROID_LOG_VERBOSE, "Xash", "native EGL enabled" );
negl.valid = true;
}
/*
========================
Android_GetGLAttribute
========================
*/
static int Android_GetGLAttribute( int eglAttr )
{
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.actcls, jni.getGLAttribute, eglAttr );
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
return ret;
}
int Android_GetSelectedPixelFormat( void )
{
return (*jni.env)->CallStaticIntMethod( jni.env, jni.actcls, jni.getSelectedPixelFormat );
} }
qboolean R_Init_Video( const int type ) qboolean R_Init_Video( const int type )
@ -73,6 +134,19 @@ qboolean R_Init_Video( const int type )
string safe; string safe;
qboolean retval; qboolean retval;
switch( Android_GetSelectedPixelFormat() )
{
case 1:
refState.desktopBitsPixel = 16;
break;
case 2:
refState.desktopBitsPixel = 8;
break;
default:
refState.desktopBitsPixel = 32;
break;
}
memset( gl_attribs, 0, sizeof( gl_attribs )); memset( gl_attribs, 0, sizeof( gl_attribs ));
memset( gl_attribs_set, 0, sizeof( gl_attribs_set )); memset( gl_attribs_set, 0, sizeof( gl_attribs_set ));
@ -138,13 +212,7 @@ qboolean R_Init_Video( const int type )
void R_Free_Video( void ) void R_Free_Video( void )
{ {
eglMakeCurrent(negl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); // (*jni.env)->CallStaticBooleanMethod( jni.env, jni.actcls, jni.deleteGLContext );
eglDestroyContext(negl.dpy, negl.context);
eglDestroySurface(negl.dpy, negl.surface);
eglTerminate(negl.dpy);
// VID_DestroyWindow (); // VID_DestroyWindow ();
@ -160,12 +228,10 @@ void R_Free_Video( void )
attribs[i++] = gl_attribs[refattr]; \ attribs[i++] = gl_attribs[refattr]; \
} }
static const EGLint *VID_GenerateConfig( void ) static size_t VID_GenerateConfig( EGLint *attribs, size_t size )
{ {
int i = 0; size_t i = 0;
static EGLint attribs[32 + 1]; memset( attribs, 0, size * sizeof( EGLint ) );
memset( attribs, 0, sizeof( attribs ));
COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE ); COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE );
COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE ); COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE );
@ -202,19 +268,18 @@ static const EGLint *VID_GenerateConfig( void )
attribs[i++] = EGL_OPENGL_ES_BIT; attribs[i++] = EGL_OPENGL_ES_BIT;
} }
attribs[i] = EGL_NONE; attribs[i++] = EGL_NONE;
return attribs; return i;
} }
static const EGLint *VID_GenerateContextConfig( void ) static size_t VID_GenerateContextConfig( EGLint *attribs, size_t size )
{ {
int i = 0; size_t i = 0;
static EGLint attribs[32 + 1];
memset( attribs, 0, sizeof( attribs )); memset( attribs, 0, size * sizeof( EGLint ));
if( Q_strcmp( negl.extensions, " EGL_KHR_create_context ") ) /*if( Q_strcmp( negl.extensions, " EGL_KHR_create_context ") )
{ {
if( gl_attribs_set[REF_GL_CONTEXT_FLAGS] ) if( gl_attribs_set[REF_GL_CONTEXT_FLAGS] )
{ {
@ -236,93 +301,36 @@ static const EGLint *VID_GenerateContextConfig( void )
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB ); COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB );
} }
else else*/
{ {
// without extension we can set only major version // without extension we can set only major version
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
} }
attribs[i++] = EGL_NONE;
attribs[i] = EGL_NONE; return i;
return attribs;
} }
qboolean VID_SetMode( void ) qboolean VID_SetMode( void )
{ {
EGLint format; EGLint format;
const EGLint *attribs = VID_GenerateConfig(); jintArray attribs, contextAttribs;
const EGLint *contextAttribs = VID_GenerateContextConfig(); static EGLint nAttribs[32+1], nContextAttribs[32+1];
const size_t attribsSize = ARRAYSIZE( nAttribs );
size_t s1 = VID_GenerateConfig(nAttribs, attribsSize);
size_t s2 = VID_GenerateContextConfig(nContextAttribs, attribsSize);
attribs = (*jni.env)->NewIntArray( jni.env, s1 );
contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 );
(*jni.env)->SetIntArrayRegion( jni.env, attribs, 0, s1, nAttribs );
(*jni.env)->SetIntArrayRegion( jni.env, contextAttribs, 0, s2, nContextAttribs );
R_ChangeDisplaySettings( 0, 0, false ); // width and height are ignored anyway R_ChangeDisplaySettings( 0, 0, false ); // width and height are ignored anyway
negl.valid = false; return (*jni.env)->CallStaticBooleanMethod( jni.env, jni.actcls, jni.createGLContext, attribs, contextAttribs );
if( ( negl.dpy = eglGetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY )
{
Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", eglGetError() );
return false;
}
if( !eglInitialize( negl.dpy, NULL, NULL ))
{
Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", eglGetError() );
return false;
}
if( !(negl.extensions = eglQueryString( negl.dpy, EGL_EXTENSIONS ) ) )
{
Con_Reportf( S_ERROR "eglQueryString(EGL_EXTENSIONS) returned error: 0x%x\n", eglGetError() );
return false;
}
if( !eglChooseConfig( negl.dpy, attribs, &negl.cfg, 1, &negl.numCfg ))
{
Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", eglGetError() );
return false;
}
if( !eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_NATIVE_VISUAL_ID, &format) )
{
Con_Reportf( S_ERROR "eglGetConfigAttrib returned error: 0x%x\n", eglGetError() );
return false;
}
if( ANativeWindow_setBuffersGeometry( negl.window, 0, 0, format ) )
{
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
return false;
}
if(( negl.surface = eglCreateWindowSurface( negl.dpy, negl.cfg, negl.window, NULL )) == EGL_NO_SURFACE )
{
Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", eglGetError() );
return false;
}
if(( negl.context = eglCreateContext( negl.dpy, negl.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT )
{
Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", eglGetError() );
return false;
}
if( !eglMakeCurrent( negl.dpy, negl.surface, negl.surface, negl.context ))
{
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", eglGetError() );
return false;
}
if( !eglBindAPI( gl_api ))
{
Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", eglGetError() );
return false;
}
__android_log_print( ANDROID_LOG_VERBOSE, "Xash", "native EGL enabled" );
negl.valid = true;
return true;
} }
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen ) rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
@ -385,32 +393,29 @@ int GL_GetAttribute( int attr, int *val )
switch( attr ) switch( attr )
{ {
case REF_GL_RED_SIZE: case REF_GL_RED_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_RED_SIZE, val ); *val = Android_GetGLAttribute( EGL_RED_SIZE );
break; return 0;
case REF_GL_GREEN_SIZE: case REF_GL_GREEN_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_GREEN_SIZE, val ); *val = Android_GetGLAttribute( EGL_GREEN_SIZE );
break; return 0;
case REF_GL_BLUE_SIZE: case REF_GL_BLUE_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_BLUE_SIZE, val ); *val = Android_GetGLAttribute( EGL_BLUE_SIZE );
break; return 0;
case REF_GL_ALPHA_SIZE: case REF_GL_ALPHA_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_ALPHA_SIZE, val ); *val = Android_GetGLAttribute( EGL_ALPHA_SIZE );
break; return 0;
case REF_GL_DEPTH_SIZE: case REF_GL_DEPTH_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_DEPTH_SIZE, val ); *val = Android_GetGLAttribute( EGL_DEPTH_SIZE );
break; return 0;
case REF_GL_STENCIL_SIZE: case REF_GL_STENCIL_SIZE:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_STENCIL_SIZE, val ); *val = Android_GetGLAttribute( EGL_STENCIL_SIZE );
break; return 0;
case REF_GL_MULTISAMPLESAMPLES: case REF_GL_MULTISAMPLESAMPLES:
ret = eglGetConfigAttrib( negl.dpy, negl.cfg, EGL_SAMPLES, val ); *val = Android_GetGLAttribute( EGL_SAMPLES );
break; return 0;
} }
if( !ret ) return -1;
return -1;
return 0;
} }
int R_MaxVideoModes( void ) int R_MaxVideoModes( void )
@ -457,5 +462,3 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
{ {
return false; return false;
} }
#endif