mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 03:24:56 +08:00
platform/android: rewrite egl part to separate not android-specific file
This commit is contained in:
@@ -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();
|
||||
|
||||
421
engine/platform/android/eglutil.c
Normal file
421
engine/platform/android/eglutil.c
Normal file
@@ -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 <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
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
|
||||
58
engine/platform/android/eglutil.h
Normal file
58
engine/platform/android/eglutil.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef EGLUTIL_H
|
||||
#define EGLUTIL_H
|
||||
#include "platform/platform.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
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
|
||||
@@ -7,18 +7,14 @@
|
||||
#include "vid_common.h"
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#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,109 +281,34 @@ 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;
|
||||
EGLint format;
|
||||
|
||||
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] )
|
||||
if( !vid_android.window )
|
||||
{
|
||||
attribs[i++] = EGL_CONFIG_CAVEAT;
|
||||
attribs[i++] = vid_android.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// BigGL support
|
||||
attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||
vid_android.gl_api = EGL_OPENGL_ES_API;
|
||||
|
||||
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 ))
|
||||
if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
attribs[i++] = EGL_OPENGL_ES2_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--; // erase EGL_RENDERABLE_TYPE
|
||||
vid_android.gles1 = true;
|
||||
Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return i;
|
||||
return vid_android.window;
|
||||
}
|
||||
|
||||
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( 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 );
|
||||
}
|
||||
else*/
|
||||
{
|
||||
// without extension we can set only major version
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||
}
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
qboolean VID_SetMode( void )
|
||||
{
|
||||
@@ -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
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user