[gl] Use a scrap for lightmaps

This gives a rather significant speed boost to timedemo demo1: from
about 2300-2360fps up to 2520-2600fps, at least when using
multi-texture.

Since it was necessary for testing the scrap, gl got the ability to set
the console background texture, too.
This commit is contained in:
Bill Currie 2022-05-11 00:27:55 +09:00
parent 7ed452027c
commit 1e65ec22f9
9 changed files with 418 additions and 232 deletions

View file

@ -154,6 +154,7 @@ QFGL_NEED (void, glFogfv, (GLenum pname, const GLfloat * params))
QFGL_NEED (void, glFogi, (GLenum pname, GLint param))
QFGL_DONT_NEED (void, glFogiv, (GLenum pname, const GLint * params))
QFGL_NEED (void, glFrontFace, (GLenum mode))
QFGL_NEED (void, glGenerateMipmap, (GLenum target))
QFGL_NEED (void, glFrustum, (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val))
QFGL_NEED (GLuint, glGenLists, (GLsizei range))
QFGL_NEED (void, glGenTextures, (GLsizei n, GLuint * textures))

View file

@ -44,7 +44,7 @@ extern model_t *gl_currentmodel;
extern GLuint gl_lightmap_textures[MAX_LIGHTMAPS];
extern qboolean gl_lightmap_modified[MAX_LIGHTMAPS];
extern instsurf_t *gl_lightmap_polys[MAX_LIGHTMAPS];
extern instsurf_t *gl_lightmap_polys;
extern glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS];
void gl_lightmap_init (void);
@ -54,5 +54,8 @@ void gl_R_CalcLightmaps (void);
struct transform_s;
extern void (*gl_R_BuildLightMap) (const struct transform_s *transform,
mod_brush_t *brush, msurface_t *surf);
int gl_R_LightmapTexture (void) __attribute__((pure));
void gl_R_FlushLightmaps (void);
#endif // __QF_GL_lightmap_h

View file

@ -48,7 +48,22 @@ int GL_LoadTexture (const char *identifier, int width, int height, const byte *d
int GL_FindTexture (const char *identifier);
void GL_TextureMode_f (void);
void GL_ReleaseTexture (int tex);
void GDT_Init (void);
void GL_TextureInit (void);
typedef struct scrap_s scrap_t;
scrap_t *GL_CreateScrap (int size, int format, int linear);
void GL_DestroyScrap (scrap_t *scrap);
void GL_ScrapClear (scrap_t *scrap);
int GL_ScrapTexture (scrap_t *scrap) __attribute__((pure));
//XXX slow!
struct subpic_s *GL_ScrapSubpic (scrap_t *scrap, int width, int height);
//XXX slow!
void GL_SubpicDelete (struct subpic_s *subpic);
void GL_SubpicUpdate (struct subpic_s *subpic, byte *data, int batch);
void GL_ScrapFlush (scrap_t *scrap);
#endif // __gl_textures_h

View file

@ -152,17 +152,8 @@ typedef struct msurface_s {
struct {
glpoly_t *polys; // multiple if warped
instsurf_t *instsurf;///< null if not part of world model/sub-model
union {
struct {
struct subpic_s *lightpic;///< light map texture ref (glsl)
byte *base;
};
struct {
int light_s;
int light_t;
int lightmaptexturenum;
};
};
struct subpic_s *lightpic;///< light map texture ref (glsl)
byte *base;
};
};

View file

@ -85,6 +85,15 @@ static cc_cell_t char_cells[256];
static GLuint translate_texture;
static int char_texture;
static int cs_texture; // crosshair texturea
static int gl_conback_texnum;
static cvar_t gl_conback_texnum_cvar = {
.name = "gl_conback_texnum",
.description =
"bind conback to this texture for debugging",
.default_value = "0",
.flags = CVAR_NONE,
.value = { .type = &cexpr_int, .value = &gl_conback_texnum },
};
static byte color_0_8[4] = { 204, 204, 204, 255 };
@ -418,6 +427,8 @@ gl_Draw_Init (void)
draw_backtile = gl_Draw_PicFromWad ("backtile");
Draw_InitText ();
Cvar_Register (&gl_conback_texnum_cvar, 0, 0);
}
static inline void
@ -817,7 +828,11 @@ gl_Draw_ConsoleBackground (int lines, byte alpha)
qfglColor4ubv (color_0_8);
// draw the console texture
qfglBindTexture (GL_TEXTURE_2D, gl->texnum);
if (gl_conback_texnum) {
qfglBindTexture (GL_TEXTURE_2D, gl_conback_texnum);
} else {
qfglBindTexture (GL_TEXTURE_2D, gl->texnum);
}
qfglBegin (GL_QUADS);
qfglTexCoord2f (0, 0 + ofs);
qfglVertex2f (0, 0);

