From 5a3e3b3977b4c0599abbb23ca608b353e0707728 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 21 Feb 2023 23:32:47 +0100 Subject: [PATCH] ref: gl: add immediate mode shim for psvita --- engine/platform/psvita/sys_psvita.c | 18 +- ref/gl/gl_local.h | 6 + ref/gl/gl_opengl.c | 6 + ref/gl/gl_rmain.c | 3 + ref/gl/gl_studio.c | 21 +- ref/gl/wscript | 2 +- utils/vgl_shim/vgl_shaders/fragment.cg.inc | 46 ++ utils/vgl_shim/vgl_shaders/vertex.cg.inc | 49 ++ utils/vgl_shim/vgl_shim.c | 532 +++++++++++++++++++++ utils/vgl_shim/vgl_shim.h | 24 + utils/vgl_shim/wscript | 25 + wscript | 3 + 12 files changed, 716 insertions(+), 19 deletions(-) create mode 100644 utils/vgl_shim/vgl_shaders/fragment.cg.inc create mode 100644 utils/vgl_shim/vgl_shaders/vertex.cg.inc create mode 100644 utils/vgl_shim/vgl_shim.c create mode 100644 utils/vgl_shim/vgl_shim.h create mode 100644 utils/vgl_shim/wscript diff --git a/engine/platform/psvita/sys_psvita.c b/engine/platform/psvita/sys_psvita.c index a9defa15..6ce1094c 100644 --- a/engine/platform/psvita/sys_psvita.c +++ b/engine/platform/psvita/sys_psvita.c @@ -25,22 +25,12 @@ GNU General Public License for more details. #define DATA_PATH "data/xash3d" -// 200MB libc heap, 512K main thread stack, 32MB for loading game DLLs, 8MB vertex pool +// 200MB libc heap, 512K main thread stack, 40MB for loading game DLLs // the rest goes to vitaGL SceUInt32 sceUserMainThreadStackSize = 512 * 1024; unsigned int _pthread_stack_default_user = 512 * 1024; unsigned int _newlib_heap_size_user = 200 * 1024 * 1024; #define VGL_MEM_THRESHOLD ( 40 * 1024 * 1024 ) -#define VGL_VERTEX_POOL_SIZE ( 4 * 1024 * 1024 ) - -/* HACK: stubs for GL functions that are missing from vitaGL */ - -static void glDrawBuffer( GLenum which ) -{ - /* nada */ -} - -/* end of GL stubs*/ /* HACKHACK: force-export stuff required by the dynamic libs */ @@ -73,7 +63,7 @@ static const vrtld_export_t aux_exports[] = VRTLD_EXPORT_SYMBOL( strchrnul ), VRTLD_EXPORT_SYMBOL( rand ), VRTLD_EXPORT_SYMBOL( srand ), - VRTLD_EXPORT_SYMBOL( glDrawBuffer ), + VRTLD_EXPORT_SYMBOL( sceGxmMapMemory ), // needed by vgl_shim VRTLD_EXPORT( "dlopen", vrtld_dlopen ), VRTLD_EXPORT( "dlclose", vrtld_dlclose ), VRTLD_EXPORT( "dlsym", vrtld_dlsym ), @@ -112,11 +102,11 @@ void PSVita_Init( void ) Sys_Error( "Could not init vrtld: %s\n", vrtld_dlerror( ) ); } - // init vitaGL with some memory budget for immediate mode vertices + // init vitaGL, leaving some memory for DLL mapping // TODO: we don't need to do this for ref_soft vglUseVram( GL_TRUE ); vglUseExtraMem( GL_TRUE ); - vglInitExtended( VGL_VERTEX_POOL_SIZE, 960, 544, VGL_MEM_THRESHOLD, 0 ); + vglInitExtended( 0, 960, 544, VGL_MEM_THRESHOLD, 0 ); } void PSVita_Shutdown( void ) diff --git a/ref/gl/gl_local.h b/ref/gl/gl_local.h index deac6e94..91d9f9c9 100644 --- a/ref/gl/gl_local.h +++ b/ref/gl/gl_local.h @@ -35,6 +35,12 @@ GNU General Public License for more details. #include "gl_export.h" #include "wadfile.h" +#if XASH_PSVITA +int VGL_ShimInit( void ); +void VGL_ShimShutdown( void ); +void VGL_ShimEndFrame( void ); +#endif + #ifndef offsetof #ifdef __GNUC__ #define offsetof(s,m) __builtin_offsetof(s,m) diff --git a/ref/gl/gl_opengl.c b/ref/gl/gl_opengl.c index 8f88b129..3921bb75 100644 --- a/ref/gl/gl_opengl.c +++ b/ref/gl/gl_opengl.c @@ -755,6 +755,8 @@ void GL_InitExtensionsBigGL( void ) #if XASH_PSVITA // NPOT textures are actually supported, but the extension is not listed in GL_EXTENSIONS GL_SetExtension( GL_ARB_TEXTURE_NPOT_EXT, true ); + // init our immediate mode override + VGL_ShimInit(); #endif } #endif @@ -824,6 +826,10 @@ void GL_ClearExtensions( void ) // now all extensions are disabled memset( glConfig.extension, 0, sizeof( glConfig.extension )); glw_state.initialized = false; +#if XASH_PSVITA + // deinit our immediate mode override + VGL_ShimShutdown(); +#endif } //======================================================================= diff --git a/ref/gl/gl_rmain.c b/ref/gl/gl_rmain.c index be5cd3d2..bc8f9229 100644 --- a/ref/gl/gl_rmain.c +++ b/ref/gl/gl_rmain.c @@ -1124,6 +1124,9 @@ R_EndFrame */ void R_EndFrame( void ) { +#if XASH_PSVITA + VGL_ShimEndFrame(); +#endif // flush any remaining 2D bits R_Set2DMode( false ); gEngfuncs.GL_SwapBuffers(); diff --git a/ref/gl/gl_studio.c b/ref/gl/gl_studio.c index 1c0aa6a4..38a9dd04 100644 --- a/ref/gl/gl_studio.c +++ b/ref/gl/gl_studio.c @@ -25,6 +25,14 @@ GNU General Public License for more details. #define EVENT_CLIENT 5000 // less than this value it's a server-side studio events #define MAX_LOCALLIGHTS 4 +#if XASH_PSVITA +// save some address space by decreasing .bss size +// we're not gonna be using the array renderer anyway +#define MAXARRAYVERTS 1 +#else +#define MAXARRAYVERTS MAXSTUDIOVERTS +#endif + typedef struct { char name[MAX_OSPATH]; @@ -112,10 +120,10 @@ typedef struct player_model_t player_models[MAX_CLIENTS]; // drawelements renderer - vec3_t arrayverts[MAXSTUDIOVERTS]; - vec2_t arraycoord[MAXSTUDIOVERTS]; - unsigned short arrayelems[MAXSTUDIOVERTS*6]; - GLubyte arraycolor[MAXSTUDIOVERTS][4]; + vec3_t arrayverts[MAXARRAYVERTS]; + vec2_t arraycoord[MAXARRAYVERTS]; + unsigned short arrayelems[MAXARRAYVERTS*6]; + GLubyte arraycolor[MAXARRAYVERTS][4]; uint numverts; uint numelems; } studio_draw_state_t; @@ -150,6 +158,11 @@ void R_StudioInit( void ) r_studio_sort_textures = gEngfuncs.Cvar_Get( "r_studio_sort_textures", "0", FCVAR_GLCONFIG, "change draw order for additive meshes" ); r_studio_drawelements = gEngfuncs.Cvar_Get( "r_studio_drawelements", "1", FCVAR_GLCONFIG, "use glDrawElements for studiomodels" ); +#if XASH_PSVITA + // don't do the same array-building work twice since that's what our FFP shim does anyway + gEngfuncs.Cvar_SetValue( "r_studio_drawelements", 0 ); +#endif + Matrix3x4_LoadIdentity( g_studio.rotationmatrix ); // g-cont. cvar disabled by Valve diff --git a/ref/gl/wscript b/ref/gl/wscript index 3416d00e..16266c9e 100644 --- a/ref/gl/wscript +++ b/ref/gl/wscript @@ -35,7 +35,7 @@ def build(bld): libs = [ 'engine_includes' ] # on PSVita do not link any libraries that are already in the main executable, but add the includes target if bld.env.DEST_OS == 'psvita': - libs += [ 'sdk_includes' ] + libs += [ 'sdk_includes', 'vgl_shim' ] else: libs += [ 'public', 'M' ] diff --git a/utils/vgl_shim/vgl_shaders/fragment.cg.inc b/utils/vgl_shim/vgl_shaders/fragment.cg.inc new file mode 100644 index 00000000..42f57d23 --- /dev/null +++ b/utils/vgl_shim/vgl_shaders/fragment.cg.inc @@ -0,0 +1,46 @@ +R""( + +#if ATTR_TEXCOORD0 +uniform sampler2D uTex0 : TEXUNIT0; +#endif +#if ATTR_TEXCOORD1 +uniform sampler2D uTex1 : TEXUNIT1; +#endif +#if FEAT_ALPHA_TEST +uniform float uAlphaTest; +#endif + +float4 main( + uniform float4 uColor +#if ATTR_COLOR + , float4 vColor : COLOR +#endif +#if ATTR_TEXCOORD0 + , float2 vTexCoord0 : TEXCOORD0 +#endif +#if ATTR_TEXCOORD1 + , float2 vTexCoord1 : TEXCOORD1 +#endif +#if ATTR_NORMAL + , float3 vNormal : TEXCOORD2 +#endif +) { +#if ATTR_COLOR + float4 c = vColor; +#else + float4 c = uColor; +#endif +#if ATTR_TEXCOORD0 + c *= tex2D(uTex0, vTexCoord0); +#endif +#if ATTR_TEXCOORD1 + c *= tex2D(uTex1, vTexCoord1); +#endif +#if FEAT_ALPHA_TEST + if (c.a <= uAlphaTest) + discard; +#endif + return c; +} + +)"" diff --git a/utils/vgl_shim/vgl_shaders/vertex.cg.inc b/utils/vgl_shim/vgl_shaders/vertex.cg.inc new file mode 100644 index 00000000..75a9919a --- /dev/null +++ b/utils/vgl_shim/vgl_shaders/vertex.cg.inc @@ -0,0 +1,49 @@ +R""( + +// has to be called this for VGL to fill it in automatically +uniform float4x4 gl_ModelViewProjectionMatrix; + +void main( + float3 inPosition +#if ATTR_COLOR + , float4 inColor +#endif +#if ATTR_NORMAL + , float3 inNormal +#endif +#if ATTR_TEXCOORD0 + , float2 inTexCoord0 +#endif +#if ATTR_TEXCOORD1 + , float2 inTexCoord1 +#endif + , float4 out vPosition : POSITION +#if ATTR_COLOR + , float4 out vColor : COLOR +#endif +#if ATTR_TEXCOORD0 + , float2 out vTexCoord0 : TEXCOORD0 +#endif +#if ATTR_TEXCOORD1 + , float2 out vTexCoord1 : TEXCOORD1 +#endif +#if ATTR_NORMAL + , float3 out vNormal : TEXCOORD2 +#endif +) { + vPosition = mul(gl_ModelViewProjectionMatrix, float4(inPosition, 1.f)); +#if ATTR_COLOR + vColor = inColor; +#endif +#if ATTR_NORMAL + vNormal = inNormal; +#endif +#if ATTR_TEXCOORD0 + vTexCoord0 = inTexCoord0; +#endif +#if ATTR_TEXCOORD1 + vTexCoord1 = inTexCoord1; +#endif +} + +)"" diff --git a/utils/vgl_shim/vgl_shim.c b/utils/vgl_shim/vgl_shim.c new file mode 100644 index 00000000..c3a6cdd6 --- /dev/null +++ b/utils/vgl_shim/vgl_shim.c @@ -0,0 +1,532 @@ +/* +vgl_shim.c - vitaGL custom immediate mode shim +Copyright (C) 2023 fgsfds + +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 +#include +#include +#include +#include + +#include "port.h" +#include "xash3d_types.h" +#include "cvardef.h" +#include "const.h" +#include "com_model.h" +#include "cl_entity.h" +#include "render_api.h" +#include "protocol.h" +#include "dlight.h" +#include "ref_api.h" +#include "com_strings.h" +#include "vgl_shim.h" + +#define MAX_SHADERLEN 4096 +#define MAX_PROGS 32 + +extern ref_api_t gEngfuncs; + +enum vgl_attrib_e +{ + VGL_ATTR_POS = 0, // 1 + VGL_ATTR_COLOR = 1, // 2 + VGL_ATTR_TEXCOORD0 = 2, // 4 + VGL_ATTR_TEXCOORD1 = 3, // 8 + VGL_ATTR_NORMAL = 4, // 16 + VGL_ATTR_MAX +}; + +// continuation of previous enum +enum vgl_flag_e +{ + VGL_FLAG_ALPHA_TEST = VGL_ATTR_MAX, + VGL_FLAG_MAX +}; + +typedef struct +{ + GLuint flags; + GLint attridx[VGL_ATTR_MAX]; + GLuint glprog; + GLint ucolor; + GLint ualpha; + GLint utex0; + GLint utex1; +} vgl_prog_t; + +static const char *vgl_vert_src = +#include "vgl_shaders/vertex.cg.inc" +; + +static const char *vgl_frag_src = +#include "vgl_shaders/fragment.cg.inc" +; + +static int vgl_init = 0; + +static struct +{ + GLfloat *attrbuf[VGL_ATTR_MAX]; + GLuint cur_flags; + GLint begin; + GLint end; + GLenum prim; + GLfloat color[4]; + GLfloat alpharef; + vgl_prog_t progs[MAX_PROGS]; + vgl_prog_t *cur_prog; + GLboolean uchanged; +} vgl; + +static const int vgl_attr_size[VGL_ATTR_MAX] = { 3, 4, 2, 2, 3 }; + +static const char *vgl_flag_name[VGL_FLAG_MAX] = +{ + "ATTR_POSITION", + "ATTR_COLOR", + "ATTR_TEXCOORD0", + "ATTR_TEXCOORD1", + "ATTR_NORMAL", + "FEAT_ALPHA_TEST", +}; + +static const char *vgl_attr_name[VGL_ATTR_MAX] = +{ + "inPosition", + "inColor", + "inTexCoord0", + "inTexCoord1", + "inNormal", +}; + +// HACK: borrow alpha test flag from internal vitaGL state +extern GLboolean alpha_test_state; + +static GLuint VGL_GenerateShader( const vgl_prog_t *prog, GLenum type ) +{ + char *shader, shader_buf[MAX_SHADERLEN + 1]; + char tmp[256]; + int i; + GLint status, len; + GLuint id; + + shader = shader_buf; + shader[0] = '\n'; + shader[1] = 0; + + for ( i = 0; i < VGL_FLAG_MAX; ++i ) + { + snprintf( tmp, sizeof( tmp ), "#define %s %d\n", vgl_flag_name[i], prog->flags & ( 1 << i ) ); + strncat( shader, tmp, MAX_SHADERLEN ); + } + + if ( type == GL_FRAGMENT_SHADER ) + strncat( shader, vgl_frag_src, MAX_SHADERLEN ); + else + strncat( shader, vgl_vert_src, MAX_SHADERLEN ); + + id = glCreateShader( type ); + len = strlen( shader ); + glShaderSource( id, 1, (const void *)&shader, &len ); + glCompileShader( id ); + glGetShaderiv( id, GL_COMPILE_STATUS, &status ); + if ( status == GL_FALSE ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGL_GenerateShader( 0x%04x, 0x%x ): compile failed:\n", prog->flags, type ); + gEngfuncs.Con_Printf( "Shader text:\n%s\n\n", shader ); + glDeleteShader( id ); + return 0; + } + + return id; +} + +static vgl_prog_t *VGL_GetProg( const GLuint flags ) +{ + int i, loc, status; + GLuint vp, fp, glprog; + vgl_prog_t *prog; + + // try to find existing prog matching this feature set + + if ( vgl.cur_prog && vgl.cur_prog->flags == flags ) + return vgl.cur_prog; + + for ( i = 0; i < MAX_PROGS; ++i ) + { + if ( vgl.progs[i].flags == flags ) + return &vgl.progs[i]; + else if ( vgl.progs[i].flags == 0 ) + break; + } + + if ( i == MAX_PROGS ) + { + gEngfuncs.Host_Error( "VGL_GetProg(): Ran out of program slots for 0x%04x\n", flags ); + return NULL; + } + + // new prog; generate shaders + + gEngfuncs.Con_DPrintf( S_NOTE "VGL_GetProg(): Generating progs for 0x%04x\n", flags ); + prog = &vgl.progs[i]; + prog->flags = flags; + + vp = VGL_GenerateShader( prog, GL_VERTEX_SHADER ); + fp = VGL_GenerateShader( prog, GL_FRAGMENT_SHADER ); + if ( !vp || !fp ) + { + prog->flags = 0; + return NULL; + } + + glprog = glCreateProgram(); + glAttachShader( glprog, vp ); + glAttachShader( glprog, fp ); + + loc = 0; + for ( i = 0; i < VGL_ATTR_MAX; ++i ) + { + if ( flags & ( 1 << i ) ) + { + prog->attridx[i] = loc; + glBindAttribLocation( glprog, loc++, vgl_attr_name[i] ); + } + else + { + prog->attridx[i] = -1; + } + } + + glLinkProgram( glprog ); + glDeleteShader( vp ); + glDeleteShader( fp ); + + glGetProgramiv( glprog, GL_LINK_STATUS, &status ); + if ( status == GL_FALSE ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGL_GetProg( 0x%04x ): link failed!\n", prog->flags ); + prog->flags = 0; + glDeleteProgram( glprog ); + return NULL; + } + + prog->ucolor = glGetUniformLocation( glprog, "uColor" ); + prog->ualpha = glGetUniformLocation( glprog, "uAlphaTest" ); + prog->utex0 = glGetUniformLocation( glprog, "uTex0" ); + prog->utex1 = glGetUniformLocation( glprog, "uTex1" ); + + // these never change + if ( prog->utex0 >= 0 ) + glUniform1i( prog->utex0, 0 ); + if ( prog->utex1 >= 0 ) + glUniform1i( prog->utex1, 1 ); + + prog->glprog = glprog; + + gEngfuncs.Con_DPrintf( S_NOTE "VGL_GetProg(): Generated progs for 0x%04x: glprog=%u ucolor=%d ualpha=%d\n", flags, glprog, prog->ucolor, prog->ualpha ); + + return prog; +} + +static vgl_prog_t *VGL_SetProg( const GLuint flags ) +{ + vgl_prog_t *prog = NULL; + + if ( flags && ( prog = VGL_GetProg( flags ) ) ) + { + if ( prog != vgl.cur_prog ) + { + glUseProgram( prog->glprog ); + vgl.uchanged = GL_TRUE; + } + if ( vgl.uchanged ) + { + if ( prog->ualpha >= 0 ) + glUniform1f( prog->ualpha, vgl.alpharef ); + if ( prog->ucolor >= 0 ) + glUniform4fv( prog->ucolor, 1, vgl.color ); + vgl.uchanged = GL_FALSE; + } + } + else + { + glUseProgram( 0 ); + } + + vgl.cur_prog = prog; + return prog; +} + +int VGL_ShimInit( void ) +{ + int i; + GLuint total, size; + + if ( vgl_init ) + return 0; + + memset( &vgl, 0, sizeof( vgl ) ); + + vgl.color[0] = 1.f; + vgl.color[1] = 1.f; + vgl.color[2] = 1.f; + vgl.color[3] = 1.f; + vgl.uchanged = GL_TRUE; + + total = 0; + for ( i = 0; i < VGL_ATTR_MAX; ++i ) + { + size = VGL_MAX_VERTS * vgl_attr_size[i] * sizeof( GLfloat ); + vgl.attrbuf[i] = memalign( 0x100, size ); + total += size; + } + + VGL_ShimInstall(); + + gEngfuncs.Con_DPrintf( S_NOTE "VGL_ShimInit(): %u bytes allocated for vertex buffer\n", total ); + + vgl_init = 1; + return 0; +} + +void VGL_ShimShutdown( void ) +{ + int i; + + if ( !vgl_init ) + return; + + glFinish(); + glUseProgram( 0 ); + + for ( i = 0; i < MAX_PROGS; ++i ) + { + if ( vgl.progs[i].flags ) + glDeleteProgram( vgl.progs[i].glprog ); + } + + for ( i = 0; i < VGL_ATTR_MAX; ++i ) + free( vgl.attrbuf[i] ); + + memset( &vgl, 0, sizeof( vgl ) ); + + vgl_init = 0; +} + +void VGL_ShimEndFrame( void ) +{ + vgl.end = vgl.begin = 0; +} + +void VGL_Begin( GLenum prim ) +{ + int i; + vgl.prim = prim; + vgl.begin = vgl.end; + // pos always enabled + vgl.cur_flags = 1 << VGL_ATTR_POS; + // disable all vertex attrib pointers + for ( i = 0; i < VGL_ATTR_MAX; ++i ) + glDisableVertexAttribArray( i ); +} + +void VGL_End( void ) +{ + int i; + vgl_prog_t *prog; + GLuint flags = vgl.cur_flags; + GLint count = vgl.end - vgl.begin; + + if ( !vgl.prim || !count ) + goto _leave; // end without begin + + if ( vgl.end > VGL_MAX_VERTS ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGL_End(): Ran out of vertex space (%d overhead)\n", vgl.end - VGL_MAX_VERTS ); + vgl.end = 0; + goto _leave; + } + + // enable alpha test if needed + if ( alpha_test_state ) + flags |= 1 << VGL_FLAG_ALPHA_TEST; + + prog = VGL_SetProg( flags ); + if ( !prog ) + { + gEngfuncs.Host_Error( "VGL_End(): Could not find program for flags 0x%04x!\n", flags ); + goto _leave; + } + + for ( i = 0; i < VGL_ATTR_MAX; ++i ) + { + if ( prog->attridx[i] >= 0 ) + { + glEnableVertexAttribArray( prog->attridx[i] ); + glVertexAttribPointer( prog->attridx[i], vgl_attr_size[i], GL_FLOAT, GL_FALSE, 0, vgl.attrbuf[i] + vgl_attr_size[i] * vgl.begin ); + } + } + + glDrawArrays( vgl.prim, 0, count ); + +_leave: + vgl.prim = GL_NONE; + vgl.begin = vgl.end; + vgl.cur_flags = 0; +} + +void VGL_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) +{ + GLfloat *p = vgl.attrbuf[VGL_ATTR_POS] + vgl.end * 3; + *p++ = x; + *p++ = y; + *p++ = z; + ++vgl.end; + if ( vgl.end >= VGL_MAX_VERTS ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGL_Vertex3f(): Vertex buffer overflow!\n" ); + vgl.end = vgl.begin = 0; + } +} + +void VGL_Vertex2f( GLfloat x, GLfloat y ) +{ + VGL_Vertex3f( x, y, 0.f ); +} + +void VGL_Vertex3fv( const GLfloat *v ) +{ + VGL_Vertex3f( v[0], v[1], v[2] ); +} + +void VGL_Color4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) +{ + vgl.color[0] = r; + vgl.color[1] = g; + vgl.color[2] = b; + vgl.color[3] = a; + vgl.uchanged = GL_TRUE; + if ( vgl.prim ) + { + // HACK: enable color attribute if we're using color inside a Begin-End pair + GLfloat *p = vgl.attrbuf[VGL_ATTR_COLOR] + vgl.end * 4; + vgl.cur_flags |= 1 << VGL_ATTR_COLOR; + *p++ = r; + *p++ = g; + *p++ = b; + *p++ = a; + } +} + +void VGL_Color3f( GLfloat r, GLfloat g, GLfloat b ) +{ + VGL_Color4f( r, g, b, 1.f ); +} + +void VGL_Color4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + VGL_Color4f( (GLfloat)r / 255.f, (GLfloat)g / 255.f, (GLfloat)b / 255.f, (GLfloat)a / 255.f ); +} + +void VGL_Color4ubv( const GLubyte *v ) +{ + VGL_Color4ub( v[0], v[1], v[2], v[3] ); +} + +void VGL_TexCoord2f( GLfloat u, GLfloat v ) +{ + // by spec glTexCoord always updates texunit 0 + GLfloat *p = vgl.attrbuf[VGL_ATTR_TEXCOORD0] + vgl.end * 2; + vgl.cur_flags |= 1 << VGL_ATTR_TEXCOORD0; + *p++ = u; + *p++ = v; +} + +void VGL_MultiTexCoord2f( GLenum tex, GLfloat u, GLfloat v ) +{ + GLfloat *p; + // assume there can only be two + if ( tex == GL_TEXTURE0 ) + { + p = vgl.attrbuf[VGL_ATTR_TEXCOORD0] + vgl.end * 2; + vgl.cur_flags |= 1 << VGL_ATTR_TEXCOORD0; + } + else + { + p = vgl.attrbuf[VGL_ATTR_TEXCOORD1] + vgl.end * 2; + vgl.cur_flags |= 1 << VGL_ATTR_TEXCOORD1; + } + *p++ = u; + *p++ = v; +} + +void VGL_Normal3fv( const GLfloat *v ) +{ + /* not sure if we actually need these */ +} + +void VGL_ShadeModel( GLenum unused ) +{ + /* this doesn't do anything in vitaGL except spit errors in debug mode, so stub it out */ +} + +void VGL_AlphaFunc( GLenum mode, GLfloat ref ) +{ + vgl.alpharef = ref; + vgl.uchanged = GL_TRUE; + // mode is always GL_GREATER +} + +void VGL_DrawBuffer( GLenum mode ) +{ + /* unsupported */ +} + +#define VGL_DECLARE_PTR( name ) extern void *pgl ## name +#define VGL_OVERRIDE_PTR( name ) pgl ## name = VGL_ ## name + +void VGL_ShimInstall( void ) +{ + VGL_DECLARE_PTR( Vertex2f ); + VGL_DECLARE_PTR( Vertex3f ); + VGL_DECLARE_PTR( Vertex3fv ); + VGL_DECLARE_PTR( Color3f ); + VGL_DECLARE_PTR( Color4f ); + VGL_DECLARE_PTR( Color4ub ); + VGL_DECLARE_PTR( Color4ubv ); + VGL_DECLARE_PTR( Normal3fv ); + VGL_DECLARE_PTR( TexCoord2f ); + VGL_DECLARE_PTR( MultiTexCoord2f ); + VGL_DECLARE_PTR( ShadeModel ); + VGL_DECLARE_PTR( DrawBuffer ); + VGL_DECLARE_PTR( AlphaFunc ); + VGL_DECLARE_PTR( Begin ); + VGL_DECLARE_PTR( End ); + VGL_OVERRIDE_PTR( Vertex2f ); + VGL_OVERRIDE_PTR( Vertex3f ); + VGL_OVERRIDE_PTR( Vertex3fv ); + VGL_OVERRIDE_PTR( Color3f ); + VGL_OVERRIDE_PTR( Color4f ); + VGL_OVERRIDE_PTR( Color4ub ); + VGL_OVERRIDE_PTR( Color4ubv ); + VGL_OVERRIDE_PTR( Normal3fv ); + VGL_OVERRIDE_PTR( TexCoord2f ); + VGL_OVERRIDE_PTR( MultiTexCoord2f ); + VGL_OVERRIDE_PTR( ShadeModel ); + VGL_OVERRIDE_PTR( DrawBuffer ); + VGL_OVERRIDE_PTR( AlphaFunc ); + VGL_OVERRIDE_PTR( Begin ); + VGL_OVERRIDE_PTR( End ); +} diff --git a/utils/vgl_shim/vgl_shim.h b/utils/vgl_shim/vgl_shim.h new file mode 100644 index 00000000..09fe26b7 --- /dev/null +++ b/utils/vgl_shim/vgl_shim.h @@ -0,0 +1,24 @@ +/* +vgl_shim.h - vitaGL custom immediate mode shim +Copyright (C) 2023 fgsfds + +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. +*/ + +#pragma once + +// max verts in a single frame +#define VGL_MAX_VERTS 16384 + +int VGL_ShimInit( void ); +void VGL_ShimInstall( void ); +void VGL_ShimShutdown( void ); +void VGL_ShimEndFrame( void ); diff --git a/utils/vgl_shim/wscript b/utils/vgl_shim/wscript new file mode 100644 index 00000000..13926864 --- /dev/null +++ b/utils/vgl_shim/wscript @@ -0,0 +1,25 @@ +#! /usr/bin/env python +# encoding: utf-8 + +import os + +def options(opt): + pass + +def configure(conf): + conf.define('REF_DLL', 1) + +def build(bld): + source = bld.path.ant_glob( [ '*.c' ] ) + includes = [ '.' ] + libs = [ 'engine_includes', 'sdk_includes' ] + bld.env.LDFLAGS += ['-fPIC'] + bld.env.CFLAGS += ['-fPIC'] + bld.stlib( + source = source, + target = 'vgl_shim', + features = 'c', + includes = includes, + use = libs, + subsystem = bld.env.MSVC_SUBSYSTEM + ) diff --git a/wscript b/wscript index c327ea8b..d03d7705 100644 --- a/wscript +++ b/wscript @@ -55,6 +55,9 @@ SUBDIRS = [ # enabled optionally Subproject('utils/mdldec', lambda x: x.env.ENABLE_UTILS), Subproject('utils/run-fuzzer', lambda x: x.env.ENABLE_FUZZER), + + # enabled on PSVita only + Subproject('utils/vgl_shim', lambda x: x.env.DEST_OS == 'psvita'), ] def options(opt):