From 7013caa07d5062aa4f099b27e4d1c17da9ddcad6 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 26 Oct 2023 04:52:41 +0300 Subject: [PATCH] platform/android: rewrite egl part to separate not android-specific file --- engine/platform/android/android_nosdl.c | 1 + engine/platform/android/eglutil.c | 421 ++++++++++++++++++++++++ engine/platform/android/eglutil.h | 58 ++++ engine/platform/android/vid_android.c | 265 ++++----------- 4 files changed, 542 insertions(+), 203 deletions(-) create mode 100644 engine/platform/android/eglutil.c create mode 100644 engine/platform/android/eglutil.h diff --git a/engine/platform/android/android_nosdl.c b/engine/platform/android/android_nosdl.c index de26603204..95f15bdb8d 100644 --- a/engine/platform/android/android_nosdl.c +++ b/engine/platform/android/android_nosdl.c @@ -879,6 +879,7 @@ void Platform_RunEvents( void ) { // (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 ); // (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 ); + Android_UpdateSurface( false ); Android_UpdateSurface( true ); SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval VID_SetMode(); diff --git a/engine/platform/android/eglutil.c b/engine/platform/android/eglutil.c new file mode 100644 index 0000000000..c14886ab87 --- /dev/null +++ b/engine/platform/android/eglutil.c @@ -0,0 +1,421 @@ +/* +eglutil.c - EGL context utility +Copyright (C) 2023 mittorn + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "platform/platform.h" +#if !defined(XASH_DEDICATED) && !XASH_SDL +#include "eglutil.h" +#include "client.h" +#include "vid_common.h" +#include +#include + +struct eglapi_s egl; + +#undef GetProcAddress // windows.h? +#define EGL_FF(x) {"egl"#x, (void*)&egl.x} +static dllfunc_t egl_funcs[] = +{ + EGL_FF(SwapInterval), + EGL_FF(SwapBuffers), + EGL_FF(GetError), + EGL_FF(GetCurrentDisplay), + EGL_FF(GetCurrentSurface), + EGL_FF(GetProcAddress), + EGL_FF(GetConfigAttrib), + EGL_FF(GetDisplay), + EGL_FF(Initialize), + EGL_FF(Terminate), + EGL_FF(QueryString), + EGL_FF(ChooseConfig), + EGL_FF(CreateWindowSurface), + EGL_FF(CreateContext), + EGL_FF(DestroyContext), + EGL_FF(MakeCurrent), + EGL_FF(BindAPI), + EGL_FF(DestroySurface), + { NULL, NULL } +}; +#undef EGL_FF +dll_info_t egl_info = { "libEGL.so", egl_funcs, false }; + +struct eglstate_s eglstate; + + + +/* +=================== + +refapi/egl wrappers + +=================== +*/ + +int EGL_SetAttribute( int attr, int val ) +{ + if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT ) + return -1; + + eglstate.gl_attribs[attr] = val; + eglstate.gl_attribs_set[attr] = true; + return 0; +} + +#define COPY_ATTR_IF_SET( refattr, attr ) \ + if( eglstate.gl_attribs_set[refattr] ) \ + { \ + attribs[i++] = attr; \ + attribs[i++] = eglstate.gl_attribs[refattr]; \ + } + +size_t EGL_GenerateConfig( EGLint *attribs, size_t size ) +{ + size_t i = 0; + + memset( attribs, 0, size * sizeof( EGLint ) ); + eglstate.gles1 = false; + memset( eglstate.gl_attribs, 0, sizeof( eglstate.gl_attribs )); + memset( eglstate.gl_attribs_set, 0, sizeof( eglstate.gl_attribs_set )); + + // refdll can request some attributes + ref.dllFuncs.GL_SetupAttributes( glw_state.safe ); + + 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_BLUE_SIZE, EGL_BLUE_SIZE ); + COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE ); + COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE ); + COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE ); + COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS ); + COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES ); + + if( eglstate.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] ) + { + attribs[i++] = EGL_CONFIG_CAVEAT; + attribs[i++] = eglstate.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE; + } + + // BigGL support + attribs[i++] = EGL_RENDERABLE_TYPE; + eglstate.gl_api = EGL_OPENGL_ES_API; + + if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] && + !( eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES )) + { + attribs[i++] = EGL_OPENGL_BIT; + eglstate.gl_api = EGL_OPENGL_API; + } + else if( eglstate.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] && + eglstate.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 ) + { + attribs[i++] = EGL_OPENGL_ES2_BIT; + } + else + { + i--; // erase EGL_RENDERABLE_TYPE + eglstate.gles1 = true; + } + + attribs[i++] = EGL_NONE; + + return i; +} + + +size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size ) +{ + size_t i = 0; + + memset( attribs, 0, size * sizeof( EGLint )); + + if( Q_strstr( eglstate.extensions, "EGL_KHR_create_context") ) + { + Con_DPrintf( S_NOTE "EGL_KHR_create_context found, setting additional context flags\n"); + + if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] ) + { + attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR + attribs[i++] = eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1); + } + + if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] ) + { + int val = eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK]; + + if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) ) + { + attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; + attribs[i++] = val; + } + } + + COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); + COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB ); + } + else + { + // without extension we can set only major version + COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); + if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] && (eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & REF_GL_CONTEXT_DEBUG_FLAG )) + { + attribs[i++] = 0x31B0; // EGL_CONTEXT_OPENGL_DEBUG; + attribs[i++] = EGL_TRUE; + } + } + + + attribs[i++] = EGL_NONE; + + return i; +} + + + +/* +========================= +EGL_GetAttribute + +query +========================= +*/ +int EGL_GetAttribute( int attr, int *val ) +{ + EGLBoolean ret; + + if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT ) + return -1; + + if( !val ) + return -1; + + switch( attr ) + { + case REF_GL_RED_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_RED_SIZE, val ); + return 0; + case REF_GL_GREEN_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_GREEN_SIZE, val ); + return 0; + case REF_GL_BLUE_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_BLUE_SIZE, val ); + return 0; + case REF_GL_ALPHA_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_ALPHA_SIZE, val ); + return 0; + case REF_GL_DEPTH_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_DEPTH_SIZE, val ); + return 0; + case REF_GL_STENCIL_SIZE: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_STENCIL_SIZE, val ); + return 0; + case REF_GL_MULTISAMPLESAMPLES: + ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_SAMPLES, val ); + return 0; + } + + return -1; +} + + +/* +========================= +EGL_UpdateSurface + +destroy old surface, recreate and make context current +must be called with valid context +========================= +*/ +qboolean EGL_UpdateSurface( void *window ) +{ + egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + + if( eglstate.surface ) + egl.DestroySurface( eglstate.dpy, eglstate.surface ); + + if( !window ) + { + Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" ); + } + + if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE ) + { + Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", egl.GetError() ); + return false; + } + + if( !egl.MakeCurrent( eglstate.dpy, eglstate.surface, eglstate.surface, eglstate.context )) + { + Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() ); + return false; + } + + return true; + +} + + +/* +========================= +EGL_CreateContext + +query attributes for ref and create context +========================= +*/ +qboolean EGL_CreateContext( void ) +{ + EGLint attribs[32+1], contextAttribs[32+1]; + const size_t attribsSize = ARRAYSIZE( attribs ); + size_t s1, s2; + + if( !eglstate.dpy && ( eglstate.dpy = egl.GetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY ) + { + Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", egl.GetError() ); + return false; + } + + eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS ); + + s1 = EGL_GenerateConfig(attribs, attribsSize); + s2 = EGL_GenerateContextConfig(contextAttribs, attribsSize); + + + if( !egl.BindAPI( eglstate.gl_api )) + { + Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", egl.GetError() ); + return false; + } + + if( !egl.Initialize( eglstate.dpy, NULL, NULL )) + { + Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", egl.GetError() ); + return false; + } + + if( !egl.ChooseConfig( eglstate.dpy, attribs, &eglstate.cfg, 1, &eglstate.numCfg )) + { + Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", egl.GetError() ); + return false; + } + + if(( eglstate.context = egl.CreateContext( eglstate.dpy, eglstate.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT ) + { + Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", egl.GetError() ); + return false; + } + + eglstate.valid = true; + eglstate.imported = false; + + return true; +} + +/* +=========================== +EGL_ImportContext + +import current egl context to use EGL functions +=========================== +*/ +qboolean EGL_ImportContext( void ) +{ + if( !egl.GetCurrentDisplay ) + return false; + + eglstate.dpy = egl.GetCurrentDisplay(); + + if( eglstate.dpy == EGL_NO_DISPLAY ) + return false; + + eglstate.surface = egl.GetCurrentSurface( EGL_DRAW ); + + if( eglstate.surface == EGL_NO_SURFACE ) + return false; + + // now check if swapBuffers does not give error + if( egl.SwapBuffers( eglstate.dpy, eglstate.surface ) == EGL_FALSE ) + return false; + + // double check + if( egl.GetError() != EGL_SUCCESS ) + return false; + + eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS ); + + eglstate.valid = eglstate.imported = true; + return true; +} + +/* +========================= +EGL_Terminate +========================= +*/ +void EGL_Terminate( void ) +{ + egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + + egl.DestroyContext( eglstate.dpy, eglstate.context ); + + egl.DestroySurface( eglstate.dpy, eglstate.surface ); + + egl.Terminate( eglstate.dpy ); + + Sys_FreeLibrary( &egl_info ); +} + +/* +========================= +EGL_GetProcAddress + +eglGetProcAddress/dlsym wrapper +========================= +*/ +void *EGL_GetProcAddress( const char *name ) +{ + void *gles; + void *addr; + + // TODO: cross-platform loading + if( eglstate.gles1 ) + { + if( !eglstate.libgles1 ) + eglstate.libgles1 = dlopen( "libGLESv1_CM.so", RTLD_NOW ); + gles = eglstate.libgles1; + } + else + { + if( !eglstate.libgles2 ) + eglstate.libgles2 = dlopen( "libGLESv2.so", RTLD_NOW ); + gles = eglstate.libgles2; + } + + if( gles && ( addr = dlsym( gles, name ))) + return addr; + + if( !egl.GetProcAddress ) + return NULL; + + return egl.GetProcAddress( name ); +} + +/* +========================= +EGL_LoadLibrary +========================= +*/ +void EGL_LoadLibrary( void ) +{ + Sys_LoadLibrary( &egl_info ); +} +#endif diff --git a/engine/platform/android/eglutil.h b/engine/platform/android/eglutil.h new file mode 100644 index 0000000000..35268d08f0 --- /dev/null +++ b/engine/platform/android/eglutil.h @@ -0,0 +1,58 @@ +#ifndef EGLUTIL_H +#define EGLUTIL_H +#include "platform/platform.h" +#include +#include + +extern struct eglstate_s +{ + qboolean valid, imported; + EGLDisplay dpy; + EGLSurface surface; + EGLContext context; + EGLConfig cfg; + EGLint numCfg; + + const char *extensions; + int gl_attribs[REF_GL_ATTRIBUTES_COUNT]; + qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT]; + EGLint gl_api; + qboolean gles1; + void *libgles1, *libgles2; +} eglstate; + +extern struct eglapi_s +{ + EGLSurface (*GetCurrentSurface)( EGLint readdraw ); + EGLDisplay (*GetCurrentDisplay)( void ); + EGLint (*GetError)( void ); + EGLBoolean (*SwapBuffers)( EGLDisplay dpy, EGLSurface surface ); + EGLBoolean (*SwapInterval)( EGLDisplay dpy, EGLint interval ); + void *(*GetProcAddress)( const char *procname ); + EGLBoolean (*GetConfigAttrib)( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value ); + EGLDisplay (*GetDisplay)( NativeDisplayType display ); + EGLBoolean (*Initialize)( EGLDisplay dpy, EGLint *major, EGLint *minor ); + EGLBoolean (*Terminate)( EGLDisplay dpy ); + const char *(*QueryString)( EGLDisplay dpy, EGLint name ); + EGLBoolean (*ChooseConfig)( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config ); + EGLSurface (*CreateWindowSurface)( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list ); + EGLContext (*CreateContext)( EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list ); + EGLBoolean (*DestroyContext)( EGLDisplay dpy, EGLContext ctx ); + EGLBoolean (*MakeCurrent)( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx ); + EGLBoolean (*BindAPI)( EGLenum api ); + EGLBoolean (*DestroySurface)( EGLDisplay dpy, EGLSurface surface ); + +} egl; + +void EGL_LoadLibrary( void ); +void * EGL_GetProcAddress( const char *name ); +void EGL_Terminate( void ); +qboolean EGL_ImportContext( void ); +qboolean EGL_CreateContext( void ); +qboolean EGL_UpdateSurface( void *window ); +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 ); +int EGL_SetAttribute( int attr, int val ); + +#endif // EGLUTIL_H diff --git a/engine/platform/android/vid_android.c b/engine/platform/android/vid_android.c index 6bc907e86e..553884526f 100644 --- a/engine/platform/android/vid_android.c +++ b/engine/platform/android/vid_android.c @@ -7,18 +7,14 @@ #include "vid_common.h" #include #include -#include -#include +#include "eglutil.h" + static struct vid_android_s { - int gl_attribs[REF_GL_ATTRIBUTES_COUNT]; - qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT]; - EGLint gl_api; - qboolean gles1; - void *libgles1, *libgles2; qboolean has_context; ANativeWindow* window; + qboolean nativeegl; } vid_android; static struct nw_s @@ -51,43 +47,6 @@ static dllfunc_t android_funcs[] = #undef NW_FF dll_info_t android_info = { "libandroid.so", android_funcs, false }; -static struct egl_s -{ - EGLSurface (*GetCurrentSurface)(EGLint readdraw); - EGLDisplay (*GetCurrentDisplay)(void); - EGLint (*GetError)(void); - EGLBoolean (*SwapBuffers)(EGLDisplay dpy, EGLSurface surface); - EGLBoolean (*SwapInterval)(EGLDisplay dpy, EGLint interval); - void *(*GetProcAddress)(const char *procname); -} egl; -#undef GetProcAddress -#define EGL_FF(x) {"egl"#x, (void*)&egl.x} -static dllfunc_t egl_funcs[] = -{ - EGL_FF(SwapInterval), - EGL_FF(SwapBuffers), - EGL_FF(GetError), - EGL_FF(GetCurrentDisplay), - EGL_FF(GetCurrentSurface), - EGL_FF(GetProcAddress), - { NULL, NULL } -}; -#undef EGL_FF -dll_info_t egl_info = { "libEGL.so", egl_funcs, false }; - - -static struct nativeegl_s -{ - qboolean valid; - void *window; - EGLDisplay dpy; - EGLSurface surface; - EGLContext context; - EGLConfig cfg; - EGLint numCfg; - - const char *extensions; -} negl; convar_t *cv_vid_scale; convar_t *cv_vid_rotate; @@ -98,8 +57,8 @@ Android_SwapInterval */ static void Android_SwapInterval( int interval ) { - if( negl.valid ) - egl.SwapInterval( negl.dpy, interval ); + if( vid_android.nativeegl && eglstate.valid ) + egl.SwapInterval( eglstate.dpy, interval ); } /* @@ -143,9 +102,9 @@ Update screen. Use native EGL if possible */ void GL_SwapBuffers( void ) { - if( negl.valid ) + if( vid_android.nativeegl && eglstate.valid ) { - egl.SwapBuffers( negl.dpy, negl.surface ); + egl.SwapBuffers( eglstate.dpy, eglstate.surface ); } else { @@ -162,9 +121,9 @@ Check if we may use native EGL without jni calls */ void Android_UpdateSurface( qboolean active ) { - negl.valid = false; + vid_android.nativeegl = false; - if( nw.release ) + if( glw_state.software || eglstate.valid ) { if( vid_android.window && !active ) { @@ -174,16 +133,28 @@ void Android_UpdateSurface( qboolean active ) if( active ) { + 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); - Con_Printf("s %p\n", surf); + Con_DPrintf("Surface handle %p\n", surf); vid_android.window = nw.fromSurface(jni.env, surf); - Con_Printf("w %p\n", vid_android.window); - nw.setBuffersGeometry(vid_android.window, 0, 0, WINDOW_FORMAT_RGB_565 ); + Con_DPrintf("NativeWindow %p\n", vid_android.window); + + if( eglstate.valid ) + egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format ); + + nw.setBuffersGeometry(vid_android.window, 0, 0, format ); + (*jni.env)->DeleteLocalRef( jni.env, surf ); } + + if( Sys_CheckParm( "-egl" )) + { + EGL_UpdateSurface( vid_android.window ); + vid_android.nativeegl = true; + } return; } @@ -199,30 +170,7 @@ void Android_UpdateSurface( qboolean active ) if( !Sys_CheckParm("-nativeegl") || !active ) return; // enabled by user - if( !egl.GetCurrentDisplay ) - return; - - negl.dpy = egl.GetCurrentDisplay(); - - if( negl.dpy == EGL_NO_DISPLAY ) - return; - - negl.surface = egl.GetCurrentSurface(EGL_DRAW); - - if( negl.surface == EGL_NO_SURFACE ) - return; - - // now check if swapBuffers does not give error - if( egl.SwapBuffers( negl.dpy, negl.surface ) == EGL_FALSE ) - return; - - // double check - if( egl.GetError() != EGL_SUCCESS ) - return; - - __android_log_print( ANDROID_LOG_VERBOSE, "Xash", "native EGL enabled" ); - - negl.valid = true; + vid_android.nativeegl = EGL_ImportContext(); } /* @@ -272,6 +220,8 @@ qboolean R_Init_Video( const int type ) VID_StartupGamma(); + Sys_LoadLibrary( &android_info ); + switch( type ) { case REF_SOFTWARE: @@ -279,7 +229,7 @@ qboolean R_Init_Video( const int type ) break; case REF_GL: glw_state.software = false; - Sys_LoadLibrary( &egl_info ); + EGL_LoadLibrary(); if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) ) glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE ); @@ -295,7 +245,6 @@ qboolean R_Init_Video( const int type ) uint arg; // Con_Reportf( S_ERROR "Native software mode isn't supported on Android yet! :(\n" ); // return false; - Sys_LoadLibrary( &android_info ); Android_UpdateSurface( true ); if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) ) return false; @@ -332,110 +281,35 @@ void R_Free_Video( void ) // R_FreeVideoModes(); Sys_FreeLibrary( &android_info ); - Sys_FreeLibrary( &egl_info ); vid_android.has_context = false; ref.dllFuncs.GL_ClearExtensions(); } -#define COPY_ATTR_IF_SET( refattr, attr ) \ - if( vid_android.gl_attribs_set[refattr] ) \ - { \ - attribs[i++] = attr; \ - attribs[i++] = vid_android.gl_attribs[refattr]; \ - } - -static size_t VID_GenerateConfig( EGLint *attribs, size_t size ) +void *Android_GetWindow( void ) { - size_t i = 0; - - memset( attribs, 0, size * sizeof( EGLint ) ); - vid_android.gles1 = false; - memset( vid_android.gl_attribs, 0, sizeof( vid_android.gl_attribs )); - memset( vid_android.gl_attribs_set, 0, sizeof( vid_android.gl_attribs_set )); - - // refdll can request some attributes - ref.dllFuncs.GL_SetupAttributes( glw_state.safe ); - - 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_BLUE_SIZE, EGL_BLUE_SIZE ); - COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE ); - COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE ); - COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE ); - COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS ); - COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES ); - - if( vid_android.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] ) - { - attribs[i++] = EGL_CONFIG_CAVEAT; - attribs[i++] = vid_android.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE; - } - - // BigGL support - attribs[i++] = EGL_RENDERABLE_TYPE; - vid_android.gl_api = EGL_OPENGL_ES_API; + EGLint format; - if( vid_android.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] && - !( vid_android.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES )) - { - attribs[i++] = EGL_OPENGL_BIT; - vid_android.gl_api = EGL_OPENGL_API; - } - else if( vid_android.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] && - vid_android.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 ) + if( !vid_android.window ) { - attribs[i++] = EGL_OPENGL_ES2_BIT; - } - else - { - i--; // erase EGL_RENDERABLE_TYPE - vid_android.gles1 = true; + return NULL; } - attribs[i++] = EGL_NONE; - - return i; -} - -static size_t VID_GenerateContextConfig( EGLint *attribs, size_t size ) -{ - size_t i = 0; - - memset( attribs, 0, size * sizeof( EGLint )); - - /*if( Q_strcmp( negl.extensions, " EGL_KHR_create_context ") ) + if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) ) { - if( vid_android.gl_attribs_set[REF_GL_CONTEXT_FLAGS] ) - { - attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR - attribs[i++] = vid_android.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1); - } - - if( vid_android.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] ) - { - int val = vid_android.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK]; - - if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) ) - { - attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; - attribs[i++] = val; - } - } - - COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); - COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB ); + Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() ); + return NULL; } - else*/ + + if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) ) { - // without extension we can set only major version - COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION ); + Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" ); + return NULL; } - attribs[i++] = EGL_NONE; - - return i; + return vid_android.window; } + qboolean VID_SetMode( void ) { EGLint format; @@ -444,14 +318,25 @@ qboolean VID_SetMode( void ) const size_t attribsSize = ARRAYSIZE( nAttribs ); size_t s1, s2; - if( vid_android.has_context ) + // create context on egl side by user request + if( !vid_android.has_context && Sys_CheckParm("-egl") ) + { + vid_android.has_context = vid_android.nativeegl = EGL_CreateContext(); + + if( vid_android.has_context ) + Android_UpdateSurface( true ); + else + return false; + } + + if( vid_android.has_context || glw_state.software ) { R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway return true; } - s1 = VID_GenerateConfig(nAttribs, attribsSize); - s2 = VID_GenerateContextConfig(nContextAttribs, attribsSize); + s1 = EGL_GenerateConfig(nAttribs, attribsSize); + s2 = EGL_GenerateContextConfig(nContextAttribs, attribsSize); attribs = (*jni.env)->NewIntArray( jni.env, s1 ); contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 ); @@ -461,8 +346,6 @@ qboolean VID_SetMode( void ) R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway - if( glw_state.software ) - return true; if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.actcls, jni.createGLContext, attribs, contextAttribs ) ) { @@ -512,18 +395,16 @@ rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_m int GL_SetAttribute( int attr, int val ) { - if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT ) - return -1; - - vid_android.gl_attribs[attr] = val; - vid_android.gl_attribs_set[attr] = true; - return 0; + return EGL_SetAttribute( attr, val ); } int GL_GetAttribute( int attr, int *val ) { EGLBoolean ret; + if( eglstate.valid ) + return EGL_GetAttribute( attr, val ); + if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT ) return -1; @@ -570,29 +451,7 @@ vidmode_t* R_GetVideoMode( int num ) void* GL_GetProcAddress( const char *name ) // RenderAPI requirement { - void *gles; - void *addr; - - if( vid_android.gles1 ) - { - if( !vid_android.libgles1 ) - vid_android.libgles1 = dlopen("libGLESv1_CM.so", RTLD_NOW); - gles = vid_android.libgles1; - } - else - { - if( !vid_android.libgles2 ) - vid_android.libgles2 = dlopen("libGLESv2.so", RTLD_NOW); - gles = vid_android.libgles2; - } - - if( gles && ( addr = dlsym(gles, name ) ) ) - return addr; - - if( !egl.GetProcAddress ) - return NULL; - - return egl.GetProcAddress( name ); + return EGL_GetProcAddress( name ); } void GL_UpdateSwapInterval( void ) @@ -652,7 +511,7 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint * if( jni.height < buffer.height ) jni.width = buffer.height; VID_SetMode(); - Android_UpdateSurface( 1 ); + Android_UpdateSurface( true ); return false; } if( buffer.format != WINDOW_FORMAT_RGB_565 ) @@ -669,4 +528,4 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint * *b = (((1 << 5) - 1) << (0)); return true; } -#endif \ No newline at end of file +#endif