View file

@ -57,6 +57,7 @@
#include "compat.h"
#include "r_internal.h"
static scrap_t *light_scrap;
static int dlightdivtable[8192];
static int gl_internalformat; // 1 or 3
static int lightmap_bytes; // 1, 3, or 4
@ -66,11 +67,12 @@ GLuint gl_lightmap_textures[MAX_LIGHTMAPS];
// LordHavoc: changed to be allocated at runtime (typically lower memory usage)
static byte *lightmaps[MAX_LIGHTMAPS];
static unsigned int blocklights[34 * 34 * 3]; //FIXME make dynamic
static unsigned *blocklights;
static int bl_extents[2];
static int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
qboolean gl_lightmap_modified[MAX_LIGHTMAPS];
instsurf_t *gl_lightmap_polys[MAX_LIGHTMAPS];
instsurf_t *gl_lightmap_polys;
glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS];
static int lmshift = 7;
@ -238,7 +240,7 @@ R_BuildLightMap_1 (const transform_t *transform, mod_brush_t *brush,
msurface_t *surf)
{
byte *dest;
int maps, size, stride, smax, tmax, i, j;
int maps, size, smax, tmax, i;
unsigned int scale;
unsigned int *bl;
@ -279,19 +281,14 @@ R_BuildLightMap_1 (const transform_t *transform, mod_brush_t *brush,
store:
// bound and shift
// Also, invert because we're using a diff blendfunc now
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
bl = blocklights;
dest = lightmaps[surf->lightmaptexturenum]
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
for (i = 0; i < tmax; i++, dest += stride) {
for (j = smax; j; j--) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
}
dest = (byte *) blocklights;
for (i = 0; i < tmax * smax; i++) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
}
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
}
static void
@ -299,7 +296,7 @@ R_BuildLightMap_3 (const transform_t *transform, mod_brush_t *brush,
msurface_t *surf)
{
byte *dest;
int maps, size, stride, smax, tmax, i, j;
int maps, size, smax, tmax, i;
unsigned int scale;
unsigned int *bl;
@ -342,22 +339,18 @@ R_BuildLightMap_3 (const transform_t *transform, mod_brush_t *brush,
store:
// bound and shift
// and invert too
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
bl = blocklights;
dest = lightmaps[surf->lightmaptexturenum]
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
for (i = 0; i < tmax; i++, dest += stride) {
for (j = 0; j < smax; j++) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
}
dest = (byte *) blocklights;
for (i = 0; i < tmax * smax; i++) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
}
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
}
static void
@ -365,7 +358,7 @@ R_BuildLightMap_4 (const transform_t *transform, mod_brush_t *brush,
msurface_t *surf)
{
byte *dest;
int maps, size, smax, tmax, i, j, stride;
int maps, size, smax, tmax, i;
unsigned int scale;
unsigned int *bl;
@ -408,23 +401,19 @@ R_BuildLightMap_4 (const transform_t *transform, mod_brush_t *brush,
store:
// bound and shift
// and invert too
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
bl = blocklights;
dest = lightmaps[surf->lightmaptexturenum]
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
for (i = 0; i < tmax; i++, dest += stride) {
for (j = 0; j < smax; j++) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = 255;
}
dest = (byte *) blocklights;
for (i = 0; i < tmax * smax; i++) {
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = min (*bl >> lmshift, 255);
bl++;
*dest++ = 255;
}
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
}
// BRUSH MODELS ===============================================================
@ -449,75 +438,33 @@ do_subimage_2 (int i)
gl_lightmap_format, GL_UNSIGNED_BYTE, block);
}
static void
GL_UploadLightmap (int i)
{
switch (gl_lightmap_subimage) {
case 2:
do_subimage_2 (i);
break;
case 1:
qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, gl_lightmap_rectchange[i].t,
BLOCK_WIDTH, gl_lightmap_rectchange[i].h,
gl_lightmap_format, GL_UNSIGNED_BYTE,
lightmaps[i] + (gl_lightmap_rectchange[i].t *
BLOCK_WIDTH) * lightmap_bytes);
break;
default:
case 0:
qfglTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, BLOCK_WIDTH,
BLOCK_HEIGHT, 0, gl_lightmap_format, GL_UNSIGNED_BYTE,
lightmaps[i]);
break;
}
}
void
gl_R_CalcLightmaps (void)
{
int i;
for (i = 0; i < MAX_LIGHTMAPS; i++) {
if (!gl_lightmap_polys[i])
continue;
if (gl_lightmap_modified[i]) {
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
GL_UploadLightmap (i);
gl_lightmap_modified[i] = false;
}
}
}
void
gl_R_BlendLightmaps (void)
{
float *v;
int i, j;
instsurf_t *sc;
glpoly_t *p;
qfglDepthMask (GL_FALSE); // don't bother writing Z
qfglBlendFunc (lm_src_blend, lm_dest_blend);
for (i = 0; i < MAX_LIGHTMAPS; i++) {
for (sc = gl_lightmap_polys[i]; sc; sc = sc->lm_chain) {
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
for (p = sc->surface->polys; p; p = p->next) {
qfglBegin (GL_POLYGON);
v = p->verts[0];
for (j = 0; j < p->numverts; j++, v += VERTEXSIZE) {
qfglTexCoord2fv (&v[5]);
qfglVertex3fv (v);
}
qfglEnd ();
}
if (sc->transform)
qfglPopMatrix ();
qfglBindTexture (GL_TEXTURE_2D, gl_R_LightmapTexture ());
for (sc = gl_lightmap_polys; sc; sc = sc->lm_chain) {
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
for (p = sc->surface->polys; p; p = p->next) {
qfglBegin (GL_POLYGON);
v = p->verts[0];
for (int j = 0; j < p->numverts; j++, v += VERTEXSIZE) {
qfglTexCoord2fv (&v[5]);
qfglVertex3fv (v);
}
qfglEnd ();
}
if (sc->transform)
qfglPopMatrix ();
}
// Return to normal blending --KB
@ -528,7 +475,6 @@ gl_R_BlendLightmaps (void)
void
gl_overbright_f (void *data, const cvar_t *cvar)
{
int num;
mod_brush_t *brush;
if (!cvar)
@ -579,61 +525,12 @@ gl_overbright_f (void *data, const cvar_t *cvar)
if (surf->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
continue;
num = surf->lightmaptexturenum;
gl_lightmap_modified[num] = true;
gl_lightmap_rectchange[num].l = 0;
gl_lightmap_rectchange[num].t = 0;
gl_lightmap_rectchange[num].w = BLOCK_WIDTH;
gl_lightmap_rectchange[num].h = BLOCK_HEIGHT;
gl_R_BuildLightMap (0, brush, surf);
}
}
// LIGHTMAP ALLOCATION ========================================================
// returns a texture number and the position inside it
static int
AllocBlock (int w, int h, int *x, int *y)
{
int best, best2, texnum, i, j;
for (texnum = 0; texnum < MAX_LIGHTMAPS; texnum++) {
best = BLOCK_HEIGHT;
for (i = 0; i < BLOCK_WIDTH - w; i++) {
best2 = 0;
for (j = 0; j < w; j++) {
if (allocated[texnum][i + j] >= best)
break;
if (allocated[texnum][i + j] > best2)
best2 = allocated[texnum][i + j];
}
if (j == w) {
// this is a valid spot
*x = i;
*y = best = best2;
}
}
if (best + h > BLOCK_HEIGHT)
continue;
// LordHavoc: allocate lightmaps only as needed
if (!lightmaps[texnum])
lightmaps[texnum] = calloc (BLOCK_WIDTH * BLOCK_HEIGHT,
lightmap_bytes);
for (i = 0; i < w; i++)
allocated[texnum][*x + i] = best + h;
return texnum;
}
Sys_Error ("AllocBlock: full");
return 0;
}
static void
GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf)
{
@ -645,9 +542,16 @@ GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf)
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
surf->lightmaptexturenum =
AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
gl_R_BuildLightMap (0, brush, surf);
surf->lightpic = GL_ScrapSubpic (light_scrap, smax, tmax);
if (!surf->lightpic) {
Sys_Error ("FIXME taniwha is being lazy");
}
if (smax > bl_extents[0]) {
bl_extents[0] = smax;
}
if (tmax > bl_extents[1]) {
bl_extents[1] = tmax;
}
}
/*
@ -665,10 +569,6 @@ GL_BuildLightmaps (model_t **models, int num_models)
r_framecount = 1; // no dlightcache
if (!gl_lightmap_textures[0]) {
qfglGenTextures (MAX_LIGHTMAPS, gl_lightmap_textures);
}
switch (r_lightmap_components) {
case 1:
gl_internalformat = 1;
@ -697,6 +597,13 @@ GL_BuildLightmaps (model_t **models, int num_models)
break;
}
if (!light_scrap) {
light_scrap = GL_CreateScrap (2048, gl_lightmap_format, 1);
} else {
GL_ScrapClear (light_scrap);
}
bl_extents[1] = bl_extents[0] = 0;
for (int j = 1; j < num_models; j++) {
m = models[j];
if (!m)
@ -716,23 +623,37 @@ GL_BuildLightmaps (model_t **models, int num_models)
}
}
int size = bl_extents[0] * bl_extents[1] * 3; // * 3 for rgb support
blocklights = realloc (blocklights, size * sizeof (blocklights[0]));
// upload all lightmaps that were filled
for (int i = 0; i < MAX_LIGHTMAPS; i++) {
if (!allocated[i][0])
break; // no more used
gl_lightmap_modified[i] = false;
gl_lightmap_rectchange[i].l = BLOCK_WIDTH;
gl_lightmap_rectchange[i].t = BLOCK_HEIGHT;
gl_lightmap_rectchange[i].w = 0;
gl_lightmap_rectchange[i].h = 0;
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (gl_Anisotropy)
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
gl_aniso);
qfglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, BLOCK_WIDTH,
BLOCK_HEIGHT, 0, gl_lightmap_format,
GL_UNSIGNED_BYTE, lightmaps[i]);
for (int j = 1; j < num_models; j++) {
m = models[j];
if (!m)
break;
if (m->path[0] == '*' || m->type != mod_brush) {
// sub model surfaces are processed as part of the main model
continue;
}
brush = &m->brush;
// non-bsp models don't have surfaces.
for (unsigned i = 0; i < brush->numsurfaces; i++) {
msurface_t *surf = brush->surfaces + i;
if (surf->lightpic) {
gl_R_BuildLightMap (0, brush, surf);
}
}
}
}
int
gl_R_LightmapTexture (void)
{
return GL_ScrapTexture (light_scrap);
}
void
gl_R_FlushLightmaps (void)
{
GL_ScrapFlush (light_scrap);
}

View file

@ -277,12 +277,11 @@ R_RenderBrushPoly_1 (msurface_t *surf)
static inline void
R_AddToLightmapChain (glbspctx_t *bctx, msurface_t *surf, instsurf_t *sc)
{
int maps, smax, tmax;
glRect_t *theRect;
int maps;
// add the poly to the proper lightmap chain
sc->lm_chain = gl_lightmap_polys[surf->lightmaptexturenum];
gl_lightmap_polys[surf->lightmaptexturenum] = sc;
sc->lm_chain = gl_lightmap_polys;
gl_lightmap_polys = sc;
// check for lightmap modification
for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++)
@ -292,24 +291,6 @@ R_AddToLightmapChain (glbspctx_t *bctx, msurface_t *surf, instsurf_t *sc)
if ((surf->dlightframe == r_framecount) || surf->cached_dlight) {
dynamic:
if (r_dynamic) {
gl_lightmap_modified[surf->lightmaptexturenum] = true;
theRect = &gl_lightmap_rectchange[surf->lightmaptexturenum];
if (surf->light_t < theRect->t) {
if (theRect->h)
theRect->h += theRect->t - surf->light_t;
theRect->t = surf->light_t;
}
if (surf->light_s < theRect->l) {
if (theRect->w)
theRect->w += theRect->l - surf->light_s;
theRect->l = surf->light_s;
}
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
if ((theRect->w + theRect->l) < (surf->light_s + smax))
theRect->w = (surf->light_s - theRect->l) + smax;
if ((theRect->h + theRect->t) < (surf->light_t + tmax))
theRect->h = (surf->light_t - theRect->t) + tmax;
gl_R_BuildLightMap (bctx->entity->transform, bctx->brush, surf);
}
}
@ -372,6 +353,7 @@ DrawTextureChains (int disable_blend, int do_bind)
// Lightmaps
qglActiveTexture (gl_mtex_enum + 1);
qfglEnable (GL_TEXTURE_2D);
qfglBindTexture (GL_TEXTURE_2D, gl_R_LightmapTexture ());
// Base Texture
qglActiveTexture (gl_mtex_enum + 0);
@ -388,7 +370,6 @@ DrawTextureChains (int disable_blend, int do_bind)
qfglEnable (GL_TEXTURE_2D);
qfglBindTexture (GL_TEXTURE_2D, tex->gl_fb_texturenum);
qglActiveTexture (gl_mtex_enum + 1);
for (s = tex->tex_chain; s; s = s->tex_chain) {
surf = s->surface;
if (s->transform) {
@ -397,8 +378,6 @@ DrawTextureChains (int disable_blend, int do_bind)
}
if (s->color && do_bind)
qfglColor4fv (s->color);
qfglBindTexture (GL_TEXTURE_2D,
gl_lightmap_textures[surf->lightmaptexturenum]);
R_RenderBrushPoly_3 (surf);
@ -413,11 +392,8 @@ DrawTextureChains (int disable_blend, int do_bind)
qglActiveTexture (gl_mtex_enum + 0);
} else {
qglActiveTexture (gl_mtex_enum + 1);
for (s = tex->tex_chain; s; s = s->tex_chain) {
surf = s->surface;
qfglBindTexture (GL_TEXTURE_2D,
gl_lightmap_textures[surf->lightmaptexturenum]);
if (s->transform) {
qfglPushMatrix ();
@ -489,7 +465,7 @@ clear_texture_chains (void)
tex->tex_chain_tail = &tex->tex_chain;
release_instsurfs ();
memset (gl_lightmap_polys, 0, sizeof (gl_lightmap_polys));
gl_lightmap_polys = 0;
}
static inline void
@ -743,7 +719,7 @@ gl_R_DrawWorld (void)
}
}
gl_R_CalcLightmaps ();
gl_R_FlushLightmaps ();
if (!Fog_GetDensity ()
|| (gl_fb_bmodels && gl_mtex_fullbright)
@ -859,19 +835,15 @@ GL_BuildSurfaceDisplayList (mod_brush_t *brush, msurface_t *surf)
// lightmap texture coordinates
s = DotProduct (vec, texinfo->vecs[0]) + texinfo->vecs[0][3];
s -= surf->texturemins[0];
s += surf->light_s * 16;
s += 8;
s /= BLOCK_WIDTH * 16;
t = DotProduct (vec, texinfo->vecs[1]) + texinfo->vecs[1][3];
s -= surf->texturemins[0];
t -= surf->texturemins[1];
t += surf->light_t * 16;
t += 8;
t /= BLOCK_HEIGHT * 16;
poly->verts[i][5] = s;
poly->verts[i][6] = t;
s += surf->lightpic->rect->x * 16 + 8;
t += surf->lightpic->rect->y * 16 + 8;
s /= 16;
t /= 16;
poly->verts[i][5] = s * surf->lightpic->size;
poly->verts[i][6] = t * surf->lightpic->size;
}
// remove co-linear points - Ed

View file

@ -48,12 +48,28 @@
#include "QF/GL/funcs.h"
#include "QF/GL/qf_textures.h"
#include "QF/GL/qf_vid.h"
#include "QF/ui/vrect.h"
#include "compat.h"
#include "r_internal.h"
#include "r_scrap.h"
#include "sbar.h"
#include "vid_internal.h"
struct scrap_s {
rscrap_t rscrap;
GLuint tnum;
int format;
int bpp;
byte *data; // local copy of the texture so updates can be batched
vrect_t *batch;
subpic_t *subpics;
struct scrap_s *next;
};
static scrap_t *scrap_list;
static int max_tex_size;
typedef struct {
GLuint texnum;
char identifier[64];
@ -625,3 +641,252 @@ SetupTexture:
return glt->texnum;
}
void
GL_ReleaseTexture (int tex)
{
GLuint tnum = tex;
qfglDeleteTextures (1, &tnum);
}
static void
gl_scraps_f (void)
{
scrap_t *scrap;
int area;
int size;
if (!scrap_list) {
Sys_Printf ("No scraps\n");
return;
}
for (scrap = scrap_list; scrap; scrap = scrap->next) {
area = R_ScrapArea (&scrap->rscrap);
// always square
size = scrap->rscrap.width;
Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n",
scrap->tnum, size, scrap->format, scrap->bpp,
area * 100 / (size * size));
if (Cmd_Argc () > 1) {
R_ScrapDump (&scrap->rscrap);
}
}
}
void
GL_TextureInit (void)
{
qfglGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size);
Sys_MaskPrintf (SYS_glt, "max texture size: %d\n", max_tex_size);
Cmd_AddCommand ("gl_scraps", gl_scraps_f, "Dump GL scrap stats");
}
scrap_t *
GL_CreateScrap (int size, int format, int linear)
{
int i;
int bpp;
scrap_t *scrap;
for (i = 0; i < 16; i++)
if (size <= 1 << i)
break;
size = 1 << i;
size = min (size, max_tex_size);
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
bpp = 1;
break;
case GL_LUMINANCE_ALPHA:
bpp = 2;
break;
case GL_RGB:
bpp = 3;
break;
case GL_RGBA:
bpp = 4;
break;
default:
Sys_Error ("GL_CreateScrap: Invalid texture format");
}
scrap = malloc (sizeof (scrap_t));
qfglGenTextures (1, &scrap->tnum);
R_ScrapInit (&scrap->rscrap, size, size);
scrap->format = format;
scrap->bpp = bpp;
scrap->subpics = 0;
scrap->next = scrap_list;
scrap_list = scrap;
scrap->data = calloc (1, size * size * bpp);
scrap->batch = 0;
qfglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfglTexImage2D (GL_TEXTURE_2D, 0, format,
size, size, 0, format, GL_UNSIGNED_BYTE, scrap->data);
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (linear) {
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
qfglGenerateMipmap (GL_TEXTURE_2D);
return scrap;
}
void
GL_ScrapClear (scrap_t *scrap)
{
subpic_t *sp;
while (scrap->subpics) {
sp = scrap->subpics;
scrap->subpics = (subpic_t *) sp->next;
free (sp);
}
R_ScrapClear (&scrap->rscrap);
}
void
GL_DestroyScrap (scrap_t *scrap)
{
scrap_t **s;
for (s = &scrap_list; *s; s = &(*s)->next) {
if (*s == scrap) {
*s = scrap->next;
break;
}
}
GL_ScrapClear (scrap);
R_ScrapDelete (&scrap->rscrap);
GL_ReleaseTexture (scrap->tnum);
free (scrap->data);
free (scrap);
}
int
GL_ScrapTexture (scrap_t *scrap)
{
return scrap->tnum;
}
subpic_t *
GL_ScrapSubpic (scrap_t *scrap, int width, int height)
{
vrect_t *rect;
subpic_t *subpic;
rect = R_ScrapAlloc (&scrap->rscrap, width, height);
if (!rect) {
return 0;
}
subpic = malloc (sizeof (subpic_t));
*((subpic_t **) &subpic->next) = scrap->subpics;
scrap->subpics = subpic;
*((scrap_t **) &subpic->scrap) = scrap;
*((vrect_t **) &subpic->rect) = rect;
*((int *) &subpic->width) = width;
*((int *) &subpic->height) = height;
*((float *) &subpic->size) = 1.0 / scrap->rscrap.width;
return subpic;
}
void
GL_SubpicDelete (subpic_t *subpic)
{
scrap_t *scrap = (scrap_t *) subpic->scrap;
vrect_t *rect = (vrect_t *) subpic->rect;
subpic_t **sp;
for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next)
if (*sp == subpic)
break;
if (*sp != subpic)
Sys_Error ("GL_ScrapDelSubpic: broken subpic");
*sp = (subpic_t *) subpic->next;
free (subpic);
R_ScrapFree (&scrap->rscrap, rect);
}
void
GL_SubpicUpdate (subpic_t *subpic, byte *data, int batch)
{
scrap_t *scrap = (scrap_t *) subpic->scrap;
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);
}*/
vrect_t *r = VRect_New (rect->x, rect->y,
rect->width, rect->height);
r->next = scrap->batch;
scrap->batch = r;
step = scrap->rscrap.width * 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 {
qfglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, rect->y,
subpic->width, subpic->height, scrap->format,
GL_UNSIGNED_BYTE, data);
}
}
void
GL_ScrapFlush (scrap_t *scrap)
{
vrect_t *rect = scrap->batch;
int size = scrap->rscrap.width;
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
qfglBindTexture (GL_TEXTURE_2D, scrap->tnum);
qfglPixelStorei(GL_UNPACK_ROW_LENGTH, size);
//qfglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
while (rect) {
vrect_t *next = rect->next;
#if 1
int x = rect->x;
int y = rect->y;
int w = rect->width;
int h = rect->height;
qfglTexSubImage2D (GL_TEXTURE_2D, 0, x, y, w, h, scrap->format,
GL_UNSIGNED_BYTE,
scrap->data + (y * size + x) * scrap->bpp);
#else
for (int i = 0; i < rect->height; i++) {
int y = rect->y + i;
qfglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, y,
rect->width, 1, scrap->format,
GL_UNSIGNED_BYTE,
scrap->data + (y * size + rect->x) * scrap->bpp);
}
#endif
VRect_Delete (rect);
rect = next;
}
qfglPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
//qfglPixelStorei(GL_UNPACK_ALIGNMENT, 4);
scrap->batch = 0;
}

View file

@ -49,6 +49,7 @@
#include "QF/GL/extensions.h"
#include "QF/GL/funcs.h"
#include "QF/GL/qf_rmain.h"
#include "QF/GL/qf_textures.h"
#include "QF/GL/qf_vid.h"
#include "compat.h"
@ -1031,6 +1032,8 @@ GL_Init_Common (void)
GL_Common_Init_Cvars ();
GL_TextureInit ();
qfglClearColor (0, 0, 0, 0);
qfglEnable (GL_TEXTURE_2D);