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
This commit is contained in:
Eric Wasylishen 2019-09-12 06:49:35 +00:00
parent f2930ef460
commit e041b958c7
4 changed files with 94 additions and 82 deletions

View file

@ -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;

View file

@ -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

View file

@ -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<MAX_LIGHTMAPS ; texnum++, last_lightmap_allocated++)
for (texnum=last_lightmap_allocated ; texnum<MAX_SANITY_LIGHTMAPS ; texnum++)
{
if (texnum == lightmap_count)
{
lightmap_count++;
lightmap = realloc(lightmap, sizeof(*lightmap)*lightmap_count);
memset(&lightmap[texnum], 0, sizeof(lightmap[texnum]));
lightmap[texnum].data = malloc(4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT);
//as we're only tracking one texture, we don't need multiple copies of allocated any more.
memset(allocated, 0, sizeof(allocated));
}
best = LMBLOCK_HEIGHT;
for (i=0 ; i<LMBLOCK_WIDTH-w ; i++)
@ -742,10 +738,10 @@ int AllocBlock (int w, int h, int *x, int *y)
for (j=0 ; j<w ; j++)
{
if (allocated[texnum][i+j] >= 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 ; i<w ; i++)
allocated[texnum][*x + i] = best + h;
allocated[*x + i] = best + h;
last_lightmap_allocated = texnum;
return texnum;
}
@ -787,7 +784,7 @@ void GL_CreateSurfaceLightmap (msurface_t *surf)
tmax = (surf->extents[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; i<MAX_LIGHTMAPS; i++)
for (i=0; i<lightmap_count; i++)
{
if (!allocated[i][0])
break; // no more used
lightmap_modified[i] = false;
lightmap_rectchange[i].l = LMBLOCK_WIDTH;
lightmap_rectchange[i].t = LMBLOCK_HEIGHT;
lightmap_rectchange[i].w = 0;
lightmap_rectchange[i].h = 0;
lm = &lightmap[i];
lm->modified = 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; i<MAX_LIGHTMAPS; i++)
for (i=0; i<lightmap_count; i++)
{
if (!allocated[i][0])
break;
GL_Bind (lightmap_textures[i]);
GL_Bind (lightmap[i].texture);
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, gl_lightmap_format,
GL_UNSIGNED_BYTE, lightmaps+i*LMBLOCK_WIDTH*LMBLOCK_HEIGHT*lightmap_bytes);
GL_UNSIGNED_BYTE, lightmap[i].data);
}
}

View file

@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskyleaf, r_showtris; //johnfitz
extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS];
byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel);
int vis_changed; //if true, force pvs to be refreshed
@ -56,7 +54,8 @@ void R_ClearTextureChains (qmodel_t *mod, texchain_t chain)
mod->textures[i]->texturechains[chain] = NULL;
// clear lightmap chains
memset (lightmap_polys, 0, sizeof(lightmap_polys));
for (i=0 ; i<lightmap_count ; i++)
lightmap[i].polys = NULL;
}
/*
@ -85,7 +84,8 @@ void R_MarkSurfaces (void)
qboolean nearwaterportal;
// clear lightmap chains
memset (lightmap_polys, 0, sizeof(lightmap_polys));
for (i=0 ; i<lightmap_count ; i++)
lightmap[i].polys = NULL;
// check this leaf for water portals
// TODO: loop through all water surfs and use distance to leaf cullbox
@ -248,7 +248,8 @@ void R_BuildLightmapChains (qmodel_t *model, texchain_t chain)
int i;
// clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo)
memset (lightmap_polys, 0, sizeof(lightmap_polys));
for (i=0 ; i<lightmap_count ; i++)
lightmap[i].polys = NULL;
// now rebuild them
for (i=0 ; i<model->numtextures ; 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 ; j<s->polys->numverts ; j++, v+= VERTEXSIZE)
@ -774,13 +775,13 @@ void R_DrawLightmapChains (void)
glpoly_t *p;
float *v;
for (i=0 ; i<MAX_LIGHTMAPS ; i++)
for (i=0 ; i<lightmap_count ; i++)
{
if (!lightmap_polys[i])
if (!lightmap[i].polys)
continue;
GL_Bind (lightmap_textures[i]);
for (p = lightmap_polys[i]; p; p=p->chain)
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);