Font rendering speedup

We now use a single texture for all text rendering instead of
generating/freeing textures for every bit of text.
This commit is contained in:
laochailan 2017-03-28 16:52:53 +02:00
parent 08657f9736
commit b804f53a45
6 changed files with 109 additions and 12 deletions

View file

@ -24,24 +24,80 @@ TTF_Font *load_font(char *name, int size) {
return f;
}
void fontrenderer_init(FontRenderer *f) {
glGenBuffers(1,&f->pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, f->pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, FONTREN_MAXW*FONTREN_MAXH*4, NULL, GL_STREAM_DRAW);
glGenTextures(1,&f->tex.gltex);
f->tex.truew = FONTREN_MAXW;
f->tex.trueh = FONTREN_MAXH;
glBindTexture(GL_TEXTURE_2D,f->tex.gltex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, f->tex.truew, f->tex.trueh, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
void fontrenderer_free(FontRenderer *f) {
glDeleteBuffers(1,&f->pbo);
glDeleteTextures(1,&f->tex.gltex);
}
void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font) {
SDL_Color clr = {255,255,255};
SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, clr);
assert(surf != NULL);
if(surf->w > FONTREN_MAXW || surf->h > FONTREN_MAXH) {
log_fatal("Text drawn (%dx%d) is too big for the internal buffer (%dx%d).", surf->pitch, surf->h, FONTREN_MAXW, FONTREN_MAXH);
}
f->tex.w = surf->w;
f->tex.h = surf->h;
glBindTexture(GL_TEXTURE_2D,f->tex.gltex);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, f->pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, FONTREN_MAXW*FONTREN_MAXH*4, NULL, GL_STREAM_DRAW);
// zero pad the texture
int winw = surf->w+1; // zero pad the texture
int winh = surf->h+1;
uint32_t *pixels = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
for(int y = 0; y < surf->h; y++) {
memcpy(pixels+y*winw, ((uint8_t *)surf->pixels)+y*surf->pitch, surf->w*4);
pixels[y*winw+surf->w]=0; // set the border to zero to avoid previously drawn text bleeding in.
}
memset(pixels+(winh-1)*winw,0,winw*4);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,winw,winh,GL_RGBA,GL_UNSIGNED_BYTE,0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
SDL_FreeSurface(surf);
}
void init_fonts(void) {
TTF_Init();
fontrenderer_init(&resources.fontren);
_fonts.standard = load_font("gfx/LinBiolinum.ttf", 20);
_fonts.mainmenu = load_font("gfx/immortal.ttf", 35);
}
Texture *load_text(const char *text, TTF_Font *font) {
Texture *tex = malloc(sizeof(Texture));
SDL_Color clr = {255,255,255};
SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, clr);
assert(surf != NULL);
void free_fonts(void) {
fontrenderer_free(&resources.fontren);
TTF_CloseFont(_fonts.standard);
TTF_CloseFont(_fonts.mainmenu);
load_sdl_surf(surf, tex);
SDL_FreeSurface(surf);
return tex;
TTF_Quit();
}
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font) {
@ -54,7 +110,8 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
*nl = '\0';
}
Texture *tex = load_text(buf, font);
fontrenderer_draw(&resources.fontren, buf, font);
Texture *tex = &resources.fontren.tex;
switch(align) {
case AL_Center:
@ -73,9 +130,9 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
if(tex->h&1)
y += 0.5;
glEnable(GL_TEXTURE_2D);
draw_texture_p(x, y, tex);
free_texture(tex);
free(buf);
}

View file

@ -17,9 +17,28 @@ typedef enum {
AL_Right
} Alignment;
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
enum {
FONTREN_MAXW = 512,
FONTREN_MAXH = 512
};
typedef struct FontRenderer FontRenderer;
struct FontRenderer {
Texture tex;
GLuint pbo;
};
void fontrenderer_init(FontRenderer *f);
void fontrenderer_free(FontRenderer *f);
void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font);
Texture *load_text(const char *text, TTF_Font *font);
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font);
void init_fonts(void);
void free_fonts(void);
int stringwidth(char *s, TTF_Font *font);
int stringheight(char *s, TTF_Font *font);
int charwidth(char c, TTF_Font *font);

View file

