mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-02-02 22:11:22 +00:00
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt. Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo". Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower. git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
parent
b2c3363718
commit
e0680cb6d3
6 changed files with 267 additions and 14 deletions
|
@ -156,6 +156,8 @@ typedef struct msurface_s
|
|||
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
int vbo_firstvert; // index of this surface's first vert in the VBO
|
||||
|
||||
// lighting info
|
||||
int dlightframe;
|
||||
unsigned int dlightbits[(MAX_DLIGHTS + 31) >> 5];
|
||||
|
|
|
@ -273,6 +273,7 @@ void R_NewMap (void)
|
|||
R_ClearParticles ();
|
||||
|
||||
GL_BuildLightmaps ();
|
||||
GL_BuildVBOs ();
|
||||
|
||||
r_framecount = 0; //johnfitz -- paranoid?
|
||||
r_visframecount = 0; //johnfitz -- paranoid?
|
||||
|
|
|
@ -92,9 +92,15 @@ qboolean gl_swap_control = false; //johnfitz
|
|||
qboolean gl_anisotropy_able = false; //johnfitz
|
||||
float gl_max_anisotropy; //johnfitz
|
||||
qboolean gl_texture_NPOT = false; //ericw
|
||||
qboolean gl_vbo_able = false; //ericw
|
||||
|
||||
PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc = NULL; //johnfitz
|
||||
PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc = NULL; //johnfitz
|
||||
PFNGLCLIENTACTIVETEXTUREARBPROC GL_ClientActiveTextureFunc = NULL; //ericw
|
||||
PFNGLBINDBUFFERARBPROC GL_BindBufferFunc = NULL; //ericw
|
||||
PFNGLBUFFERDATAARBPROC GL_BufferDataFunc = NULL; //ericw
|
||||
PFNGLDELETEBUFFERSARBPROC GL_DeleteBuffersFunc = NULL; //ericw
|
||||
PFNGLGENBUFFERSARBPROC GL_GenBuffersFunc = NULL; //ericw
|
||||
|
||||
//====================================
|
||||
|
||||
|
@ -634,6 +640,7 @@ static void VID_Restart (void)
|
|||
|
||||
GL_Init ();
|
||||
TexMgr_ReloadImages ();
|
||||
GL_BuildVBOs ();
|
||||
GL_SetupState ();
|
||||
|
||||
//warpimages needs to be recalculated
|
||||
|
@ -789,6 +796,28 @@ static void GL_CheckExtensions (void)
|
|||
{
|
||||
int swap_control;
|
||||
|
||||
//
|
||||
// ARB_vertex_buffer_object
|
||||
//
|
||||
if (COM_CheckParm("-novbo"))
|
||||
Con_Warning ("Vertex buffer objects disabled at command line\n");
|
||||
else
|
||||
{
|
||||
GL_BindBufferFunc = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB");
|
||||
GL_BufferDataFunc = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB");
|
||||
GL_DeleteBuffersFunc = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB");
|
||||
GL_GenBuffersFunc = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB");
|
||||
if (GL_BindBufferFunc && GL_BufferDataFunc && GL_DeleteBuffersFunc && GL_GenBuffersFunc)
|
||||
{
|
||||
Con_Printf("FOUND: ARB_vertex_buffer_object\n");
|
||||
gl_vbo_able = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Warning ("ARB_vertex_buffer_object not available\n");
|
||||
}
|
||||
}
|
||||
|
||||
// multitexture
|
||||
//
|
||||
if (COM_CheckParm("-nomtex"))
|
||||
|
@ -797,7 +826,8 @@ static void GL_CheckExtensions (void)
|
|||
{
|
||||
GL_MTexCoord2fFunc = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord2fARB");
|
||||
GL_SelectTextureFunc = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
|
||||
if (GL_MTexCoord2fFunc && GL_SelectTextureFunc)
|
||||
GL_ClientActiveTextureFunc = (PFNGLCLIENTACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glClientActiveTextureARB");
|
||||
if (GL_MTexCoord2fFunc && GL_SelectTextureFunc && GL_ClientActiveTextureFunc)
|
||||
{
|
||||
Con_Printf("FOUND: ARB_multitexture\n");
|
||||
gl_mtexable = true;
|
||||
|
@ -1376,7 +1406,13 @@ void VID_Init (void)
|
|||
// new proc by S.A., called by alt-return key binding.
|
||||
void VID_Toggle (void)
|
||||
{
|
||||
static qboolean vid_toggle_works = true;
|
||||
// disabling the fast path because with SDL 1.2 it invalidates VBOs (using them
|
||||
// causes a crash, sugesting that the fullscreen toggle created a new GL context,
|
||||
// although texture objects remain valid for some reason).
|
||||
//
|
||||
// SDL2 does promise window resizes / fullscreen changes preserve the GL context,
|
||||
// so we could use the fast path with SDL2. --ericw
|
||||
static qboolean vid_toggle_works = false;
|
||||
qboolean toggleWorked;
|
||||
|
||||
S_ClearBuffer ();
|
||||
|
|
|
@ -154,6 +154,7 @@ extern qboolean mtexenabled;
|
|||
extern qboolean gl_mtexable;
|
||||
extern PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc;
|
||||
extern PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc;
|
||||
extern PFNGLCLIENTACTIVETEXTUREARBPROC GL_ClientActiveTextureFunc;
|
||||
|
||||
//johnfitz -- anisotropic filtering
|
||||
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||
|
@ -161,6 +162,14 @@ extern PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc;
|
|||
extern float gl_max_anisotropy;
|
||||
extern qboolean gl_anisotropy_able;
|
||||
|
||||
//ericw -- VBO
|
||||
extern PFNGLBINDBUFFERARBPROC GL_BindBufferFunc;
|
||||
extern PFNGLBUFFERDATAARBPROC GL_BufferDataFunc;
|
||||
extern PFNGLDELETEBUFFERSARBPROC GL_DeleteBuffersFunc;
|
||||
extern PFNGLGENBUFFERSARBPROC GL_GenBuffersFunc;
|
||||
extern qboolean gl_vbo_able;
|
||||
//ericw
|
||||
|
||||
//ericw -- NPOT texture support
|
||||
extern qboolean gl_texture_NPOT;
|
||||
|
||||
|
@ -265,6 +274,7 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain
|
|||
|
||||
void R_RenderDlights (void);
|
||||
void GL_BuildLightmaps (void);
|
||||
void GL_BuildVBOs (void);
|
||||
void R_RebuildAllLightmaps (void);
|
||||
|
||||
int R_LightPoint (vec3_t p);
|
||||
|
|
|
@ -950,6 +950,90 @@ void GL_BuildLightmaps (void)
|
|||
//johnfitz
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================
|
||||
|
||||
VBO support
|
||||
|
||||
=============================================================
|
||||
*/
|
||||
|
||||
static GLuint gl_bmodel_vbo = 0;
|
||||
|
||||
/*
|
||||
==================
|
||||
GL_BuildVBOs
|
||||
|
||||
Deletes gl_bmodel_vbo if it already exists, then rebuilds it with all
|
||||
surfaces from world + all brush models
|
||||
==================
|
||||
*/
|
||||
void GL_BuildVBOs (void)
|
||||
{
|
||||
unsigned int numverts, varray_bytes, varray_index;
|
||||
int i, j;
|
||||
qmodel_t *m;
|
||||
float *varray;
|
||||
|
||||
if (!(gl_vbo_able && gl_mtexable))
|
||||
return;
|
||||
|
||||
// ask GL for a name for our VBO
|
||||
GL_DeleteBuffersFunc (1, &gl_bmodel_vbo);
|
||||
GL_GenBuffersFunc (1, &gl_bmodel_vbo);
|
||||
|
||||
// count all verts in all models
|
||||
numverts = 0;
|
||||
for (j=1 ; j<MAX_MODELS ; j++)
|
||||
{
|
||||
m = cl.model_precache[j];
|
||||
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
numverts += m->surfaces[i].numedges;
|
||||
}
|
||||
}
|
||||
|
||||
// build vertex array
|
||||
varray_bytes = VERTEXSIZE * sizeof(float) * numverts;
|
||||
varray = (float *) malloc (varray_bytes);
|
||||
varray_index = 0;
|
||||
|
||||
for (j=1 ; j<MAX_MODELS ; j++)
|
||||
{
|
||||
m = cl.model_precache[j];
|
||||
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
msurface_t *s = &m->surfaces[i];
|
||||
s->vbo_firstvert = varray_index;
|
||||
memcpy (&varray[VERTEXSIZE * varray_index], s->polys->verts, VERTEXSIZE * sizeof(float) * s->numedges);
|
||||
varray_index += s->numedges;
|
||||
}
|
||||
}
|
||||
|
||||
// upload to GPU
|
||||
GL_BindBufferFunc (GL_ARRAY_BUFFER, gl_bmodel_vbo);
|
||||
GL_BufferDataFunc (GL_ARRAY_BUFFER, varray_bytes, varray, GL_STATIC_DRAW);
|
||||
free (varray);
|
||||
|
||||
// setup vertex array. this will need to move if we use vertex arrays for other things
|
||||
glVertexPointer (3, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0));
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
|
||||
GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB);
|
||||
glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 3);
|
||||
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB);
|
||||
glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 5);
|
||||
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AddDynamicLights
|
||||
|
|
142
Quake/r_world.c
142
Quake/r_world.c
|
@ -410,6 +410,121 @@ void R_DrawTextureChains_Glow (qmodel_t *model, entity_t *ent, texchain_t chain)
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
// VBO SUPPORT
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
R_MultitexturedDrawGLPoly
|
||||
|
||||
Fallback immediate mode code to draw a multitexutred glpoly_t
|
||||
================
|
||||
*/
|
||||
static void R_MultitexturedDrawGLPoly (glpoly_t *p)
|
||||
{
|
||||
float *v;
|
||||
int j;
|
||||
|
||||
glBegin(GL_POLYGON);
|
||||
v = p->verts[0];
|
||||
for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
|
||||
{
|
||||
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]);
|
||||
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]);
|
||||
glVertex3fv (v);
|
||||
}
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
static unsigned int R_NumTriangleIndicesForSurf (msurface_t *s)
|
||||
{
|
||||
return 3 * (s->numedges - 2);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_TriangleIndicesForSurf
|
||||
|
||||
Writes out the triangle indices needed to draw s as a triangle list.
|
||||
The number of indices it will write is given by R_NumTriangleIndicesForSurf.
|
||||
================
|
||||
*/
|
||||
static void R_TriangleIndicesForSurf (msurface_t *s, unsigned int *dest)
|
||||
{
|
||||
int i;
|
||||
for (i=2; i<s->numedges; i++)
|
||||
{
|
||||
*dest++ = s->vbo_firstvert;
|
||||
*dest++ = s->vbo_firstvert + i - 1;
|
||||
*dest++ = s->vbo_firstvert + i;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_BATCH_SIZE 4096
|
||||
|
||||
static unsigned int vbo_indices[MAX_BATCH_SIZE];
|
||||
static unsigned int num_vbo_indices;
|
||||
|
||||
/*
|
||||
================
|
||||
R_ClearBatch
|
||||
================
|
||||
*/
|
||||
static void R_ClearBatch ()
|
||||
{
|
||||
if (!(gl_vbo_able && gl_mtexable)) return;
|
||||
|
||||
num_vbo_indices = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_FlushBatch
|
||||
|
||||
Draw the current batch if non-empty and clears it, ready for more R_BatchSurface calls.
|
||||
================
|
||||
*/
|
||||
static void R_FlushBatch ()
|
||||
{
|
||||
if (!(gl_vbo_able && gl_mtexable)) return;
|
||||
|
||||
if (num_vbo_indices > 0)
|
||||
{
|
||||
glDrawElements (GL_TRIANGLES, num_vbo_indices, GL_UNSIGNED_INT, vbo_indices);
|
||||
num_vbo_indices = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_BatchSurface
|
||||
|
||||
Add the surface to the current batch, or just draw it immediately if we're not
|
||||
using VBOs.
|
||||
================
|
||||
*/
|
||||
static void R_BatchSurface (msurface_t *s)
|
||||
{
|
||||
int num_surf_indices;
|
||||
|
||||
if (!(gl_vbo_able && gl_mtexable))
|
||||
{
|
||||
R_MultitexturedDrawGLPoly (s->polys);
|
||||
return;
|
||||
}
|
||||
|
||||
num_surf_indices = R_NumTriangleIndicesForSurf (s);
|
||||
|
||||
if (num_vbo_indices + num_surf_indices > MAX_BATCH_SIZE)
|
||||
R_FlushBatch();
|
||||
|
||||
R_TriangleIndicesForSurf (s, &vbo_indices[num_vbo_indices]);
|
||||
num_vbo_indices += num_surf_indices;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawTextureChains_Multitexture -- johnfitz
|
||||
|
@ -417,11 +532,11 @@ R_DrawTextureChains_Multitexture -- johnfitz
|
|||
*/
|
||||
void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_t chain)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
msurface_t *s;
|
||||
texture_t *t;
|
||||
float *v;
|
||||
qboolean bound;
|
||||
int lastlightmap;
|
||||
|
||||
for (i=0 ; i<model->numtextures ; i++)
|
||||
{
|
||||
|
@ -430,7 +545,10 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_
|
|||
if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE))
|
||||
continue;
|
||||
|
||||
R_ClearBatch ();
|
||||
|
||||
bound = false;
|
||||
lastlightmap = 0; // avoid compiler warning
|
||||
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
||||
if (!s->culled)
|
||||
{
|
||||
|
@ -443,20 +561,22 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_
|
|||
|
||||
GL_EnableMultitexture(); // selects TEXTURE1
|
||||
bound = true;
|
||||
lastlightmap = s->lightmaptexturenum;
|
||||
}
|
||||
R_RenderDynamicLightmaps (s);
|
||||
|
||||
if (s->lightmaptexturenum != lastlightmap)
|
||||
R_FlushBatch ();
|
||||
|
||||
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
||||
glBegin(GL_POLYGON);
|
||||
v = s->polys->verts[0];
|
||||
for (j=0 ; j<s->polys->numverts ; j++, v+= VERTEXSIZE)
|
||||
{
|
||||
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]);
|
||||
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]);
|
||||
glVertex3fv (v);
|
||||
}
|
||||
glEnd ();
|
||||
lastlightmap = s->lightmaptexturenum;
|
||||
R_BatchSurface (s);
|
||||
|
||||
rs_brushpasses++;
|
||||
}
|
||||
|
||||
R_FlushBatch ();
|
||||
|
||||
GL_DisableMultitexture(); // selects TEXTURE0
|
||||
|
||||
if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
||||
|
|
Loading…
Reference in a new issue