2011-09-16 05:56:54 +00:00
/*
Copyright ( C ) 2006 - 2007 Mark Olsen
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 2
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 .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include "quakedef.h"
# include "glquake.h"
2016-02-10 23:23:43 +00:00
extern float sys_dpi_x ;
extern float sys_dpi_y ;
2017-10-13 17:50:28 +00:00
extern cvar_t vid_vsync ;
2011-09-16 05:56:54 +00:00
static dllhandle_t * sys_gl_module = NULL ;
2017-10-13 17:50:28 +00:00
static rendererinfo_t gles1rendererinfo ;
2011-09-16 05:56:54 +00:00
2017-10-13 17:50:28 +00:00
static void * GLES_GetSymbol ( char * symname )
2011-09-16 05:56:54 +00:00
{
2019-04-15 18:43:42 +00:00
//Can't use android's eglGetProcAddress
//1) it gives less efficient stubs
//2) it has a limited number of such stubs, and the limit is too low for core functions too
2011-09-16 05:56:54 +00:00
void * ret ;
ret = Sys_GetAddressForName ( sys_gl_module , symname ) ;
if ( ! ret )
Sys_Warn ( " GLES_GetSymbol: couldn't find %s \n " , symname ) ;
return ret ;
}
2012-11-27 03:23:19 +00:00
2017-10-13 17:50:28 +00:00
# include <EGL/egl.h>
# include <android/native_window.h>
# include <jni.h>
# include <android/native_window_jni.h>
2011-09-16 05:56:54 +00:00
2017-10-13 17:50:28 +00:00
/*android is a real fucking pain*/
2016-02-10 23:23:43 +00:00
2017-10-13 17:50:28 +00:00
static EGLDisplay sys_display ;
static EGLSurface sys_surface ;
static EGLContext sys_context ;
2019-04-15 18:43:42 +00:00
ANativeWindow * sys_nativewindow ;
2011-09-16 05:56:54 +00:00
void GLVID_DeInit ( void )
{
2017-10-13 17:50:28 +00:00
if ( sys_display )
2011-09-16 05:56:54 +00:00
{
2012-11-27 03:23:19 +00:00
eglMakeCurrent ( sys_display , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2017-10-13 17:50:28 +00:00
if ( sys_context )
2011-09-16 05:56:54 +00:00
eglDestroyContext ( sys_display , sys_context ) ;
2017-10-13 17:50:28 +00:00
2011-09-16 05:56:54 +00:00
if ( sys_surface ! = EGL_NO_SURFACE )
eglDestroySurface ( sys_display , sys_surface ) ;
2017-10-13 17:50:28 +00:00
2012-11-27 03:23:19 +00:00
eglTerminate ( sys_display ) ;
2011-09-16 05:56:54 +00:00
}
2017-10-13 17:50:28 +00:00
sys_display = EGL_NO_DISPLAY ;
sys_context = EGL_NO_CONTEXT ;
sys_surface = EGL_NO_SURFACE ;
2018-04-27 16:40:50 +00:00
GL_ForgetPointers ( ) ;
2017-10-13 17:50:28 +00:00
Sys_Printf ( " GLVID_DeInited \n " ) ;
2011-09-16 05:56:54 +00:00
}
2019-06-17 04:21:41 +00:00
/*static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg)
2019-04-15 18:43:42 +00:00
{
struct
{
EGLint attr ;
const char * attrname ;
} eglattrs [ ] =
{
{ EGL_ALPHA_SIZE , " EGL_ALPHA_SIZE " } ,
{ EGL_ALPHA_MASK_SIZE , " EGL_ALPHA_MASK_SIZE " } ,
{ EGL_BIND_TO_TEXTURE_RGB , " EGL_BIND_TO_TEXTURE_RGB " } ,
{ EGL_BIND_TO_TEXTURE_RGBA , " EGL_BIND_TO_TEXTURE_RGBA " } ,
{ EGL_BLUE_SIZE , " EGL_BLUE_SIZE " } ,
{ EGL_BUFFER_SIZE , " EGL_BUFFER_SIZE " } ,
{ EGL_COLOR_BUFFER_TYPE , " EGL_COLOR_BUFFER_TYPE " } ,
{ EGL_CONFIG_CAVEAT , " EGL_CONFIG_CAVEAT " } ,
{ EGL_CONFIG_ID , " EGL_CONFIG_ID " } ,
{ EGL_CONFORMANT , " EGL_CONFORMANT " } ,
{ EGL_DEPTH_SIZE , " EGL_DEPTH_SIZE " } ,
{ EGL_GREEN_SIZE , " EGL_GREEN_SIZE " } ,
{ EGL_LEVEL , " EGL_LEVEL " } ,
{ EGL_LUMINANCE_SIZE , " EGL_LUMINANCE_SIZE " } ,
{ EGL_MAX_PBUFFER_WIDTH , " EGL_MAX_PBUFFER_WIDTH " } ,
{ EGL_MAX_PBUFFER_HEIGHT , " EGL_MAX_PBUFFER_HEIGHT " } ,
{ EGL_MAX_PBUFFER_PIXELS , " EGL_MAX_PBUFFER_PIXELS " } ,
{ EGL_MAX_SWAP_INTERVAL , " EGL_MAX_SWAP_INTERVAL " } ,
{ EGL_MIN_SWAP_INTERVAL , " EGL_MIN_SWAP_INTERVAL " } ,
{ EGL_NATIVE_RENDERABLE , " EGL_NATIVE_RENDERABLE " } ,
{ EGL_NATIVE_VISUAL_ID , " EGL_NATIVE_VISUAL_ID " } ,
{ EGL_NATIVE_VISUAL_TYPE , " EGL_NATIVE_VISUAL_TYPE " } ,
{ EGL_RED_SIZE , " EGL_RED_SIZE " } ,
{ EGL_RENDERABLE_TYPE , " EGL_RENDERABLE_TYPE " } ,
{ EGL_SAMPLE_BUFFERS , " EGL_SAMPLE_BUFFERS " } ,
{ EGL_SAMPLES , " EGL_SAMPLES " } ,
{ EGL_STENCIL_SIZE , " EGL_STENCIL_SIZE " } ,
{ EGL_SURFACE_TYPE , " EGL_SURFACE_TYPE " } ,
{ EGL_TRANSPARENT_TYPE , " EGL_TRANSPARENT_TYPE " } ,
{ EGL_TRANSPARENT_RED_VALUE , " EGL_TRANSPARENT_RED_VALUE " } ,
{ EGL_TRANSPARENT_GREEN_VALUE , " EGL_TRANSPARENT_GREEN_VALUE " } ,
{ EGL_TRANSPARENT_BLUE_VALUE , " EGL_TRANSPARENT_BLUE_VALUE " } ,
} ;
size_t i ;
EGLint val ;
for ( i = 0 ; i < countof ( eglattrs ) ; i + + )
{
if ( eglGetConfigAttrib ( egldpy , cfg , eglattrs [ i ] . attr , & val ) )
Sys_Printf ( " %i.%s: %i \n " , ( int ) cfg , eglattrs [ i ] . attrname , val ) ;
else
Sys_Printf ( " %i.%s: UNKNOWN \n " , ( int ) cfg , eglattrs [ i ] . attrname ) ;
}
} ;
2019-06-17 04:21:41 +00:00
*/
2011-09-16 05:56:54 +00:00
qboolean GLVID_Init ( rendererstate_t * info , unsigned char * palette )
{
2017-10-13 17:50:28 +00:00
Sys_Printf ( " GLVID_Initing... \n " ) ;
2019-04-15 18:43:42 +00:00
if ( ! sys_nativewindow )
2017-10-13 17:50:28 +00:00
{
Sys_Printf ( " GLVID_Init failed: no window known yet \n " ) ;
return false ; //not at this time...
}
// vid.pixelwidth = ANativeWindow_getWidth(sys_window);
// vid.pixelheight = ANativeWindow_getHeight(sys_window);
2011-09-16 05:56:54 +00:00
vid . numpages = 3 ;
2017-10-13 17:50:28 +00:00
EGLint attribs [ ] = {
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES_BIT ,
2011-09-16 05:56:54 +00:00
EGL_SURFACE_TYPE , EGL_WINDOW_BIT ,
EGL_BLUE_SIZE , ( info - > bpp = = 16 ) ? 5 : 8 ,
EGL_GREEN_SIZE , ( info - > bpp = = 16 ) ? 6 : 8 ,
EGL_RED_SIZE , ( info - > bpp = = 16 ) ? 5 : 8 ,
EGL_DEPTH_SIZE , 16 ,
// EGL_STENCIL_SIZE, 8,
EGL_NONE
} ;
2017-10-13 17:50:28 +00:00
EGLint w , h , format ;
2011-09-16 05:56:54 +00:00
EGLint numConfigs ;
EGLConfig config ;
2017-10-13 17:50:28 +00:00
int glesversion ;
2011-09-16 05:56:54 +00:00
2017-10-13 17:50:28 +00:00
sys_display = eglGetDisplay ( EGL_DEFAULT_DISPLAY ) ;
if ( sys_display = = EGL_NO_DISPLAY )
2011-09-16 05:56:54 +00:00
{
GLVID_DeInit ( ) ;
return false ;
}
2017-10-13 17:50:28 +00:00
if ( ! eglInitialize ( sys_display , NULL , NULL ) )
2011-09-16 05:56:54 +00:00
{
GLVID_DeInit ( ) ;
return false ;
}
2017-10-13 17:50:28 +00:00
# ifdef EGL_VERSION_1_5
attribs [ 1 ] = EGL_OPENGL_ES3_BIT ;
if ( info - > renderer = = & gles1rendererinfo | | ! eglChooseConfig ( sys_display , attribs , & config , 1 , & numConfigs ) )
# endif
{
attribs [ 1 ] = EGL_OPENGL_ES2_BIT ;
if ( info - > renderer = = & gles1rendererinfo | | ! eglChooseConfig ( sys_display , attribs , & config , 1 , & numConfigs ) )
{
//gles2 was added in egl1.3
attribs [ 1 ] = EGL_OPENGL_ES_BIT ;
if ( ! eglChooseConfig ( sys_display , attribs , & config , 1 , & numConfigs ) )
{
//EGL_RENDERABLE_TYPE added in egl1.2
if ( ! eglChooseConfig ( sys_display , attribs + 2 , & config , 1 , & numConfigs ) )
{
GLVID_DeInit ( ) ;
return false ;
}
}
}
}
eglGetConfigAttrib ( sys_display , config , EGL_RENDERABLE_TYPE , & format ) ;
if ( info - > renderer = = & gles1rendererinfo & & ( format & EGL_OPENGL_ES_BIT ) )
glesversion = 1 ;
# ifdef EGL_VERSION_1_5
else if ( format & EGL_OPENGL_ES3_BIT )
glesversion = 3 ;
# endif
else if ( format & EGL_OPENGL_ES2_BIT )
glesversion = 2 ;
else
glesversion = 1 ;
Sys_Printf ( " Creating gles %i context \n " , glesversion ) ;
2019-06-17 04:21:41 +00:00
// EGL_ShowConfig(sys_display, config);
2019-04-15 18:43:42 +00:00
sys_surface = eglCreateWindowSurface ( sys_display , config , sys_nativewindow , NULL ) ;
2017-10-13 17:50:28 +00:00
if ( ! sys_surface )
return false ;
EGLint ctxattribs [ ] = { EGL_CONTEXT_CLIENT_VERSION , glesversion , EGL_NONE } ;
2019-04-15 18:43:42 +00:00
sys_context = eglCreateContext ( sys_display , config , NULL , ctxattribs ) ;
if ( ! sys_context )
return false ;
2011-09-16 05:56:54 +00:00
if ( eglMakeCurrent ( sys_display , sys_surface , sys_surface , sys_context ) = = EGL_FALSE )
return false ;
eglQuerySurface ( sys_display , sys_surface , EGL_WIDTH , & w ) ;
eglQuerySurface ( sys_display , sys_surface , EGL_HEIGHT , & h ) ;
vid . pixelwidth = w ;
vid . pixelheight = h ;
2019-04-15 18:43:42 +00:00
/*now that the context is created, load the dll so that we don't have to crash from eglGetProcAddress issues*/
unsigned int gl_major_version = 0 ;
const char * ( * eglGetString ) ( GLenum ) = ( void * ) eglGetProcAddress ( " glGetString " ) ;
const char * s = eglGetString ( GL_VERSION ) ;
while ( * s & & ( * s < ' 0 ' | | * s > ' 9 ' ) )
s + + ;
gl_major_version = atoi ( s ) ;
const char * driver ;
2019-06-17 04:21:41 +00:00
if ( ( glesversion < = 1 ) ! = ( gl_major_version < = 1 ) )
{
Con_Printf ( CON_ERROR " Requested gles %i context, but got incompatible %i instead. \n " , glesversion , gl_major_version ) ;
GLVID_DeInit ( ) ;
return false ;
}
if ( gl_major_version > = 3 )
2019-04-15 18:43:42 +00:00
driver = " libGLESv3.so " ;
else if ( gl_major_version > = 2 )
driver = " libGLESv2.so " ;
else
driver = " libGLESv1_CM.so " ;
Sys_Printf ( " Loading %s \n " , driver ) ;
sys_gl_module = Sys_LoadLibrary ( driver , NULL ) ;
if ( ! sys_gl_module )
{
GLVID_DeInit ( ) ;
return false ;
}
2017-10-13 17:50:28 +00:00
if ( ! GL_Init ( info , GLES_GetSymbol ) )
return false ;
Sys_Printf ( " GLVID_Inited... \n " ) ;
vid_vsync . modified = true ;
return true ;
2011-09-16 05:56:54 +00:00
}
2014-03-30 00:39:37 +00:00
void GLVID_SwapBuffers ( void )
2011-09-16 05:56:54 +00:00
{
2017-10-13 17:50:28 +00:00
if ( vid_vsync . modified )
{
int interval ;
vid_vsync . modified = false ;
if ( * vid_vsync . string )
interval = vid_vsync . ival ;
else
interval = 1 ; //default is to always vsync, according to EGL docs, so lets just do that.
eglSwapInterval ( sys_display , interval ) ;
2019-04-15 18:43:42 +00:00
Sys_Printf ( " Swap interval changed \n " ) ;
2017-10-13 17:50:28 +00:00
}
2011-09-16 05:56:54 +00:00
eglSwapBuffers ( sys_display , sys_surface ) ;
2019-04-15 18:43:42 +00:00
TRACE ( ( " Swap Buffers \n " ) ) ;
2017-10-13 17:50:28 +00:00
EGLint w , h ;
eglQuerySurface ( sys_display , sys_surface , EGL_WIDTH , & w ) ;
eglQuerySurface ( sys_display , sys_surface , EGL_HEIGHT , & h ) ;
if ( w ! = vid . pixelwidth | | h ! = vid . pixelheight )
{
vid . pixelwidth = w ;
vid . pixelheight = h ;
extern cvar_t vid_conautoscale ;
Cvar_ForceCallback ( & vid_conautoscale ) ;
2019-04-15 18:43:42 +00:00
Sys_Printf ( " Video Resized \n " ) ;
2017-10-13 17:50:28 +00:00
}
2011-09-16 05:56:54 +00:00
}
2016-07-28 15:57:22 +00:00
qboolean GLVID_ApplyGammaRamps ( unsigned int gammarampsize , unsigned short * ramps )
2011-09-16 05:56:54 +00:00
{
2013-05-14 13:02:54 +00:00
return false ;
2011-09-16 05:56:54 +00:00
}
2016-07-12 00:40:13 +00:00
void GLVID_SetCaption ( const const char * caption )
2011-09-16 05:56:54 +00:00
{
2017-10-13 17:50:28 +00:00
// :(
2011-09-16 05:56:54 +00:00
}
2017-10-13 17:50:28 +00:00
void VID_Register ( void )
{
//many android devices have drivers for both gles1 AND gles2.
//we default to gles2 because its more capable, but some people might want to try using gles1. so register a renderer for that.
//the init code explicitly checks for our gles1rendererinfo and tries to create a gles1 context instead.
extern rendererinfo_t openglrendererinfo ;
gles1rendererinfo = openglrendererinfo ;
gles1rendererinfo . description = " OpenGL ES 1 " ;
memset ( & gles1rendererinfo . name , 0 , sizeof ( gles1rendererinfo . name ) ) ; //make sure there's no 'gl' etc names.
gles1rendererinfo . name [ 0 ] = " gles1 " ;
2020-05-16 13:12:58 +00:00
R_RegisterRenderer ( NULL , & gles1rendererinfo ) ;
2017-10-13 17:50:28 +00:00
}
# ifdef VKQUAKE
# include "../vk/vkrenderer.h"
static qboolean VKVID_CreateSurface ( void )
{
VkResult err ;
VkAndroidSurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR } ;
createInfo . flags = 0 ;
2019-04-15 18:43:42 +00:00
createInfo . window = sys_nativewindow ;
2017-10-13 17:50:28 +00:00
err = vkCreateAndroidSurfaceKHR ( vk . instance , & createInfo , NULL , & vk . surface ) ;
switch ( err )
{
default :
Con_Printf ( " Unknown vulkan device creation error: %x \n " , err ) ;
return false ;
case VK_SUCCESS :
break ;
}
return true ;
}
static qboolean VKVID_Init ( rendererstate_t * info , unsigned char * palette )
{
//this is simpler than most platforms, as the window itself is handled by java code, and we can't create/destroy it here
//(android surfaces can be resized/resampled separately from their window, and are always 'fullscreen' anyway, so this isn't actually an issue for once)
const char * extnames [ ] = { VK_KHR_ANDROID_SURFACE_EXTENSION_NAME , NULL } ;
2017-11-30 17:59:11 +00:00
Sys_Printf ( " initialising vulkan... \n " ) ;
2019-04-15 18:43:42 +00:00
if ( ! sys_nativewindow )
2017-10-13 17:50:28 +00:00
{
Sys_Printf ( " VKVID_Init failed: no window known yet \n " ) ;
return false ;
}
# ifdef VK_NO_PROTOTYPES
dllhandle_t * hInstVulkan = NULL ;
if ( ! hInstVulkan )
hInstVulkan = * info - > subrenderer ? Sys_LoadLibrary ( info - > subrenderer , NULL ) : NULL ;
if ( ! hInstVulkan )
hInstVulkan = Sys_LoadLibrary ( " libvulkan.so " , NULL ) ;
if ( ! hInstVulkan )
{
Con_Printf ( " Unable to load libvulkan.so \n No Vulkan drivers are installed \n " ) ;
return false ;
}
vkGetInstanceProcAddr = ( PFN_vkGetInstanceProcAddr ) Sys_GetAddressForName ( hInstVulkan , " vkGetInstanceProcAddr " ) ;
# endif
return VK_Init ( info , extnames , VKVID_CreateSurface , NULL ) ;
}
void VKVID_DeInit ( void )
{
VK_Shutdown ( ) ;
//that's all folks.
}
static void VKVID_SwapBuffers ( void )
{
// :(
}
rendererinfo_t vkrendererinfo =
{
" Vulkan " ,
{
" vk " ,
" Vulkan "
} ,
QR_VULKAN ,
VK_Draw_Init ,
VK_Draw_Shutdown ,
VK_UpdateFiltering ,
VK_LoadTextureMips ,
VK_DestroyTexture ,
VK_R_Init ,
VK_R_DeInit ,
VK_R_RenderView ,
VKVID_Init ,
VKVID_DeInit ,
VKVID_SwapBuffers ,
GLVID_ApplyGammaRamps ,
NULL , //_CreateCursor,
NULL , //_SetCursor,
NULL , //_DestroyCursor,
GLVID_SetCaption ,
VKVID_GetRGBInfo ,
VK_SCR_UpdateScreen ,
VKBE_SelectMode ,
VKBE_DrawMesh_List ,
VKBE_DrawMesh_Single ,
VKBE_SubmitBatch ,
VKBE_GetTempBatch ,
VKBE_DrawWorld ,
VKBE_Init ,
VKBE_GenBrushModelVBO ,
VKBE_ClearVBO ,
VKBE_UploadAllLightmaps ,
VKBE_SelectEntity ,
VKBE_SelectDLight ,
VKBE_Scissor ,
VKBE_LightCullModel ,
VKBE_VBO_Begin ,
VKBE_VBO_Data ,
VKBE_VBO_Finish ,
VKBE_VBO_Destroy ,
VKBE_RenderToTextureUpdate2d ,
" no more "
} ;
# endif