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,
while in GLES1 is enabled. Needs `gl1_multitexture 1` & `vid_restart`.
* **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.
* **gl1_discardfb**: If `1`, clear color, depth and stencil buffers at
the start of a frame, and discard them at the end if possible. If
`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)

View file

@ -150,6 +150,7 @@ void LM_FreeLightmapBuffers(void);
void Scrap_Free(void);
void Scrap_Init(void);
extern void R_SetDefaultState(void);
extern void R_ResetGLBuffer(void);
void
@ -630,6 +631,19 @@ R_PolyBlend(void)
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
R_SetupFrame(void)
{
@ -707,7 +721,7 @@ R_SetupFrame(void)
vid.height - r_newrefdef.height - r_newrefdef.y,
r_newrefdef.width, r_newrefdef.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5);
R_ResetClearColor();
glDisable(GL_SCISSOR_TEST);
}
}
@ -857,6 +871,19 @@ R_Clear(void)
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)
{
glClear(clearFlags);
@ -1183,9 +1210,9 @@ RI_RenderFrame(refdef_t *fd)
}
#ifdef YQ2_GL1_GLES
#define DEFAULT_LMCOPIES "1"
#define GLES1_ENABLED_ONLY "1"
#else
#define DEFAULT_LMCOPIES "0"
#define GLES1_ENABLED_ONLY "0"
#endif
void
@ -1242,10 +1269,8 @@ 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);
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", DEFAULT_LMCOPIES, CVAR_ARCHIVE);
#ifdef YQ2_GL1_GLES
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", "1", CVAR_ARCHIVE);
#endif
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE);
@ -1283,7 +1308,7 @@ R_Register(void)
ri.Cmd_AddCommand("gl_strings", R_Strings);
}
#undef DEFAULT_LMCOPIES
#undef GLES1_ENABLED_ONLY
/*
* Changes the video mode
@ -1687,13 +1712,14 @@ 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.
/* Discard framebuffer: Enables the use of a "performance hint" to the graphic
* 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
* external/uniform memory, actions that are useless for Quake 2 rendering path.
* 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
R_Printf(PRINT_ALL, " - Discard framebuffer: ");
@ -1706,9 +1732,8 @@ RI_Init(void)
if (gl1_discardfb->value)
{
if (qglDiscardFramebufferEXT)
if (qglDiscardFramebufferEXT) // enough to verify availability
{
gl_config.discardfb = true;
R_Printf(PRINT_ALL, "Okay\n");
}
else
@ -1738,6 +1763,7 @@ RI_Init(void)
// ----
R_ResetClearColor();
R_SetDefaultState();
Scrap_Init();
@ -1970,7 +1996,7 @@ RI_SetPalette(const unsigned char *palette)
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5);
R_ResetClearColor();
}
/* R_DrawBeam */

View file

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

View file

@ -38,6 +38,8 @@ static SDL_GLContext context = NULL;
qboolean IsHighDPIaware = false;
static qboolean vsyncActive = false;
extern cvar_t *gl1_discardfb;
// ----
/*
@ -47,13 +49,26 @@ void
RI_EndFrame(void)
{
R_ApplyGLBuffer(); // to draw buffered 2D text
#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 };
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments);
switch ((int)gl1_discardfb->value)
{
case 1:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 3, &attachments[0]);
break;
case 2:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, &attachments[1]);
break;
default:
break;
}
}
#endif
SDL_GL_SwapWindow(window);
}

View file

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