Merge surface mark & cull optimization from vkQuake

* Remove separate surface culling pass. Instead always build texture chains every frame & cull in mark surfaces.
* Optimize R_CullBox & R_BackFaceCull
This commit is contained in:
Axel Gneiting 2021-07-07 23:55:50 +03:00 committed by Ozkan Sezer
parent d6e68b6f19
commit 3fc32bf7fe
6 changed files with 173 additions and 339 deletions

View file

@ -140,7 +140,6 @@ typedef struct glpoly_s
typedef struct msurface_s typedef struct msurface_s
{ {
int visframe; // should be drawn when node is crossed int visframe; // should be drawn when node is crossed
qboolean culled; // johnfitz -- for frustum culling
float mins[3]; // johnfitz -- for frustum culling float mins[3]; // johnfitz -- for frustum culling
float maxs[3]; // johnfitz -- for frustum culling float maxs[3]; // johnfitz -- for frustum culling

View file

@ -272,48 +272,21 @@ qboolean R_CullBox (vec3_t emins, vec3_t emaxs)
{ {
int i; int i;
mplane_t *p; mplane_t *p;
byte signbits;
float vec[3];
for (i = 0;i < 4;i++) for (i = 0;i < 4;i++)
{ {
p = frustum + i; p = frustum + i;
switch(p->signbits) signbits = p->signbits;
{ vec[0] = ((signbits % 2)<1) ? emaxs[0] : emins[0];
default: vec[1] = ((signbits % 4)<2) ? emaxs[1] : emins[1];
case 0: vec[2] = ((signbits % 8)<4) ? emaxs[2] : emins[2];
if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist) if (p->normal[0]*vec[0] + p->normal[1]*vec[1] + p->normal[2]*vec[2] < p->dist)
return true; return true;
break;
case 1:
if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist)
return true;
break;
case 2:
if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist)
return true;
break;
case 3:
if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist)
return true;
break;
case 4:
if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist)
return true;
break;
case 5:
if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist)
return true;
break;
case 6:
if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist)
return true;
break;
case 7:
if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist)
return true;
break;
}
} }
return false; return false;
} }
/* /*
=============== ===============
R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation
@ -585,8 +558,6 @@ void R_SetupView (void)
R_MarkSurfaces (); //johnfitz -- create texture chains from PVS R_MarkSurfaces (); //johnfitz -- create texture chains from PVS
R_CullSurfaces (); //johnfitz -- do after R_SetFrustum and R_MarkSurfaces
R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear
R_Clear (); R_Clear ();

View file

@ -86,17 +86,6 @@ static void R_SetClearColor_f (cvar_t *var)
glClearColor (rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0,0); glClearColor (rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0,0);
} }
/*
====================
R_Novis_f -- johnfitz
====================
*/
static void R_VisChanged (cvar_t *var)
{
extern int vis_changed;
vis_changed = 1;
}
/* /*
=============== ===============
R_Model_ExtraFlags_List_f -- johnfitz -- called when r_nolerp_list or r_noshadow_list cvar changes R_Model_ExtraFlags_List_f -- johnfitz -- called when r_nolerp_list or r_noshadow_list cvar changes
@ -189,7 +178,6 @@ void R_Init (void)
Cvar_SetCallback (&r_wateralpha, R_SetWateralpha_f); Cvar_SetCallback (&r_wateralpha, R_SetWateralpha_f);
Cvar_RegisterVariable (&r_dynamic); Cvar_RegisterVariable (&r_dynamic);
Cvar_RegisterVariable (&r_novis); Cvar_RegisterVariable (&r_novis);
Cvar_SetCallback (&r_novis, R_VisChanged);
Cvar_RegisterVariable (&r_speeds); Cvar_RegisterVariable (&r_speeds);
Cvar_RegisterVariable (&r_pos); Cvar_RegisterVariable (&r_pos);
@ -214,7 +202,6 @@ void R_Init (void)
Cvar_RegisterVariable (&r_drawflat); Cvar_RegisterVariable (&r_drawflat);
Cvar_RegisterVariable (&r_flatlightstyles); Cvar_RegisterVariable (&r_flatlightstyles);
Cvar_RegisterVariable (&r_oldskyleaf); Cvar_RegisterVariable (&r_oldskyleaf);
Cvar_SetCallback (&r_oldskyleaf, R_VisChanged);
Cvar_RegisterVariable (&r_drawworld); Cvar_RegisterVariable (&r_drawworld);
Cvar_RegisterVariable (&r_showtris); Cvar_RegisterVariable (&r_showtris);
Cvar_RegisterVariable (&r_showbboxes); Cvar_RegisterVariable (&r_showbboxes);
@ -595,6 +582,7 @@ void R_DeleteShaders (void)
} }
gl_num_programs = 0; gl_num_programs = 0;
} }
GLuint current_array_buffer, current_element_array_buffer; GLuint current_array_buffer, current_element_array_buffer;
/* /*

View file

@ -550,7 +550,6 @@ void Sky_ProcessTextureChains (void)
continue; continue;
for (s = t->texturechains[chain_world]; s; s = s->texturechain) for (s = t->texturechains[chain_world]; s; s = s->texturechain)
if (!s->culled)
Sky_ProcessPoly (s->polys); Sky_ProcessPoly (s->polys);
} }
} }
@ -983,7 +982,7 @@ void Sky_DrawSky (void)
int i; int i;
//in these special render modes, the sky faces are handled in the normal world/brush renderer //in these special render modes, the sky faces are handled in the normal world/brush renderer
if (r_drawflat_cheatsafe || r_lightmap_cheatsafe ) if (r_drawflat_cheatsafe || r_lightmap_cheatsafe)
return; return;
// //
@ -1020,7 +1019,7 @@ void Sky_DrawSky (void)
if (skybox_name[0]) if (skybox_name[0])
Sky_DrawSkyBox (); Sky_DrawSkyBox ();
else else
Sky_DrawSkyLayers(); Sky_DrawSkyLayers ();
glDepthMask(1); glDepthMask(1);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);

View file

@ -341,7 +341,6 @@ void R_NewGame (void);
void R_AnimateLight (void); void R_AnimateLight (void);
void R_MarkSurfaces (void); void R_MarkSurfaces (void);
void R_CullSurfaces (void);
qboolean R_CullBox (vec3_t emins, vec3_t emaxs); qboolean R_CullBox (vec3_t emins, vec3_t emaxs);
void R_StoreEfrags (efrag_t **ppefrag); void R_StoreEfrags (efrag_t **ppefrag);
qboolean R_CullModelForEntity (entity_t *e); qboolean R_CullModelForEntity (entity_t *e);

View file

@ -28,8 +28,6 @@ extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskylea
byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel); byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel);
int vis_changed; //if true, force pvs to be refreshed
//============================================================================== //==============================================================================
// //
// SETUP CHAINS // SETUP CHAINS
@ -69,6 +67,26 @@ void R_ChainSurface (msurface_t *surf, texchain_t chain)
surf->texinfo->texture->texturechains[chain] = surf; surf->texinfo->texture->texturechains[chain] = surf;
} }
/*
================
R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg
================
*/
qboolean R_BackFaceCull (msurface_t *surf)
{
double dot;
if (surf->plane->type < 3)
dot = r_refdef.vieworg[surf->plane->type] - surf->plane->dist;
else
dot = DotProduct (r_refdef.vieworg, surf->plane->normal) - surf->plane->dist;
if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
return true;
return false;
}
/* /*
=============== ===============
R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains
@ -78,7 +96,6 @@ void R_MarkSurfaces (void)
{ {
byte *vis; byte *vis;
mleaf_t *leaf; mleaf_t *leaf;
mnode_t *node;
msurface_t *surf, **mark; msurface_t *surf, **mark;
int i, j; int i, j;
qboolean nearwaterportal; qboolean nearwaterportal;
@ -102,20 +119,12 @@ void R_MarkSurfaces (void)
else else
vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
// if surface chains don't need regenerating, just add static entities and return
if (r_oldviewleaf == r_viewleaf && !vis_changed && !nearwaterportal)
{
leaf = &cl.worldmodel->leafs[1];
for (i=0 ; i<cl.worldmodel->numleafs ; i++, leaf++)
if (vis[i>>3] & (1<<(i&7)))
if (leaf->efrags)
R_StoreEfrags (&leaf->efrags);
return;
}
vis_changed = false;
r_visframecount++; r_visframecount++;
r_oldviewleaf = r_viewleaf;
// set all chains to null
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
if (cl.worldmodel->textures[i])
cl.worldmodel->textures[i]->texturechains[chain_world] = NULL;
// iterate through leaves, marking surfaces // iterate through leaves, marking surfaces
leaf = &cl.worldmodel->leafs[1]; leaf = &cl.worldmodel->leafs[1];
@ -123,145 +132,32 @@ void R_MarkSurfaces (void)
{ {
if (vis[i>>3] & (1<<(i&7))) if (vis[i>>3] & (1<<(i&7)))
{ {
if (R_CullBox(leaf->minmaxs, leaf->minmaxs + 3))
continue;
if (r_oldskyleaf.value || leaf->contents != CONTENTS_SKY) if (r_oldskyleaf.value || leaf->contents != CONTENTS_SKY)
for (j=0, mark = leaf->firstmarksurface; j<leaf->nummarksurfaces; j++, mark++) for (j=0, mark = leaf->firstmarksurface; j<leaf->nummarksurfaces; j++, mark++)
(*mark)->visframe = r_visframecount; {
surf = *mark;
if (surf->visframe != r_visframecount)
{
surf->visframe = r_visframecount;
if (!R_CullBox(surf->mins, surf->maxs) && !R_BackFaceCull (surf))
{
rs_brushpolys++; //count wpolys here
R_ChainSurface(surf, chain_world);
R_RenderDynamicLightmaps(surf);
if (surf->texinfo->texture->warpimage)
surf->texinfo->texture->update_warp = true;
}
}
}
// add static models // add static models
if (leaf->efrags) if (leaf->efrags)
R_StoreEfrags (&leaf->efrags); R_StoreEfrags (&leaf->efrags);
} }
} }
// set all chains to null
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
if (cl.worldmodel->textures[i])
cl.worldmodel->textures[i]->texturechains[chain_world] = NULL;
// rebuild chains
#if 1
//iterate through surfaces one node at a time to rebuild chains
//need to do it this way if we want to work with tyrann's skip removal tool
//becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump
//nor does it remove references to them in each leaf's marksurfaces list
for (i=0, node = cl.worldmodel->nodes ; i<cl.worldmodel->numnodes ; i++, node++)
for (j=0, surf=&cl.worldmodel->surfaces[node->firstsurface] ; j<node->numsurfaces ; j++, surf++)
if (surf->visframe == r_visframecount)
{
R_ChainSurface(surf, chain_world);
}
#else
//the old way
surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
for (i=0 ; i<cl.worldmodel->nummodelsurfaces ; i++, surf++)
{
if (surf->visframe == r_visframecount)
{
R_ChainSurface(surf, chain_world);
}
}
#endif
}
/*
================
R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg
================
*/
qboolean R_BackFaceCull (msurface_t *surf)
{
double dot;
switch (surf->plane->type)
{
case PLANE_X:
dot = r_refdef.vieworg[0] - surf->plane->dist;
break;
case PLANE_Y:
dot = r_refdef.vieworg[1] - surf->plane->dist;
break;
case PLANE_Z:
dot = r_refdef.vieworg[2] - surf->plane->dist;
break;
default:
dot = DotProduct (r_refdef.vieworg, surf->plane->normal) - surf->plane->dist;
break;
}
if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
return true;
return false;
}
/*
================
R_CullSurfaces -- johnfitz
================
*/
void R_CullSurfaces (void)
{
msurface_t *s;
int i;
texture_t *t;
if (!r_drawworld_cheatsafe)
return;
// ericw -- instead of testing (s->visframe == r_visframecount) on all world
// surfaces, use the chained surfaces, which is exactly the same set of sufaces
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
{
t = cl.worldmodel->textures[i];
if (!t || !t->texturechains[chain_world])
continue;
for (s = t->texturechains[chain_world]; s; s = s->texturechain)
{
if (R_CullBox(s->mins, s->maxs) || R_BackFaceCull (s))
s->culled = true;
else
{
s->culled = false;
rs_brushpolys++; //count wpolys here
if (s->texinfo->texture->warpimage)
s->texinfo->texture->update_warp = true;
}
}
}
}
/*
================
R_BuildLightmapChains -- johnfitz -- used for r_lightmap 1
ericw -- now always used at the start of R_DrawTextureChains for the
mh dynamic lighting speedup
================
*/
void R_BuildLightmapChains (qmodel_t *model, texchain_t chain)
{
texture_t *t;
msurface_t *s;
int i;
// clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo)
for (i=0 ; i<lightmap_count ; i++)
lightmaps[i].polys = NULL;
// now rebuild them
for (i=0 ; i<model->numtextures ; i++)
{
t = model->textures[i];
if (!t || !t->texturechains[chain])
continue;
for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
R_RenderDynamicLightmaps (s);
}
} }
//============================================================================== //==============================================================================
@ -323,7 +219,6 @@ void R_DrawTextureChains_ShowTris (qmodel_t *model, texchain_t chain)
if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB)) if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
{ {
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
for (p = s->polys->next; p; p = p->next) for (p = s->polys->next; p; p = p->next)
{ {
DrawGLTriangleFan (p); DrawGLTriangleFan (p);
@ -332,7 +227,6 @@ void R_DrawTextureChains_ShowTris (qmodel_t *model, texchain_t chain)
else else
{ {
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
DrawGLTriangleFan (s->polys); DrawGLTriangleFan (s->polys);
} }
@ -361,7 +255,6 @@ void R_DrawTextureChains_Drawflat (qmodel_t *model, texchain_t chain)
if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB)) if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
{ {
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
for (p = s->polys->next; p; p = p->next) for (p = s->polys->next; p; p = p->next)
{ {
srand((unsigned int) (uintptr_t) p); srand((unsigned int) (uintptr_t) p);
@ -373,7 +266,6 @@ void R_DrawTextureChains_Drawflat (qmodel_t *model, texchain_t chain)
else else
{ {
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
srand((unsigned int) (uintptr_t) s->polys); srand((unsigned int) (uintptr_t) s->polys);
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
@ -409,7 +301,6 @@ void R_DrawTextureChains_Glow (qmodel_t *model, entity_t *ent, texchain_t chain)
bound = false; bound = false;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -526,7 +417,6 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_
bound = false; bound = false;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -581,7 +471,6 @@ void R_DrawTextureChains_NoTexture (qmodel_t *model, texchain_t chain)
bound = false; bound = false;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -616,7 +505,6 @@ void R_DrawTextureChains_TextureOnly (qmodel_t *model, entity_t *ent, texchain_t
bound = false; bound = false;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -680,7 +568,6 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain
bound = false; bound = false;
entalpha = 1.0f; entalpha = 1.0f;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -708,7 +595,6 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain
bound = false; bound = false;
entalpha = 1.0f; entalpha = 1.0f;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -754,7 +640,6 @@ void R_DrawTextureChains_White (qmodel_t *model, texchain_t chain)
continue; continue;
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
DrawGLPoly (s->polys); DrawGLPoly (s->polys);
rs_brushpasses++; rs_brushpasses++;
@ -971,7 +856,6 @@ void R_DrawTextureChains_GLSL (qmodel_t *model, entity_t *ent, texchain_t chain)
bound = false; bound = false;
lastlightmap = 0; // avoid compiler warning lastlightmap = 0; // avoid compiler warning
for (s = t->texturechains[chain]; s; s = s->texturechain) for (s = t->texturechains[chain]; s; s = s->texturechain)
if (!s->culled)
{ {
if (!bound) //only bind once we are sure we need this texture if (!bound) //only bind once we are sure we need this texture
{ {
@ -1031,12 +915,6 @@ void R_DrawTextureChains (qmodel_t *model, entity_t *ent, texchain_t chain)
else else
entalpha = 1; entalpha = 1;
// ericw -- the mh dynamic lightmap speedup: make a first pass through all
// surfaces we are going to draw, and rebuild any lightmaps that need it.
// this also chains surfaces by lightmap which is used by r_lightmap 1.
// the previous implementation of the speedup uploaded lightmaps one frame
// late which was visible under some conditions, this method avoids that.
R_BuildLightmapChains (model, chain);
R_UploadLightmaps (); R_UploadLightmaps ();
if (r_drawflat_cheatsafe) if (r_drawflat_cheatsafe)