Call glTexSubImage2D only once per frame.

Instead of once per surface... ouch. Gives about 20% speed boost on demo1
(154.7->185.7)
This commit is contained in:
Bill Currie 2012-07-02 20:01:28 +09:00
parent 602cd84e21
commit 1a6b56b0a2
6 changed files with 69 additions and 13 deletions

View file

@ -38,5 +38,6 @@ void glsl_R_BuildLightmaps (struct model_s **models, int num_models);
void glsl_R_CalcLightmaps (void); void glsl_R_CalcLightmaps (void);
extern void (*glsl_R_BuildLightMap) (msurface_t *surf); extern void (*glsl_R_BuildLightMap) (msurface_t *surf);
int glsl_R_LightmapTexture (void); int glsl_R_LightmapTexture (void);
void glsl_R_FlushLightmaps (void);
#endif//__QF_GLSL_lightmap_h #endif//__QF_GLSL_lightmap_h

View file

@ -58,6 +58,7 @@ void GLSL_ScrapClear (scrap_t *scrap);
int GLSL_ScrapTexture (scrap_t *scrap); int GLSL_ScrapTexture (scrap_t *scrap);
subpic_t *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow! subpic_t *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow!
void GLSL_SubpicDelete (subpic_t *subpic); //XXX slow! void GLSL_SubpicDelete (subpic_t *subpic); //XXX slow!
void GLSL_SubpicUpdate (subpic_t *subpic, byte *data); void GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch);
void GLSL_ScrapFlush (scrap_t *scrap);
#endif//__QF_GLSL_textures_h #endif//__QF_GLSL_textures_h

View file

@ -1106,6 +1106,7 @@ glsl_R_DrawWorld (void)
} }
} }
glsl_R_FlushLightmaps ();
bsp_begin (); bsp_begin ();
qfeglActiveTexture (GL_TEXTURE0 + 0); qfeglActiveTexture (GL_TEXTURE0 + 0);
for (i = 0; i < r_num_texture_chains; i++) { for (i = 0; i < r_num_texture_chains; i++) {

View file

@ -123,6 +123,7 @@ static qpic_t *crosshair_pic;
static qpic_t *white_pic; static qpic_t *white_pic;
static qpic_t *backtile_pic; static qpic_t *backtile_pic;
static hashtab_t *pic_cache; static hashtab_t *pic_cache;
static cvar_t *glsl_conback_texnum;
static qpic_t * static qpic_t *
make_glpic (const char *name, qpic_t *p) make_glpic (const char *name, qpic_t *p)
@ -444,6 +445,10 @@ glsl_Draw_Init (void)
qfeglBindTexture (GL_TEXTURE_2D, gl->texnum); qfeglBindTexture (GL_TEXTURE_2D, gl->texnum);
qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glsl_conback_texnum = Cvar_Get ("glsl_conback_texnum", "0", CVAR_NONE,
NULL, "bind conback to this texture for "
"debugging");
} }
static inline void static inline void
@ -684,6 +689,9 @@ glsl_Draw_ConsoleBackground (int lines, byte alpha)
qfeglUniform1i (quake_icon.icon.location, 0); qfeglUniform1i (quake_icon.icon.location, 0);
qfeglActiveTexture (GL_TEXTURE0 + 0); qfeglActiveTexture (GL_TEXTURE0 + 0);
qfeglEnable (GL_TEXTURE_2D); qfeglEnable (GL_TEXTURE_2D);
if (glsl_conback_texnum->int_val)
qfeglBindTexture (GL_TEXTURE_2D, glsl_conback_texnum->int_val);
else
qfeglBindTexture (GL_TEXTURE_2D, conback_texture); qfeglBindTexture (GL_TEXTURE_2D, conback_texture);
qfeglUniform1i (quake_icon.palette.location, 1); qfeglUniform1i (quake_icon.palette.location, 1);

View file

@ -141,7 +141,7 @@ R_BuildLightMap_1 (msurface_t *surf)
memset (blocklights, 0, size * sizeof (blocklights[0])); memset (blocklights, 0, size * sizeof (blocklights[0]));
if (!r_worldentity.model->lightdata) { if (!r_worldentity.model->lightdata) {
// because we by-pass the inversion, "no light" = "full bright" // because we by-pass the inversion, "no light" = "full bright"
GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights); GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
return; return;
} }
@ -174,7 +174,7 @@ R_BuildLightMap_1 (msurface_t *surf)
*out++ = t; *out++ = t;
} }
GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights); GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
} }
static void static void
@ -252,3 +252,9 @@ glsl_R_LightmapTexture (void)
{ {
return GLSL_ScrapTexture (light_scrap); return GLSL_ScrapTexture (light_scrap);
} }
void
glsl_R_FlushLightmaps (void)
{
GLSL_ScrapFlush (light_scrap);
}

