From e041b958c778e823806a22c19cad37e8f9d22210 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Thu, 12 Sep 2019 06:49:35 +0000 Subject: [PATCH] r_brush.c: dynamically allocate lightmaps, from QuakeSpasm-Spike This raises LMBLOCK_WIDTH/HEIGHT from 128 to 256 which should be supported everywhere and decrease draw calls git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1628 af15c1b1-3010-417e-b628-4374ebc0bcbd --- Quake/bspfile.h | 2 + Quake/glquake.h | 18 ++++++- Quake/r_brush.c | 133 +++++++++++++++++++++++------------------------- Quake/r_world.c | 23 +++++---- 4 files changed, 94 insertions(+), 82 deletions(-) diff --git a/Quake/bspfile.h b/Quake/bspfile.h index 6da832f0..ae743e07 100644 --- a/Quake/bspfile.h +++ b/Quake/bspfile.h @@ -228,6 +228,8 @@ typedef struct } dledge_t; #define MAXLIGHTMAPS 4 +#define LMBLOCK_WIDTH 256 //FIXME: make dynamic. if we have a decent card there's no real reason not to use 4k or 16k (assuming there's no lightstyles/dynamics that need uploading...) +#define LMBLOCK_HEIGHT 256 //Alternatively, use texture arrays, which would avoid the need to switch textures as often. typedef struct { short planenum; diff --git a/Quake/glquake.h b/Quake/glquake.h index e9d250ea..5f0971b0 100644 --- a/Quake/glquake.h +++ b/Quake/glquake.h @@ -292,8 +292,22 @@ extern overflowtimes_t dev_overflows; //this stores the last time overflow messa //johnfitz -- moved here from r_brush.c extern int gl_lightmap_format, lightmap_bytes; -#define MAX_LIGHTMAPS 512 //johnfitz -- was 64 -extern gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array +typedef struct glRect_s { + unsigned short l,t,w,h; +} glRect_t; +struct lightmap_s +{ + gltexture_t *texture; + glpoly_t *polys; + qboolean modified; + glRect_t rectchange; + + // the lightmap texture data needs to be kept in + // main memory so texsubimage can update properly + byte *data;//[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; +}; +extern struct lightmap_s *lightmap; +extern int lightmap_count; //allocated lightmaps extern int gl_warpimagesize; //johnfitz -- for water warp diff --git a/Quake/r_brush.c b/Quake/r_brush.c index 81083c26..e7e4c2b8 100644 --- a/Quake/r_brush.c +++ b/Quake/r_brush.c @@ -30,28 +30,14 @@ extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix int gl_lightmap_format; int lightmap_bytes; -#define LMBLOCK_WIDTH 128 -#define LMBLOCK_HEIGHT 128 - -gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array +#define MAX_SANITY_LIGHTMAPS (1u<<20) +struct lightmap_s *lightmap; +int lightmap_count; +int last_lightmap_allocated; +int allocated[LMBLOCK_WIDTH]; unsigned blocklights[LMBLOCK_WIDTH*LMBLOCK_HEIGHT*3]; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (LMBLOCK_WIDTH*LMBLOCK_HEIGHT) -typedef struct glRect_s { - unsigned char l,t,w,h; -} glRect_t; - -glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; -qboolean lightmap_modified[MAX_LIGHTMAPS]; -glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; - -int allocated[MAX_LIGHTMAPS][LMBLOCK_WIDTH]; -int last_lightmap_allocated; //ericw -- optimization: remember the index of the last lightmap AllocBlock stored a surf in - -// the lightmap texture data needs to be kept in -// main memory so texsubimage can update properly -byte lightmaps[4*MAX_LIGHTMAPS*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; - /* =============== @@ -677,8 +663,8 @@ void R_RenderDynamicLightmaps (msurface_t *fa) return; // add to lightmap chain - fa->polys->chain = lightmap_polys[fa->lightmaptexturenum]; - lightmap_polys[fa->lightmaptexturenum] = fa->polys; + fa->polys->chain = lightmap[fa->lightmaptexturenum].polys; + lightmap[fa->lightmaptexturenum].polys = fa->polys; // check for lightmap modification for (maps=0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++) @@ -691,8 +677,9 @@ void R_RenderDynamicLightmaps (msurface_t *fa) dynamic: if (r_dynamic.value) { - lightmap_modified[fa->lightmaptexturenum] = true; - theRect = &lightmap_rectchange[fa->lightmaptexturenum]; + struct lightmap_s *lm = &lightmap[fa->lightmaptexturenum]; + lm->modified = true; + theRect = &lm->rectchange; if (fa->light_t < theRect->t) { if (theRect->h) theRect->h += theRect->t - fa->light_t; @@ -709,7 +696,7 @@ dynamic: theRect->w = (fa->light_s-theRect->l)+smax; if ((theRect->h + theRect->t) < (fa->light_t + tmax)) theRect->h = (fa->light_t-theRect->t)+tmax; - base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*LMBLOCK_WIDTH*LMBLOCK_HEIGHT; + base = lm->data; base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; R_BuildLightMap (fa, base, LMBLOCK_WIDTH*lightmap_bytes); } @@ -732,8 +719,17 @@ int AllocBlock (int w, int h, int *x, int *y) // This makes AllocBlock much faster on large levels (can shave off 3+ seconds // of load time on a level with 180 lightmaps), at a cost of not quite packing // lightmaps as tightly vs. not doing this (uses ~5% more lightmaps) - for (texnum=last_lightmap_allocated ; texnum= best) + if (allocated[i+j] >= best) break; - if (allocated[texnum][i+j] > best2) - best2 = allocated[texnum][i+j]; + if (allocated[i+j] > best2) + best2 = allocated[i+j]; } if (j == w) { // this is a valid spot @@ -758,8 +754,9 @@ int AllocBlock (int w, int h, int *x, int *y) continue; for (i=0 ; iextents[1]>>4)+1; surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); - base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*LMBLOCK_WIDTH*LMBLOCK_HEIGHT; + base = lightmap[surf->lightmaptexturenum].data; base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes; R_BuildLightMap (surf, base, LMBLOCK_WIDTH*lightmap_bytes); } @@ -876,19 +873,19 @@ with all the surfaces from all brush models void GL_BuildLightmaps (void) { char name[16]; - byte *data; int i, j; + struct lightmap_s *lm; qmodel_t *m; - memset (allocated, 0, sizeof(allocated)); - last_lightmap_allocated = 0; - r_framecount = 1; // no dlightcache - //johnfitz -- null out array (the gltexture objects themselves were already freed by Mod_ClearAll) - for (i=0; i < MAX_LIGHTMAPS; i++) - lightmap_textures[i] = NULL; - //johnfitz + //Spike -- wipe out all the lightmap data (johnfitz -- the gltexture objects were already freed by Mod_ClearAll) + for (i=0; i < lightmap_count; i++) + free(lightmap[i].data); + free(lightmap); + lightmap = NULL; + last_lightmap_allocated = 0; + lightmap_count = 0; gl_lightmap_format = GL_RGBA;//FIXME: hardcoded for now! @@ -927,27 +924,28 @@ void GL_BuildLightmaps (void) // // upload all lightmaps that were filled // - for (i=0; imodified = false; + lm->rectchange.l = LMBLOCK_WIDTH; + lm->rectchange.t = LMBLOCK_HEIGHT; + lm->rectchange.w = 0; + lm->rectchange.h = 0; //johnfitz -- use texture manager sprintf(name, "lightmap%03i",i); - data = lightmaps+i*LMBLOCK_WIDTH*LMBLOCK_HEIGHT*lightmap_bytes; - lightmap_textures[i] = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, - SRC_LIGHTMAP, data, "", (src_offset_t)data, TEXPREF_LINEAR | TEXPREF_NOPICMIP); + lm->texture = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, + SRC_LIGHTMAP, lm->data, "", (src_offset_t)lm->data, TEXPREF_LINEAR | TEXPREF_NOPICMIP); //johnfitz } //johnfitz -- warn about exceeding old limits + //Spike: note that this warning isn't accurate. + // I've doubled the lmblock dimensions, so the standard limit is more like 64/4 now. + // additionally, ericw already changed the allocation strategy, which results in false positives. if (i >= 64) - Con_DWarning ("%i lightmaps exceeds standard limit of 64 (max = %d).\n", i, MAX_LIGHTMAPS); + Con_DWarning ("%i lightmaps exceeds standard limit of 64 (max = %d).\n", i, MAX_SANITY_LIGHTMAPS); //johnfitz } @@ -1252,20 +1250,19 @@ assumes lightmap texture is already bound */ static void R_UploadLightmap(int lmap) { - glRect_t *theRect; + struct lightmap_s *lm = &lightmap[lmap]; - if (!lightmap_modified[lmap]) + if (!lm->modified) return; - lightmap_modified[lmap] = false; + lm->modified = false; - theRect = &lightmap_rectchange[lmap]; - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, - GL_UNSIGNED_BYTE, lightmaps+(lmap* LMBLOCK_HEIGHT + theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); - theRect->l = LMBLOCK_WIDTH; - theRect->t = LMBLOCK_HEIGHT; - theRect->h = 0; - theRect->w = 0; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lm->rectchange.t, LMBLOCK_WIDTH, lm->rectchange.h, gl_lightmap_format, + GL_UNSIGNED_BYTE, lm->data+lm->rectchange.t*LMBLOCK_WIDTH*lightmap_bytes); + lm->rectchange.l = LMBLOCK_WIDTH; + lm->rectchange.t = LMBLOCK_HEIGHT; + lm->rectchange.h = 0; + lm->rectchange.w = 0; rs_dynamiclightmaps++; } @@ -1274,12 +1271,12 @@ void R_UploadLightmaps (void) { int lmap; - for (lmap = 0; lmap < MAX_LIGHTMAPS; lmap++) + for (lmap = 0; lmap < lightmap_count; lmap++) { - if (!lightmap_modified[lmap]) + if (!lightmap[lmap].modified) continue; - GL_Bind (lightmap_textures[lmap]); + GL_Bind (lightmap[lmap].texture); R_UploadLightmap(lmap); } } @@ -1309,19 +1306,17 @@ void R_RebuildAllLightmaps (void) { if (fa->flags & SURF_DRAWTILED) continue; - base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*LMBLOCK_WIDTH*LMBLOCK_HEIGHT; + base = lightmap[fa->lightmaptexturenum].data; base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; R_BuildLightMap (fa, base, LMBLOCK_WIDTH*lightmap_bytes); } } //for each lightmap, upload it - for (i=0; itextures[i]->texturechains[chain] = NULL; // clear lightmap chains - memset (lightmap_polys, 0, sizeof(lightmap_polys)); + for (i=0 ; inumtextures ; i++) @@ -538,7 +539,7 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_ GL_EnableMultitexture(); // selects TEXTURE1 bound = true; } - GL_Bind (lightmap_textures[s->lightmaptexturenum]); + GL_Bind (lightmap[s->lightmaptexturenum].texture); glBegin(GL_POLYGON); v = s->polys->verts[0]; for (j=0 ; jpolys->numverts ; j++, v+= VERTEXSIZE) @@ -774,13 +775,13 @@ void R_DrawLightmapChains (void) glpoly_t *p; float *v; - for (i=0 ; ichain) + GL_Bind (lightmap[i].texture); + for (p = lightmap[i].polys; p; p=p->chain) { glBegin (GL_POLYGON); v = p->verts[0]; @@ -984,7 +985,7 @@ void R_DrawTextureChains_GLSL (qmodel_t *model, entity_t *ent, texchain_t chain) R_FlushBatch (); GL_SelectTexture (GL_TEXTURE1); - GL_Bind (lightmap_textures[s->lightmaptexturenum]); + GL_Bind (lightmap[s->lightmaptexturenum].texture); lastlightmap = s->lightmaptexturenum; R_BatchSurface (s);