gl1_discardfb functionality expanded

Now also available in GL1. Includes a call to glClear at the beginning
of each frame, pointing to the same buffers that are discarded at the
end. When value is 1, operates over color, depth and stencil buffers.
When it's 2, only does depth and stencil, ignoring color. These
changes provide a performance improvement on mobile/embedded.
This commit is contained in:
Jaime Moreira 2024-09-20 19:36:08 -03:00
parent e21479cbd2
commit f2ea0b51b5
5 changed files with 64 additions and 26 deletions

View file

@ -517,9 +517,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
(dynamic lighting) causes slowdown. By default in GL1 is disabled, (dynamic lighting) causes slowdown. By default in GL1 is disabled,
while in GLES1 is enabled. Needs `gl1_multitexture 1` & `vid_restart`. while in GLES1 is enabled. Needs `gl1_multitexture 1` & `vid_restart`.
* **gl1_discardfb**: Only available in ES1. If set to `1` (default), * **gl1_discardfb**: If `1`, clear color, depth and stencil buffers at
send a hint to discard framebuffers after finishing a frame. Useful the start of a frame, and discard them at the end if possible. If
for GPUs that attempt to reuse them, something Quake 2 doesn't do. `2`, do only depth and stencil, no color. Increases performance in
mobile / embedded. Default in GL1 is `0`, while in GLES1 is `1`.
## Graphics (OpenGL 3.2 and OpenGL ES3 only) ## Graphics (OpenGL 3.2 and OpenGL ES3 only)

View file

@ -150,6 +150,7 @@ void LM_FreeLightmapBuffers(void);
void Scrap_Free(void); void Scrap_Free(void);
void Scrap_Init(void); void Scrap_Init(void);
extern void R_SetDefaultState(void);
extern void R_ResetGLBuffer(void); extern void R_ResetGLBuffer(void);
void void
@ -630,6 +631,19 @@ R_PolyBlend(void)
glColor4f(1, 1, 1, 1); glColor4f(1, 1, 1, 1);
} }
static void
R_ResetClearColor(void)
{
if (gl1_discardfb->value == 1 && !r_clear->value)
{
glClearColor(0, 0, 0, 0.5);
}
else
{
glClearColor(1, 0, 0.5, 0.5);
}
}
void void
R_SetupFrame(void) R_SetupFrame(void)
{ {
@ -707,7 +721,7 @@ R_SetupFrame(void)
vid.height - r_newrefdef.height - r_newrefdef.y, vid.height - r_newrefdef.height - r_newrefdef.y,
r_newrefdef.width, r_newrefdef.height); r_newrefdef.width, r_newrefdef.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5); R_ResetClearColor();
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
} }
@ -857,6 +871,19 @@ R_Clear(void)
gldepthmax = 1; gldepthmax = 1;
} }
switch ((int)gl1_discardfb->value)
{
case 1:
if (gl_state.stereo_mode == STEREO_MODE_NONE)
{
clearFlags |= GL_COLOR_BUFFER_BIT;
}
case 2:
clearFlags |= GL_STENCIL_BUFFER_BIT;
default:
break;
}
if (clearFlags) if (clearFlags)
{ {
glClear(clearFlags); glClear(clearFlags);
@ -1183,9 +1210,9 @@ RI_RenderFrame(refdef_t *fd)
} }
#ifdef YQ2_GL1_GLES #ifdef YQ2_GL1_GLES
#define DEFAULT_LMCOPIES "1" #define GLES1_ENABLED_ONLY "1"
#else #else
#define DEFAULT_LMCOPIES "0" #define GLES1_ENABLED_ONLY "0"
#endif #endif
void void
@ -1242,10 +1269,8 @@ R_Register(void)
gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE); gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE);
gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE); gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE);
gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE); gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE);
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", DEFAULT_LMCOPIES, CVAR_ARCHIVE); gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
#ifdef YQ2_GL1_GLES gl1_discardfb = ri.Cvar_Get("gl1_discardfb", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", "1", CVAR_ARCHIVE);
#endif
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0); gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE); r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE);
@ -1283,7 +1308,7 @@ R_Register(void)
ri.Cmd_AddCommand("gl_strings", R_Strings); ri.Cmd_AddCommand("gl_strings", R_Strings);
} }
#undef DEFAULT_LMCOPIES #undef GLES1_ENABLED_ONLY
/* /*
* Changes the video mode * Changes the video mode
@ -1687,28 +1712,28 @@ RI_Init(void)
// ---- // ----
/* Discard framebuffer: Available only on GLES1, enables the use of a "performance hint" /* Discard framebuffer: Enables the use of a "performance hint" to the graphic
* to the graphic driver, to get rid of the contents of the depth and stencil buffers. * driver in GLES1, to get rid of the contents of the different framebuffers.
* Useful for some GPUs that may attempt to keep them and/or write them back to * 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. * external/uniform memory, actions that are useless for Quake 2 rendering path.
* https://registry.khronos.org/OpenGL/extensions/EXT/EXT_discard_framebuffer.txt * https://registry.khronos.org/OpenGL/extensions/EXT/EXT_discard_framebuffer.txt
* This extension is used by 'gl1_discardfb', and regardless of its existence,
* that cvar will enable glClear at the start of each frame, helping mobile GPUs.
*/ */
gl_config.discardfb = false;
#ifdef YQ2_GL1_GLES #ifdef YQ2_GL1_GLES
R_Printf(PRINT_ALL, " - Discard framebuffer: "); R_Printf(PRINT_ALL, " - Discard framebuffer: ");
if (strstr(gl_config.extensions_string, "GL_EXT_discard_framebuffer")) if (strstr(gl_config.extensions_string, "GL_EXT_discard_framebuffer"))
{ {
qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *)) qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *))
RI_GetProcAddress ("glDiscardFramebufferEXT"); RI_GetProcAddress ("glDiscardFramebufferEXT");
} }
if (gl1_discardfb->value) if (gl1_discardfb->value)
{ {
if (qglDiscardFramebufferEXT) if (qglDiscardFramebufferEXT) // enough to verify availability
{ {
gl_config.discardfb = true;
R_Printf(PRINT_ALL, "Okay\n"); R_Printf(PRINT_ALL, "Okay\n");
} }
else else
@ -1738,6 +1763,7 @@ RI_Init(void)
// ---- // ----
R_ResetClearColor();
R_SetDefaultState(); R_SetDefaultState();
Scrap_Init(); Scrap_Init();
@ -1970,7 +1996,7 @@ RI_SetPalette(const unsigned char *palette)
glClearColor(0, 0, 0, 0); glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5); R_ResetClearColor();
} }
/* R_DrawBeam */ /* R_DrawBeam */