View file

@ -56,6 +56,8 @@ struct scrap_s {
int size; // in pixels, for now, always square, power of 2 int size; // in pixels, for now, always square, power of 2
int format; int format;
int bpp; int bpp;
byte *data; // local copy of the texture so updates can be batched
vrect_t *batch;
vrect_t *free_rects; vrect_t *free_rects;
vrect_t *rects; vrect_t *rects;
subpic_t *subpics; subpic_t *subpics;
@ -282,7 +284,6 @@ GLSL_CreateScrap (int size, int format)
int i; int i;
int bpp; int bpp;
scrap_t *scrap; scrap_t *scrap;
byte *data;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
if (size <= 1 << i) if (size <= 1 << i)
@ -317,18 +318,18 @@ GLSL_CreateScrap (int size, int format)
scrap->next = scrap_list; scrap->next = scrap_list;
scrap_list = scrap; scrap_list = scrap;
data = calloc (1, size * size * bpp); scrap->data = calloc (1, size * size * bpp);
scrap->batch = 0;
qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum); qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfeglTexImage2D (GL_TEXTURE_2D, 0, format, qfeglTexImage2D (GL_TEXTURE_2D, 0, format,
size, size, 0, format, GL_UNSIGNED_BYTE, data); size, size, 0, format, GL_UNSIGNED_BYTE, scrap->data);
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//FIXME parameterize (linear for lightmaps) //FIXME parameterize (linear for lightmaps)
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qfeglGenerateMipmap (GL_TEXTURE_2D); qfeglGenerateMipmap (GL_TEXTURE_2D);
free (data);
return scrap; return scrap;
} }
@ -372,6 +373,7 @@ GLSL_DestroyScrap (scrap_t *scrap)
GLSL_ScrapClear (scrap); GLSL_ScrapClear (scrap);
VRect_Delete (scrap->free_rects); VRect_Delete (scrap->free_rects);
GLSL_ReleaseTexture (scrap->tnum); GLSL_ReleaseTexture (scrap->tnum);
free (scrap->data);
free (scrap); free (scrap);
} }
@ -480,13 +482,50 @@ GLSL_SubpicDelete (subpic_t *subpic)
} }
void void
GLSL_SubpicUpdate (subpic_t *subpic, byte *data) GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch)
{ {
scrap_t *scrap = (scrap_t *) subpic->scrap; scrap_t *scrap = (scrap_t *) subpic->scrap;
vrect_t *rect = (vrect_t *) subpic->rect; vrect_t *rect = (vrect_t *) subpic->rect;
byte *dest;
int step, sbytes;
int i;
if (batch) {
if (scrap->batch) {
vrect_t *r = scrap->batch;
scrap->batch = VRect_Union (r, rect);
VRect_Delete (r);
} else {
scrap->batch = VRect_New (rect->x, rect->y,
rect->width, rect->height);
}
step = scrap->size * scrap->bpp;
sbytes = subpic->width * scrap->bpp;
dest = scrap->data + rect->y * step + rect->x * scrap->bpp;
for (i = 0; i < subpic->height; i++, dest += step, data += sbytes)
memcpy (dest, data, sbytes);
} else {
qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum); qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfeglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, rect->y, qfeglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, rect->y,
subpic->width, subpic->height, scrap->format, subpic->width, subpic->height, scrap->format,
GL_UNSIGNED_BYTE, data); GL_UNSIGNED_BYTE, data);
} }
}
void
GLSL_ScrapFlush (scrap_t *scrap)
{
vrect_t *rect = scrap->batch;;
if (!rect)
return;
//FIXME: it seems gl (as opposed to egl) allows row step to be specified.
//should update to not update the entire horizontal block
qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfeglTexSubImage2D (GL_TEXTURE_2D, 0, 0, rect->y,
scrap->size, rect->height, scrap->format,
GL_UNSIGNED_BYTE,
scrap->data + rect->y * scrap->size * scrap->bpp);
VRect_Delete (rect);
scrap->batch = 0;
}