GL1 unified draw calls, init

Implemented a batching procedure, to try to group meshes in a buffer
and use a final GL call to draw them all in one step, instead of the
many GL draw calls existing today.
For now, only 2D textures are included, especifically console text
("conchars"), scrap and tiles. It's not worth doing this for
individual 2D elements (e.g. crosshair).
This commit is contained in:
Jaime Moreira 2024-07-15 06:56:02 -04:00
parent 4503333b3a
commit 50aebd2de4
6 changed files with 206 additions and 61 deletions

View file

@ -590,6 +590,7 @@ set(GL1-Source
${REF_SRC_DIR}/gl1/gl1_surf.c ${REF_SRC_DIR}/gl1/gl1_surf.c
${REF_SRC_DIR}/gl1/gl1_warp.c ${REF_SRC_DIR}/gl1/gl1_warp.c
${REF_SRC_DIR}/gl1/gl1_sdl.c ${REF_SRC_DIR}/gl1/gl1_sdl.c
${REF_SRC_DIR}/gl1/gl1_buffer.c
${REF_SRC_DIR}/files/models.c ${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c ${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c ${REF_SRC_DIR}/files/stb.c

View file

@ -959,6 +959,7 @@ REFGL1_OBJS_ := \
src/client/refresh/gl1/gl1_surf.o \ src/client/refresh/gl1/gl1_surf.o \
src/client/refresh/gl1/gl1_warp.o \ src/client/refresh/gl1/gl1_warp.o \
src/client/refresh/gl1/gl1_sdl.o \ src/client/refresh/gl1/gl1_sdl.o \
src/client/refresh/gl1/gl1_buffer.o \
src/client/refresh/files/surf.o \ src/client/refresh/files/surf.o \
src/client/refresh/files/models.o \ src/client/refresh/files/models.o \
src/client/refresh/files/pcx.o \ src/client/refresh/files/pcx.o \

View file

@ -0,0 +1,171 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2024 Jaime Moreira
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Drawing buffer: sort of a "Q3A shader" handler, allows to join multiple
* draw calls into one, by grouping those which share the same
* characteristics (mostly the same texture).
*
* =======================================================================
*/
#include "header/local.h"
#define MAX_VERTICES 16384
#define MAX_INDICES (MAX_VERTICES * 4)
typedef struct // 832k aprox.
{
buffered_draw_t type;
GLfloat
vtx[MAX_VERTICES * 3], // vertexes
tex[MAX_TEXTURE_UNITS][MAX_VERTICES * 2], // texture coords
clr[MAX_VERTICES * 4]; // color components
GLushort
idx[MAX_INDICES], // indices
vtx_ptr, idx_ptr; // pointers for array positions
int texture[MAX_TEXTURE_UNITS];
int flags; // entity flags
float alpha;
} glbuffer_t;
glbuffer_t gl_buf;
GLuint vt, tx, cl; // indices for arrays in gl_buf
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
void
R_ApplyGLBuffer(void)
{
// Properties of batched draws here
GLint vtx_size;
qboolean texture;
if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0)
{
return;
}
// defaults for drawing
vtx_size = 3;
texture = true;
// choosing features by type
switch (gl_buf.type)
{
case buf_2d:
vtx_size = 2;
break;
default:
break;
}
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx);
if (texture)
{
R_Bind(gl_buf.texture[0]);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, gl_buf.tex[0]);
}
// All set, we can finally draw
glDrawElements(GL_TRIANGLES, gl_buf.idx_ptr, GL_UNSIGNED_SHORT, gl_buf.idx);
// ... and now, turn back everything as it was
if (texture)
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}
glDisableClientState( GL_VERTEX_ARRAY );
gl_buf.vtx_ptr = gl_buf.idx_ptr = 0;
}
void
R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha)
{
if ( gl_buf.type != type || gl_buf.texture[0] != colortex )
{
R_ApplyGLBuffer();
gl_buf.type = type;
gl_buf.texture[0] = colortex;
gl_buf.texture[1] = lighttex;
gl_buf.flags = flags;
gl_buf.alpha = alpha;
}
}
void
R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty)
{
static const GLushort idx_max = MAX_INDICES - 7;
static const GLushort vtx_max = MAX_VERTICES - 5;
unsigned int i;
if (gl_buf.idx_ptr > idx_max || gl_buf.vtx_ptr > vtx_max)
{
R_ApplyGLBuffer();
}
i = gl_buf.vtx_ptr * 2; // vertex index
// "Quad" = 2-triangle GL_TRIANGLE_FAN
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+3;
// up left corner coords
gl_buf.vtx[i] = ul_vx;
gl_buf.vtx[i+1] = ul_vy;
// up right
gl_buf.vtx[i+2] = dr_vx;
gl_buf.vtx[i+3] = ul_vy;
// down right
gl_buf.vtx[i+4] = dr_vx;
gl_buf.vtx[i+5] = dr_vy;
// and finally, down left
gl_buf.vtx[i+6] = ul_vx;
gl_buf.vtx[i+7] = dr_vy;
gl_buf.tex[0][i] = ul_tx;
gl_buf.tex[0][i+1] = ul_ty;
gl_buf.tex[0][i+2] = dr_tx;
gl_buf.tex[0][i+3] = ul_ty;
gl_buf.tex[0][i+4] = dr_tx;
gl_buf.tex[0][i+5] = dr_ty;
gl_buf.tex[0][i+6] = ul_tx;
gl_buf.tex[0][i+7] = dr_ty;
gl_buf.vtx_ptr += 4;
}

View file