@ -404,6 +404,7 @@ void load_resources(void) {
}
void free_resources(bool all) {
free_fonts();
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
ResourceHandler *handler = get_handler(type);

View file

@ -102,6 +102,7 @@ typedef struct Resources {
FBO fbg[2];
FBO fsec;
PostprocessShader *stage_postprocess;
FontRenderer fontren;
} Resources;
extern Resources resources;

View file

@ -180,6 +180,7 @@ typedef const GLubyte * (GLAPIENTRY *tsglGetString_ptr)(GLenum name);
typedef GLint (APIENTRY *tsglGetUniformLocation_ptr)(GLuint program, const GLchar *name);
typedef void (APIENTRY *tsglLinkProgram_ptr)(GLuint program);
typedef void (GLAPIENTRY *tsglLoadIdentity_ptr)(void);
typedef void * (APIENTRY *tsglMapBuffer_ptr)(GLenum target, GLenum access);
typedef void (GLAPIENTRY *tsglMatrixMode_ptr)(GLenum mode);
typedef void (GLAPIENTRY *tsglNormalPointer_ptr)(GLenum type, GLsizei stride, const GLvoid *ptr);
typedef void (GLAPIENTRY *tsglOrtho_ptr)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val);
@ -195,6 +196,7 @@ typedef void (GLAPIENTRY *tsglTexCoordPointer_ptr)(GLint size, GLenum type, GLsi
typedef void (GLAPIENTRY *tsglTexImage2D_ptr)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (GLAPIENTRY *tsglTexParameterf_ptr)(GLenum target, GLenum pname, GLfloat param);
typedef void (GLAPIENTRY *tsglTexParameteri_ptr)(GLenum target, GLenum pname, GLint param);
typedef void (GLAPIENTRY *tsglTexSubImage2D_ptr)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (GLAPIENTRY *tsglTranslatef_ptr)(GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRY *tsglUniform1f_ptr)(GLint location, GLfloat v0);
typedef void (APIENTRY *tsglUniform1fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
@ -215,6 +217,7 @@ typedef void (APIENTRY *tsglUniform4fv_ptr)(GLint location, GLsizei count, const
typedef void (APIENTRY *tsglUniform4fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform4iv_ptr)(GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRY *tsglUniform4uiv_ptr)(GLint location, GLsizei count, const GLuint *value);
typedef GLboolean (APIENTRY *tsglUnmapBuffer_ptr)(GLenum target);
typedef void (APIENTRY *tsglUseProgram_ptr)(GLuint program);
typedef void (GLAPIENTRY *tsglVertexPointer_ptr)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLsizei height);
@ -270,6 +273,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glGetUniformLocation
#undef glLinkProgram
#undef glLoadIdentity
#undef glMapBuffer
#undef glMatrixMode
#undef glNormalPointer
#undef glOrtho
@ -285,6 +289,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glTexImage2D
#undef glTexParameterf
#undef glTexParameteri
#undef glTexSubImage2D
#undef glTranslatef
#undef glUniform1f
#undef glUniform1fv
@ -305,6 +310,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glUniform4fv
#undef glUniform4iv
#undef glUniform4uiv
#undef glUnmapBuffer
#undef glUseProgram
#undef glVertexPointer
#undef glViewport
@ -361,6 +367,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glGetUniformLocation tsglGetUniformLocation
#define glLinkProgram tsglLinkProgram
#define glLoadIdentity tsglLoadIdentity
#define glMapBuffer tsglMapBuffer
#define glMatrixMode tsglMatrixMode
#define glNormalPointer tsglNormalPointer
#define glOrtho tsglOrtho
@ -376,6 +383,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glTexImage2D tsglTexImage2D
#define glTexParameterf tsglTexParameterf
#define glTexParameteri tsglTexParameteri
#define glTexSubImage2D tsglTexSubImage2D
#define glTranslatef tsglTranslatef
#define glUniform1f tsglUniform1f
#define glUniform1fv tsglUniform1fv
@ -396,6 +404,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glUniform4fv tsglUniform4fv
#define glUniform4iv tsglUniform4iv
#define glUniform4uiv tsglUniform4uiv
#define glUnmapBuffer tsglUnmapBuffer
#define glUseProgram tsglUseProgram
#define glVertexPointer tsglVertexPointer
#define glViewport tsglViewport
@ -454,6 +463,7 @@ GLDEF(glGetString, tsglGetString, tsglGetString_ptr) \
GLDEF(glGetUniformLocation, tsglGetUniformLocation, tsglGetUniformLocation_ptr) \
GLDEF(glLinkProgram, tsglLinkProgram, tsglLinkProgram_ptr) \
GLDEF(glLoadIdentity, tsglLoadIdentity, tsglLoadIdentity_ptr) \
GLDEF(glMapBuffer, tsglMapBuffer, tsglMapBuffer_ptr) \
GLDEF(glMatrixMode, tsglMatrixMode, tsglMatrixMode_ptr) \
GLDEF(glNormalPointer, tsglNormalPointer, tsglNormalPointer_ptr) \
GLDEF(glOrtho, tsglOrtho, tsglOrtho_ptr) \
@ -469,6 +479,7 @@ GLDEF(glTexCoordPointer, tsglTexCoordPointer, tsglTexCoordPointer_ptr) \
GLDEF(glTexImage2D, tsglTexImage2D, tsglTexImage2D_ptr) \
GLDEF(glTexParameterf, tsglTexParameterf, tsglTexParameterf_ptr) \
GLDEF(glTexParameteri, tsglTexParameteri, tsglTexParameteri_ptr) \
GLDEF(glTexSubImage2D, tsglTexSubImage2D, tsglTexSubImage2D_ptr) \
GLDEF(glTranslatef, tsglTranslatef, tsglTranslatef_ptr) \
GLDEF(glUniform1f, tsglUniform1f, tsglUniform1f_ptr) \
GLDEF(glUniform1fv, tsglUniform1fv, tsglUniform1fv_ptr) \
@ -489,6 +500,7 @@ GLDEF(glUniform4fv, tsglUniform4fv, tsglUniform4fv_ptr) \
GLDEF(glUniform4fv, tsglUniform4fv, tsglUniform4fv_ptr) \
GLDEF(glUniform4iv, tsglUniform4iv, tsglUniform4iv_ptr) \
GLDEF(glUniform4uiv, tsglUniform4uiv, tsglUniform4uiv_ptr) \
GLDEF(glUnmapBuffer, tsglUnmapBuffer, tsglUnmapBuffer_ptr) \
GLDEF(glUseProgram, tsglUseProgram, tsglUseProgram_ptr) \
GLDEF(glVertexPointer, tsglVertexPointer, tsglVertexPointer_ptr) \
GLDEF(glViewport, tsglViewport, tsglViewport_ptr)
@ -551,6 +563,7 @@ GLAPI const GLubyte * GLAPIENTRY glGetString( GLenum name );
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
GLAPI void APIENTRY glLinkProgram (GLuint program);
GLAPI void GLAPIENTRY glLoadIdentity( void );
GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access);
GLAPI void GLAPIENTRY glMatrixMode( GLenum mode );
GLAPI void GLAPIENTRY glNormalPointer( GLenum type, GLsizei stride, const GLvoid *ptr );
GLAPI void GLAPIENTRY glOrtho( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
@ -566,6 +579,7 @@ GLAPI void GLAPIENTRY glTexCoordPointer( GLint size, GLenum type, GLsizei stride
GLAPI void GLAPIENTRY glTexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
GLAPI void GLAPIENTRY glTexParameterf( GLenum target, GLenum pname, GLfloat param );
GLAPI void GLAPIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param );
GLAPI void GLAPIENTRY glTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
GLAPI void GLAPIENTRY glTranslatef( GLfloat x, GLfloat y, GLfloat z );
GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0);
GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value);
@ -586,6 +600,7 @@ GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *
GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value);
GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value);
GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target);
GLAPI void APIENTRY glUseProgram (GLuint program);
GLAPI void GLAPIENTRY glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei height );
@ -641,6 +656,7 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglGetUniformLocation glGetUniformLocation
#define tsglLinkProgram glLinkProgram
#define tsglLoadIdentity glLoadIdentity
#define tsglMapBuffer glMapBuffer
#define tsglMatrixMode glMatrixMode
#define tsglNormalPointer glNormalPointer
#define tsglOrtho glOrtho
@ -656,6 +672,7 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglTexImage2D glTexImage2D
#define tsglTexParameterf glTexParameterf
#define tsglTexParameteri glTexParameteri
#define tsglTexSubImage2D glTexSubImage2D
#define tsglTranslatef glTranslatef
#define tsglUniform1f glUniform1f
#define tsglUniform1fv glUniform1fv
@ -676,6 +693,7 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglUniform4fv glUniform4fv
#define tsglUniform4iv glUniform4iv
#define tsglUniform4uiv glUniform4uiv
#define tsglUnmapBuffer glUnmapBuffer
#define tsglUseProgram glUseProgram
#define tsglVertexPointer glVertexPointer
#define tsglViewport glViewport

View file

@ -107,6 +107,7 @@ static void APIENTRY video_gl_debug(
case GL_DEBUG_SEVERITY_LOW: strsev = "low"; break;
case GL_DEBUG_SEVERITY_MEDIUM: strsev = "medium"; break;
case GL_DEBUG_SEVERITY_HIGH: strsev = "high"; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: if(type == GL_DEBUG_TYPE_OTHER) return; break;
}
log_custom(lvl, "[OpenGL debug, %s, %s] %i: %s", strtype, strsev, id, message);