From 0596d23e4c2de255092fe7e1f3f32513b6055440 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sat, 27 Jul 2024 23:18:06 -0400 Subject: [PATCH] GLES1 renderer: discard framebuffer Available only on GLES1, allows to use a "performance hint" to the GPU to discard the contents of depth and stencil buffers after each frame. Some hardware might want to reuse them, but Quake 2 doesn't work that way. Controlled by gl1_discardfb cvar, default `1`. --- doc/040_cvarlist.md | 4 +++ src/client/refresh/gl1/gl1_main.c | 41 +++++++++++++++++++++++++++ src/client/refresh/gl1/gl1_sdl.c | 7 +++++ src/client/refresh/gl1/header/local.h | 1 + src/client/refresh/gl1/header/qgl.h | 2 ++ src/client/refresh/gl1/qgl.c | 3 ++ 6 files changed, 58 insertions(+) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 6e343476..1dc10f2c 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -492,6 +492,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable` * **gl1_stencilshadow**: If `gl_shadows` is set to `1`, this makes them look a bit better (no flickering) by using the stencil buffer. +* **gl1_discardfb**: Only available in ES1. If set to `1` (default), + send a hint to discard framebuffers after finishing a frame. Useful + for GPUs that attempt to reuse them, something Quake 2 doesn't do. + ## Graphics (OpenGL 3.2 and OpenGL ES3 only) diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index c9e32345..0c8203b8 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -91,6 +91,7 @@ cvar_t *gl1_particle_square; cvar_t *gl1_palettedtexture; cvar_t *gl1_pointparameters; cvar_t *gl1_multitexture; +cvar_t *gl1_discardfb; cvar_t *gl_drawbuffer; cvar_t *gl_lightmap; @@ -1224,6 +1225,9 @@ R_Register(void) gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE); gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE); gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE); +#ifdef YQ2_GL1_GLES + gl1_discardfb = ri.Cvar_Get("gl1_discardfb", "1", CVAR_ARCHIVE); +#endif gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0); r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE); @@ -1641,6 +1645,43 @@ RI_Init(void) // ---- + /* Discard framebuffer: Available only on GLES1, enables the use of a "performance hint" + * to the graphic driver, to get rid of the contents of the depth and stencil buffers. + * Useful for some GPUs that may attempt to keep them and/or write them back to + * external/uniform memory, actions that are useless for Quake 2 rendering path. + * https://registry.khronos.org/OpenGL/extensions/EXT/EXT_discard_framebuffer.txt + */ + gl_config.discardfb = false; + +#ifdef YQ2_GL1_GLES + R_Printf(PRINT_ALL, " - Discard framebuffer: "); + + if (strstr(gl_config.extensions_string, "GL_EXT_discard_framebuffer")) + { + qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *)) + RI_GetProcAddress ("glDiscardFramebufferEXT"); + } + + if (gl1_discardfb->value) + { + if (qglDiscardFramebufferEXT) + { + gl_config.discardfb = true; + R_Printf(PRINT_ALL, "Okay\n"); + } + else + { + R_Printf(PRINT_ALL, "Failed\n"); + } + } + else + { + R_Printf(PRINT_ALL, "Disabled\n"); + } +#endif + + // ---- + /* Big lightmaps: this used to be fast, but after the implementation of the "GL Buffer", it * became too evident that the bigger the texture, the slower the call to glTexSubImage2D() is. * Original logic remains, but it's preferable not to make it visible to the user. diff --git a/src/client/refresh/gl1/gl1_sdl.c b/src/client/refresh/gl1/gl1_sdl.c index a47e802a..4f0dc592 100644 --- a/src/client/refresh/gl1/gl1_sdl.c +++ b/src/client/refresh/gl1/gl1_sdl.c @@ -47,6 +47,13 @@ void RI_EndFrame(void) { R_ApplyGLBuffer(); // to draw buffered 2D text +#ifdef YQ2_GL1_GLES + if (gl_config.discardfb) + { + static const GLenum attachments[] = { GL_DEPTH_EXT, GL_STENCIL_EXT }; + qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments); + } +#endif SDL_GL_SwapWindow(window); } diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 3f07e045..8514bffd 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -429,6 +429,7 @@ typedef struct qboolean palettedtexture; qboolean pointparameters; qboolean multitexture; + qboolean discardfb; // ---- diff --git a/src/client/refresh/gl1/header/qgl.h b/src/client/refresh/gl1/header/qgl.h index ef7e2472..ec1c05f9 100644 --- a/src/client/refresh/gl1/header/qgl.h +++ b/src/client/refresh/gl1/header/qgl.h @@ -100,5 +100,7 @@ extern void ( APIENTRY *qglColorTableEXT ) ( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * ); extern void ( APIENTRY *qglActiveTexture ) ( GLenum texture ); extern void ( APIENTRY *qglClientActiveTexture ) ( GLenum texture ); +extern void ( APIENTRY *qglDiscardFramebufferEXT ) ( GLenum target, + GLsizei numAttachments, const GLenum *attachments ); #endif diff --git a/src/client/refresh/gl1/qgl.c b/src/client/refresh/gl1/qgl.c index 913283a9..7c8f4ad0 100644 --- a/src/client/refresh/gl1/qgl.c +++ b/src/client/refresh/gl1/qgl.c @@ -44,6 +44,8 @@ void (APIENTRY *qglColorTableEXT)(GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); void (APIENTRY *qglActiveTexture) (GLenum texture); void (APIENTRY *qglClientActiveTexture) (GLenum texture); +void (APIENTRY *qglDiscardFramebufferEXT) (GLenum target, + GLsizei numAttachments, const GLenum *attachments); /* ========================================================================= */ @@ -54,6 +56,7 @@ void QGL_EXT_Reset ( void ) qglColorTableEXT = NULL; qglActiveTexture = NULL; qglClientActiveTexture = NULL; + qglDiscardFramebufferEXT = NULL; } /* ========================================================================= */