@ -77,31 +77,10 @@ RDraw_CharScaled(int x, int y, int num, float scale)
scaledSize = 8*scale; scaledSize = 8*scale;
R_Bind(draw_chars->texnum); R_UpdateGLBuffer(buf_2d, draw_chars->texnum, 0, 0, 1);
GLfloat vtx[] = { R_Buffer2DQuad(x, y, x + scaledSize, y + scaledSize,
x, y, fcol, frow, fcol + size, frow + size);
x + scaledSize, y,
x + scaledSize, y + scaledSize,
x, y + scaledSize
};
GLfloat tex[] = {
fcol, frow,
fcol + size, frow,
fcol + size, frow + size,
fcol, frow + size
};
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, vtx );
glTexCoordPointer( 2, GL_FLOAT, 0, tex );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
} }
image_t * image_t *
@ -190,6 +169,14 @@ RDraw_PicScaled(int x, int y, char *pic, float factor)
Scrap_Upload(); Scrap_Upload();
} }
if (gl->texnum == TEXNUM_SCRAPS)
{
R_UpdateGLBuffer(buf_2d, TEXNUM_SCRAPS, 0, 0, 1);
R_Buffer2DQuad(x, y, x + gl->width * factor, y + gl->height * factor,
gl->sl, gl->tl, gl->sh, gl->th);
return;
}
R_Bind(gl->texnum); R_Bind(gl->texnum);
GLfloat vtx[] = { GLfloat vtx[] = {
@ -235,31 +222,10 @@ RDraw_TileClear(int x, int y, int w, int h, char *pic)
return; return;
} }
R_Bind(image->texnum); R_UpdateGLBuffer(buf_2d, image->texnum, 0, 0, 1);
GLfloat vtx[] = { R_Buffer2DQuad(x, y, x + w, y + h, x / 64.0, y / 64.0,
x, y, ( x + w ) / 64.0, ( y + h ) / 64.0);
x + w, y,
x + w, y + h,
x, y + h
};
GLfloat tex[] = {
x / 64.0, y / 64.0,
( x + w ) / 64.0, y / 64.0,
( x + w ) / 64.0, ( y + h ) / 64.0,
x / 64.0, ( y + h ) / 64.0
};
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, vtx );
glTexCoordPointer( 2, GL_FLOAT, 0, tex );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
} }
/* /*
@ -306,6 +272,7 @@ RDraw_Fill(int x, int y, int w, int h, int c)
void void
RDraw_FadeScreen(void) RDraw_FadeScreen(void)
{ {
R_ApplyGLBuffer(); // draw what needs to be hidden
glEnable(GL_BLEND); glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glColor4f(0, 0, 0, 0.8); glColor4f(0, 0, 0, 0.8);

View file

@ -46,6 +46,7 @@ static qboolean vsyncActive = false;
void void
RI_EndFrame(void) RI_EndFrame(void)
{ {
R_ApplyGLBuffer(); // to draw buffered 2D text
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }

View file

@ -39,17 +39,18 @@
#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX #define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX
#endif #endif
#define TEXNUM_LIGHTMAPS 1024 #define MAX_LIGHTMAPS 128
#define TEXNUM_SCRAPS 1152
#define TEXNUM_IMAGES 1153
#define MAX_GLTEXTURES 1024
#define MAX_SCRAPS 1 #define MAX_SCRAPS 1
#define TEXNUM_LIGHTMAPS 1024
#define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS)
#define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS)
#define MAX_GLTEXTURES 1024
#define BLOCK_WIDTH 128 // default values; now defined in glstate_t #define BLOCK_WIDTH 128 // default values; now defined in glstate_t
#define BLOCK_HEIGHT 128 #define BLOCK_HEIGHT 128
#define REF_VERSION "Yamagi Quake II OpenGL Refresher" #define REF_VERSION "Yamagi Quake II OpenGL Refresher"
#define BACKFACE_EPSILON 0.01 #define BACKFACE_EPSILON 0.01
#define LIGHTMAP_BYTES 4 #define LIGHTMAP_BYTES 4
#define MAX_LIGHTMAPS 128 #define MAX_TEXTURE_UNITS 2
#define GL_LIGHTMAP_FORMAT GL_RGBA #define GL_LIGHTMAP_FORMAT GL_RGBA
/* up / down */ /* up / down */
@ -106,19 +107,17 @@ typedef enum
rserr_unknown rserr_unknown
} rserr_t; } rserr_t;
typedef enum
{
buf_2d
} buffered_draw_t;
#include "model.h" #include "model.h"
void R_SetDefaultState(void); void R_SetDefaultState(void);
extern float gldepthmin, gldepthmax; extern float gldepthmin, gldepthmax;
typedef struct
{
float x, y, z;
float s, t;
float r, g, b;
} glvert_t;
extern image_t gltextures[MAX_GLTEXTURES]; extern image_t gltextures[MAX_GLTEXTURES];
extern int numgltextures; extern int numgltextures;
@ -287,6 +286,11 @@ void R_TextureAlphaMode(char *string);
void R_TextureSolidMode(char *string); void R_TextureSolidMode(char *string);
int Scrap_AllocBlock(int w, int h, int *x, int *y); int Scrap_AllocBlock(int w, int h, int *x, int *y);
void R_ApplyGLBuffer(void);
void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha);
void R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty);
#ifdef DEBUG #ifdef DEBUG
void glCheckError_(const char *file, const char *function, int line); void glCheckError_(const char *file, const char *function, int line);
// Ideally, the following list should contain all OpenGL calls. // Ideally, the following list should contain all OpenGL calls.
@ -380,7 +384,7 @@ typedef struct
int lightmap_textures; int lightmap_textures;
int currenttextures[2]; int currenttextures[MAX_TEXTURE_UNITS];
int currenttmu; int currenttmu;
GLenum currenttarget; GLenum currenttarget;