From: havoc Date: Tue, 10 Sep 2002 22:27:59 +0000 (+0000) Subject: optimizing R_DrawSurfaces and WorldNode functions X-Git-Tag: RELEASE_0_2_0_RC1~256 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=6d8a43b977296dbaee1af8a032ad3fa8e41700dd;p=xonotic%2Fdarkplaces.git optimizing R_DrawSurfaces and WorldNode functions visframe and pvsframe are now arrays rather than part of the surface struct, resulting in less cache misses git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2350 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_rsurf.c b/gl_rsurf.c index 5f23baaa..b98ff500 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -31,12 +31,11 @@ static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4]; cvar_t r_ambient = {0, "r_ambient", "0"}; cvar_t r_vertexsurfaces = {0, "r_vertexsurfaces", "0"}; cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"}; -//cvar_t r_drawportals = {0, "r_drawportals", "0"}; +cvar_t r_drawportals = {0, "r_drawportals", "0"}; cvar_t r_testvis = {0, "r_testvis", "0"}; cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"}; cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"}; cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"}; -cvar_t r_cullsurface = {0, "r_cullsurface", "0"}; static int dlightdivtable[32768]; @@ -44,7 +43,6 @@ static int dlightdivtable[32768]; int r_pvsframecount = 0; mleaf_t *r_pvsviewleaf = NULL; int r_pvsviewleafnovis = 0; -msurface_t *r_pvsfirstsurface = NULL; static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) { @@ -1421,7 +1419,7 @@ Cshader_t *Cshaders[4] = void R_DrawSurfaces(entity_render_t *ent, int sky, int normal) { - int i, alttextures, texframe, framecount, numtextures, numsurfaces; + int i, alttextures, texframe, framecount, numtextures, numsurfaces, *surfacevisframes; texture_t *t, *textures; model_t *model; msurface_t *surf, *surfaces; @@ -1430,6 +1428,10 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal) if (!ent->model) return; + // mark the surfaces touched by dynamic lights + if (normal && r_dynamic.integer) + R_MarkLights(ent); + R_Mesh_Matrix(&ent->matrix); model = ent->model; @@ -1438,79 +1440,59 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal) Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg); - textures = model->textures; numtextures = model->numtextures; - surfaces = model->surfaces + model->firstmodelsurface; + textures = model->textures; numsurfaces = model->nummodelsurfaces; + surfaces = model->surfaces + model->firstmodelsurface; + surfacevisframes = model->surfacevisframes + model->firstmodelsurface; for (i = 0;i < numtextures;i++) textures[i].surfacechain = NULL; for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++) { - if (surf->visframe == r_framecount) + if (surfacevisframes[i] == r_framecount) { +#if !WORLDNODECULLBACKFACES // mark any backface surfaces as not visible if (PlaneDist(modelorg, surf->plane) < surf->plane->dist) { if (!(surf->flags & SURF_PLANEBACK)) - surf->visframe = -1; + surfacevisframes[i] = -1; } else { - if (surf->flags & SURF_PLANEBACK) - surf->visframe = -1; + if ((surf->flags & SURF_PLANEBACK)) + surfacevisframes[i] = -1; } - if (surf->visframe == r_framecount) + if (surfacevisframes[i] == r_framecount) +#endif { - if (r_cullsurface.integer && R_CullBox (surf->poly_mins, surf->poly_maxs)) - surf->visframe = -1; - else + c_faces++; + t = surf->texinfo->texture; + if (t->animated) { - c_faces++; - t = surf->texinfo->texture; - if (t->animated) - { - framecount = t->anim_total[alttextures]; - if (framecount >= 2) - t = t->anim_frames[alttextures][texframe % framecount]; - else - t = t->anim_frames[alttextures][0]; - } - surf->currenttexture = t; - surf->texturechain = t->surfacechain; - t->surfacechain = surf; + framecount = t->anim_total[alttextures]; + if (framecount >= 2) + t = t->anim_frames[alttextures][texframe % framecount]; + else + t = t->anim_frames[alttextures][0]; } - } - } - } - - if (sky) - for (i = 0, t = textures;i < numtextures;i++, t++) - if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY]) - t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t); - - if (normal) - { - if (r_dynamic.integer) - R_MarkLights(ent); - - if (!r_vertexsurfaces.integer) - { - for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++) - { - if (surf->visframe == r_framecount && surf->lightmaptexture != NULL) + surf->currenttexture = t; + surf->texturechain = t->surfacechain; + t->surfacechain = surf; + if (surf->lightmaptexture != NULL) { if (surf->cached_dlight - || surf->cached_ambient != r_ambient.value - || surf->cached_lightscalebit != lightscalebit) + || surf->cached_ambient != r_ambient.value + || surf->cached_lightscalebit != lightscalebit) R_BuildLightMap(ent, surf, false); // base lighting changed else if (r_dynamic.integer) { if (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0] - || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1] - || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2] - || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3])))))))) + || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1] + || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2] + || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3])))))))) R_BuildLightMap(ent, surf, false); // base lighting changed else if (surf->dlightframe == r_framecount && r_dlightmap.integer) R_BuildLightMap(ent, surf, true); // only dlights @@ -1518,14 +1500,19 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal) } } } + } + if (sky) + for (i = 0, t = textures;i < numtextures;i++, t++) + if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY]) + t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t); + + if (normal) for (i = 0, t = textures;i < numtextures;i++, t++) if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_NORMAL]) t->shader->shaderfunc[SHADERSTAGE_NORMAL](ent, t); - } } -/* static void R_DrawPortal_Callback(const void *calldata1, int calldata2) { int i; @@ -1540,14 +1527,14 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2) R_Mesh_Matrix(&ent->matrix); R_Mesh_State(&m); R_Mesh_ResizeCheck(portal->numpoints, portal->numpoints - 2); - for (i = 0;i < mesh->numtriangles;i++) + for (i = 0;i < portal->numpoints - 2;i++) { varray_element[i * 3 + 0] = 0; varray_element[i * 3 + 1] = i + 1; varray_element[i * 3 + 2] = i + 2; } i = portal - ent->model->portals; - R_FillColors(varray_color, mesh->numverts, + R_FillColors(varray_color, portal->numpoints, ((i & 0x0007) >> 0) * (1.0f / 7.0f) * mesh_colorscale, ((i & 0x0038) >> 3) * (1.0f / 7.0f) * mesh_colorscale, ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * mesh_colorscale, @@ -1574,7 +1561,7 @@ static void R_DrawPortals(entity_render_t *ent) for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++) { - if (portal->here->visframe == r_framecount || portal->past->visframe == r_framecount) + if (portal->here->pvsframe == r_pvsframecount || portal->past->pvsframe == r_pvsframecount) { VectorClear(temp); for (i = 0;i < portal->numpoints;i++) @@ -1586,36 +1573,90 @@ static void R_DrawPortals(entity_render_t *ent) } } } -*/ void R_DrawBrushModel(entity_render_t *ent, int sky, int normal) { - int i; + int i, numsurfaces, *surfacevisframes, *surfacepvsframes; msurface_t *surf; model_t *model; +#if WORLDNODECULLBACKFACES vec3_t modelorg; +#endif // because bmodels can be reused, we have to decide which things to render // from scratch every time model = ent->model; +#if WORLDNODECULLBACKFACES Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg); - for (i = 0;i < model->nummodelsurfaces;i++) +#endif + numsurfaces = model->nummodelsurfaces; + surf = model->surfaces + model->firstmodelsurface; + surfacevisframes = model->surfacevisframes + model->firstmodelsurface; + surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface; + for (i = 0;i < numsurfaces;i++, surf++) { - surf = model->surfaces + model->firstmodelsurface + i; - surf->visframe = r_framecount; - surf->pvsframe = -1; - surf->worldnodeframe = -1; - surf->lightframe = -1; +#if WORLDNODECULLBACKFACES + // mark any backface surfaces as not visible + if (PlaneDist(modelorg, surf->plane) < surf->plane->dist) + { + if ((surf->flags & SURF_PLANEBACK)) + { + surfacevisframes[i] = r_framecount; + surfacepvsframes[i] = r_pvsframecount; + } + } + else + { + if (!(surf->flags & SURF_PLANEBACK)) + { + surfacevisframes[i] = r_framecount; + surfacepvsframes[i] = r_pvsframecount; + } + } +#else + surfacevisframes[i] = r_framecount; + surfacepvsframes[i] = r_pvsframecount; +#endif surf->dlightframe = -1; } R_DrawSurfaces(ent, sky, normal); } -void R_SurfaceWorldNode (void) +void R_SurfaceWorldNode (entity_render_t *ent) { - msurface_t *surf; - for (surf = r_pvsfirstsurface;surf;surf = surf->pvschain) - surf->visframe = r_framecount; + int i, numsurfaces, *surfacevisframes, *surfacepvsframes; + msurface_t *surfaces, *surf; + model_t *model; + vec3_t modelorg; + + model = ent->model; + numsurfaces = model->nummodelsurfaces; + surfaces = model->surfaces + model->firstmodelsurface; + surfacevisframes = model->surfacevisframes + model->firstmodelsurface; + surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface; + Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg); + + for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++) + { + if (surfacepvsframes[i] == r_pvsframecount) + { +#if WORLDNODECULLBACKFACES + if (PlaneDist(modelorg, surf->plane) < surf->plane->dist) + { + if ((surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs)) + surfacevisframes[i] = r_framecount; + } + else + { + if (!(surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs)) + surfacevisframes[i] = r_framecount; + } +#else + if (R_NotCulledBox (surf->poly_mins, surf->poly_maxs)) + surfacevisframes[i] = r_framecount; +#endif + } + } } /* @@ -1681,15 +1722,21 @@ loc1: static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { - int c, leafstackpos; + int c, leafstackpos, *mark, *surfacevisframes; +#if WORLDNODECULLBACKFACES + int n; + msurface_t *surf; +#endif mleaf_t *leaf, *leafstack[8192]; mportal_t *p; - msurface_t **mark; vec3_t modelorg; + msurface_t *surfaces; // LordHavoc: portal-passage worldnode with PVS; // follows portals leading outward from viewleaf, does not venture // offscreen or into leafs that are not visible, faster than Quake's // RecursiveWorldNode + surfaces = ent->model->surfaces; + surfacevisframes = ent->model->surfacevisframes; Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg); viewleaf->worldnodeframe = r_framecount; leafstack[0] = viewleaf; @@ -1698,12 +1745,32 @@ static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { c_leafs++; leaf = leafstack[--leafstackpos]; - // only useful for drawing portals - //leaf->visframe = r_framecount; // draw any surfaces bounding this leaf if (leaf->nummarksurfaces) + { for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--) - (*mark++)->visframe = r_framecount; + { +#if WORLDNODECULLBACKFACES + n = *mark++; + if (surfacevisframes[n] != r_framecount) + { + surf = surfaces + n; + if (PlaneDist(modelorg, surf->plane) < surf->plane->dist) + { + if ((surf->flags & SURF_PLANEBACK)) + surfacevisframes[n] = r_framecount; + } + else + { + if (!(surf->flags & SURF_PLANEBACK)) + surfacevisframes[n] = r_framecount; + } + } +#else + surfacevisframes[*mark++] = r_framecount; +#endif + } + } // follow portals into other leafs for (p = leaf->portals;p;p = p->next) { @@ -1717,17 +1784,16 @@ static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) } } } - //if (r_drawportals.integer) - // R_DrawPortals(ent); + if (r_drawportals.integer) + R_DrawPortals(ent); } void R_PVSUpdate (mleaf_t *viewleaf) { - int i, j, l, c, bits; + int i, j, l, c, bits, *surfacepvsframes, *mark; mleaf_t *leaf; qbyte *vis; - msurface_t **mark, *surf; if (r_pvsviewleaf == viewleaf && r_pvsviewleafnovis == r_novis.integer) return; @@ -1738,6 +1804,7 @@ void R_PVSUpdate (mleaf_t *viewleaf) if (viewleaf) { + surfacepvsframes = cl.worldmodel->surfacepvsframes; vis = Mod_LeafPVS (viewleaf, cl.worldmodel); for (j = 0;j < cl.worldmodel->numleafs;j += 8) { @@ -1755,23 +1822,11 @@ void R_PVSUpdate (mleaf_t *viewleaf) leaf->pvsframe = r_pvsframecount; // mark surfaces bounding this leaf as visible for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--) - (*mark++)->pvsframe = r_pvsframecount; + surfacepvsframes[*mark++] = r_pvsframecount; } } } } - // build pvs surfacechain - r_pvsfirstsurface = NULL; - mark = &r_pvsfirstsurface; - for (c = cl.worldmodel->nummodelsurfaces, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;c;c--, surf++) - { - if (surf->pvsframe == r_pvsframecount) - { - *mark = surf; - mark = &surf->pvschain; - } - } - *mark = NULL; } } @@ -1788,7 +1843,7 @@ void R_DrawWorld (entity_render_t *ent) if (!viewleaf) return; if (r_surfaceworldnode.integer || viewleaf->contents == CONTENTS_SOLID) - R_SurfaceWorldNode (); + R_SurfaceWorldNode (ent); else R_PortalWorldNode (ent, viewleaf); R_DrawSurfaces(ent, true, true); @@ -1824,7 +1879,6 @@ static void gl_surf_newmap(void) r_pvsframecount = 1; r_pvsviewleaf = NULL; r_pvsviewleafnovis = false; - r_pvsfirstsurface = NULL; } void GL_Surf_Init(void) @@ -1837,12 +1891,11 @@ void GL_Surf_Init(void) Cvar_RegisterVariable(&r_ambient); Cvar_RegisterVariable(&r_vertexsurfaces); Cvar_RegisterVariable(&r_dlightmap); - //Cvar_RegisterVariable(&r_drawportals); + Cvar_RegisterVariable(&r_drawportals); Cvar_RegisterVariable(&r_testvis); Cvar_RegisterVariable(&r_floatbuildlightmap); Cvar_RegisterVariable(&r_detailtextures); Cvar_RegisterVariable(&r_surfaceworldnode); - Cvar_RegisterVariable(&r_cullsurface); R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap); } diff --git a/model_brush.c b/model_brush.c index 785ef2d0..b9667414 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1287,9 +1287,12 @@ static void Mod_LoadFaces (lump_t *l) loadmodel->surfaces = out; loadmodel->numsurfaces = count; + loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); for (surfnum = 0;surfnum < count;surfnum++, in++, out++) { + out->number = surfnum; // FIXME: validate edges, texinfo, etc? out->firstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); @@ -1599,21 +1602,21 @@ Mod_LoadMarksurfaces */ static void Mod_LoadMarksurfaces (lump_t *l) { - int i, j; - short *in; + int i, j; + short *in; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); loadmodel->nummarksurfaces = l->filelen / sizeof(*in); - loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *)); + loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int)); for (i = 0;i < loadmodel->nummarksurfaces;i++) { j = (unsigned) LittleShort(in[i]); if (j >= loadmodel->numsurfaces) Host_Error ("Mod_ParseMarksurfaces: bad surface number"); - loadmodel->marksurfaces[i] = loadmodel->surfaces + j; + loadmodel->marksurfaces[i] = j; } } diff --git a/model_brush.h b/model_brush.h index 19832c18..26c1c15f 100644 --- a/model_brush.h +++ b/model_brush.h @@ -154,12 +154,14 @@ surfmesh_t; typedef struct msurface_s { + // surface number, to avoid having to do a divide to find the number of a surface from it's address + int number; // should be drawn if visframe == r_framecount (set by WorldNode functions) - int visframe; + //int visframe; // should be drawn if onscreen and not a backface (used for setting visframe) - int pvsframe; + //int pvsframe; // chain of surfaces marked visible by pvs - struct msurface_s *pvschain; + //struct msurface_s *pvschain; // the node plane this is on, backwards if SURF_PLANEBACK flag set mplane_t *plane; @@ -207,7 +209,7 @@ typedef struct msurface_s // avoid redundent addition of dlights int lightframe; // only render each surface once - int worldnodeframe; + //int worldnodeframe; // these cause lightmap updates if regenerated // values currently used in lightmap @@ -266,7 +268,7 @@ typedef struct mleaf_s qbyte *compressed_vis; - msurface_t **firstmarksurface; + int *firstmarksurface; int nummarksurfaces; qbyte ambient_sound_level[NUM_AMBIENTS]; } diff --git a/model_shared.h b/model_shared.h index d0280aa5..d58fc9bc 100644 --- a/model_shared.h +++ b/model_shared.h @@ -143,6 +143,9 @@ typedef struct model_s int numsurfaces; msurface_t *surfaces; + int *surfacevisframes; + int *surfacepvsframes; + msurface_t *surfacepvsnext; int numsurfedges; int *surfedges; @@ -151,7 +154,7 @@ typedef struct model_s dclipnode_t *clipnodes; int nummarksurfaces; - msurface_t **marksurfaces; + int *marksurfaces; hull_t hulls[MAX_MAP_HULLS]; diff --git a/r_light.c b/r_light.c index 57b9cc68..29e88876 100644 --- a/r_light.c +++ b/r_light.c @@ -219,11 +219,12 @@ DYNAMIC LIGHTS R_MarkLights ============= */ +extern int r_pvsframecount; static void R_OldMarkLights (entity_render_t *ent, vec3_t lightorigin, rdlight_t *rd, int bit, int bitindex, mnode_t *node) { float ndist, maxdist; msurface_t *surf; - int i; + int i, *surfacepvsframes; int d, impacts, impactt; float dist, dist2, impact[3]; @@ -233,6 +234,7 @@ static void R_OldMarkLights (entity_render_t *ent, vec3_t lightorigin, rdlight_t // for comparisons to minimum acceptable light maxdist = rd->cullradius2; + surfacepvsframes = ent->model->surfacepvsframes; loc0: if (node->contents < 0) return; @@ -254,7 +256,7 @@ loc0: surf = ent->model->surfaces + node->firstsurface; for (i = 0;i < node->numsurfaces;i++, surf++) { - if (surf->visframe != r_framecount) + if (surfacepvsframes[surf->number] != r_pvsframecount) continue; dist = ndist; if (surf->flags & SURF_PLANEBACK) @@ -329,8 +331,8 @@ static void R_VisMarkLights (entity_render_t *ent, rdlight_t *rd, int bit, int b mleaf_t *pvsleaf; vec3_t lightorigin; model_t *model; - int i, k, m, c, leafnum; - msurface_t *surf, **mark; + int i, k, m, c, leafnum, *surfacepvsframes, *mark; + msurface_t *surf; mleaf_t *leaf; qbyte *in; int row; @@ -363,6 +365,7 @@ static void R_VisMarkLights (entity_render_t *ent, rdlight_t *rd, int bit, int b maxdist = rd->cullradius2; row = (model->numleafs+7)>>3; + surfacepvsframes = model->surfacepvsframes; k = 0; while (k < row) @@ -388,12 +391,12 @@ static void R_VisMarkLights (entity_render_t *ent, rdlight_t *rd, int bit, int b mark = leaf->firstmarksurface; do { - surf = *mark++; + surf = model->surfaces + *mark++; // if not visible in current frame, or already marked because it was in another leaf we passed, skip if (surf->lightframe == lightframe) continue; surf->lightframe = lightframe; - if (surf->visframe != r_framecount) + if (surfacepvsframes[surf->number] != r_pvsframecount) continue; dist = PlaneDiff(lightorigin, surf->plane); if (surf->flags & SURF_PLANEBACK)