View file

@ -169,7 +169,6 @@ R_Strings(void)
void void
R_SetDefaultState(void) R_SetDefaultState(void)
{ {
glClearColor(1, 0, 0.5, 0.5);
glDisable(GL_MULTISAMPLE); glDisable(GL_MULTISAMPLE);
glCullFace(GL_FRONT); glCullFace(GL_FRONT);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);

View file

@ -38,6 +38,8 @@ static SDL_GLContext context = NULL;
qboolean IsHighDPIaware = false; qboolean IsHighDPIaware = false;
static qboolean vsyncActive = false; static qboolean vsyncActive = false;
extern cvar_t *gl1_discardfb;
// ---- // ----
/* /*
@ -47,13 +49,26 @@ void
RI_EndFrame(void) RI_EndFrame(void)
{ {
R_ApplyGLBuffer(); // to draw buffered 2D text R_ApplyGLBuffer(); // to draw buffered 2D text
#ifdef YQ2_GL1_GLES #ifdef YQ2_GL1_GLES
if (gl_config.discardfb) static const GLenum attachments[3] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT};
if (qglDiscardFramebufferEXT)
{ {
static const GLenum attachments[] = { GL_DEPTH_EXT, GL_STENCIL_EXT }; switch ((int)gl1_discardfb->value)
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments); {
case 1:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 3, &attachments[0]);
break;
case 2:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, &attachments[1]);
break;
default:
break;
}
} }
#endif #endif
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }

View file

@ -148,8 +148,6 @@ typedef struct // 832k aprox.
#include "model.h" #include "model.h"
void R_SetDefaultState(void);
extern glbuffer_t gl_buf; extern glbuffer_t gl_buf;
extern float gldepthmin, gldepthmax; extern float gldepthmin, gldepthmax;
@ -427,7 +425,6 @@ typedef struct
qboolean pointparameters; qboolean pointparameters;
qboolean multitexture; qboolean multitexture;
qboolean lightmapcopies; // many copies of same lightmap, for embedded qboolean lightmapcopies; // many copies of same lightmap, for embedded
qboolean discardfb;
// ---- // ----